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 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
|
(*
* 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.
*)
open Sexplib.Std
exception Parse_error of string * string with sexp
let need_more x = Parse_error ("not enough data", x)
type t = string (* length 6 only *)
let compare = String.compare
(* Raw MAC address off the wire (network endian) *)
let of_bytes_exn x =
if String.length x <> 6
then raise (Parse_error ("MAC is exactly 6 bytes", x))
else x
let of_bytes x = try Some (of_bytes_exn x) with _ -> None
let int_of_hex_char c =
let c = int_of_char (Char.uppercase c) - 48 in
if c > 9
then if c > 16
then c - 7 (* upper hex offset *)
else -1 (* :;<=>?@ *)
else c
let is_hex i = i >=0 && i < 16
let bad_char i s =
let msg = Printf.sprintf "invalid character '%c' at %d" s.[i] i
in Parse_error (msg, s)
let parse_hex_int term s i =
let len = String.length s in
let rec hex prev =
let j = !i in
if j >= len then prev
else let c = s.[j] in
let k = int_of_hex_char c in
if is_hex k
then (incr i; hex ((prev lsl 4) + k))
else if List.mem c term
then prev
else raise (bad_char j s)
in
let i = !i in
if i < len
then if is_hex (int_of_hex_char s.[i])
then hex 0
else raise (bad_char i s)
else raise (need_more s)
let parse_sextuple s i =
let m = String.create 6 in
try
let p = !i in
m.[0] <- Char.chr (parse_hex_int [':';'-'] s i);
if !i >= String.length s
then raise (need_more s)
else
let sep = [s.[!i]] in
(if !i - p <> 2 then raise (Parse_error ("hex pairs required",s)));
incr i;
for k=1 to 4 do
let p = !i in
m.[k] <- Char.chr (parse_hex_int sep s i);
(if !i - p <> 2 then raise (Parse_error ("hex pairs required",s)));
incr i;
done;
let p = !i in
m.[5] <- Char.chr (parse_hex_int [] s i);
(if !i - p <> 2 then raise (Parse_error ("hex pairs required",s)));
m
with Invalid_argument "Char.chr" ->
raise (Parse_error ("address segment too large",s))
(* Read a MAC address colon-separated string *)
let of_string_exn x = parse_sextuple x (ref 0)
let of_string x = try Some (of_string_exn x) with _ -> None
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_bytes x = x
let sexp_of_t m = Sexplib.Sexp.Atom (to_string m)
let t_of_sexp m =
match m with
| Sexplib.Sexp.Atom m -> of_string_exn m
| _ -> raise (Failure "Macaddr.t: Unexpected non-atom in sexp")
let broadcast = String.make 6 '\255'
let make_local bytegenf =
let x = String.create 6 in
(* set locally administered and unicast bits *)
x.[0] <- Char.chr ((((bytegenf 0) lor 2) lsr 1) lsl 1);
for i = 1 to 5 do x.[i] <- Char.chr (bytegenf i) done;
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
|