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
134
135
136
open Sexplib.Std
exception Parse_error of string * string [@@deriving sexp]
let need_more x = Parse_error ("not enough data", x)
type t = Bytes.t
let compare = Bytes.compare
let of_bytes_exn x =
if String.length x <> 6
then raise (Parse_error ("MAC is exactly 6 bytes", x))
else Bytes.of_string 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_ascii c) - 48 in
if c > 9
then if c > 16
then c - 7
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 = Bytes.create 6 in
try
let p = !i in
Bytes.set 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
Bytes.set 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
Bytes.set 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 _ ->
raise (Parse_error ("address segment too large",s))
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 (Bytes.get 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 = Bytes.to_string x
let pp ppf i =
Format.fprintf ppf "%s" (to_string i)
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 = Bytes.make 6 '\255'
let make_local bytegenf =
let x = Bytes.create 6 in
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;
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