From e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 10 Apr 2024 22:34:10 +0200 Subject: Adding upstream version 4.2.2. Signed-off-by: Daniel Baumann --- epan/manuf.c | 329 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 329 insertions(+) create mode 100644 epan/manuf.c (limited to 'epan/manuf.c') diff --git a/epan/manuf.c b/epan/manuf.c new file mode 100644 index 00000000..94adbf5b --- /dev/null +++ b/epan/manuf.c @@ -0,0 +1,329 @@ +/* manuf.c + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "manuf.h" +#include + +// MA-L / OUI - MAC Address Block Large (24-bit prefix) +#define MA_L 0 +// MA-M - MAC Address Block Medium (28-bit prefix) +#define MA_M 1 +// MA-S / OUI-36 - MAC Address Block Small (36-bit prefix) +#define MA_S 2 + +typedef struct { + uint8_t oui24[3]; + /* Identifies the 3-byte prefix as part of MA-M or MA-S (or MA-L if none of those). */ + uint8_t kind; +} manuf_registry_t; + +typedef struct { + uint8_t oui24[3]; + const char *short_name; + const char *long_name; +} manuf_oui24_t; + +typedef struct { + uint8_t oui28[4]; + const char *short_name; + const char *long_name; +} manuf_oui28_t; + +typedef struct { + uint8_t oui36[5]; + const char *short_name; + const char *long_name; +} manuf_oui36_t; + +#include "manuf-data.c" + +static int +compare_oui24_registry(const void *key, const void *element) +{ + const uint8_t *addr = (const uint8_t *)key; + const manuf_registry_t *entry = (const manuf_registry_t *)element; + + return memcmp(addr, entry->oui24, 3); +} + +static int +compare_oui24_entry(const void *key, const void *element) +{ + const uint8_t *addr = (const uint8_t *)key; + const manuf_oui24_t *oui = (const manuf_oui24_t *)element; + + return memcmp(addr, oui->oui24, 3); +} + +static int +compare_oui28_entry(const void *key, const void *element) +{ + const uint8_t *addr = (const uint8_t *)key; + const manuf_oui28_t *oui = (const manuf_oui28_t *)element; + + // The caller is expected to have masked out (addr[3] & 0xF0). + return memcmp(addr, oui->oui28, 4); +} + +static int +compare_oui36_entry(const void *key, const void *element) +{ + const uint8_t *addr = (const uint8_t *)key; + const manuf_oui36_t *oui = (const manuf_oui36_t *)element; + + // The caller is expected to have masked out (addr[4] & 0xF0). + return memcmp(addr, oui->oui36, 5); +} + +static int +select_registry(const uint8_t addr[6]) +{ + const manuf_registry_t *entry; + + entry = bsearch(addr, ieee_registry_table, G_N_ELEMENTS(ieee_registry_table), sizeof(manuf_registry_t), compare_oui24_registry); + if (entry) + return entry->kind; + return MA_L; +} + +static const manuf_oui24_t * +manuf_oui24_lookup(const uint8_t addr[6]) +{ + return bsearch(addr, global_manuf_oui24_table, + G_N_ELEMENTS(global_manuf_oui24_table), + sizeof(manuf_oui24_t), + compare_oui24_entry); +} + +static const manuf_oui28_t * +manuf_oui28_lookup(const uint8_t addr[6]) +{ + const uint8_t addr28[6] = { addr[0], addr[1], addr[2], addr[3] & 0xF0, }; + return bsearch(addr28, global_manuf_oui28_table, + G_N_ELEMENTS(global_manuf_oui28_table), + sizeof(manuf_oui28_t), + compare_oui28_entry); +} + +static const manuf_oui36_t * +manuf_oui36_lookup(const uint8_t addr[6]) +{ + const uint8_t addr36[6] = { addr[0], addr[1], addr[2], addr[3], addr[4] & 0xF0, }; + return bsearch(addr36, global_manuf_oui36_table, + G_N_ELEMENTS(global_manuf_oui36_table), + sizeof(manuf_oui36_t), + compare_oui36_entry); +} + +const char * +ws_manuf_lookup_str(const uint8_t addr[6], const char **long_name_ptr) +{ + uint8_t addr_copy[6]; + memcpy(addr_copy, addr, 6); + /* Mask out the broadcast/multicast flag */ + addr_copy[0] &= 0xFE; + + const char *short_name = NULL, *long_name = NULL; + + switch (select_registry(addr_copy)) { + case MA_L: + { + const manuf_oui24_t *ptr = manuf_oui24_lookup(addr_copy); + if (ptr) { + short_name = ptr->short_name; + long_name = ptr->long_name; + } + break; + } + case MA_M: + { + const manuf_oui28_t *ptr = manuf_oui28_lookup(addr_copy); + if (ptr) { + short_name = ptr->short_name; + long_name = ptr->long_name; + } + break; + } + case MA_S: + { + const manuf_oui36_t *ptr = manuf_oui36_lookup(addr_copy); + if (ptr) { + short_name = ptr->short_name; + long_name = ptr->long_name; + } + break; + } + default: + ws_assert_not_reached(); + } + + if (long_name_ptr) { + *long_name_ptr = long_name; + } + return short_name; +} + +static inline struct ws_manuf * +copy_oui24(struct ws_manuf *dst, const manuf_oui24_t *src) +{ + memcpy(dst->block, src->oui24, sizeof(src->oui24)); + dst->block[3] = 0; + dst->block[4] = 0; + dst->mask = 24; + dst->short_name = src->short_name; + dst->long_name = src->long_name; + return dst; +} + +static inline struct ws_manuf * +copy_oui28(struct ws_manuf *dst, const manuf_oui28_t *src) +{ + memcpy(dst->block, src->oui28, sizeof(src->oui28)); + dst->block[4] = 0; + dst->mask = 28; + dst->short_name = src->short_name; + dst->long_name = src->long_name; + return dst; +} + +static inline struct ws_manuf * +copy_oui36(struct ws_manuf *dst, const manuf_oui36_t *src) +{ + memcpy(dst->block, src->oui36, sizeof(src->oui36)); + dst->mask = 36; + dst->short_name = src->short_name; + dst->long_name = src->long_name; + return dst; +} + +void +ws_manuf_iter_init(ws_manuf_iter_t *iter) +{ + iter->idx24 = 0; + copy_oui24(&iter->buf24, &global_manuf_oui24_table[iter->idx24]); + iter->idx28 = 0; + copy_oui28(&iter->buf28, &global_manuf_oui28_table[iter->idx28]); + iter->idx36 = 0; + copy_oui36(&iter->buf36, &global_manuf_oui36_table[iter->idx36]); +} + +/** + * Iterate between 3 registries in ascending order. This is not the same as + * fully iterating through one registry followed by another. For example, after + * visiting "00:55:B1", it could go to "00:55:DA:00/28", and eventually end up + * at "00:56:2B" again. + * + * The "iter" structure must be zero initialized before the first iteration. + */ +bool +ws_manuf_iter_next(ws_manuf_iter_t *iter, struct ws_manuf *result) +{ + struct ws_manuf *vector[3] = { NULL, NULL, NULL }; + size_t idx = 0; + struct ws_manuf *ptr; + + /* Read current positions. */ + if (iter->idx24 < G_N_ELEMENTS(global_manuf_oui24_table)) { + vector[idx++] = &iter->buf24; + } + if (iter->idx28 < G_N_ELEMENTS(global_manuf_oui28_table)) { + vector[idx++] = &iter->buf28; + } + if (iter->idx36 < G_N_ELEMENTS(global_manuf_oui36_table)) { + vector[idx++] = &iter->buf36; + } + + /* None remaining, we're done. */ + if (idx == 0) + return false; + + /* Select smallest current prefix out of the 3 registries. + * There is at least one entry and index 0 is non-empty. */ + ptr = vector[0]; + for (size_t i = 1; i < idx; i++) { + if (vector[i] && memcmp(vector[i]->block, ptr->block, MANUF_BLOCK_SIZE) < 0) { + ptr = vector[i]; + } + } + + /* We have the next smallest element, return result. */ + memcpy(result, ptr, sizeof(struct ws_manuf)); + + /* Advance iterator and copy new element. */ + if (ptr->mask == 24) { + iter->idx24++; + if (iter->idx24 < G_N_ELEMENTS(global_manuf_oui24_table)) { + copy_oui24(&iter->buf24, &global_manuf_oui24_table[iter->idx24]); + } + } + else if (ptr->mask == 28) { + iter->idx28++; + if (iter->idx28 < G_N_ELEMENTS(global_manuf_oui28_table)) { + copy_oui28(&iter->buf28, &global_manuf_oui28_table[iter->idx28]); + } + } + else if (ptr->mask == 36) { + iter->idx36++; + if (iter->idx36 < G_N_ELEMENTS(global_manuf_oui36_table)) { + copy_oui36(&iter->buf36, &global_manuf_oui36_table[iter->idx36]); + } + } + else + ws_assert_not_reached(); + + return true; +} + +const char * +ws_manuf_block_str(char *buf, size_t buf_size, const struct ws_manuf *ptr) +{ + if (ptr->mask == 24) { + /* The mask is implied as the full 24 bits when printing a traditional OUI.*/ + snprintf(buf, buf_size, "%02"PRIX8":%02"PRIX8":%02"PRIX8, + ptr->block[0], ptr->block[1], ptr->block[2]); + } + else if (ptr->mask == 28) { + snprintf(buf, buf_size, "%02"PRIX8":%02"PRIX8":%02"PRIX8":%02"PRIX8"/28", + ptr->block[0], ptr->block[1], ptr->block[2], ptr->block[3]); + } + else if (ptr->mask == 36) { + snprintf(buf, buf_size, "%02"PRIX8":%02"PRIX8":%02"PRIX8":%02"PRIX8":%02"PRIX8"/36", + ptr->block[0], ptr->block[1], ptr->block[2], ptr->block[3], ptr->block[4]); + } + else { + ws_assert_not_reached(); + } + + return buf; +} + +void +ws_manuf_dump(FILE *fp) +{ + ws_manuf_iter_t iter; + struct ws_manuf item; + char strbuf[64]; + + ws_manuf_iter_init(&iter); + + while (ws_manuf_iter_next(&iter, &item)) { + fprintf(fp, "%-17s\t%-12s\t%s\n", + ws_manuf_block_str(strbuf, sizeof(strbuf), &item), + item.short_name, + item.long_name); + } +} + +size_t +ws_manuf_count(void) +{ + return G_N_ELEMENTS(global_manuf_oui24_table) + + G_N_ELEMENTS(global_manuf_oui28_table) + + G_N_ELEMENTS(global_manuf_oui36_table); +} -- cgit v1.2.3