xref: /freebsd/usr.sbin/bsnmpd/modules/snmp_bridge/bridge_addrs.c (revision f02a1e579450e1ffe500f7f27594f58a9f045daa)
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
1117850265eSShteryana Shopova  * interface. Update the first bridge address if neccessary.
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 /*
1397850265eSShteryana Shopova  * Find an address entry's possition 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