Coverage Report

Created: 2025-02-15 06:25

/src/wireshark/epan/manuf.c
Line
Count
Source (jump to first uncovered line)
1
/* manuf.c
2
 *
3
 * Wireshark - Network traffic analyzer
4
 * By Gerald Combs <gerald@wireshark.org>
5
 * Copyright 1998 Gerald Combs
6
 *
7
 * SPDX-License-Identifier: GPL-2.0-or-later
8
 */
9
10
#include "manuf.h"
11
#include <stdlib.h>
12
13
// MA-L / OUI - MAC Address Block Large (24-bit prefix)
14
87.4k
#define MA_L 0
15
// MA-M - MAC Address Block Medium (28-bit prefix)
16
933
#define MA_M 1
17
// MA-S / OUI-36 - MAC Address Block Small (36-bit prefix)
18
201
#define MA_S 2
19
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;
25
26
typedef struct {
27
    uint8_t oui24[3];
28
    const char *short_name;
29
    const char *long_name;
30
} manuf_oui24_t;
31
32
typedef struct {
33
    uint8_t oui28[4];
34
    const char *short_name;
35
    const char *long_name;
36
} manuf_oui28_t;
37
38
typedef struct {
39
    uint8_t oui36[5];
40
    const char *short_name;
41
    const char *long_name;
42
} manuf_oui36_t;
43
44
#include "manuf-data.c"
45
46
static int
47
compare_oui24_registry(const void *key, const void *element)
48
384k
{
49
384k
    const uint8_t *addr = (const uint8_t *)key;
50
384k
    const manuf_registry_t *entry = (const manuf_registry_t *)element;
51
52
384k
    return memcmp(addr, entry->oui24, 3);
53
384k
}
54
55
static int
56
compare_oui24_entry(const void *key, const void *element)
57
665k
{
58
665k
    const uint8_t *addr = (const uint8_t *)key;
59
665k
    const manuf_oui24_t *oui = (const manuf_oui24_t *)element;
60
61
665k
    return memcmp(addr, oui->oui24, 3);
62
665k
}
63
64
static int
65
compare_oui28_entry(const void *key, const void *element)
66
9.53k
{
67
9.53k
    const uint8_t *addr = (const uint8_t *)key;
68
9.53k
    const manuf_oui28_t *oui = (const manuf_oui28_t *)element;
69
70
    // The caller is expected to have masked out (addr[3] & 0xF0).
71
9.53k
    return memcmp(addr, oui->oui28, 4);
72
9.53k
}
73
74
static int
75
compare_oui36_entry(const void *key, const void *element)
76
1.28k
{
77
1.28k
    const uint8_t *addr = (const uint8_t *)key;
78
1.28k
    const manuf_oui36_t *oui = (const manuf_oui36_t *)element;
79
80
    // The caller is expected to have masked out (addr[4] & 0xF0).
81
1.28k
    return memcmp(addr, oui->oui36, 5);
82
1.28k
}
83
84
static int
85
select_registry(const uint8_t addr[6])
86
44.7k
{
87
44.7k
    const manuf_registry_t *entry;
88
89
44.7k
    entry = bsearch(addr, ieee_registry_table, G_N_ELEMENTS(ieee_registry_table), sizeof(manuf_registry_t), compare_oui24_registry);
90
44.7k
    if (entry)
91
1.05k
        return entry->kind;
92
43.7k
    return MA_L;
93
44.7k
}
94
95
static const manuf_oui24_t *
96
manuf_oui24_lookup(const uint8_t addr[6])
97
43.7k
{
98
43.7k
    return bsearch(addr, global_manuf_oui24_table,
99
43.7k
                    G_N_ELEMENTS(global_manuf_oui24_table),
100
43.7k
                    sizeof(manuf_oui24_t),
101
43.7k
                    compare_oui24_entry);
102
43.7k
}
103
104
static const manuf_oui28_t *
105
manuf_oui28_lookup(const uint8_t addr[6])
106
849
{
107
849
    const uint8_t addr28[6] = { addr[0], addr[1], addr[2], addr[3] & 0xF0, };
108
849
    return bsearch(addr28, global_manuf_oui28_table,
109
849
                    G_N_ELEMENTS(global_manuf_oui28_table),
110
849
                    sizeof(manuf_oui28_t),
111
849
                    compare_oui28_entry);
112
849
}
113
114
static const manuf_oui36_t *
115
manuf_oui36_lookup(const uint8_t addr[6])
116
110
{
117
110
    const uint8_t addr36[6] = { addr[0], addr[1], addr[2], addr[3], addr[4] & 0xF0, };
118
110
    return bsearch(addr36, global_manuf_oui36_table,
119
110
                    G_N_ELEMENTS(global_manuf_oui36_table),
120
110
                    sizeof(manuf_oui36_t),
121
110
                    compare_oui36_entry);
122
110
}
123
124
const char *
125
ws_manuf_lookup(const uint8_t addr[6], const char **long_name_ptr, unsigned *mask_ptr)
126
37.4k
{
127
37.4k
    uint8_t addr_copy[6];
128
37.4k
    memcpy(addr_copy, addr, 6);
129
    /* Mask out the broadcast/multicast flag */
130
37.4k
    addr_copy[0] &= 0xFE;
131
132
37.4k
    const char *short_name = NULL, *long_name = NULL;
133
37.4k
    unsigned mask = 0;
134
135
37.4k
    switch (select_registry(addr_copy)) {
136
36.5k
        case MA_L:
137
36.5k
        {
138
36.5k
            const manuf_oui24_t *ptr = manuf_oui24_lookup(addr_copy);
139
36.5k
            if (ptr) {
140
0
                short_name = ptr->short_name;
141
0
                long_name = ptr->long_name;
142
0
                mask = 24;
143
0
            }
144
36.5k
            break;
145
0
        }
146
849
        case MA_M:
147
849
        {
148
849
            const manuf_oui28_t *ptr = manuf_oui28_lookup(addr_copy);
149
849
            if (ptr) {
150
804
                short_name = ptr->short_name;
151
804
                long_name = ptr->long_name;
152
804
                mask = 28;
153
804
            }
154
849
            break;
155
0
        }
156
110
        case MA_S:
157
110
        {
158
110
            const manuf_oui36_t *ptr = manuf_oui36_lookup(addr_copy);
159
110
            if (ptr) {
160
75
                short_name = ptr->short_name;
161
75
                long_name = ptr->long_name;
162
75
                mask = 36;
163
75
            }
164
110
            break;
165
0
        }
166
0
        default:
167
0
            ws_assert_not_reached();
168
37.4k
    }
169
170
37.4k
    if (mask_ptr) {
171
8.01k
        *mask_ptr = mask;
172
8.01k
    }
173
37.4k
    if (long_name_ptr) {
174
37.4k
        *long_name_ptr = long_name;
175
37.4k
    }
176
37.4k
    return short_name;
177
37.4k
}
178
179
const char *
180
ws_manuf_lookup_str(const uint8_t addr[6], const char **long_name_ptr)
181
29.4k
{
182
29.4k
    return ws_manuf_lookup(addr, long_name_ptr, NULL);
183
29.4k
}
184
185
const char *
186
ws_manuf_lookup_oui24(const uint8_t oui[3], const char **long_name_ptr)
187
7.27k
{
188
7.27k
    uint8_t addr_copy[6] = {0};
189
7.27k
    memcpy(addr_copy, oui, 3);
190
    /* Mask out the broadcast/multicast flag */
191
7.27k
    addr_copy[0] &= 0xFE;
192
193
7.27k
    const char *short_name = NULL, *long_name = NULL;
194
195
7.27k
    switch (select_registry(addr_copy)) {
196
7.18k
        case MA_L:
197
7.18k
        {
198
7.18k
            const manuf_oui24_t *ptr = manuf_oui24_lookup(addr_copy);
199
7.18k
            if (ptr) {
200
801
                short_name = ptr->short_name;
201
801
                long_name = ptr->long_name;
202
801
            }
203
7.18k
            break;
204
0
        }
205
84
        case MA_M:
206
91
        case MA_S:
207
91
        {
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.
211
             */
212
91
            break;
213
84
        }
214
0
        default:
215
0
            ws_assert_not_reached();
216
7.27k
    }
217
218
7.27k
    if (long_name_ptr) {
219
7.27k
        *long_name_ptr = long_name;
220
7.27k
    }
221
7.27k
    return short_name;
222
7.27k
}
223
224
static inline struct ws_manuf *
225
copy_oui24(struct ws_manuf *dst, const manuf_oui24_t *src)
226
0
{
227
0
    memcpy(dst->block, src->oui24, sizeof(src->oui24));
228
0
    dst->block[3] = 0;
229
0
    dst->block[4] = 0;
230
0
    dst->mask = 24;
231
0
    dst->short_name = src->short_name;
232
0
    dst->long_name = src->long_name;
233
0
    return dst;
234
0
}
235
236
static inline struct ws_manuf *
237
copy_oui28(struct ws_manuf *dst, const manuf_oui28_t *src)
238
0
{
239
0
    memcpy(dst->block, src->oui28, sizeof(src->oui28));
240
0
    dst->block[4] = 0;
241
0
    dst->mask = 28;
242
0
    dst->short_name = src->short_name;
243
0
    dst->long_name = src->long_name;
244
0
    return dst;
245
0
}
246
247
static inline struct ws_manuf *
248
copy_oui36(struct ws_manuf *dst, const manuf_oui36_t *src)
249
0
{
250
0
    memcpy(dst->block, src->oui36, sizeof(src->oui36));
251
0
    dst->mask = 36;
252
0
    dst->short_name = src->short_name;
253
0
    dst->long_name = src->long_name;
254
0
    return dst;
255
0
}
256
257
void
258
ws_manuf_iter_init(ws_manuf_iter_t *iter)
259
0
{
260
0
    iter->idx24 = 0;
261
0
    copy_oui24(&iter->buf24, &global_manuf_oui24_table[iter->idx24]);
262
0
    iter->idx28 = 0;
263
0
    copy_oui28(&iter->buf28, &global_manuf_oui28_table[iter->idx28]);
264
0
    iter->idx36 = 0;
265
0
    copy_oui36(&iter->buf36, &global_manuf_oui36_table[iter->idx36]);
266
0
}
267
268
/**
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.
273
 *
274
 * The "iter" structure must be zero initialized before the first iteration.
275
 */
