2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 2006 Shteryana Shopova <syrinx@FreeBSD.org>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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
28 * Bridge MIB implementation for SNMPd.
34 #include <sys/queue.h>
35 #include <sys/socket.h>
36 #include <sys/types.h>
38 #include <net/ethernet.h>
40 #include <net/if_mib.h>
49 #include <bsnmp/snmpmod.h>
50 #include <bsnmp/snmp_mibII.h>
52 #include "bridge_tree.h"
53 #include "bridge_snmp.h"
55 TAILQ_HEAD(tp_entries, tp_entry);
58 * Free the bridge address list.
61 bridge_tpe_free(struct tp_entries *headp)
65 while ((t = TAILQ_FIRST(headp)) != NULL) {
66 TAILQ_REMOVE(headp, t, tp_e);
72 * Free the bridge address entries from the address list,
73 * for the specified bridge interface only.
76 bridge_tpe_bif_free(struct tp_entries *headp,
77 struct bridge_if *bif)
81 while (bif->f_tpa != NULL && bif->sysindex == bif->f_tpa->sysindex) {
82 tp = TAILQ_NEXT(bif->f_tpa, tp_e);
83 TAILQ_REMOVE(headp, bif->f_tpa, tp_e);
90 * Compare two mac addresses.
96 bridge_compare_macs(const uint8_t *m1, const uint8_t *m2)
100 for (i = 0; i < ETHER_ADDR_LEN; i++) {
111 * Insert an address entry in the bridge address TAILQ starting to search
112 * for its place from the position of the first bridge address for the bridge
113 * interface. Update the first bridge address if necessary.
116 bridge_addrs_insert_at(struct tp_entries *headp,
117 struct tp_entry *ta, struct tp_entry **f_tpa)
121 assert(f_tpa != NULL);
124 t1 != NULL && ta->sysindex == t1->sysindex;
125 t1 = TAILQ_NEXT(t1, tp_e)) {
126 if (bridge_compare_macs(ta->tp_addr, t1->tp_addr) < 0) {
127 TAILQ_INSERT_BEFORE(t1, ta, tp_e);
135 TAILQ_INSERT_TAIL(headp, ta, tp_e);
137 TAILQ_INSERT_BEFORE(t1, ta, tp_e);
141 * Find an address entry's position in the address list
142 * according to bridge interface name.
144 static struct tp_entry *
145 bridge_addrs_find_pos(struct tp_entries *headp, uint32_t b_idx)
150 if ((t1 = TAILQ_FIRST(headp)) == NULL ||
151 bridge_compare_sysidx(b_idx, t1->sysindex) < 0)
154 t_idx = t1->sysindex;
156 for (t1 = TAILQ_NEXT(t1, tp_e); t1 != NULL; t1 = TAILQ_NEXT(t1, tp_e)) {
158 if (t1->sysindex != t_idx) {
159 if (bridge_compare_sysidx(b_idx, t1->sysindex) < 0)
160 return (TAILQ_PREV(t1, tp_entries, tp_e));
162 t_idx = t1->sysindex;
167 t1 = TAILQ_LAST(headp, tp_entries);
173 * Insert a bridge address in the bridge addresses list.
176 bridge_addrs_bif_insert(struct tp_entries *headp, struct tp_entry *te,
177 struct tp_entry **f_tpa)
179 struct tp_entry *temp;
182 bridge_addrs_insert_at(headp, te, f_tpa);
184 temp = bridge_addrs_find_pos(headp, te->sysindex);
187 TAILQ_INSERT_HEAD(headp, te, tp_e);
189 TAILQ_INSERT_AFTER(headp, temp, te, tp_e);
194 static struct tp_entries tp_entries = TAILQ_HEAD_INITIALIZER(tp_entries);
195 static time_t address_list_age;
198 bridge_addrs_update_listage(void)
200 address_list_age = time(NULL);
204 bridge_addrs_fini(void)
206 bridge_tpe_free(&tp_entries);
210 bridge_addrs_free(struct bridge_if *bif)
212 bridge_tpe_bif_free(&tp_entries, bif);
216 * Find the first address in the list.
218 static struct tp_entry *
219 bridge_addrs_first(void)
221 return (TAILQ_FIRST(&tp_entries));
225 * Find the next address in the list.
227 static struct tp_entry *
228 bridge_addrs_next(struct tp_entry *te)
230 return (TAILQ_NEXT(te, tp_e));
234 * Find the first address, learnt by the specified bridge interface.
237 bridge_addrs_bif_first(struct bridge_if *bif)
243 * Find the next address, learnt by the specified bridge interface.
246 bridge_addrs_bif_next(struct tp_entry *te)
248 struct tp_entry *te_next;
250 if ((te_next = TAILQ_NEXT(te, tp_e)) == NULL ||
251 te_next->sysindex != te->sysindex)
258 * Remove a bridge address from the list.
261 bridge_addrs_remove(struct tp_entry *te, struct bridge_if *bif)
263 if (bif->f_tpa == te)
264 bif->f_tpa = bridge_addrs_bif_next(te);
266 TAILQ_REMOVE(&tp_entries, te, tp_e);
271 * Allocate memory for a new bridge address and insert it in the list.
274 bridge_new_addrs(uint8_t *mac, struct bridge_if *bif)
278 if ((te = (struct tp_entry *) malloc(sizeof(*te))) == NULL) {
279 syslog(LOG_ERR, "bridge new address: failed: %s",
284 bzero(te, sizeof(*te));
286 te->sysindex = bif->sysindex;
287 bcopy(mac, te->tp_addr, ETHER_ADDR_LEN);
288 bridge_addrs_bif_insert(&tp_entries, te, &(bif->f_tpa));
294 * Given a mac address, learnt on a bridge,
295 * find the corrsponding TP entry for it.
298 bridge_addrs_find(uint8_t *mac, struct bridge_if *bif)
302 for (te = bif->f_tpa; te != NULL; te = TAILQ_NEXT(te, tp_e)) {
303 if (te->sysindex != bif->sysindex) {
308 if (bridge_compare_macs(te->tp_addr, mac) == 0)
316 bridge_addrs_dump(struct bridge_if *bif)
320 syslog(LOG_ERR, "Addresses count - %d", bif->num_addrs);
321 for (te = bridge_addrs_bif_first(bif); te != NULL;
322 te = bridge_addrs_bif_next(te)) {
323 syslog(LOG_ERR, "address %x:%x:%x:%x:%x:%x on port %d.%d",
324 te->tp_addr[0], te->tp_addr[1], te->tp_addr[2],
325 te->tp_addr[3], te->tp_addr[4], te->tp_addr[5],
326 te->sysindex, te->port_no);
335 * Construct the SNMP index from the address DST Mac.
338 bridge_addrs_index_append(struct asn_oid *oid, uint sub,
339 const struct tp_entry *te)
343 oid->len = sub + ETHER_ADDR_LEN + 1;
344 oid->subs[sub] = ETHER_ADDR_LEN;
346 for (i = 1; i <= ETHER_ADDR_LEN; i++)
347 oid->subs[sub + i] = te->tp_addr[i - 1];
351 * Find the address entry for the SNMP index from the default bridge only.
353 static struct tp_entry *
354 bridge_addrs_get(const struct asn_oid *oid, uint sub,
355 struct bridge_if *bif)
358 uint8_t tp_addr[ETHER_ADDR_LEN];
360 if (oid->len - sub != ETHER_ADDR_LEN + 1 ||
361 oid->subs[sub] != ETHER_ADDR_LEN)
364 for (i = 0; i < ETHER_ADDR_LEN; i++)
365 tp_addr[i] = oid->subs[sub + i + 1];
367 return (bridge_addrs_find(tp_addr, bif));
371 * Find the next address entry for the SNMP index
372 * from the default bridge only.
374 static struct tp_entry *
375 bridge_addrs_getnext(const struct asn_oid *oid, uint sub,
376 struct bridge_if *bif)
379 uint8_t tp_addr[ETHER_ADDR_LEN];
380 static struct tp_entry *te;
382 if (oid->len - sub == 0)
383 return (bridge_addrs_bif_first(bif));
385 if (oid->len - sub != ETHER_ADDR_LEN + 1 ||
386 oid->subs[sub] != ETHER_ADDR_LEN)
389 for (i = 0; i < ETHER_ADDR_LEN; i++)
390 tp_addr[i] = oid->subs[sub + i + 1];
392 if ((te = bridge_addrs_find(tp_addr, bif)) == NULL)
395 return (bridge_addrs_bif_next(te));
399 op_dot1d_tp_fdb(struct snmp_context *c __unused, struct snmp_value *val,
400 uint sub, uint iidx __unused, enum snmp_op op)
402 struct bridge_if *bif;
405 if ((bif = bridge_get_default()) == NULL)
406 return (SNMP_ERR_NOSUCHNAME);
408 if (time(NULL) - bif->addrs_age > bridge_get_data_maxage() &&
409 bridge_update_addrs(bif) <= 0)
410 return (SNMP_ERR_NOSUCHNAME);
414 if ((te = bridge_addrs_get(&val->var, sub, bif)) == NULL)
415 return (SNMP_ERR_NOSUCHNAME);
418 case SNMP_OP_GETNEXT:
419 if ((te = bridge_addrs_getnext(&val->var, sub, bif)) == NULL)
420 return (SNMP_ERR_NOSUCHNAME);
421 bridge_addrs_index_append(&val->var, sub, te);
425 return (SNMP_ERR_NOT_WRITEABLE);
427 case SNMP_OP_ROLLBACK:
434 switch (val->var.subs[sub - 1]) {
435 case LEAF_dot1dTpFdbAddress:
436 return (string_get(val, te->tp_addr, ETHER_ADDR_LEN));
437 case LEAF_dot1dTpFdbPort :
438 val->v.integer = te->port_no;
439 return (SNMP_ERR_NOERROR);
440 case LEAF_dot1dTpFdbStatus:
441 val->v.integer = te->status;
442 return (SNMP_ERR_NOERROR);
449 * Private BEGEMOT-BRIDGE-MIB specifics.
453 * Construct the SNMP index from the bridge interface name
454 * and the address DST Mac.
457 bridge_addrs_begemot_index_append(struct asn_oid *oid, uint sub,
458 const struct tp_entry *te)
463 if ((b_name = bridge_if_find_name(te->sysindex)) == NULL)
466 n_len = strlen(b_name);
468 oid->subs[oid->len++] = n_len;
470 for (i = 1; i <= n_len; i++)
471 oid->subs[oid->len++] = b_name[i - 1];
473 oid->subs[oid->len++] = ETHER_ADDR_LEN;
474 for (i = 1 ; i <= ETHER_ADDR_LEN; i++)
475 oid->subs[oid->len++] = te->tp_addr[i - 1];
481 * Find a bridge address entry by the bridge interface name
482 * and the address DST Mac.
484 static struct tp_entry *
485 bridge_addrs_begemot_get(const struct asn_oid *oid, uint sub)
488 uint8_t tp_addr[ETHER_ADDR_LEN];
489 char bif_name[IFNAMSIZ];
490 struct bridge_if *bif;
492 n_len = oid->subs[sub];
493 if (oid->len - sub != n_len + ETHER_ADDR_LEN + 3 ||
494 n_len >= IFNAMSIZ || oid->subs[sub + n_len + 1] != ETHER_ADDR_LEN)
497 for (i = 0; i < n_len; i++)
498 bif_name[i] = oid->subs[n_len + i + 1];
501 for (i = 1; i <= ETHER_ADDR_LEN; i++)
502 tp_addr[i - 1] = oid->subs[n_len + i + 1];
504 if ((bif = bridge_if_find_ifname(bif_name)) == NULL)
507 return (bridge_addrs_find(tp_addr, bif));
511 * Find the next bridge address entry by the bridge interface name
512 * and the address DST Mac.
514 static struct tp_entry *
515 bridge_addrs_begemot_getnext(const struct asn_oid *oid, uint sub)
518 uint8_t tp_addr[ETHER_ADDR_LEN];
519 char bif_name[IFNAMSIZ];
520 struct bridge_if *bif;
523 if (oid->len - sub == 0)
524 return (bridge_addrs_first());
526 n_len = oid->subs[sub];
527 if (oid->len - sub != n_len + ETHER_ADDR_LEN + 2 ||
528 n_len >= IFNAMSIZ || oid->subs[sub + n_len + 1] != ETHER_ADDR_LEN)
531 for (i = 1; i <= n_len; i++)
532 bif_name[i - 1] = oid->subs[sub + i];
534 bif_name[i - 1] = '\0';
536 for (i = 1; i <= ETHER_ADDR_LEN; i++)
537 tp_addr[i - 1] = oid->subs[sub + n_len + i + 1];
539 if ((bif = bridge_if_find_ifname(bif_name)) == NULL ||
540 (tp = bridge_addrs_find(tp_addr, bif)) == NULL)
543 return (bridge_addrs_next(tp));
547 op_begemot_tp_fdb(struct snmp_context *c __unused, struct snmp_value *val,
548 uint sub, uint iidx __unused, enum snmp_op op)
552 if (time(NULL) - address_list_age > bridge_get_data_maxage())
553 bridge_update_all_addrs();
557 if ((te = bridge_addrs_begemot_get(&val->var, sub)) == NULL)
558 return (SNMP_ERR_NOSUCHNAME);
561 case SNMP_OP_GETNEXT:
562 if ((te = bridge_addrs_begemot_getnext(&val->var,
564 bridge_addrs_begemot_index_append(&val->var,
566 return (SNMP_ERR_NOSUCHNAME);
570 return (SNMP_ERR_NOT_WRITEABLE);
572 case SNMP_OP_ROLLBACK:
579 switch (val->var.subs[sub - 1]) {
580 case LEAF_begemotBridgeTpFdbAddress:
581 return (string_get(val, te->tp_addr, ETHER_ADDR_LEN));
582 case LEAF_begemotBridgeTpFdbPort:
583 val->v.integer = te->port_no;
584 return (SNMP_ERR_NOERROR);
585 case LEAF_begemotBridgeTpFdbStatus:
586 val->v.integer = te->status;
587 return (SNMP_ERR_NOERROR);