123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136(*
* 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.
*)openSexplib.StdexceptionParse_errorofstring*string[@@derivingsexp]letneed_morex=Parse_error("not enough data",x)typet=Bytes.t(* length 6 only *)letcompare=Bytes.compare(* Raw MAC address off the wire (network endian) *)letof_bytes_exnx=ifString.lengthx<>6thenraise(Parse_error("MAC is exactly 6 bytes",x))elseBytes.of_stringxletof_bytesx=trySome(of_bytes_exnx)with_->Noneletint_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]]in(if!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)));incri;done;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=trySome(of_string_exnx)with_->Noneletchrixi=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_bytesx=Bytes.to_stringxletppppfi=Format.fprintfppf"%s"(to_stringi)letsexp_of_tm=Sexplib.Sexp.Atom(to_stringm)lett_of_sexpm=matchmwith|Sexplib.Sexp.Atomm->of_string_exnm|_->raise(Failure"Macaddr.t: Unexpected non-atom in sexp")letbroadcast=Bytes.make6'\255'letmake_localbytegenf=letx=Bytes.create6in(* set locally administered and unicast bits *)Bytes.setx0(Char.chr((((bytegenf0)lor2)lsr1)lsl1));fori=1to5doBytes.setxi(Char.chr(bytegenfi))done;xletget_ouix=((chrix0)lsl16)lor((chrix1)lsl8)lor(chrix2)letis_localx=(((chrix0)lsr1)land1)=1letis_unicastx=((chrix0)land1)=0