attr_dissector_fn_t
[wireshark-sm.git] / epan / manuf.c
blobde1f31dc8c75fe59ee0abe47c3d69c129d7592e5
1 /* manuf.c
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
8 */
10 #include "manuf.h"
11 #include <stdlib.h>
13 // MA-L / OUI - MAC Address Block Large (24-bit prefix)
14 #define MA_L 0
15 // MA-M - MAC Address Block Medium (28-bit prefix)
16 #define MA_M 1
17 // MA-S / OUI-36 - MAC Address Block Small (36-bit prefix)
18 #define MA_S 2
20 typedef struct {
21 uint8_t oui24[3];
22 /* Identifies the 3-byte prefix as part of MA-M or MA-S (or MA-L if none of those). */
23 uint8_t kind;
24 } manuf_registry_t;
26 typedef struct {
27 uint8_t oui24[3];
28 const char *short_name;
29 const char *long_name;
30 } manuf_oui24_t;
32 typedef struct {
33 uint8_t oui28[4];
34 const char *short_name;
35 const char *long_name;
36 } manuf_oui28_t;
38 typedef struct {
39 uint8_t oui36[5];
40 const char *short_name;
41 const char *long_name;
42 } manuf_oui36_t;
44 #include "manuf-data.c"
46 static int
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);
55 static int
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);
64 static int
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);
74 static int
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);
84 static int
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);
90 if (entry)
91 return entry->kind;
92 return MA_L;
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);
124 const char *
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;
133 unsigned mask = 0;
135 switch (select_registry(addr_copy)) {
136 case MA_L:
138 const manuf_oui24_t *ptr = manuf_oui24_lookup(addr_copy);
139 if (ptr) {
140 short_name = ptr->short_name;
141 long_name = ptr->long_name;
142 mask = 24;
144 break;
146 case MA_M:
148 const manuf_oui28_t *ptr = manuf_oui28_lookup(addr_copy);
149 if (ptr) {
150 short_name = ptr->short_name;
151 long_name = ptr->long_name;
152 mask = 28;
154 break;
156 case MA_S:
158 const manuf_oui36_t *ptr = manuf_oui36_lookup(addr_copy);
159 if (ptr) {
160 short_name = ptr->short_name;
161 long_name = ptr->long_name;
162 mask = 36;
164 break;
166 default:
167 ws_assert_not_reached();
170 if (mask_ptr) {
171 *mask_ptr = mask;
173 if (long_name_ptr) {
174 *long_name_ptr = long_name;
176 return short_name;
179 const char *
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);
185 const char *
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)) {
196 case MA_L:
198 const manuf_oui24_t *ptr = manuf_oui24_lookup(addr_copy);
199 if (ptr) {
200 short_name = ptr->short_name;
201 long_name = ptr->long_name;
203 break;
205 case MA_M:
206 case MA_S:
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.
212 break;
214 default:
215 ws_assert_not_reached();
218 if (long_name_ptr) {
219 *long_name_ptr = long_name;
221 return short_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));
228 dst->block[3] = 0;
229 dst->block[4] = 0;
230 dst->mask = 24;
231 dst->short_name = src->short_name;
232 dst->long_name = src->long_name;
233 return dst;
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));
240 dst->block[4] = 0;
241 dst->mask = 28;
242 dst->short_name = src->short_name;
243 dst->long_name = src->long_name;
244 return dst;
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));
251 dst->mask = 36;
252 dst->short_name = src->short_name;
253 dst->long_name = src->long_name;
254 return dst;
257 void
258 ws_manuf_iter_init(ws_manuf_iter_t *iter)
260 iter->idx24 = 0;
261 copy_oui24(&iter->buf24, &global_manuf_oui24_table[iter->idx24]);
262 iter->idx28 = 0;
263 copy_oui28(&iter->buf28, &global_manuf_oui28_table[iter->idx28]);
264 iter->idx36 = 0;
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.
276 bool
277 ws_manuf_iter_next(ws_manuf_iter_t *iter, struct ws_manuf *result)
279 struct ws_manuf *vector[3] = { NULL, NULL, NULL };
280 size_t idx = 0;
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. */
295 if (idx == 0)
296 return false;
298 /* Select smallest current prefix out of the 3 registries.
299 * There is at least one entry and index 0 is non-empty. */
300 ptr = vector[0];
301 for (size_t i = 1; i < idx; i++) {
302 if (vector[i] && memcmp(vector[i]->block, ptr->block, MANUF_BLOCK_SIZE) < 0) {
303 ptr = vector[i];
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) {
312 iter->idx24++;
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) {
318 iter->idx28++;
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) {
324 iter->idx36++;
325 if (iter->idx36 < G_N_ELEMENTS(global_manuf_oui36_table)) {
326 copy_oui36(&iter->buf36, &global_manuf_oui36_table[iter->idx36]);
329 else
330 ws_assert_not_reached();
332 return true;
335 const char *
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]);
351 else {
352 ws_assert_not_reached();
355 return buf;
358 void
359 ws_manuf_dump(FILE *fp)
361 ws_manuf_iter_t iter;
362 struct ws_manuf item;
363 char strbuf[64];
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),
370 item.short_name,
371 item.long_name);
375 size_t
376 ws_manuf_count(void)
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);