17850265eSShteryana Shopova /*- 2*1de7b4b8SPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3*1de7b4b8SPedro F. Giffuni * 47850265eSShteryana Shopova * Copyright (c) 2006 Shteryana Shopova <syrinx@FreeBSD.org> 57850265eSShteryana Shopova * All rights reserved. 67850265eSShteryana Shopova * 77850265eSShteryana Shopova * Redistribution and use in source and binary forms, with or without 87850265eSShteryana Shopova * modification, are permitted provided that the following conditions 97850265eSShteryana Shopova * are met: 107850265eSShteryana Shopova * 1. Redistributions of source code must retain the above copyright 117850265eSShteryana Shopova * notice, this list of conditions and the following disclaimer. 127850265eSShteryana Shopova * 2. Redistributions in binary form must reproduce the above copyright 137850265eSShteryana Shopova * notice, this list of conditions and the following disclaimer in the 147850265eSShteryana Shopova * documentation and/or other materials provided with the distribution. 157850265eSShteryana Shopova * 167850265eSShteryana Shopova * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 177850265eSShteryana Shopova * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 187850265eSShteryana Shopova * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 197850265eSShteryana Shopova * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 207850265eSShteryana Shopova * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 217850265eSShteryana Shopova * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 227850265eSShteryana Shopova * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 237850265eSShteryana Shopova * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 247850265eSShteryana Shopova * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 257850265eSShteryana Shopova * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 267850265eSShteryana Shopova * SUCH DAMAGE. 277850265eSShteryana Shopova * 287850265eSShteryana Shopova * Bridge MIB implementation for SNMPd. 297850265eSShteryana Shopova * Bridge addresses. 307850265eSShteryana Shopova * 317850265eSShteryana Shopova * $FreeBSD$ 327850265eSShteryana Shopova */ 337850265eSShteryana Shopova 347850265eSShteryana Shopova #include <sys/queue.h> 357850265eSShteryana Shopova #include <sys/socket.h> 367850265eSShteryana Shopova #include <sys/types.h> 377850265eSShteryana Shopova 387850265eSShteryana Shopova #include <net/ethernet.h> 397850265eSShteryana Shopova #include <net/if.h> 407850265eSShteryana Shopova #include <net/if_mib.h> 417850265eSShteryana Shopova 427850265eSShteryana Shopova #include <assert.h> 437850265eSShteryana Shopova #include <errno.h> 447850265eSShteryana Shopova #include <stdarg.h> 457850265eSShteryana Shopova #include <string.h> 467850265eSShteryana Shopova #include <stdlib.h> 477850265eSShteryana Shopova #include <syslog.h> 487850265eSShteryana Shopova 497850265eSShteryana Shopova #include <bsnmp/snmpmod.h> 507850265eSShteryana Shopova #include <bsnmp/snmp_mibII.h> 517850265eSShteryana Shopova 527850265eSShteryana Shopova #include "bridge_tree.h" 537850265eSShteryana Shopova #include "bridge_snmp.h" 547850265eSShteryana Shopova 557850265eSShteryana Shopova TAILQ_HEAD(tp_entries, tp_entry); 567850265eSShteryana Shopova 577850265eSShteryana Shopova /* 587850265eSShteryana Shopova * Free the bridge address list. 597850265eSShteryana Shopova */ 607850265eSShteryana Shopova static void 617850265eSShteryana Shopova bridge_tpe_free(struct tp_entries *headp) 627850265eSShteryana Shopova { 637850265eSShteryana Shopova struct tp_entry *t; 647850265eSShteryana Shopova 657850265eSShteryana Shopova while ((t = TAILQ_FIRST(headp)) != NULL) { 667850265eSShteryana Shopova TAILQ_REMOVE(headp, t, tp_e); 677850265eSShteryana Shopova free(t); 687850265eSShteryana Shopova } 697850265eSShteryana Shopova } 707850265eSShteryana Shopova 717850265eSShteryana Shopova /* 727850265eSShteryana Shopova * Free the bridge address entries from the address list, 737850265eSShteryana Shopova * for the specified bridge interface only. 747850265eSShteryana Shopova */ 757850265eSShteryana Shopova static void 767850265eSShteryana Shopova bridge_tpe_bif_free(struct tp_entries *headp, 777850265eSShteryana Shopova struct bridge_if *bif) 787850265eSShteryana Shopova { 797850265eSShteryana Shopova struct tp_entry *tp; 807850265eSShteryana Shopova 817850265eSShteryana Shopova while (bif->f_tpa != NULL && bif->sysindex == bif->f_tpa->sysindex) { 827850265eSShteryana Shopova tp = TAILQ_NEXT(bif->f_tpa, tp_e); 837850265eSShteryana Shopova TAILQ_REMOVE(headp, bif->f_tpa, tp_e); 847850265eSShteryana Shopova free(bif->f_tpa); 857850265eSShteryana Shopova bif->f_tpa = tp; 867850265eSShteryana Shopova } 877850265eSShteryana Shopova } 887850265eSShteryana Shopova 897850265eSShteryana Shopova /* 907850265eSShteryana Shopova * Compare two mac addresses. 917850265eSShteryana Shopova * m1 < m2 : -1 927850265eSShteryana Shopova * m1 > m2 : +1 937850265eSShteryana Shopova * m1 = m2 : 0 947850265eSShteryana Shopova */ 957850265eSShteryana Shopova static int 967850265eSShteryana Shopova bridge_compare_macs(const uint8_t *m1, const uint8_t *m2) 977850265eSShteryana Shopova { 987850265eSShteryana Shopova int i; 997850265eSShteryana Shopova 1007850265eSShteryana Shopova for (i = 0; i < ETHER_ADDR_LEN; i++) { 1017850265eSShteryana Shopova if (m1[i] < m2[i]) 1027850265eSShteryana Shopova return (-1); 1037850265eSShteryana Shopova if (m1[i] > m2[i]) 1047850265eSShteryana Shopova return (1); 1057850265eSShteryana Shopova } 1067850265eSShteryana Shopova 1077850265eSShteryana Shopova return (0); 1087850265eSShteryana Shopova } 1097850265eSShteryana Shopova 1107850265eSShteryana Shopova /* 1117850265eSShteryana Shopova * Insert an address entry in the bridge address TAILQ starting to search 1127850265eSShteryana Shopova * for its place from the position of the first bridge address for the bridge 1133df5ecacSUlrich Spörlein * interface. Update the first bridge address if necessary. 1147850265eSShteryana Shopova */ 1157850265eSShteryana Shopova static void 1167850265eSShteryana Shopova bridge_addrs_insert_at(struct tp_entries *headp, 1177850265eSShteryana Shopova struct tp_entry *ta, struct tp_entry **f_tpa) 1187850265eSShteryana Shopova { 1197850265eSShteryana Shopova struct tp_entry *t1; 1207850265eSShteryana Shopova 1217850265eSShteryana Shopova assert(f_tpa != NULL); 1227850265eSShteryana Shopova 1237850265eSShteryana Shopova for (t1 = *f_tpa; 1247850265eSShteryana Shopova t1 != NULL && ta->sysindex == t1->sysindex; 1257850265eSShteryana Shopova t1 = TAILQ_NEXT(t1, tp_e)) { 1267850265eSShteryana Shopova if (bridge_compare_macs(ta->tp_addr, t1->tp_addr) < 0) { 1277850265eSShteryana Shopova TAILQ_INSERT_BEFORE(t1, ta, tp_e); 1287850265eSShteryana Shopova if (*f_tpa == t1) 1297850265eSShteryana Shopova (*f_tpa) = ta; 1307850265eSShteryana Shopova return; 1317850265eSShteryana Shopova } 1327850265eSShteryana Shopova } 1337850265eSShteryana Shopova 1347850265eSShteryana Shopova if (t1 == NULL) 1357850265eSShteryana Shopova TAILQ_INSERT_TAIL(headp, ta, tp_e); 1367850265eSShteryana Shopova else 1377850265eSShteryana Shopova TAILQ_INSERT_BEFORE(t1, ta, tp_e); 1387850265eSShteryana Shopova } 1397850265eSShteryana Shopova 1407850265eSShteryana Shopova /* 1413df5ecacSUlrich Spörlein * Find an address entry's position in the address list 1427850265eSShteryana Shopova * according to bridge interface name. 1437850265eSShteryana Shopova */ 1447850265eSShteryana Shopova static struct tp_entry * 1457850265eSShteryana Shopova bridge_addrs_find_pos(struct tp_entries *headp, uint32_t b_idx) 1467850265eSShteryana Shopova { 1477850265eSShteryana Shopova uint32_t t_idx; 1487850265eSShteryana Shopova struct tp_entry *t1; 1497850265eSShteryana Shopova 1507850265eSShteryana Shopova if ((t1 = TAILQ_FIRST(headp)) == NULL || 1517850265eSShteryana Shopova bridge_compare_sysidx(b_idx, t1->sysindex) < 0) 1527850265eSShteryana Shopova return (NULL); 1537850265eSShteryana Shopova 1547850265eSShteryana Shopova t_idx = t1->sysindex; 1557850265eSShteryana Shopova 1567850265eSShteryana Shopova for (t1 = TAILQ_NEXT(t1, tp_e); t1 != NULL; t1 = TAILQ_NEXT(t1, tp_e)) { 1577850265eSShteryana Shopova 1587850265eSShteryana Shopova if (t1->sysindex != t_idx) { 1597850265eSShteryana Shopova if (bridge_compare_sysidx(b_idx, t1->sysindex) < 0) 1607850265eSShteryana Shopova return (TAILQ_PREV(t1, tp_entries, tp_e)); 1617850265eSShteryana Shopova else 1627850265eSShteryana Shopova t_idx = t1->sysindex; 1637850265eSShteryana Shopova } 1647850265eSShteryana Shopova } 1657850265eSShteryana Shopova 1667850265eSShteryana Shopova if (t1 == NULL) 1677850265eSShteryana Shopova t1 = TAILQ_LAST(headp, tp_entries); 1687850265eSShteryana Shopova 1697850265eSShteryana Shopova return (t1); 1707850265eSShteryana Shopova } 1717850265eSShteryana Shopova 1727850265eSShteryana Shopova /* 1737850265eSShteryana Shopova * Insert a bridge address in the bridge addresses list. 1747850265eSShteryana Shopova */ 1757850265eSShteryana Shopova static void 1767850265eSShteryana Shopova bridge_addrs_bif_insert(struct tp_entries *headp, struct tp_entry *te, 1777850265eSShteryana Shopova struct tp_entry **f_tpa) 1787850265eSShteryana Shopova { 1797850265eSShteryana Shopova struct tp_entry *temp; 1807850265eSShteryana Shopova 1817850265eSShteryana Shopova if (*f_tpa != NULL) 1827850265eSShteryana Shopova bridge_addrs_insert_at(headp, te, f_tpa); 1837850265eSShteryana Shopova else { 1847850265eSShteryana Shopova temp = bridge_addrs_find_pos(headp, te->sysindex); 1857850265eSShteryana Shopova 1867850265eSShteryana Shopova if (temp == NULL) 1877850265eSShteryana Shopova TAILQ_INSERT_HEAD(headp, te, tp_e); 1887850265eSShteryana Shopova else 1897850265eSShteryana Shopova TAILQ_INSERT_AFTER(headp, temp, te, tp_e); 1907850265eSShteryana Shopova *f_tpa = te; 1917850265eSShteryana Shopova } 1927850265eSShteryana Shopova } 1937850265eSShteryana Shopova 1947850265eSShteryana Shopova static struct tp_entries tp_entries = TAILQ_HEAD_INITIALIZER(tp_entries); 1957850265eSShteryana Shopova static time_t address_list_age; 1967850265eSShteryana Shopova 1977850265eSShteryana Shopova void 1987850265eSShteryana Shopova bridge_addrs_update_listage(void) 1997850265eSShteryana Shopova { 2007850265eSShteryana Shopova address_list_age = time(NULL); 2017850265eSShteryana Shopova } 2027850265eSShteryana Shopova 2037850265eSShteryana Shopova void 2047850265eSShteryana Shopova bridge_addrs_fini(void) 2057850265eSShteryana Shopova { 2067850265eSShteryana Shopova bridge_tpe_free(&tp_entries); 2077850265eSShteryana Shopova } 2087850265eSShteryana Shopova 2097850265eSShteryana Shopova void 2107850265eSShteryana Shopova bridge_addrs_free(struct bridge_if *bif) 2117850265eSShteryana Shopova { 2127850265eSShteryana Shopova bridge_tpe_bif_free(&tp_entries, bif); 2137850265eSShteryana Shopova } 2147850265eSShteryana Shopova 2157850265eSShteryana Shopova /* 2167850265eSShteryana Shopova * Find the first address in the list. 2177850265eSShteryana Shopova */ 2187850265eSShteryana Shopova static struct tp_entry * 2197850265eSShteryana Shopova bridge_addrs_first(void) 2207850265eSShteryana Shopova { 2217850265eSShteryana Shopova return (TAILQ_FIRST(&tp_entries)); 2227850265eSShteryana Shopova } 2237850265eSShteryana Shopova 2247850265eSShteryana Shopova /* 2257850265eSShteryana Shopova * Find the next address in the list. 2267850265eSShteryana Shopova */ 2277850265eSShteryana Shopova static struct tp_entry * 2287850265eSShteryana Shopova bridge_addrs_next(struct tp_entry *te) 2297850265eSShteryana Shopova { 2307850265eSShteryana Shopova return (TAILQ_NEXT(te, tp_e)); 2317850265eSShteryana Shopova } 2327850265eSShteryana Shopova 2337850265eSShteryana Shopova /* 2347850265eSShteryana Shopova * Find the first address, learnt by the specified bridge interface. 2357850265eSShteryana Shopova */ 2367850265eSShteryana Shopova struct tp_entry * 2377850265eSShteryana Shopova bridge_addrs_bif_first(struct bridge_if *bif) 2387850265eSShteryana Shopova { 2397850265eSShteryana Shopova return (bif->f_tpa); 2407850265eSShteryana Shopova } 2417850265eSShteryana Shopova 2427850265eSShteryana Shopova /* 2437850265eSShteryana Shopova * Find the next address, learnt by the specified bridge interface. 2447850265eSShteryana Shopova */ 2457850265eSShteryana Shopova struct tp_entry * 2467850265eSShteryana Shopova bridge_addrs_bif_next(struct tp_entry *te) 2477850265eSShteryana Shopova { 2487850265eSShteryana Shopova struct tp_entry *te_next; 2497850265eSShteryana Shopova 2507850265eSShteryana Shopova if ((te_next = TAILQ_NEXT(te, tp_e)) == NULL || 2517850265eSShteryana Shopova te_next->sysindex != te->sysindex) 2527850265eSShteryana Shopova return (NULL); 2537850265eSShteryana Shopova 2547850265eSShteryana Shopova return (te_next); 2557850265eSShteryana Shopova } 2567850265eSShteryana Shopova 2577850265eSShteryana Shopova /* 2587850265eSShteryana Shopova * Remove a bridge address from the list. 2597850265eSShteryana Shopova */ 2607850265eSShteryana Shopova void 2617850265eSShteryana Shopova bridge_addrs_remove(struct tp_entry *te, struct bridge_if *bif) 2627850265eSShteryana Shopova { 2637850265eSShteryana Shopova if (bif->f_tpa == te) 2647850265eSShteryana Shopova bif->f_tpa = bridge_addrs_bif_next(te); 2657850265eSShteryana Shopova 2667850265eSShteryana Shopova TAILQ_REMOVE(&tp_entries, te, tp_e); 2677850265eSShteryana Shopova free(te); 2687850265eSShteryana Shopova } 2697850265eSShteryana Shopova 2707850265eSShteryana Shopova /* 2717850265eSShteryana Shopova * Allocate memory for a new bridge address and insert it in the list. 2727850265eSShteryana Shopova */ 2737850265eSShteryana Shopova struct tp_entry * 2747850265eSShteryana Shopova bridge_new_addrs(uint8_t *mac, struct bridge_if *bif) 2757850265eSShteryana Shopova { 2767850265eSShteryana Shopova struct tp_entry *te; 2777850265eSShteryana Shopova 2787850265eSShteryana Shopova if ((te = (struct tp_entry *) malloc(sizeof(*te))) == NULL) { 2797850265eSShteryana Shopova syslog(LOG_ERR, "bridge new address: failed: %s", 2807850265eSShteryana Shopova strerror(errno)); 2817850265eSShteryana Shopova return (NULL); 2827850265eSShteryana Shopova } 2837850265eSShteryana Shopova 2847850265eSShteryana Shopova bzero(te, sizeof(*te)); 2857850265eSShteryana Shopova 2867850265eSShteryana Shopova te->sysindex = bif->sysindex; 2877850265eSShteryana Shopova bcopy(mac, te->tp_addr, ETHER_ADDR_LEN); 2887850265eSShteryana Shopova bridge_addrs_bif_insert(&tp_entries, te, &(bif->f_tpa)); 2897850265eSShteryana Shopova 2907850265eSShteryana Shopova return (te); 2917850265eSShteryana Shopova } 2927850265eSShteryana Shopova 2937850265eSShteryana Shopova /* 2947850265eSShteryana Shopova * Given a mac address, learnt on a bridge, 2957850265eSShteryana Shopova * find the corrsponding TP entry for it. 2967850265eSShteryana Shopova */ 2977850265eSShteryana Shopova struct tp_entry * 2987850265eSShteryana Shopova bridge_addrs_find(uint8_t *mac, struct bridge_if *bif) 2997850265eSShteryana Shopova { 3007850265eSShteryana Shopova struct tp_entry *te; 3017850265eSShteryana Shopova 3027850265eSShteryana Shopova for (te = bif->f_tpa; te != NULL; te = TAILQ_NEXT(te, tp_e)) { 3037850265eSShteryana Shopova if (te->sysindex != bif->sysindex) { 3047850265eSShteryana Shopova te = NULL; 3057850265eSShteryana Shopova break; 3067850265eSShteryana Shopova } 3077850265eSShteryana Shopova 3087850265eSShteryana Shopova if (bridge_compare_macs(te->tp_addr, mac) == 0) 3097850265eSShteryana Shopova break; 3107850265eSShteryana Shopova } 3117850265eSShteryana Shopova 3127850265eSShteryana Shopova return (te); 3137850265eSShteryana Shopova } 3147850265eSShteryana Shopova 3157850265eSShteryana Shopova void 3167850265eSShteryana Shopova bridge_addrs_dump(struct bridge_if *bif) 3177850265eSShteryana Shopova { 3187850265eSShteryana Shopova struct tp_entry *te; 3197850265eSShteryana Shopova 3207850265eSShteryana Shopova syslog(LOG_ERR, "Addresses count - %d", bif->num_addrs); 3217850265eSShteryana Shopova for (te = bridge_addrs_bif_first(bif); te != NULL; 3227850265eSShteryana Shopova te = bridge_addrs_bif_next(te)) { 3237850265eSShteryana Shopova syslog(LOG_ERR, "address %x:%x:%x:%x:%x:%x on port %d.%d", 3247850265eSShteryana Shopova te->tp_addr[0], te->tp_addr[1], te->tp_addr[2], 3257850265eSShteryana Shopova te->tp_addr[3], te->tp_addr[4], te->tp_addr[5], 3267850265eSShteryana Shopova te->sysindex, te->port_no); 3277850265eSShteryana Shopova } 3287850265eSShteryana Shopova } 3297850265eSShteryana Shopova 3307850265eSShteryana Shopova /* 3317850265eSShteryana Shopova * RFC4188 specifics. 3327850265eSShteryana Shopova */ 3337850265eSShteryana Shopova 3347850265eSShteryana Shopova /* 3357850265eSShteryana Shopova * Construct the SNMP index from the address DST Mac. 3367850265eSShteryana Shopova */ 3377850265eSShteryana Shopova static void 3387850265eSShteryana Shopova bridge_addrs_index_append(struct asn_oid *oid, uint sub, 3397850265eSShteryana Shopova const struct tp_entry *te) 3407850265eSShteryana Shopova { 3417850265eSShteryana Shopova int i; 3427850265eSShteryana Shopova 3437850265eSShteryana Shopova oid->len = sub + ETHER_ADDR_LEN + 1; 3447850265eSShteryana Shopova oid->subs[sub] = ETHER_ADDR_LEN; 3457850265eSShteryana Shopova 3467850265eSShteryana Shopova for (i = 1; i <= ETHER_ADDR_LEN; i++) 3477850265eSShteryana Shopova oid->subs[sub + i] = te->tp_addr[i - 1]; 3487850265eSShteryana Shopova } 3497850265eSShteryana Shopova 3507850265eSShteryana Shopova /* 3517850265eSShteryana Shopova * Find the address entry for the SNMP index from the default bridge only. 3527850265eSShteryana Shopova */ 3537850265eSShteryana Shopova static struct tp_entry * 3547850265eSShteryana Shopova bridge_addrs_get(const struct asn_oid *oid, uint sub, 3557850265eSShteryana Shopova struct bridge_if *bif) 3567850265eSShteryana Shopova { 3577850265eSShteryana Shopova int i; 3587850265eSShteryana Shopova uint8_t tp_addr[ETHER_ADDR_LEN]; 3597850265eSShteryana Shopova 3607850265eSShteryana Shopova if (oid->len - sub != ETHER_ADDR_LEN + 1 || 3617850265eSShteryana Shopova oid->subs[sub] != ETHER_ADDR_LEN) 3627850265eSShteryana Shopova return (NULL); 3637850265eSShteryana Shopova 3647850265eSShteryana Shopova for (i = 0; i < ETHER_ADDR_LEN; i++) 3657850265eSShteryana Shopova tp_addr[i] = oid->subs[sub + i + 1]; 3667850265eSShteryana Shopova 3677850265eSShteryana Shopova return (bridge_addrs_find(tp_addr, bif)); 3687850265eSShteryana Shopova } 3697850265eSShteryana Shopova 3707850265eSShteryana Shopova /* 3717850265eSShteryana Shopova * Find the next address entry for the SNMP index 3727850265eSShteryana Shopova * from the default bridge only. 3737850265eSShteryana Shopova */ 3747850265eSShteryana Shopova static struct tp_entry * 3757850265eSShteryana Shopova bridge_addrs_getnext(const struct asn_oid *oid, uint sub, 3767850265eSShteryana Shopova struct bridge_if *bif) 3777850265eSShteryana Shopova { 3787850265eSShteryana Shopova int i; 3797850265eSShteryana Shopova uint8_t tp_addr[ETHER_ADDR_LEN]; 3807850265eSShteryana Shopova static struct tp_entry *te; 3817850265eSShteryana Shopova 3827850265eSShteryana Shopova if (oid->len - sub == 0) 3837850265eSShteryana Shopova return (bridge_addrs_bif_first(bif)); 3847850265eSShteryana Shopova 3857850265eSShteryana Shopova if (oid->len - sub != ETHER_ADDR_LEN + 1 || 3867850265eSShteryana Shopova oid->subs[sub] != ETHER_ADDR_LEN) 3877850265eSShteryana Shopova return (NULL); 3887850265eSShteryana Shopova 3897850265eSShteryana Shopova for (i = 0; i < ETHER_ADDR_LEN; i++) 3907850265eSShteryana Shopova tp_addr[i] = oid->subs[sub + i + 1]; 3917850265eSShteryana Shopova 3927850265eSShteryana Shopova if ((te = bridge_addrs_find(tp_addr, bif)) == NULL) 3937850265eSShteryana Shopova return (NULL); 3947850265eSShteryana Shopova 3957850265eSShteryana Shopova return (bridge_addrs_bif_next(te)); 3967850265eSShteryana Shopova } 3977850265eSShteryana Shopova 3987850265eSShteryana Shopova int 3997850265eSShteryana Shopova op_dot1d_tp_fdb(struct snmp_context *c __unused, struct snmp_value *val, 4007850265eSShteryana Shopova uint sub, uint iidx __unused, enum snmp_op op) 4017850265eSShteryana Shopova { 4027850265eSShteryana Shopova struct bridge_if *bif; 4037850265eSShteryana Shopova struct tp_entry *te; 4047850265eSShteryana Shopova 4057850265eSShteryana Shopova if ((bif = bridge_get_default()) == NULL) 4067850265eSShteryana Shopova return (SNMP_ERR_NOSUCHNAME); 4077850265eSShteryana Shopova 4087850265eSShteryana Shopova if (time(NULL) - bif->addrs_age > bridge_get_data_maxage() && 4097850265eSShteryana Shopova bridge_update_addrs(bif) <= 0) 4107850265eSShteryana Shopova return (SNMP_ERR_NOSUCHNAME); 4117850265eSShteryana Shopova 4127850265eSShteryana Shopova switch (op) { 4137850265eSShteryana Shopova case SNMP_OP_GET: 4147850265eSShteryana Shopova if ((te = bridge_addrs_get(&val->var, sub, bif)) == NULL) 4157850265eSShteryana Shopova return (SNMP_ERR_NOSUCHNAME); 416f02a1e57SShteryana Shopova goto get; 4177850265eSShteryana Shopova 4187850265eSShteryana Shopova case SNMP_OP_GETNEXT: 4197850265eSShteryana Shopova if ((te = bridge_addrs_getnext(&val->var, sub, bif)) == NULL) 4207850265eSShteryana Shopova return (SNMP_ERR_NOSUCHNAME); 4217850265eSShteryana Shopova bridge_addrs_index_append(&val->var, sub, te); 422f02a1e57SShteryana Shopova goto get; 4237850265eSShteryana Shopova 4247850265eSShteryana Shopova case SNMP_OP_SET: 4257850265eSShteryana Shopova return (SNMP_ERR_NOT_WRITEABLE); 4267850265eSShteryana Shopova 4277850265eSShteryana Shopova case SNMP_OP_ROLLBACK: 4287850265eSShteryana Shopova case SNMP_OP_COMMIT: 429f02a1e57SShteryana Shopova break; 4307850265eSShteryana Shopova } 431f02a1e57SShteryana Shopova abort(); 4327850265eSShteryana Shopova 433f02a1e57SShteryana Shopova get: 4347850265eSShteryana Shopova switch (val->var.subs[sub - 1]) { 4357850265eSShteryana Shopova case LEAF_dot1dTpFdbAddress: 436f02a1e57SShteryana Shopova return (string_get(val, te->tp_addr, ETHER_ADDR_LEN)); 4377850265eSShteryana Shopova case LEAF_dot1dTpFdbPort : 4387850265eSShteryana Shopova val->v.integer = te->port_no; 439f02a1e57SShteryana Shopova return (SNMP_ERR_NOERROR); 4407850265eSShteryana Shopova case LEAF_dot1dTpFdbStatus: 4417850265eSShteryana Shopova val->v.integer = te->status; 442f02a1e57SShteryana Shopova return (SNMP_ERR_NOERROR); 4437850265eSShteryana Shopova } 4447850265eSShteryana Shopova 445f02a1e57SShteryana Shopova abort(); 4467850265eSShteryana Shopova } 4477850265eSShteryana Shopova 4487850265eSShteryana Shopova /* 4497850265eSShteryana Shopova * Private BEGEMOT-BRIDGE-MIB specifics. 4507850265eSShteryana Shopova */ 4517850265eSShteryana Shopova 4527850265eSShteryana Shopova /* 4537850265eSShteryana Shopova * Construct the SNMP index from the bridge interface name 4547850265eSShteryana Shopova * and the address DST Mac. 4557850265eSShteryana Shopova */ 4567850265eSShteryana Shopova static int 4577850265eSShteryana Shopova bridge_addrs_begemot_index_append(struct asn_oid *oid, uint sub, 4587850265eSShteryana Shopova const struct tp_entry *te) 4597850265eSShteryana Shopova { 4607850265eSShteryana Shopova uint i, n_len; 4617850265eSShteryana Shopova const char *b_name; 4627850265eSShteryana Shopova 4637850265eSShteryana Shopova if ((b_name = bridge_if_find_name(te->sysindex)) == NULL) 4647850265eSShteryana Shopova return (-1); 4657850265eSShteryana Shopova 4667850265eSShteryana Shopova n_len = strlen(b_name); 4677850265eSShteryana Shopova oid->len = sub++; 4687850265eSShteryana Shopova oid->subs[oid->len++] = n_len; 4697850265eSShteryana Shopova 4707850265eSShteryana Shopova for (i = 1; i <= n_len; i++) 4717850265eSShteryana Shopova oid->subs[oid->len++] = b_name[i - 1]; 4727850265eSShteryana Shopova 4737850265eSShteryana Shopova oid->subs[oid->len++] = ETHER_ADDR_LEN; 4747850265eSShteryana Shopova for (i = 1 ; i <= ETHER_ADDR_LEN; i++) 4757850265eSShteryana Shopova oid->subs[oid->len++] = te->tp_addr[i - 1]; 4767850265eSShteryana Shopova 4777850265eSShteryana Shopova return (0); 4787850265eSShteryana Shopova } 4797850265eSShteryana Shopova 4807850265eSShteryana Shopova /* 4817850265eSShteryana Shopova * Find a bridge address entry by the bridge interface name 4827850265eSShteryana Shopova * and the address DST Mac. 4837850265eSShteryana Shopova */ 4847850265eSShteryana Shopova static struct tp_entry * 4857850265eSShteryana Shopova bridge_addrs_begemot_get(const struct asn_oid *oid, uint sub) 4867850265eSShteryana Shopova { 4877850265eSShteryana Shopova uint i, n_len; 4887850265eSShteryana Shopova uint8_t tp_addr[ETHER_ADDR_LEN]; 4897850265eSShteryana Shopova char bif_name[IFNAMSIZ]; 4907850265eSShteryana Shopova struct bridge_if *bif; 4917850265eSShteryana Shopova 4927850265eSShteryana Shopova n_len = oid->subs[sub]; 4937850265eSShteryana Shopova if (oid->len - sub != n_len + ETHER_ADDR_LEN + 3 || 4947850265eSShteryana Shopova n_len >= IFNAMSIZ || oid->subs[sub + n_len + 1] != ETHER_ADDR_LEN) 4957850265eSShteryana Shopova return (NULL); 4967850265eSShteryana Shopova 4977850265eSShteryana Shopova for (i = 0; i < n_len; i++) 4987850265eSShteryana Shopova bif_name[i] = oid->subs[n_len + i + 1]; 4997850265eSShteryana Shopova bif_name[i] = '\0'; 5007850265eSShteryana Shopova 5017850265eSShteryana Shopova for (i = 1; i <= ETHER_ADDR_LEN; i++) 5027850265eSShteryana Shopova tp_addr[i - 1] = oid->subs[n_len + i + 1]; 5037850265eSShteryana Shopova 5047850265eSShteryana Shopova if ((bif = bridge_if_find_ifname(bif_name)) == NULL) 5057850265eSShteryana Shopova return (NULL); 5067850265eSShteryana Shopova 5077850265eSShteryana Shopova return (bridge_addrs_find(tp_addr, bif)); 5087850265eSShteryana Shopova } 5097850265eSShteryana Shopova 5107850265eSShteryana Shopova /* 5117850265eSShteryana Shopova * Find the next bridge address entry by the bridge interface name 5127850265eSShteryana Shopova * and the address DST Mac. 5137850265eSShteryana Shopova */ 5147850265eSShteryana Shopova static struct tp_entry * 5157850265eSShteryana Shopova bridge_addrs_begemot_getnext(const struct asn_oid *oid, uint sub) 5167850265eSShteryana Shopova { 5177850265eSShteryana Shopova uint i, n_len; 5187850265eSShteryana Shopova uint8_t tp_addr[ETHER_ADDR_LEN]; 5197850265eSShteryana Shopova char bif_name[IFNAMSIZ]; 5207850265eSShteryana Shopova struct bridge_if *bif; 5217850265eSShteryana Shopova struct tp_entry *tp; 5227850265eSShteryana Shopova 5237850265eSShteryana Shopova if (oid->len - sub == 0) 5247850265eSShteryana Shopova return (bridge_addrs_first()); 5257850265eSShteryana Shopova 5267850265eSShteryana Shopova n_len = oid->subs[sub]; 5277850265eSShteryana Shopova if (oid->len - sub != n_len + ETHER_ADDR_LEN + 2 || 5287850265eSShteryana Shopova n_len >= IFNAMSIZ || oid->subs[sub + n_len + 1] != ETHER_ADDR_LEN) 5297850265eSShteryana Shopova return (NULL); 5307850265eSShteryana Shopova 5317850265eSShteryana Shopova for (i = 1; i <= n_len; i++) 5327850265eSShteryana Shopova bif_name[i - 1] = oid->subs[sub + i]; 5337850265eSShteryana Shopova 5347850265eSShteryana Shopova bif_name[i - 1] = '\0'; 5357850265eSShteryana Shopova 5367850265eSShteryana Shopova for (i = 1; i <= ETHER_ADDR_LEN; i++) 5377850265eSShteryana Shopova tp_addr[i - 1] = oid->subs[sub + n_len + i + 1]; 5387850265eSShteryana Shopova 5397850265eSShteryana Shopova if ((bif = bridge_if_find_ifname(bif_name)) == NULL || 5407850265eSShteryana Shopova (tp = bridge_addrs_find(tp_addr, bif)) == NULL) 5417850265eSShteryana Shopova return (NULL); 5427850265eSShteryana Shopova 5437850265eSShteryana Shopova return (bridge_addrs_next(tp)); 5447850265eSShteryana Shopova } 5457850265eSShteryana Shopova 5467850265eSShteryana Shopova int 5477850265eSShteryana Shopova op_begemot_tp_fdb(struct snmp_context *c __unused, struct snmp_value *val, 5487850265eSShteryana Shopova uint sub, uint iidx __unused, enum snmp_op op) 5497850265eSShteryana Shopova { 5505b6598a8SShteryana Shopova struct tp_entry *te; 5517850265eSShteryana Shopova 5527850265eSShteryana Shopova if (time(NULL) - address_list_age > bridge_get_data_maxage()) 5537850265eSShteryana Shopova bridge_update_all_addrs(); 5547850265eSShteryana Shopova 5557850265eSShteryana Shopova switch (op) { 5567850265eSShteryana Shopova case SNMP_OP_GET: 5577850265eSShteryana Shopova if ((te = bridge_addrs_begemot_get(&val->var, sub)) == NULL) 5587850265eSShteryana Shopova return (SNMP_ERR_NOSUCHNAME); 559f02a1e57SShteryana Shopova goto get; 5607850265eSShteryana Shopova 5617850265eSShteryana Shopova case SNMP_OP_GETNEXT: 5627850265eSShteryana Shopova if ((te = bridge_addrs_begemot_getnext(&val->var, 5637850265eSShteryana Shopova sub)) == NULL || 5647850265eSShteryana Shopova bridge_addrs_begemot_index_append(&val->var, 5657850265eSShteryana Shopova sub, te) < 0) 5667850265eSShteryana Shopova return (SNMP_ERR_NOSUCHNAME); 567f02a1e57SShteryana Shopova goto get; 5687850265eSShteryana Shopova 5697850265eSShteryana Shopova case SNMP_OP_SET: 5707850265eSShteryana Shopova return (SNMP_ERR_NOT_WRITEABLE); 5717850265eSShteryana Shopova 5727850265eSShteryana Shopova case SNMP_OP_ROLLBACK: 5737850265eSShteryana Shopova case SNMP_OP_COMMIT: 574f02a1e57SShteryana Shopova break; 5757850265eSShteryana Shopova } 576f02a1e57SShteryana Shopova abort(); 5777850265eSShteryana Shopova 578f02a1e57SShteryana Shopova get: 5797850265eSShteryana Shopova switch (val->var.subs[sub - 1]) { 5807850265eSShteryana Shopova case LEAF_begemotBridgeTpFdbAddress: 581f02a1e57SShteryana Shopova return (string_get(val, te->tp_addr, ETHER_ADDR_LEN)); 5827850265eSShteryana Shopova case LEAF_begemotBridgeTpFdbPort: 5837850265eSShteryana Shopova val->v.integer = te->port_no; 584f02a1e57SShteryana Shopova return (SNMP_ERR_NOERROR); 5857850265eSShteryana Shopova case LEAF_begemotBridgeTpFdbStatus: 5867850265eSShteryana Shopova val->v.integer = te->status; 587f02a1e57SShteryana Shopova return (SNMP_ERR_NOERROR); 5887850265eSShteryana Shopova } 5897850265eSShteryana Shopova 590f02a1e57SShteryana Shopova abort(); 5917850265eSShteryana Shopova } 592