1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
|
(*
* 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.
*)
exception Parse_error of string * string
let need_more x = Parse_error ("not enough data", x)
let try_with_result fn a =
try Ok (fn a) with Parse_error (msg, _) -> Error (`Msg ("Macaddr: " ^ msg))
type t = string (* length 6 only *)
let compare = String.compare
(* Raw MAC address off the wire (network endian) *)
let of_octets_exn x =
if String.length x <> 6 then raise (Parse_error ("MAC is exactly 6 bytes", x))
else x
let of_octets x = try_with_result of_octets_exn x
exception Invalid_hex_digit of char
let hex_digit c =
match Char.uppercase_ascii c with
| '0' .. '9' as c -> Char.code c - 48
| 'A' .. 'F' as c -> Char.code c - 55
| c -> raise_notrace (Invalid_hex_digit c)
let hex_byte x i =
(hex_digit (String.get x i) lsl 4) + hex_digit (String.get x (succ i))
(* Read a MAC address colon-separated string *)
let of_string_exn x =
if String.length x < (2 * 6) + 5 then raise (need_more x);
if String.length x <> (2 * 6) + 5 then
raise (Parse_error ("macaddr string is too long", x));
let m = Bytes.create 6 in
try
for i = 0 to 5 do
Bytes.set_uint8 m i (hex_byte x (3 * i))
done;
let sep = x.[2] in
(match sep with
| ':' | '-' -> ()
| _ ->
raise
(Parse_error (Printf.sprintf "Invalid macaddr separator: %C" sep, x)));
for i = 1 to 4 do
if x.[(3 * i) + 2] <> sep then
raise
(Parse_error
( Printf.sprintf "Invalid macaddr separator, first was %C, now %C"
sep
x.[(3 * i) + 2],
x ))
done;
Bytes.unsafe_to_string m
with Invalid_hex_digit c ->
raise (Parse_error (Printf.sprintf "Invalid macaddr hex digit: %C" c, x))
let of_string x = try_with_result of_string_exn x
let chri x i = Char.code x.[i]
let to_string ?(sep = ':') x =
Printf.sprintf "%02x%c%02x%c%02x%c%02x%c%02x%c%02x" (chri x 0) sep (chri x 1)
sep (chri x 2) sep (chri x 3) sep (chri x 4) sep (chri x 5)
let to_octets x = x
let pp ppf i = Format.fprintf ppf "%s" (to_string i)
let broadcast = String.make 6 '\255'
let make_local bytegenf =
let x = Bytes.create 6 in
(* set locally administered and unicast bits *)
Bytes.set x 0 (Char.chr (((bytegenf 0 lor 2) lsr 1) lsl 1));
for i = 1 to 5 do
Bytes.set x i (Char.chr (bytegenf i))
done;
Bytes.unsafe_to_string x
let get_oui x = (chri x 0 lsl 16) lor (chri x 1 lsl 8) lor chri x 2
let is_local x = (chri x 0 lsr 1) land 1 = 1
let is_unicast x = chri x 0 land 1 = 0
|