17850265eSShteryana Shopova /*- 2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 31de7b4b8SPedro 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 528e9b3e70SHartmut Brandt #define SNMPTREE_TYPES 537850265eSShteryana Shopova #include "bridge_tree.h" 547850265eSShteryana Shopova #include "bridge_snmp.h" 557850265eSShteryana Shopova 567850265eSShteryana Shopova TAILQ_HEAD(tp_entries, tp_entry); 577850265eSShteryana Shopova 587850265eSShteryana Shopova /* 597850265eSShteryana Shopova * Free the bridge address list. 607850265eSShteryana Shopova */ 617850265eSShteryana Shopova static void 627850265eSShteryana Shopova bridge_tpe_free(struct tp_entries *headp) 637850265eSShteryana Shopova { 647850265eSShteryana Shopova struct tp_entry *t; 657850265eSShteryana Shopova 667850265eSShteryana Shopova while ((t = TAILQ_FIRST(headp)) != NULL) { 677850265eSShteryana Shopova TAILQ_REMOVE(headp, t, tp_e); 687850265eSShteryana Shopova free(t); 697850265eSShteryana Shopova } 707850265eSShteryana Shopova } 717850265eSShteryana Shopova 727850265eSShteryana Shopova /* 737850265eSShteryana Shopova * Free the bridge address entries from the address list, 747850265eSShteryana Shopova * for the specified bridge interface only. 757850265eSShteryana Shopova */ 767850265eSShteryana Shopova static void 777850265eSShteryana Shopova bridge_tpe_bif_free(struct tp_entries *headp, 787850265eSShteryana Shopova struct bridge_if *bif) 797850265eSShteryana Shopova { 807850265eSShteryana Shopova struct tp_entry *tp; 817850265eSShteryana Shopova 827850265eSShteryana Shopova while (bif->f_tpa != NULL && bif->sysindex == bif->f_tpa->sysindex) { 837850265eSShteryana Shopova tp = TAILQ_NEXT(bif->f_tpa, tp_e); 847850265eSShteryana Shopova TAILQ_REMOVE(headp, bif->f_tpa, tp_e); 857850265eSShteryana Shopova free(bif->f_tpa); 867850265eSShteryana Shopova bif->f_tpa = tp; 877850265eSShteryana Shopova } 887850265eSShteryana Shopova } 897850265eSShteryana Shopova 907850265eSShteryana Shopova /* 917850265eSShteryana Shopova * Compare two mac addresses. 927850265eSShteryana Shopova * m1 < m2 : -1 937850265eSShteryana Shopova * m1 > m2 : +1 947850265eSShteryana Shopova * m1 = m2 : 0 957850265eSShteryana Shopova */ 967850265eSShteryana Shopova static int 977850265eSShteryana Shopova bridge_compare_macs(const uint8_t *m1, const uint8_t *m2) 987850265eSShteryana Shopova { 997850265eSShteryana Shopova int i; 1007850265eSShteryana Shopova 1017850265eSShteryana Shopova for (i = 0; i < ETHER_ADDR_LEN; i++) { 1027850265eSShteryana Shopova if (m1[i] < m2[i]) 1037850265eSShteryana Shopova return (-1); 1047850265eSShteryana Shopova if (m1[i] > m2[i]) 1057850265eSShteryana Shopova return (1); 1067850265eSShteryana Shopova } 1077850265eSShteryana Shopova 1087850265eSShteryana Shopova return (0); 1097850265eSShteryana Shopova } 1107850265eSShteryana Shopova 1117850265eSShteryana Shopova /* 1127850265eSShteryana Shopova * Insert an address entry in the bridge address TAILQ starting to search 1137850265eSShteryana Shopova * for its place from the position of the first bridge address for the bridge 1143df5ecacSUlrich Spörlein * interface. Update the first bridge address if necessary. 1157850265eSShteryana Shopova */ 1167850265eSShteryana Shopova static void 1177850265eSShteryana Shopova bridge_addrs_insert_at(struct tp_entries *headp, 1187850265eSShteryana Shopova struct tp_entry *ta, struct tp_entry **f_tpa) 1197850265eSShteryana Shopova { 1207850265eSShteryana Shopova struct tp_entry *t1; 1217850265eSShteryana Shopova 1227850265eSShteryana Shopova assert(f_tpa != NULL); 1237850265eSShteryana Shopova 1247850265eSShteryana Shopova for (t1 = *f_tpa; 1257850265eSShteryana Shopova t1 != NULL && ta->sysindex == t1->sysindex; 1267850265eSShteryana Shopova t1 = TAILQ_NEXT(t1, tp_e)) { 1277850265eSShteryana Shopova if (bridge_compare_macs(ta->tp_addr, t1->tp_addr) < 0) { 1287850265eSShteryana Shopova TAILQ_INSERT_BEFORE(t1, ta, tp_e); 1297850265eSShteryana Shopova if (*f_tpa == t1) 1307850265eSShteryana Shopova (*f_tpa) = ta; 1317850265eSShteryana Shopova return; 1327850265eSShteryana Shopova } 1337850265eSShteryana Shopova } 1347850265eSShteryana Shopova 1357850265eSShteryana Shopova if (t1 == NULL) 1367850265eSShteryana Shopova TAILQ_INSERT_TAIL(headp, ta, tp_e); 1377850265eSShteryana Shopova else 1387850265eSShteryana Shopova TAILQ_INSERT_BEFORE(t1, ta, tp_e); 1397850265eSShteryana Shopova } 1407850265eSShteryana Shopova 1417850265eSShteryana Shopova /* 1423df5ecacSUlrich Spörlein * Find an address entry's position in the address list 1437850265eSShteryana Shopova * according to bridge interface name. 1447850265eSShteryana Shopova */ 1457850265eSShteryana Shopova static struct tp_entry * 1467850265eSShteryana Shopova bridge_addrs_find_pos(struct tp_entries *headp, uint32_t b_idx) 1477850265eSShteryana Shopova { 1487850265eSShteryana Shopova uint32_t t_idx; 1497850265eSShteryana Shopova struct tp_entry *t1; 1507850265eSShteryana Shopova 1517850265eSShteryana Shopova if ((t1 = TAILQ_FIRST(headp)) == NULL || 1527850265eSShteryana Shopova bridge_compare_sysidx(b_idx, t1->sysindex) < 0) 1537850265eSShteryana Shopova return (NULL); 1547850265eSShteryana Shopova 1557850265eSShteryana Shopova t_idx = t1->sysindex; 1567850265eSShteryana Shopova 1577850265eSShteryana Shopova for (t1 = TAILQ_NEXT(t1, tp_e); t1 != NULL; t1 = TAILQ_NEXT(t1, tp_e)) { 1587850265eSShteryana Shopova 1597850265eSShteryana Shopova if (t1->sysindex != t_idx) { 1607850265eSShteryana Shopova if (bridge_compare_sysidx(b_idx, t1->sysindex) < 0) 1617850265eSShteryana Shopova return (TAILQ_PREV(t1, tp_entries, tp_e)); 1627850265eSShteryana Shopova else 1637850265eSShteryana Shopova t_idx = t1->sysindex; 1647850265eSShteryana Shopova } 1657850265eSShteryana Shopova } 1667850265eSShteryana Shopova 1677850265eSShteryana Shopova if (t1 == NULL) 1687850265eSShteryana Shopova t1 = TAILQ_LAST(headp, tp_entries); 1697850265eSShteryana Shopova 1707850265eSShteryana Shopova return (t1); 1717850265eSShteryana Shopova } 1727850265eSShteryana Shopova 1737850265eSShteryana Shopova /* 1747850265eSShteryana Shopova * Insert a bridge address in the bridge addresses list. 1757850265eSShteryana Shopova */ 1767850265eSShteryana Shopova static void 1777850265eSShteryana Shopova bridge_addrs_bif_insert(struct tp_entries *headp, struct tp_entry *te, 1787850265eSShteryana Shopova struct tp_entry **f_tpa) 1797850265eSShteryana Shopova { 1807850265eSShteryana Shopova struct tp_entry *temp; 1817850265eSShteryana Shopova 1827850265eSShteryana Shopova if (*f_tpa != NULL) 1837850265eSShteryana Shopova bridge_addrs_insert_at(headp, te, f_tpa); 1847850265eSShteryana Shopova else { 1857850265eSShteryana Shopova temp = bridge_addrs_find_pos(headp, te->sysindex); 1867850265eSShteryana Shopova 1877850265eSShteryana Shopova if (temp == NULL) 1887850265eSShteryana Shopova TAILQ_INSERT_HEAD(headp, te, tp_e); 1897850265eSShteryana Shopova else 1907850265eSShteryana Shopova TAILQ_INSERT_AFTER(headp, temp, te, tp_e); 1917850265eSShteryana Shopova *f_tpa = te; 1927850265eSShteryana Shopova } 1937850265eSShteryana Shopova } 1947850265eSShteryana Shopova 1957850265eSShteryana Shopova static struct tp_entries tp_entries = TAILQ_HEAD_INITIALIZER(tp_entries); 1967850265eSShteryana Shopova static time_t address_list_age; 1977850265eSShteryana Shopova 1987850265eSShteryana Shopova void 1997850265eSShteryana Shopova bridge_addrs_update_listage(void) 2007850265eSShteryana Shopova { 2017850265eSShteryana Shopova address_list_age = time(NULL); 2027850265eSShteryana Shopova } 2037850265eSShteryana Shopova 2047850265eSShteryana Shopova void 2057850265eSShteryana Shopova bridge_addrs_fini(void) 2067850265eSShteryana Shopova { 2077850265eSShteryana Shopova bridge_tpe_free(&tp_entries); 2087850265eSShteryana Shopova } 2097850265eSShteryana Shopova 2107850265eSShteryana Shopova void 2117850265eSShteryana Shopova bridge_addrs_free(struct bridge_if *bif) 2127850265eSShteryana Shopova { 2137850265eSShteryana Shopova bridge_tpe_bif_free(&tp_entries, bif); 2147850265eSShteryana Shopova } 2157850265eSShteryana Shopova 2167850265eSShteryana Shopova /* 2177850265eSShteryana Shopova * Find the first address in the list. 2187850265eSShteryana Shopova */ 2197850265eSShteryana Shopova static struct tp_entry * 2207850265eSShteryana Shopova bridge_addrs_first(void) 2217850265eSShteryana Shopova { 2227850265eSShteryana Shopova return (TAILQ_FIRST(&tp_entries)); 2237850265eSShteryana Shopova } 2247850265eSShteryana Shopova 2257850265eSShteryana Shopova /* 2267850265eSShteryana Shopova * Find the next address in the list. 2277850265eSShteryana Shopova */ 2287850265eSShteryana Shopova static struct tp_entry * 2297850265eSShteryana Shopova bridge_addrs_next(struct tp_entry *te) 2307850265eSShteryana Shopova { 2317850265eSShteryana Shopova return (TAILQ_NEXT(te, tp_e)); 2327850265eSShteryana Shopova } 2337850265eSShteryana Shopova 2347850265eSShteryana Shopova /* 2357850265eSShteryana Shopova * Find the first address, learnt by the specified bridge interface. 2367850265eSShteryana Shopova */ 2377850265eSShteryana Shopova struct tp_entry * 2387850265eSShteryana Shopova bridge_addrs_bif_first(struct bridge_if *bif) 2397850265eSShteryana Shopova { 2407850265eSShteryana Shopova return (bif->f_tpa); 2417850265eSShteryana Shopova } 2427850265eSShteryana Shopova 2437850265eSShteryana Shopova /* 2447850265eSShteryana Shopova * Find the next address, learnt by the specified bridge interface. 2457850265eSShteryana Shopova */ 2467850265eSShteryana Shopova struct tp_entry * 2477850265eSShteryana Shopova bridge_addrs_bif_next(struct tp_entry *te) 2487850265eSShteryana Shopova { 2497850265eSShteryana Shopova struct tp_entry *te_next; 2507850265eSShteryana Shopova 2517850265eSShteryana Shopova if ((te_next = TAILQ_NEXT(te, tp_e)) == NULL || 2527850265eSShteryana Shopova te_next->sysindex != te->sysindex) 2537850265eSShteryana Shopova return (NULL); 2547850265eSShteryana Shopova 2557850265eSShteryana Shopova return (te_next); 2567850265eSShteryana Shopova } 2577850265eSShteryana Shopova 2587850265eSShteryana Shopova /* 2597850265eSShteryana Shopova * Remove a bridge address from the list. 2607850265eSShteryana Shopova */ 2617850265eSShteryana Shopova void 2627850265eSShteryana Shopova bridge_addrs_remove(struct tp_entry *te, struct bridge_if *bif) 2637850265eSShteryana Shopova { 2647850265eSShteryana Shopova if (bif->f_tpa == te) 2657850265eSShteryana Shopova bif->f_tpa = bridge_addrs_bif_next(te); 2667850265eSShteryana Shopova 2677850265eSShteryana Shopova TAILQ_REMOVE(&tp_entries, te, tp_e); 2687850265eSShteryana Shopova free(te); 2697850265eSShteryana Shopova } 2707850265eSShteryana Shopova 2717850265eSShteryana Shopova /* 2727850265eSShteryana Shopova * Allocate memory for a new bridge address and insert it in the list. 2737850265eSShteryana Shopova */ 2747850265eSShteryana Shopova struct tp_entry * 2757850265eSShteryana Shopova bridge_new_addrs(uint8_t *mac, struct bridge_if *bif) 2767850265eSShteryana Shopova { 2777850265eSShteryana Shopova struct tp_entry *te; 2787850265eSShteryana Shopova 2797850265eSShteryana Shopova if ((te = (struct tp_entry *) malloc(sizeof(*te))) == NULL) { 2807850265eSShteryana Shopova syslog(LOG_ERR, "bridge new address: failed: %s", 2817850265eSShteryana Shopova strerror(errno)); 2827850265eSShteryana Shopova return (NULL); 2837850265eSShteryana Shopova } 2847850265eSShteryana Shopova 2857850265eSShteryana Shopova bzero(te, sizeof(*te)); 2867850265eSShteryana Shopova 2877850265eSShteryana Shopova te->sysindex = bif->sysindex; 2887850265eSShteryana Shopova bcopy(mac, te->tp_addr, ETHER_ADDR_LEN); 2897850265eSShteryana Shopova bridge_addrs_bif_insert(&tp_entries, te, &(bif->f_tpa)); 2907850265eSShteryana Shopova 2917850265eSShteryana Shopova return (te); 2927850265eSShteryana Shopova } 2937850265eSShteryana Shopova 2947850265eSShteryana Shopova /* 2957850265eSShteryana Shopova * Given a mac address, learnt on a bridge, 2967850265eSShteryana Shopova * find the corrsponding TP entry for it. 2977850265eSShteryana Shopova */ 2987850265eSShteryana Shopova struct tp_entry * 2997850265eSShteryana Shopova bridge_addrs_find(uint8_t *mac, struct bridge_if *bif) 3007850265eSShteryana Shopova { 3017850265eSShteryana Shopova struct tp_entry *te; 3027850265eSShteryana Shopova 3037850265eSShteryana Shopova for (te = bif->f_tpa; te != NULL; te = TAILQ_NEXT(te, tp_e)) { 3047850265eSShteryana Shopova if (te->sysindex != bif->sysindex) { 3057850265eSShteryana Shopova te = NULL; 3067850265eSShteryana Shopova break; 3077850265eSShteryana Shopova } 3087850265eSShteryana Shopova 3097850265eSShteryana Shopova if (bridge_compare_macs(te->tp_addr, mac) == 0) 3107850265eSShteryana Shopova break; 3117850265eSShteryana Shopova } 3127850265eSShteryana Shopova 3137850265eSShteryana Shopova return (te); 3147850265eSShteryana Shopova } 3157850265eSShteryana Shopova 3167850265eSShteryana Shopova void 3177850265eSShteryana Shopova bridge_addrs_dump(struct bridge_if *bif) 3187850265eSShteryana Shopova { 3197850265eSShteryana Shopova struct tp_entry *te; 3207850265eSShteryana Shopova 3217850265eSShteryana Shopova syslog(LOG_ERR, "Addresses count - %d", bif->num_addrs); 3227850265eSShteryana Shopova for (te = bridge_addrs_bif_first(bif); te != NULL; 3237850265eSShteryana Shopova te = bridge_addrs_bif_next(te)) { 3247850265eSShteryana Shopova syslog(LOG_ERR, "address %x:%x:%x:%x:%x:%x on port %d.%d", 3257850265eSShteryana Shopova te->tp_addr[0], te->tp_addr[1], te->tp_addr[2], 3267850265eSShteryana Shopova te->tp_addr[3], te->tp_addr[4], te->tp_addr[5], 3277850265eSShteryana Shopova te->sysindex, te->port_no); 3287850265eSShteryana Shopova } 3297850265eSShteryana Shopova } 3307850265eSShteryana Shopova 3317850265eSShteryana Shopova /* 3327850265eSShteryana Shopova * RFC4188 specifics. 3337850265eSShteryana Shopova */ 3347850265eSShteryana Shopova 3357850265eSShteryana Shopova /* 3367850265eSShteryana Shopova * Construct the SNMP index from the address DST Mac. 3377850265eSShteryana Shopova */ 3387850265eSShteryana Shopova static void 3397850265eSShteryana Shopova bridge_addrs_index_append(struct asn_oid *oid, uint sub, 3407850265eSShteryana Shopova const struct tp_entry *te) 3417850265eSShteryana Shopova { 3427850265eSShteryana Shopova int i; 3437850265eSShteryana Shopova 3447850265eSShteryana Shopova oid->len = sub + ETHER_ADDR_LEN + 1; 3457850265eSShteryana Shopova oid->subs[sub] = ETHER_ADDR_LEN; 3467850265eSShteryana Shopova 3477850265eSShteryana Shopova for (i = 1; i <= ETHER_ADDR_LEN; i++) 3487850265eSShteryana Shopova oid->subs[sub + i] = te->tp_addr[i - 1]; 3497850265eSShteryana Shopova } 3507850265eSShteryana Shopova 3517850265eSShteryana Shopova /* 3527850265eSShteryana Shopova * Find the address entry for the SNMP index from the default bridge only. 3537850265eSShteryana Shopova */ 3547850265eSShteryana Shopova static struct tp_entry * 3557850265eSShteryana Shopova bridge_addrs_get(const struct asn_oid *oid, uint sub, 3567850265eSShteryana Shopova struct bridge_if *bif) 3577850265eSShteryana Shopova { 3587850265eSShteryana Shopova int i; 3597850265eSShteryana Shopova uint8_t tp_addr[ETHER_ADDR_LEN]; 3607850265eSShteryana Shopova 3617850265eSShteryana Shopova if (oid->len - sub != ETHER_ADDR_LEN + 1 || 3627850265eSShteryana Shopova oid->subs[sub] != ETHER_ADDR_LEN) 3637850265eSShteryana Shopova return (NULL); 3647850265eSShteryana Shopova 3657850265eSShteryana Shopova for (i = 0; i < ETHER_ADDR_LEN; i++) 3667850265eSShteryana Shopova tp_addr[i] = oid->subs[sub + i + 1]; 3677850265eSShteryana Shopova 3687850265eSShteryana Shopova return (bridge_addrs_find(tp_addr, bif)); 3697850265eSShteryana Shopova } 3707850265eSShteryana Shopova 3717850265eSShteryana Shopova /* 3727850265eSShteryana Shopova * Find the next address entry for the SNMP index 3737850265eSShteryana Shopova * from the default bridge only. 3747850265eSShteryana Shopova */ 3757850265eSShteryana Shopova static struct tp_entry * 3767850265eSShteryana Shopova bridge_addrs_getnext(const struct asn_oid *oid, uint sub, 3777850265eSShteryana Shopova struct bridge_if *bif) 3787850265eSShteryana Shopova { 3797850265eSShteryana Shopova int i; 3807850265eSShteryana Shopova uint8_t tp_addr[ETHER_ADDR_LEN]; 3817850265eSShteryana Shopova static struct tp_entry *te; 3827850265eSShteryana Shopova 3837850265eSShteryana Shopova if (oid->len - sub == 0) 3847850265eSShteryana Shopova return (bridge_addrs_bif_first(bif)); 3857850265eSShteryana Shopova 3867850265eSShteryana Shopova if (oid->len - sub != ETHER_ADDR_LEN + 1 || 3877850265eSShteryana Shopova oid->subs[sub] != ETHER_ADDR_LEN) 3887850265eSShteryana Shopova return (NULL); 3897850265eSShteryana Shopova 3907850265eSShteryana Shopova for (i = 0; i < ETHER_ADDR_LEN; i++) 3917850265eSShteryana Shopova tp_addr[i] = oid->subs[sub + i + 1]; 3927850265eSShteryana Shopova 3937850265eSShteryana Shopova if ((te = bridge_addrs_find(tp_addr, bif)) == NULL) 3947850265eSShteryana Shopova return (NULL); 3957850265eSShteryana Shopova 3967850265eSShteryana Shopova return (bridge_addrs_bif_next(te)); 3977850265eSShteryana Shopova } 3987850265eSShteryana Shopova 3997850265eSShteryana Shopova int 4007850265eSShteryana Shopova op_dot1d_tp_fdb(struct snmp_context *c __unused, struct snmp_value *val, 4017850265eSShteryana Shopova uint sub, uint iidx __unused, enum snmp_op op) 4027850265eSShteryana Shopova { 4037850265eSShteryana Shopova struct bridge_if *bif; 4047850265eSShteryana Shopova struct tp_entry *te; 4057850265eSShteryana Shopova 4067850265eSShteryana Shopova if ((bif = bridge_get_default()) == NULL) 4077850265eSShteryana Shopova return (SNMP_ERR_NOSUCHNAME); 4087850265eSShteryana Shopova 4097850265eSShteryana Shopova if (time(NULL) - bif->addrs_age > bridge_get_data_maxage() && 4107850265eSShteryana Shopova bridge_update_addrs(bif) <= 0) 4117850265eSShteryana Shopova return (SNMP_ERR_NOSUCHNAME); 4127850265eSShteryana Shopova 4137850265eSShteryana Shopova switch (op) { 4147850265eSShteryana Shopova case SNMP_OP_GET: 4157850265eSShteryana Shopova if ((te = bridge_addrs_get(&val->var, sub, bif)) == NULL) 4167850265eSShteryana Shopova return (SNMP_ERR_NOSUCHNAME); 417f02a1e57SShteryana Shopova goto get; 4187850265eSShteryana Shopova 4197850265eSShteryana Shopova case SNMP_OP_GETNEXT: 4207850265eSShteryana Shopova if ((te = bridge_addrs_getnext(&val->var, sub, bif)) == NULL) 4217850265eSShteryana Shopova return (SNMP_ERR_NOSUCHNAME); 4227850265eSShteryana Shopova bridge_addrs_index_append(&val->var, sub, te); 423f02a1e57SShteryana Shopova goto get; 4247850265eSShteryana Shopova 4257850265eSShteryana Shopova case SNMP_OP_SET: 4267850265eSShteryana Shopova return (SNMP_ERR_NOT_WRITEABLE); 4277850265eSShteryana Shopova 4287850265eSShteryana Shopova case SNMP_OP_ROLLBACK: 4297850265eSShteryana Shopova case SNMP_OP_COMMIT: 430f02a1e57SShteryana Shopova break; 4317850265eSShteryana Shopova } 432f02a1e57SShteryana Shopova abort(); 4337850265eSShteryana Shopova 434f02a1e57SShteryana Shopova get: 4357850265eSShteryana Shopova switch (val->var.subs[sub - 1]) { 4367850265eSShteryana Shopova case LEAF_dot1dTpFdbAddress: 437f02a1e57SShteryana Shopova return (string_get(val, te->tp_addr, ETHER_ADDR_LEN)); 4387850265eSShteryana Shopova case LEAF_dot1dTpFdbPort : 4397850265eSShteryana Shopova val->v.integer = te->port_no; 440f02a1e57SShteryana Shopova return (SNMP_ERR_NOERROR); 4417850265eSShteryana Shopova case LEAF_dot1dTpFdbStatus: 4427850265eSShteryana Shopova val->v.integer = te->status; 443f02a1e57SShteryana Shopova return (SNMP_ERR_NOERROR); 4447850265eSShteryana Shopova } 4457850265eSShteryana Shopova 446f02a1e57SShteryana Shopova abort(); 4477850265eSShteryana Shopova } 4487850265eSShteryana Shopova 4497850265eSShteryana Shopova /* 4507850265eSShteryana Shopova * Private BEGEMOT-BRIDGE-MIB specifics. 4517850265eSShteryana Shopova */ 4527850265eSShteryana Shopova 4537850265eSShteryana Shopova /* 4547850265eSShteryana Shopova * Construct the SNMP index from the bridge interface name 4557850265eSShteryana Shopova * and the address DST Mac. 4567850265eSShteryana Shopova */ 4577850265eSShteryana Shopova static int 4587850265eSShteryana Shopova bridge_addrs_begemot_index_append(struct asn_oid *oid, uint sub, 4597850265eSShteryana Shopova const struct tp_entry *te) 4607850265eSShteryana Shopova { 4617850265eSShteryana Shopova uint i, n_len; 4627850265eSShteryana Shopova const char *b_name; 4637850265eSShteryana Shopova 4647850265eSShteryana Shopova if ((b_name = bridge_if_find_name(te->sysindex)) == NULL) 4657850265eSShteryana Shopova return (-1); 4667850265eSShteryana Shopova 4677850265eSShteryana Shopova n_len = strlen(b_name); 4687850265eSShteryana Shopova oid->len = sub++; 4697850265eSShteryana Shopova oid->subs[oid->len++] = n_len; 4707850265eSShteryana Shopova 4717850265eSShteryana Shopova for (i = 1; i <= n_len; i++) 4727850265eSShteryana Shopova oid->subs[oid->len++] = b_name[i - 1]; 4737850265eSShteryana Shopova 4747850265eSShteryana Shopova oid->subs[oid->len++] = ETHER_ADDR_LEN; 4757850265eSShteryana Shopova for (i = 1 ; i <= ETHER_ADDR_LEN; i++) 4767850265eSShteryana Shopova oid->subs[oid->len++] = te->tp_addr[i - 1]; 4777850265eSShteryana Shopova 4787850265eSShteryana Shopova return (0); 4797850265eSShteryana Shopova } 4807850265eSShteryana Shopova 4817850265eSShteryana Shopova /* 4827850265eSShteryana Shopova * Find a bridge address entry by the bridge interface name 4837850265eSShteryana Shopova * and the address DST Mac. 4847850265eSShteryana Shopova */ 4857850265eSShteryana Shopova static struct tp_entry * 4867850265eSShteryana Shopova bridge_addrs_begemot_get(const struct asn_oid *oid, uint sub) 4877850265eSShteryana Shopova { 4887850265eSShteryana Shopova uint i, n_len; 4897850265eSShteryana Shopova uint8_t tp_addr[ETHER_ADDR_LEN]; 4907850265eSShteryana Shopova char bif_name[IFNAMSIZ]; 4917850265eSShteryana Shopova struct bridge_if *bif; 4927850265eSShteryana Shopova 4937850265eSShteryana Shopova n_len = oid->subs[sub]; 4947850265eSShteryana Shopova if (oid->len - sub != n_len + ETHER_ADDR_LEN + 3 || 4957850265eSShteryana Shopova n_len >= IFNAMSIZ || oid->subs[sub + n_len + 1] != ETHER_ADDR_LEN) 4967850265eSShteryana Shopova return (NULL); 4977850265eSShteryana Shopova 4987850265eSShteryana Shopova for (i = 0; i < n_len; i++) 4997850265eSShteryana Shopova bif_name[i] = oid->subs[n_len + i + 1]; 5007850265eSShteryana Shopova bif_name[i] = '\0'; 5017850265eSShteryana Shopova 5027850265eSShteryana Shopova for (i = 1; i <= ETHER_ADDR_LEN; i++) 5037850265eSShteryana Shopova tp_addr[i - 1] = oid->subs[n_len + i + 1]; 5047850265eSShteryana Shopova 5057850265eSShteryana Shopova if ((bif = bridge_if_find_ifname(bif_name)) == NULL) 5067850265eSShteryana Shopova return (NULL); 5077850265eSShteryana Shopova 5087850265eSShteryana Shopova return (bridge_addrs_find(tp_addr, bif)); 5097850265eSShteryana Shopova } 5107850265eSShteryana Shopova 5117850265eSShteryana Shopova /* 5127850265eSShteryana Shopova * Find the next bridge address entry by the bridge interface name 5137850265eSShteryana Shopova * and the address DST Mac. 5147850265eSShteryana Shopova */ 5157850265eSShteryana Shopova static struct tp_entry * 5167850265eSShteryana Shopova bridge_addrs_begemot_getnext(const struct asn_oid *oid, uint sub) 5177850265eSShteryana Shopova { 5187850265eSShteryana Shopova uint i, n_len; 5197850265eSShteryana Shopova uint8_t tp_addr[ETHER_ADDR_LEN]; 5207850265eSShteryana Shopova char bif_name[IFNAMSIZ]; 5217850265eSShteryana Shopova struct bridge_if *bif; 5227850265eSShteryana Shopova struct tp_entry *tp; 5237850265eSShteryana Shopova 5247850265eSShteryana Shopova if (oid->len - sub == 0) 5257850265eSShteryana Shopova return (bridge_addrs_first()); 5267850265eSShteryana Shopova 5277850265eSShteryana Shopova n_len = oid->subs[sub]; 5287850265eSShteryana Shopova if (oid->len - sub != n_len + ETHER_ADDR_LEN + 2 || 5297850265eSShteryana Shopova n_len >= IFNAMSIZ || oid->subs[sub + n_len + 1] != ETHER_ADDR_LEN) 5307850265eSShteryana Shopova return (NULL); 5317850265eSShteryana Shopova 5327850265eSShteryana Shopova for (i = 1; i <= n_len; i++) 5337850265eSShteryana Shopova bif_name[i - 1] = oid->subs[sub + i]; 5347850265eSShteryana Shopova 5357850265eSShteryana Shopova bif_name[i - 1] = '\0'; 5367850265eSShteryana Shopova 5377850265eSShteryana Shopova for (i = 1; i <= ETHER_ADDR_LEN; i++) 5387850265eSShteryana Shopova tp_addr[i - 1] = oid->subs[sub + n_len + i + 1]; 5397850265eSShteryana Shopova 5407850265eSShteryana Shopova if ((bif = bridge_if_find_ifname(bif_name)) == NULL || 5417850265eSShteryana Shopova (tp = bridge_addrs_find(tp_addr, bif)) == NULL) 5427850265eSShteryana Shopova return (NULL); 5437850265eSShteryana Shopova 5447850265eSShteryana Shopova return (bridge_addrs_next(tp)); 5457850265eSShteryana Shopova } 5467850265eSShteryana Shopova 5477850265eSShteryana Shopova int 5487850265eSShteryana Shopova op_begemot_tp_fdb(struct snmp_context *c __unused, struct snmp_value *val, 5497850265eSShteryana Shopova uint sub, uint iidx __unused, enum snmp_op op) 5507850265eSShteryana Shopova { 5515b6598a8SShteryana Shopova struct tp_entry *te; 5527850265eSShteryana Shopova 5537850265eSShteryana Shopova if (time(NULL) - address_list_age > bridge_get_data_maxage()) 5547850265eSShteryana Shopova bridge_update_all_addrs(); 5557850265eSShteryana Shopova 5567850265eSShteryana Shopova switch (op) { 5577850265eSShteryana Shopova case SNMP_OP_GET: 5587850265eSShteryana Shopova if ((te = bridge_addrs_begemot_get(&val->var, sub)) == NULL) 5597850265eSShteryana Shopova return (SNMP_ERR_NOSUCHNAME); 560f02a1e57SShteryana Shopova goto get; 5617850265eSShteryana Shopova 5627850265eSShteryana Shopova case SNMP_OP_GETNEXT: 5637850265eSShteryana Shopova if ((te = bridge_addrs_begemot_getnext(&val->var, 5647850265eSShteryana Shopova sub)) == NULL || 5657850265eSShteryana Shopova bridge_addrs_begemot_index_append(&val->var, 5667850265eSShteryana Shopova sub, te) < 0) 5677850265eSShteryana Shopova return (SNMP_ERR_NOSUCHNAME); 568f02a1e57SShteryana Shopova goto get; 5697850265eSShteryana Shopova 5707850265eSShteryana Shopova case SNMP_OP_SET: 5717850265eSShteryana Shopova return (SNMP_ERR_NOT_WRITEABLE); 5727850265eSShteryana Shopova 5737850265eSShteryana Shopova case SNMP_OP_ROLLBACK: 5747850265eSShteryana Shopova case SNMP_OP_COMMIT: 575f02a1e57SShteryana Shopova break; 5767850265eSShteryana Shopova } 577f02a1e57SShteryana Shopova abort(); 5787850265eSShteryana Shopova 579f02a1e57SShteryana Shopova get: 5807850265eSShteryana Shopova switch (val->var.subs[sub - 1]) { 5817850265eSShteryana Shopova case LEAF_begemotBridgeTpFdbAddress: 582f02a1e57SShteryana Shopova return (string_get(val, te->tp_addr, ETHER_ADDR_LEN)); 5837850265eSShteryana Shopova case LEAF_begemotBridgeTpFdbPort: 5847850265eSShteryana Shopova val->v.integer = te->port_no; 585f02a1e57SShteryana Shopova return (SNMP_ERR_NOERROR); 5867850265eSShteryana Shopova case LEAF_begemotBridgeTpFdbStatus: 5877850265eSShteryana Shopova val->v.integer = te->status; 588f02a1e57SShteryana Shopova return (SNMP_ERR_NOERROR); 5897850265eSShteryana Shopova } 5907850265eSShteryana Shopova 591f02a1e57SShteryana Shopova abort(); 5927850265eSShteryana Shopova } 593