3 * Wireshark - Network traffic analyzer
4 * By Gerald Combs <gerald@wireshark.org>
5 * Copyright 1998 Gerald Combs
7 * SPDX-License-Identifier: GPL-2.0-or-later
13 // MA-L / OUI - MAC Address Block Large (24-bit prefix)
15 // MA-M - MAC Address Block Medium (28-bit prefix)
17 // MA-S / OUI-36 - MAC Address Block Small (36-bit prefix)
22 /* Identifies the 3-byte prefix as part of MA-M or MA-S (or MA-L if none of those). */
28 const char *short_name
;
29 const char *long_name
;
34 const char *short_name
;
35 const char *long_name
;
40 const char *short_name
;
41 const char *long_name
;
44 #include "manuf-data.c"
47 compare_oui24_registry(const void *key
, const void *element
)
49 const uint8_t *addr
= (const uint8_t *)key
;
50 const manuf_registry_t
*entry
= (const manuf_registry_t
*)element
;
52 return memcmp(addr
, entry
->oui24
, 3);
56 compare_oui24_entry(const void *key
, const void *element
)
58 const uint8_t *addr
= (const uint8_t *)key
;
59 const manuf_oui24_t
*oui
= (const manuf_oui24_t
*)element
;
61 return memcmp(addr
, oui
->oui24
, 3);
65 compare_oui28_entry(const void *key
, const void *element
)
67 const uint8_t *addr
= (const uint8_t *)key
;
68 const manuf_oui28_t
*oui
= (const manuf_oui28_t
*)element
;
70 // The caller is expected to have masked out (addr[3] & 0xF0).
71 return memcmp(addr
, oui
->oui28
, 4);
75 compare_oui36_entry(const void *key
, const void *element
)
77 const uint8_t *addr
= (const uint8_t *)key
;
78 const manuf_oui36_t
*oui
= (const manuf_oui36_t
*)element
;
80 // The caller is expected to have masked out (addr[4] & 0xF0).
81 return memcmp(addr
, oui
->oui36
, 5);
85 select_registry(const uint8_t addr
[6])
87 const manuf_registry_t
*entry
;
89 entry
= bsearch(addr
, ieee_registry_table
, G_N_ELEMENTS(ieee_registry_table
), sizeof(manuf_registry_t
), compare_oui24_registry
);
95 static const manuf_oui24_t
*
96 manuf_oui24_lookup(const uint8_t addr
[6])
98 return bsearch(addr
, global_manuf_oui24_table
,
99 G_N_ELEMENTS(global_manuf_oui24_table
),
100 sizeof(manuf_oui24_t
),
101 compare_oui24_entry
);
104 static const manuf_oui28_t
*
105 manuf_oui28_lookup(const uint8_t addr
[6])
107 const uint8_t addr28
[6] = { addr
[0], addr
[1], addr
[2], addr
[3] & 0xF0, };
108 return bsearch(addr28
, global_manuf_oui28_table
,
109 G_N_ELEMENTS(global_manuf_oui28_table
),
110 sizeof(manuf_oui28_t
),
111 compare_oui28_entry
);
114 static const manuf_oui36_t
*
115 manuf_oui36_lookup(const uint8_t addr
[6])
117 const uint8_t addr36
[6] = { addr
[0], addr
[1], addr
[2], addr
[3], addr
[4] & 0xF0, };
118 return bsearch(addr36
, global_manuf_oui36_table
,
119 G_N_ELEMENTS(global_manuf_oui36_table
),
120 sizeof(manuf_oui36_t
),
121 compare_oui36_entry
);
125 ws_manuf_lookup(const uint8_t addr
[6], const char **long_name_ptr
, unsigned *mask_ptr
)
127 uint8_t addr_copy
[6];
128 memcpy(addr_copy
, addr
, 6);
129 /* Mask out the broadcast/multicast flag */
130 addr_copy
[0] &= 0xFE;
132 const char *short_name
= NULL
, *long_name
= NULL
;
135 switch (select_registry(addr_copy
)) {
138 const manuf_oui24_t
*ptr
= manuf_oui24_lookup(addr_copy
);
140 short_name
= ptr
->short_name
;
141 long_name
= ptr
->long_name
;
148 const manuf_oui28_t
*ptr
= manuf_oui28_lookup(addr_copy
);
150 short_name
= ptr
->short_name
;
151 long_name
= ptr
->long_name
;
158 const manuf_oui36_t
*ptr
= manuf_oui36_lookup(addr_copy
);
160 short_name
= ptr
->short_name
;
161 long_name
= ptr
->long_name
;
167 ws_assert_not_reached();
174 *long_name_ptr
= long_name
;
180 ws_manuf_lookup_str(const uint8_t addr
[6], const char **long_name_ptr
)
182 return ws_manuf_lookup(addr
, long_name_ptr
, NULL
);
186 ws_manuf_lookup_oui24(const uint8_t oui
[3], const char **long_name_ptr
)
188 uint8_t addr_copy
[6] = {0};
189 memcpy(addr_copy
, oui
, 3);
190 /* Mask out the broadcast/multicast flag */
191 addr_copy
[0] &= 0xFE;
193 const char *short_name
= NULL
, *long_name
= NULL
;
195 switch (select_registry(addr_copy
)) {
198 const manuf_oui24_t
*ptr
= manuf_oui24_lookup(addr_copy
);
200 short_name
= ptr
->short_name
;
201 long_name
= ptr
->long_name
;
208 /* XXX: These are officially registered to
209 * "IEEE Registration Authority" and we could return that, but
210 * we'd have to change expectatins elsewhere in the code.
215 ws_assert_not_reached();
219 *long_name_ptr
= long_name
;
224 static inline struct ws_manuf
*
225 copy_oui24(struct ws_manuf
*dst
, const manuf_oui24_t
*src
)
227 memcpy(dst
->block
, src
->oui24
, sizeof(src
->oui24
));
231 dst
->short_name
= src
->short_name
;
232 dst
->long_name
= src
->long_name
;
236 static inline struct ws_manuf
*
237 copy_oui28(struct ws_manuf
*dst
, const manuf_oui28_t
*src
)
239 memcpy(dst
->block
, src
->oui28
, sizeof(src
->oui28
));
242 dst
->short_name
= src
->short_name
;
243 dst
->long_name
= src
->long_name
;
247 static inline struct ws_manuf
*
248 copy_oui36(struct ws_manuf
*dst
, const manuf_oui36_t
*src
)
250 memcpy(dst
->block
, src
->oui36
, sizeof(src
->oui36
));
252 dst
->short_name
= src
->short_name
;
253 dst
->long_name
= src
->long_name
;
258 ws_manuf_iter_init(ws_manuf_iter_t
*iter
)
261 copy_oui24(&iter
->buf24
, &global_manuf_oui24_table
[iter
->idx24
]);
263 copy_oui28(&iter
->buf28
, &global_manuf_oui28_table
[iter
->idx28
]);
265 copy_oui36(&iter
->buf36
, &global_manuf_oui36_table
[iter
->idx36
]);
269 * Iterate between 3 registries in ascending order. This is not the same as
270 * fully iterating through one registry followed by another. For example, after
271 * visiting "00:55:B1", it could go to "00:55:DA:00/28", and eventually end up
272 * at "00:56:2B" again.
274 * The "iter" structure must be zero initialized before the first iteration.
277 ws_manuf_iter_next(ws_manuf_iter_t
*iter
, struct ws_manuf
*result
)
279 struct ws_manuf
*vector
[3] = { NULL
, NULL
, NULL
};
281 struct ws_manuf
*ptr
;
283 /* Read current positions. */
284 if (iter
->idx24
< G_N_ELEMENTS(global_manuf_oui24_table
)) {
285 vector
[idx
++] = &iter
->buf24
;
287 if (iter
->idx28
< G_N_ELEMENTS(global_manuf_oui28_table
)) {
288 vector
[idx
++] = &iter
->buf28
;
290 if (iter
->idx36
< G_N_ELEMENTS(global_manuf_oui36_table
)) {
291 vector
[idx
++] = &iter
->buf36
;
294 /* None remaining, we're done. */
298 /* Select smallest current prefix out of the 3 registries.
299 * There is at least one entry and index 0 is non-empty. */
301 for (size_t i
= 1; i
< idx
; i
++) {
302 if (vector
[i
] && memcmp(vector
[i
]->block
, ptr
->block
, MANUF_BLOCK_SIZE
) < 0) {
307 /* We have the next smallest element, return result. */
308 memcpy(result
, ptr
, sizeof(struct ws_manuf
));
310 /* Advance iterator and copy new element. */
311 if (ptr
->mask
== 24) {
313 if (iter
->idx24
< G_N_ELEMENTS(global_manuf_oui24_table
)) {
314 copy_oui24(&iter
->buf24
, &global_manuf_oui24_table
[iter
->idx24
]);
317 else if (ptr
->mask
== 28) {
319 if (iter
->idx28
< G_N_ELEMENTS(global_manuf_oui28_table
)) {
320 copy_oui28(&iter
->buf28
, &global_manuf_oui28_table
[iter
->idx28
]);
323 else if (ptr
->mask
== 36) {
325 if (iter
->idx36
< G_N_ELEMENTS(global_manuf_oui36_table
)) {
326 copy_oui36(&iter
->buf36
, &global_manuf_oui36_table
[iter
->idx36
]);
330 ws_assert_not_reached();
336 ws_manuf_block_str(char *buf
, size_t buf_size
, const struct ws_manuf
*ptr
)
338 if (ptr
->mask
== 24) {
339 /* The mask is implied as the full 24 bits when printing a traditional OUI.*/
340 snprintf(buf
, buf_size
, "%02"PRIX8
":%02"PRIX8
":%02"PRIX8
,
341 ptr
->block
[0], ptr
->block
[1], ptr
->block
[2]);
343 else if (ptr
->mask
== 28) {
344 snprintf(buf
, buf_size
, "%02"PRIX8
":%02"PRIX8
":%02"PRIX8
":%02"PRIX8
"/28",
345 ptr
->block
[0], ptr
->block
[1], ptr
->block
[2], ptr
->block
[3]);
347 else if (ptr
->mask
== 36) {
348 snprintf(buf
, buf_size
, "%02"PRIX8
":%02"PRIX8
":%02"PRIX8
":%02"PRIX8
":%02"PRIX8
"/36",
349 ptr
->block
[0], ptr
->block
[1], ptr
->block
[2], ptr
->block
[3], ptr
->block
[4]);
352 ws_assert_not_reached();
359 ws_manuf_dump(FILE *fp
)
361 ws_manuf_iter_t iter
;
362 struct ws_manuf item
;
365 ws_manuf_iter_init(&iter
);
367 while (ws_manuf_iter_next(&iter
, &item
)) {
368 fprintf(fp
, "%-17s\t%-12s\t%s\n",
369 ws_manuf_block_str(strbuf
, sizeof(strbuf
), &item
),
378 return G_N_ELEMENTS(global_manuf_oui24_table
) +
379 G_N_ELEMENTS(global_manuf_oui28_table
) +
380 G_N_ELEMENTS(global_manuf_oui36_table
);