wireshark/epan/manuf.c

263 lines
7 KiB
C

/* manuf.c
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* Copyright 1998 Gerald Combs
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "manuf.h"
#include <stdlib.h>
#define MA_L 0
#define MA_M 1
#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_entry(const void *a, const void *b)
{
return memcmp(a, ((const manuf_oui24_t *)b)->oui24, 3);
}
static int
compare_oui28_entry(const void *a, const void *b)
{
uint8_t addr[4];
memcpy(addr, a, 4);
addr[3] &= 0xF0;
return memcmp(addr, ((const manuf_oui28_t *)b)->oui28, 4);
}
static int
compare_oui36_entry(const void *a, const void *b)
{
uint8_t addr[5];
memcpy(addr, a, 5);
addr[4] &= 0xF0;
return memcmp(addr, ((const manuf_oui36_t *)b)->oui36, 5);
}
static int
select_registry(const uint8_t addr[6])
{
manuf_registry_t *entry;
entry = bsearch(addr, ieee_registry_table, G_N_ELEMENTS(ieee_registry_table), sizeof(manuf_registry_t), compare_oui24_entry);
if (entry)
return entry->kind;
return MA_L;
}
static struct ws_manuf *
manuf_oui24_lookup(const uint8_t addr[6], struct ws_manuf *result)
{
manuf_oui24_t *oui24 = bsearch(addr, global_manuf_oui24_table, G_N_ELEMENTS(global_manuf_oui24_table), sizeof(manuf_oui24_t), compare_oui24_entry);
if (!oui24)
return NULL;
memcpy(result->addr, oui24->oui24, sizeof(oui24->oui24));
result->mask = 24;
result->short_name = oui24->short_name;
result->long_name = oui24->long_name;
return result;
}
static struct ws_manuf *
manuf_oui28_lookup(const uint8_t addr[6], struct ws_manuf *result)
{
manuf_oui28_t *oui28 = bsearch(addr, global_manuf_oui28_table, G_N_ELEMENTS(global_manuf_oui28_table), sizeof(manuf_oui28_t), compare_oui28_entry);
if (!oui28)
return NULL;
memcpy(result->addr, oui28->oui28, sizeof(oui28->oui28));
result->mask = 28;
result->short_name = oui28->short_name;
result->long_name = oui28->long_name;
return result;
}
static struct ws_manuf *
manuf_oui36_lookup(const uint8_t addr[6], struct ws_manuf *result)
{
manuf_oui36_t *oui36 = bsearch(addr, global_manuf_oui36_table, G_N_ELEMENTS(global_manuf_oui36_table), sizeof(manuf_oui36_t), compare_oui36_entry);
if (!oui36)
return NULL;
memcpy(result->addr, oui36->oui36, sizeof(oui36->oui36));
result->mask = 36;
result->short_name = oui36->short_name;
result->long_name = oui36->long_name;
return result;
}
struct ws_manuf *
ws_manuf_lookup(const uint8_t addr[6], struct ws_manuf *result)
{
memset(result, 0, sizeof(*result));
uint8_t addr_copy[6];
memcpy(addr_copy, addr, 6);
/* Mask out the broadcast/multicast flag */
addr_copy[0] &= 0xFE;
switch (select_registry(addr_copy)) {
case MA_L:
return manuf_oui24_lookup(addr_copy, result);
break;
case MA_M:
return manuf_oui28_lookup(addr_copy, result);
break;
case MA_S:
return manuf_oui36_lookup(addr_copy, result);
break;
default:
break;
}
ws_assert_not_reached();
}
void
ws_manuf_iter_init(ws_manuf_iter_t *iter)
{
memset(iter, 0, sizeof(*iter));
}
#define NUM_REGISTRIES 3
/* Iterate between 3 registries in ascending order. */
struct ws_manuf *
ws_manuf_iter_next(ws_manuf_iter_t *iter, struct ws_manuf manuf[NUM_REGISTRIES])
{
manuf_oui24_t *ptr24 = NULL;
manuf_oui28_t *ptr28 = NULL;
manuf_oui36_t *ptr36 = NULL;
struct ws_manuf *ptr;
memset(manuf, 0, NUM_REGISTRIES * sizeof(struct ws_manuf));
ptr = manuf;
/* Read current positions. */
if (iter->idx24 < G_N_ELEMENTS(global_manuf_oui24_table)) {
ptr24 = &global_manuf_oui24_table[iter->idx24];
memcpy(ptr->addr, ptr24->oui24, sizeof(ptr24->oui24));
ptr->mask = 24;
ptr->short_name = ptr24->short_name;
ptr->long_name = ptr24->long_name;
ptr++;
}
if (iter->idx28 < G_N_ELEMENTS(global_manuf_oui28_table)) {
ptr28 = &global_manuf_oui28_table[iter->idx28];
memcpy(ptr->addr, ptr28->oui28, sizeof(ptr28->oui28));
ptr->mask = 28;
ptr->short_name = ptr28->short_name;
ptr->long_name = ptr28->long_name;
ptr++;
}
if (iter->idx36 < G_N_ELEMENTS(global_manuf_oui36_table)) {
ptr36 = &global_manuf_oui36_table[iter->idx36];
memcpy(ptr->addr, ptr36->oui36, sizeof(ptr36->oui36));
ptr->mask = 36;
ptr->short_name = ptr36->short_name;
ptr->long_name = ptr36->long_name;
}
/* None read. */
if (manuf->long_name == NULL)
return NULL;
/* Select smallest current prefix out of the 3 registries.
* There is at least one entry and index 0 is non-empty. */
ptr = &manuf[0];
for (size_t i = 1; i < NUM_REGISTRIES; i++) {
if (manuf[i].long_name && memcmp(manuf[i].addr, ptr->addr, 6) < 0) {
ptr = &manuf[i];
}
}
/* Advance iterator. */
if (ptr24 && ptr->long_name == ptr24->long_name)
iter->idx24++;
else if (ptr28 && ptr->long_name == ptr28->long_name)
iter->idx28++;
else if (ptr36 && ptr->long_name == ptr36->long_name)
iter->idx36++;
else
ws_assert_not_reached();
return ptr;
}
const char *
ws_manuf_block_str(char *buf, size_t buf_size, const struct ws_manuf *ptr)
{
if (ptr->mask == 24) {
snprintf(buf, buf_size, "%02"PRIX8":%02"PRIX8":%02"PRIX8,
ptr->addr[0], ptr->addr[1], ptr->addr[2]);
}
else if (ptr->mask == 28) {
snprintf(buf, buf_size, "%02"PRIX8":%02"PRIX8":%02"PRIX8":%02"PRIX8"/%"PRIu8,
ptr->addr[0], ptr->addr[1], ptr->addr[2], ptr->addr[3], ptr->mask);
}
else if (ptr->mask == 36) {
snprintf(buf, buf_size, "%02"PRIX8":%02"PRIX8":%02"PRIX8":%02"PRIX8":%02"PRIX8"/%"PRIu8,
ptr->addr[0], ptr->addr[1], ptr->addr[2], ptr->addr[3], ptr->addr[4], ptr->mask);
}
else {
ws_assert_not_reached();
}
return buf;
}
void
ws_manuf_dump(FILE *fp)
{
ws_manuf_iter_t iter;
struct ws_manuf manuf[3];
struct ws_manuf *ptr;
char strbuf[64];
ws_manuf_iter_init(&iter);
while ((ptr = ws_manuf_iter_next(&iter, manuf))) {
fprintf(fp, "%-17s\t%s\n",
ws_manuf_block_str(strbuf, sizeof(strbuf), ptr),
ptr->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);
}