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
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 = Bytes.t
let compare = Bytes.compare
let of_octets_exn x =
if String.length x <> 6 then raise (Parse_error ("MAC is exactly 6 bytes", x))
else Bytes.of_string x
let of_octets x = try_with_result of_octets_exn x
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_with_result of_string_exn x
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_octets x = Bytes.to_string x
let pp ppf i = Format.fprintf ppf "%s" (to_string i)
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