276
bool
277
ws_manuf_iter_next(ws_manuf_iter_t *iter, struct ws_manuf *result)
278
0
{
279
0
    struct ws_manuf *vector[3] = { NULL, NULL, NULL };
280
0
    size_t idx = 0;
281
0
    struct ws_manuf *ptr;
282
283
    /* Read current positions. */
284
0
    if (iter->idx24 < G_N_ELEMENTS(global_manuf_oui24_table)) {
285
0
        vector[idx++] = &iter->buf24;
286
0
    }
287
0
    if (iter->idx28 < G_N_ELEMENTS(global_manuf_oui28_table)) {
288
0
        vector[idx++] = &iter->buf28;
289
0
    }
290
0
    if (iter->idx36 < G_N_ELEMENTS(global_manuf_oui36_table)) {
291
0
        vector[idx++] = &iter->buf36;
292
0
    }
293
294
    /* None remaining, we're done. */
295
0
    if (idx == 0)
296
0
        return false;
297
298
    /* Select smallest current prefix out of the 3 registries.
299
     * There is at least one entry and index 0 is non-empty. */
300
0
    ptr = vector[0];
301
0
    for (size_t i = 1; i < idx; i++) {
302
0
        if (vector[i] && memcmp(vector[i]->block, ptr->block, MANUF_BLOCK_SIZE) < 0) {
303
0
            ptr = vector[i];
304
0
        }
305
0
    }
306
307
    /* We have the next smallest element, return result. */
308
0
    memcpy(result, ptr, sizeof(struct ws_manuf));
309
310
    /* Advance iterator and copy new element. */
311
0
    if (ptr->mask == 24) {
312
0
        iter->idx24++;
313
0
        if (iter->idx24 < G_N_ELEMENTS(global_manuf_oui24_table)) {
314
0
            copy_oui24(&iter->buf24, &global_manuf_oui24_table[iter->idx24]);
315
0
        }
316
0
    }
317
0
    else if (ptr->mask == 28) {
318
0
        iter->idx28++;
319
0
        if (iter->idx28 < G_N_ELEMENTS(global_manuf_oui28_table)) {
320
0
            copy_oui28(&iter->buf28, &global_manuf_oui28_table[iter->idx28]);
321
0
        }
322
0
    }
323
0
    else if (ptr->mask == 36) {
324
0
        iter->idx36++;
325
0
        if (iter->idx36 < G_N_ELEMENTS(global_manuf_oui36_table)) {
326
0
            copy_oui36(&iter->buf36, &global_manuf_oui36_table[iter->idx36]);
327
0
        }
328
0
    }
329
0
    else
330
0
        ws_assert_not_reached();
331
332
0
    return true;
333
0
}
334
335
const char *
336
ws_manuf_block_str(char *buf, size_t buf_size, const struct ws_manuf *ptr)
337
0
{
338
0
    if (ptr->mask == 24) {
339
        /* The mask is implied as the full 24 bits when printing a traditional OUI.*/
340
0
        snprintf(buf, buf_size, "%02"PRIX8":%02"PRIX8":%02"PRIX8,
341
0
            ptr->block[0], ptr->block[1], ptr->block[2]);
342
0
    }
343
0
    else if (ptr->mask == 28) {
344
0
        snprintf(buf, buf_size, "%02"PRIX8":%02"PRIX8":%02"PRIX8":%02"PRIX8"/28",
345
0
            ptr->block[0], ptr->block[1], ptr->block[2], ptr->block[3]);
346
0
    }
347
0
    else if (ptr->mask == 36) {
348
0
        snprintf(buf, buf_size, "%02"PRIX8":%02"PRIX8":%02"PRIX8":%02"PRIX8":%02"PRIX8"/36",
349
0
            ptr->block[0], ptr->block[1], ptr->block[2], ptr->block[3], ptr->block[4]);
350
0
    }
351
0
    else {
352
0
        ws_assert_not_reached();
353
0
    }
354
355
0
    return buf;
356
0
}
357
358
void
359
ws_manuf_dump(FILE *fp)
360
0
{
361
0
    ws_manuf_iter_t iter;
362
0
    struct ws_manuf item;
363
0
    char strbuf[64];
364
365
0
    ws_manuf_iter_init(&iter);
366
367
0
    while (ws_manuf_iter_next(&iter, &item)) {
368
0
        fprintf(fp, "%-17s\t%-12s\t%s\n",
369
0
            ws_manuf_block_str(strbuf, sizeof(strbuf), &item),
370
0
            item.short_name,
371
0
            item.long_name);
372
0
    }
373
0
}
374
375
size_t
376
ws_manuf_count(void)
377
0
{
378
0
    return G_N_ELEMENTS(global_manuf_oui24_table) +
379
0
            G_N_ELEMENTS(global_manuf_oui28_table) +
380
0
            G_N_ELEMENTS(global_manuf_oui36_table);
381
0
}