1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798(*
* 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=string(* length 6 only *)letcompare=String.compare(* Raw MAC address off the wire (network endian) *)letof_octets_exnx=ifString.lengthx<>6thenraise(Parse_error("MAC is exactly 6 bytes",x))elsexletof_octetsx=try_with_resultof_octets_exnxexceptionInvalid_hex_digitofcharlethex_digitc=matchChar.uppercase_asciicwith|'0'..'9'asc->Char.codec-48|'A'..'F'asc->Char.codec-55|c->raise_notrace(Invalid_hex_digitc)lethex_bytexi=(hex_digit(String.getxi)lsl4)+hex_digit(String.getx(succi))(* Read a MAC address colon-separated string *)letof_string_exnx=ifString.lengthx<(2*6)+5thenraise(need_morex);ifString.lengthx<>(2*6)+5thenraise(Parse_error("macaddr string is too long",x));letm=Bytes.create6intryfori=0to5doBytes.set_uint8mi(hex_bytex(3*i))done;letsep=x.[2]in(matchsepwith|':'|'-'->()|_->raise(Parse_error(Printf.sprintf"Invalid macaddr separator: %C"sep,x)));fori=1to4doifx.[(3*i)+2]<>septhenraise(Parse_error(Printf.sprintf"Invalid macaddr separator, first was %C, now %C"sepx.[(3*i)+2],x))done;Bytes.unsafe_to_stringmwithInvalid_hex_digitc->raise(Parse_error(Printf.sprintf"Invalid macaddr hex digit: %C"c,x))letof_stringx=try_with_resultof_string_exnxletchrixi=Char.codex.[i]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=xletppppfi=Format.fprintfppf"%s"(to_stringi)letbroadcast=String.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;Bytes.unsafe_to_stringxletget_ouix=(chrix0lsl16)lor(chrix1lsl8)lorchrix2letis_localx=(chrix0lsr1)land1=1letis_unicastx=chrix0land1=0