Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/usr.sbin/bsnmpd/modules/snmp_bridge/bridge_addrs.c
107769 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2006 Shteryana Shopova <[email protected]>
5
* All rights reserved.
6
*
7
* Redistribution and use in source and binary forms, with or without
8
* modification, are permitted provided that the following conditions
9
* are met:
10
* 1. Redistributions of source code must retain the above copyright
11
* notice, this list of conditions and the following disclaimer.
12
* 2. Redistributions in binary form must reproduce the above copyright
13
* notice, this list of conditions and the following disclaimer in the
14
* documentation and/or other materials provided with the distribution.
15
*
16
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26
* SUCH DAMAGE.
27
*
28
* Bridge MIB implementation for SNMPd.
29
* Bridge addresses.
30
*/
31
32
#include <sys/queue.h>
33
#include <sys/socket.h>
34
#include <sys/types.h>
35
36
#include <net/ethernet.h>
37
#include <net/if.h>
38
#include <net/if_mib.h>
39
40
#include <assert.h>
41
#include <errno.h>
42
#include <stdarg.h>
43
#include <string.h>
44
#include <stdlib.h>
45
#include <syslog.h>
46
47
#include <bsnmp/snmpmod.h>
48
#include <bsnmp/snmp_mibII.h>
49
50
#define SNMPTREE_TYPES
51
#include "bridge_tree.h"
52
#include "bridge_snmp.h"
53
54
TAILQ_HEAD(tp_entries, tp_entry);
55
56
/*
57
* Free the bridge address list.
58
*/
59
static void
60
bridge_tpe_free(struct tp_entries *headp)
61
{
62
struct tp_entry *t;
63
64
while ((t = TAILQ_FIRST(headp)) != NULL) {
65
TAILQ_REMOVE(headp, t, tp_e);
66
free(t);
67
}
68
}
69
70
/*
71
* Free the bridge address entries from the address list,
72
* for the specified bridge interface only.
73
*/
74
static void
75
bridge_tpe_bif_free(struct tp_entries *headp,
76
struct bridge_if *bif)
77
{
78
struct tp_entry *tp;
79
80
while (bif->f_tpa != NULL && bif->sysindex == bif->f_tpa->sysindex) {
81
tp = TAILQ_NEXT(bif->f_tpa, tp_e);
82
TAILQ_REMOVE(headp, bif->f_tpa, tp_e);
83
free(bif->f_tpa);
84
bif->f_tpa = tp;
85
}
86
}
87
88
/*
89
* Compare two mac addresses.
90
* m1 < m2 : -1
91
* m1 > m2 : +1
92
* m1 = m2 : 0
93
*/
94
static int
95
bridge_compare_macs(const uint8_t *m1, const uint8_t *m2)
96
{
97
int i;
98
99
for (i = 0; i < ETHER_ADDR_LEN; i++) {
100
if (m1[i] < m2[i])
101
return (-1);
102
if (m1[i] > m2[i])
103
return (1);
104
}
105
106
return (0);
107
}
108
109
/*
110
* Insert an address entry in the bridge address TAILQ starting to search
111
* for its place from the position of the first bridge address for the bridge
112
* interface. Update the first bridge address if necessary.
113
*/
114
static void
115
bridge_addrs_insert_at(struct tp_entries *headp,
116
struct tp_entry *ta, struct tp_entry **f_tpa)
117
{
118
struct tp_entry *t1;
119
120
assert(f_tpa != NULL);
121
122
for (t1 = *f_tpa;
123
t1 != NULL && ta->sysindex == t1->sysindex;
124
t1 = TAILQ_NEXT(t1, tp_e)) {
125
if (bridge_compare_macs(ta->tp_addr, t1->tp_addr) < 0) {
126
TAILQ_INSERT_BEFORE(t1, ta, tp_e);
127
if (*f_tpa == t1)
128
(*f_tpa) = ta;
129
return;
130
}
131
}
132
133
if (t1 == NULL)
134
TAILQ_INSERT_TAIL(headp, ta, tp_e);
135
else
136
TAILQ_INSERT_BEFORE(t1, ta, tp_e);
137
}
138
139
/*
140
* Find an address entry's position in the address list
141
* according to bridge interface name.
142
*/
143
static struct tp_entry *
144
bridge_addrs_find_pos(struct tp_entries *headp, uint32_t b_idx)
145
{
146
uint32_t t_idx;
147
struct tp_entry *t1;
148
149
if ((t1 = TAILQ_FIRST(headp)) == NULL ||
150
bridge_compare_sysidx(b_idx, t1->sysindex) < 0)
151
return (NULL);
152
153
t_idx = t1->sysindex;
154
155
for (t1 = TAILQ_NEXT(t1, tp_e); t1 != NULL; t1 = TAILQ_NEXT(t1, tp_e)) {
156
157
if (t1->sysindex != t_idx) {
158
if (bridge_compare_sysidx(b_idx, t1->sysindex) < 0)
159
return (TAILQ_PREV(t1, tp_entries, tp_e));
160
else
161
t_idx = t1->sysindex;
162
}
163
}
164
165
if (t1 == NULL)
166
t1 = TAILQ_LAST(headp, tp_entries);
167
168
return (t1);
169
}
170
171
/*
172
* Insert a bridge address in the bridge addresses list.
173
*/
174
static void
175
bridge_addrs_bif_insert(struct tp_entries *headp, struct tp_entry *te,
176
struct tp_entry **f_tpa)
177
{
178
struct tp_entry *temp;
179
180
if (*f_tpa != NULL)
181
bridge_addrs_insert_at(headp, te, f_tpa);
182
else {
183
temp = bridge_addrs_find_pos(headp, te->sysindex);
184
185
if (temp == NULL)
186
TAILQ_INSERT_HEAD(headp, te, tp_e);
187
else
188
TAILQ_INSERT_AFTER(headp, temp, te, tp_e);
189
*f_tpa = te;
190
}
191
}
192
193
static struct tp_entries tp_entries = TAILQ_HEAD_INITIALIZER(tp_entries);
194
static time_t address_list_age;
195
196
void
197
bridge_addrs_update_listage(void)
198
{
199
address_list_age = time(NULL);
200
}
201
202
void
203
bridge_addrs_fini(void)
204
{
205
bridge_tpe_free(&tp_entries);
206
}
207
208
void
209
bridge_addrs_free(struct bridge_if *bif)
210
{
211
bridge_tpe_bif_free(&tp_entries, bif);
212
}
213
214
/*
215
* Find the first address in the list.
216
*/
217
static struct tp_entry *
218
bridge_addrs_first(void)
219
{
220
return (TAILQ_FIRST(&tp_entries));
221
}
222
223
/*
224
* Find the next address in the list.
225
*/
226
static struct tp_entry *
227
bridge_addrs_next(struct tp_entry *te)
228
{
229
return (TAILQ_NEXT(te, tp_e));
230
}
231
232
/*
233
* Find the first address, learnt by the specified bridge interface.
234
*/
235
struct tp_entry *
236
bridge_addrs_bif_first(struct bridge_if *bif)
237
{
238
return (bif->f_tpa);
239
}
240
241
/*
242
* Find the next address, learnt by the specified bridge interface.
243
*/
244
struct tp_entry *
245
bridge_addrs_bif_next(struct tp_entry *te)
246
{
247
struct tp_entry *te_next;
248
249
if ((te_next = TAILQ_NEXT(te, tp_e)) == NULL ||
250
te_next->sysindex != te->sysindex)
251
return (NULL);
252
253
return (te_next);
254
}
255
256
/*
257
* Remove a bridge address from the list.
258
*/
259
void
260
bridge_addrs_remove(struct tp_entry *te, struct bridge_if *bif)
261
{
262
if (bif->f_tpa == te)
263
bif->f_tpa = bridge_addrs_bif_next(te);
264
265
TAILQ_REMOVE(&tp_entries, te, tp_e);
266
free(te);
267
}
268
269
/*
270
* Allocate memory for a new bridge address and insert it in the list.
271
*/
272
struct tp_entry *
273
bridge_new_addrs(uint8_t *mac, struct bridge_if *bif)
274
{
275
struct tp_entry *te;
276
277
if ((te = (struct tp_entry *) malloc(sizeof(*te))) == NULL) {
278
syslog(LOG_ERR, "bridge new address: failed: %s",
279
strerror(errno));
280
return (NULL);
281
}
282
283
bzero(te, sizeof(*te));
284
285
te->sysindex = bif->sysindex;
286
bcopy(mac, te->tp_addr, ETHER_ADDR_LEN);
287
bridge_addrs_bif_insert(&tp_entries, te, &(bif->f_tpa));
288
289
return (te);
290
}
291
292
/*
293
* Given a mac address, learnt on a bridge,
294
* find the corrsponding TP entry for it.
295
*/
296
struct tp_entry *
297
bridge_addrs_find(uint8_t *mac, struct bridge_if *bif)
298
{
299
struct tp_entry *te;
300
301
for (te = bif->f_tpa; te != NULL; te = TAILQ_NEXT(te, tp_e)) {
302
if (te->sysindex != bif->sysindex) {
303
te = NULL;
304
break;
305
}
306
307
if (bridge_compare_macs(te->tp_addr, mac) == 0)
308
break;
309
}
310
311
return (te);
312
}
313
314
void
315
bridge_addrs_dump(struct bridge_if *bif)
316
{
317
struct tp_entry *te;
318
319
syslog(LOG_ERR, "Addresses count - %d", bif->num_addrs);
320
for (te = bridge_addrs_bif_first(bif); te != NULL;
321
te = bridge_addrs_bif_next(te)) {
322
syslog(LOG_ERR, "address %x:%x:%x:%x:%x:%x on port %d.%d",
323
te->tp_addr[0], te->tp_addr[1], te->tp_addr[2],
324
te->tp_addr[3], te->tp_addr[4], te->tp_addr[5],
325
te->sysindex, te->port_no);
326
}
327
}
328
329
/*
330
* RFC4188 specifics.
331
*/
332
333
/*
334
* Construct the SNMP index from the address DST Mac.
335
*/
336
static void
337
bridge_addrs_index_append(struct asn_oid *oid, uint sub,
338
const struct tp_entry *te)
339
{
340
int i;
341
342
oid->len = sub + ETHER_ADDR_LEN + 1;
343
oid->subs[sub] = ETHER_ADDR_LEN;
344
345
for (i = 1; i <= ETHER_ADDR_LEN; i++)
346
oid->subs[sub + i] = te->tp_addr[i - 1];
347
}
348
349
/*
350
* Find the address entry for the SNMP index from the default bridge only.
351
*/
352
static struct tp_entry *
353
bridge_addrs_get(const struct asn_oid *oid, uint sub,
354
struct bridge_if *bif)
355
{
356
int i;
357
uint8_t tp_addr[ETHER_ADDR_LEN];
358
359
if (oid->len - sub != ETHER_ADDR_LEN + 1 ||
360
oid->subs[sub] != ETHER_ADDR_LEN)
361
return (NULL);
362
363
for (i = 0; i < ETHER_ADDR_LEN; i++)
364
tp_addr[i] = oid->subs[sub + i + 1];
365
366
return (bridge_addrs_find(tp_addr, bif));
367
}
368
369
/*
370
* Find the next address entry for the SNMP index
371
* from the default bridge only.
372
*/
373
static struct tp_entry *
374
bridge_addrs_getnext(const struct asn_oid *oid, uint sub,
375
struct bridge_if *bif)
376
{
377
int i;
378
uint8_t tp_addr[ETHER_ADDR_LEN];
379
static struct tp_entry *te;
380
381
if (oid->len - sub == 0)
382
return (bridge_addrs_bif_first(bif));
383
384
if (oid->len - sub != ETHER_ADDR_LEN + 1 ||
385
oid->subs[sub] != ETHER_ADDR_LEN)
386
return (NULL);
387
388
for (i = 0; i < ETHER_ADDR_LEN; i++)
389
tp_addr[i] = oid->subs[sub + i + 1];
390
391
if ((te = bridge_addrs_find(tp_addr, bif)) == NULL)
392
return (NULL);
393
394
return (bridge_addrs_bif_next(te));
395
}
396
397
int
398
op_dot1d_tp_fdb(struct snmp_context *c __unused, struct snmp_value *val,
399
uint sub, uint iidx __unused, enum snmp_op op)
400
{
401
struct bridge_if *bif;
402
struct tp_entry *te;
403
404
if ((bif = bridge_get_default()) == NULL)
405
return (SNMP_ERR_NOSUCHNAME);
406
407
if (time(NULL) - bif->addrs_age > bridge_get_data_maxage() &&
408
bridge_update_addrs(bif) <= 0)
409
return (SNMP_ERR_NOSUCHNAME);
410
411
switch (op) {
412
case SNMP_OP_GET:
413
if ((te = bridge_addrs_get(&val->var, sub, bif)) == NULL)
414
return (SNMP_ERR_NOSUCHNAME);
415
goto get;
416
417
case SNMP_OP_GETNEXT:
418
if ((te = bridge_addrs_getnext(&val->var, sub, bif)) == NULL)
419
return (SNMP_ERR_NOSUCHNAME);
420
bridge_addrs_index_append(&val->var, sub, te);
421
goto get;
422
423
case SNMP_OP_SET:
424
return (SNMP_ERR_NOT_WRITEABLE);
425
426
case SNMP_OP_ROLLBACK:
427
case SNMP_OP_COMMIT:
428
break;
429
}
430
abort();
431
432
get:
433
switch (val->var.subs[sub - 1]) {
434
case LEAF_dot1dTpFdbAddress:
435
return (string_get(val, te->tp_addr, ETHER_ADDR_LEN));
436
case LEAF_dot1dTpFdbPort :
437
val->v.integer = te->port_no;
438
return (SNMP_ERR_NOERROR);
439
case LEAF_dot1dTpFdbStatus:
440
val->v.integer = te->status;
441
return (SNMP_ERR_NOERROR);
442
}
443
444
abort();
445
}
446
447
/*
448
* Private BEGEMOT-BRIDGE-MIB specifics.
449
*/
450
451
/*
452
* Construct the SNMP index from the bridge interface name
453
* and the address DST Mac.
454
*/
455
static int
456
bridge_addrs_begemot_index_append(struct asn_oid *oid, uint sub,
457
const struct tp_entry *te)
458
{
459
uint i, n_len;
460
const char *b_name;
461
462
if ((b_name = bridge_if_find_name(te->sysindex)) == NULL)
463
return (-1);
464
465
n_len = strlen(b_name);
466
oid->len = sub++;
467
oid->subs[oid->len++] = n_len;
468
469
for (i = 1; i <= n_len; i++)
470
oid->subs[oid->len++] = b_name[i - 1];
471
472
oid->subs[oid->len++] = ETHER_ADDR_LEN;
473
for (i = 1 ; i <= ETHER_ADDR_LEN; i++)
474
oid->subs[oid->len++] = te->tp_addr[i - 1];
475
476
return (0);
477
}
478
479
/*
480
* Find a bridge address entry by the bridge interface name
481
* and the address DST Mac.
482
*/
483
static struct tp_entry *
484
bridge_addrs_begemot_get(const struct asn_oid *oid, uint sub)
485
{
486
uint i, n_len;
487
uint8_t tp_addr[ETHER_ADDR_LEN];
488
char bif_name[IFNAMSIZ];
489
struct bridge_if *bif;
490
491
n_len = oid->subs[sub];
492
if (oid->len - sub != n_len + ETHER_ADDR_LEN + 3 ||
493
n_len >= IFNAMSIZ || oid->subs[sub + n_len + 1] != ETHER_ADDR_LEN)
494
return (NULL);
495
496
for (i = 0; i < n_len; i++)
497
bif_name[i] = oid->subs[n_len + i + 1];
498
bif_name[i] = '\0';
499
500
for (i = 1; i <= ETHER_ADDR_LEN; i++)
501
tp_addr[i - 1] = oid->subs[n_len + i + 1];
502
503
if ((bif = bridge_if_find_ifname(bif_name)) == NULL)
504
return (NULL);
505
506
return (bridge_addrs_find(tp_addr, bif));
507
}
508
509
/*
510
* Find the next bridge address entry by the bridge interface name
511
* and the address DST Mac.
512
*/
513
static struct tp_entry *
514
bridge_addrs_begemot_getnext(const struct asn_oid *oid, uint sub)
515
{
516
uint i, n_len;
517
uint8_t tp_addr[ETHER_ADDR_LEN];
518
char bif_name[IFNAMSIZ];
519
struct bridge_if *bif;
520
struct tp_entry *tp;
521
522
if (oid->len - sub == 0)
523
return (bridge_addrs_first());
524
525
n_len = oid->subs[sub];
526
if (oid->len - sub != n_len + ETHER_ADDR_LEN + 2 ||
527
n_len >= IFNAMSIZ || oid->subs[sub + n_len + 1] != ETHER_ADDR_LEN)
528
return (NULL);
529
530
for (i = 1; i <= n_len; i++)
531
bif_name[i - 1] = oid->subs[sub + i];
532
533
bif_name[i - 1] = '\0';
534
535
for (i = 1; i <= ETHER_ADDR_LEN; i++)
536
tp_addr[i - 1] = oid->subs[sub + n_len + i + 1];
537
538
if ((bif = bridge_if_find_ifname(bif_name)) == NULL ||
539
(tp = bridge_addrs_find(tp_addr, bif)) == NULL)
540
return (NULL);
541
542
return (bridge_addrs_next(tp));
543
}
544
545
int
546
op_begemot_tp_fdb(struct snmp_context *c __unused, struct snmp_value *val,
547
uint sub, uint iidx __unused, enum snmp_op op)
548
{
549
struct tp_entry *te;
550
551
if (time(NULL) - address_list_age > bridge_get_data_maxage())
552
bridge_update_all_addrs();
553
554
switch (op) {
555
case SNMP_OP_GET:
556
if ((te = bridge_addrs_begemot_get(&val->var, sub)) == NULL)
557
return (SNMP_ERR_NOSUCHNAME);
558
goto get;
559
560
case SNMP_OP_GETNEXT:
561
if ((te = bridge_addrs_begemot_getnext(&val->var,
562
sub)) == NULL ||
563
bridge_addrs_begemot_index_append(&val->var,
564
sub, te) < 0)
565
return (SNMP_ERR_NOSUCHNAME);
566
goto get;
567
568
case SNMP_OP_SET:
569
return (SNMP_ERR_NOT_WRITEABLE);
570
571
case SNMP_OP_ROLLBACK:
572
case SNMP_OP_COMMIT:
573
break;
574
}
575
abort();
576
577
get:
578
switch (val->var.subs[sub - 1]) {
579
case LEAF_begemotBridgeTpFdbAddress:
580
return (string_get(val, te->tp_addr, ETHER_ADDR_LEN));
581
case LEAF_begemotBridgeTpFdbPort:
582
val->v.integer = te->port_no;
583
return (SNMP_ERR_NOERROR);
584
case LEAF_begemotBridgeTpFdbStatus:
585
val->v.integer = te->status;
586
return (SNMP_ERR_NOERROR);
587
}
588
589
abort();
590
}
591
592