123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114(*
* Copyright (c) 2010 Anil Madhavapeddy <anil@recoil.org>
* Copyright (c) 2014 David Sheets <sheets@alum.mit.edu>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*)exceptionParse_errorofstring*stringletneed_morex=Parse_error("not enough data",x)lettry_with_resultfna=tryOk(fna)withParse_error(msg,_)->Error(`Msg("Macaddr: "^msg))typet=Bytes.t(* length 6 only *)letcompare=Bytes.compare(* Raw MAC address off the wire (network endian) *)letof_octets_exnx=ifString.lengthx<>6thenraise(Parse_error("MAC is exactly 6 bytes",x))elseBytes.of_stringxletof_octetsx=try_with_resultof_octets_exnxletint_of_hex_charc=letc=int_of_char(Char.uppercase_asciic)-48inifc>9thenifc>16thenc-7(* upper hex offset *)else-1(* :;<=>?@ *)elsecletis_hexi=i>=0&&i<16letbad_charis=letmsg=Printf.sprintf"invalid character '%c' at %d"s.[i]iinParse_error(msg,s)letparse_hex_inttermsi=letlen=String.lengthsinletrechexprev=letj=!iinifj>=lenthenprevelseletc=s.[j]inletk=int_of_hex_charcinifis_hexkthen(incri;hex((prevlsl4)+k))elseifList.memctermthenprevelseraise(bad_charjs)inleti=!iinifi<lenthenifis_hex(int_of_hex_chars.[i])thenhex0elseraise(bad_charis)elseraise(need_mores)letparse_sextuplesi=letm=Bytes.create6intryletp=!iinBytes.setm0(Char.chr(parse_hex_int[':';'-']si));if!i>=String.lengthsthenraise(need_mores)elseletsep=[s.[!i]]inif!i-p<>2thenraise(Parse_error("hex pairs required",s));incri;fork=1to4doletp=!iinBytes.setmk(Char.chr(parse_hex_intsepsi));if!i-p<>2thenraise(Parse_error("hex pairs required",s));incridone;letp=!iinBytes.setm5(Char.chr(parse_hex_int[]si));if!i-p<>2thenraise(Parse_error("hex pairs required",s));mwithInvalid_argument_->raise(Parse_error("address segment too large",s))(* Read a MAC address colon-separated string *)letof_string_exnx=parse_sextuplex(ref0)letof_stringx=try_with_resultof_string_exnxletchrixi=Char.code(Bytes.getxi)letto_string?(sep=':')x=Printf.sprintf"%02x%c%02x%c%02x%c%02x%c%02x%c%02x"(chrix0)sep(chrix1)sep(chrix2)sep(chrix3)sep(chrix4)sep(chrix5)letto_octetsx=Bytes.to_stringxletppppfi=Format.fprintfppf"%s"(to_stringi)letbroadcast=Bytes.make6'\255'letmake_localbytegenf=letx=Bytes.create6in(* set locally administered and unicast bits *)Bytes.setx0(Char.chr(((bytegenf0lor2)lsr1)lsl1));fori=1to5doBytes.setxi(Char.chr(bytegenfi))done;xletget_ouix=(chrix0lsl16)lor(chrix1lsl8)lorchrix2letis_localx=(chrix0lsr1)land1=1letis_unicastx=chrix0land1=0