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