bridge_if.c revision 310903
150027Speter/*-
272376Sjake * Copyright (c) 2006 Shteryana Shopova <syrinx@FreeBSD.org>
372376Sjake * All rights reserved.
450027Speter *
550027Speter * Redistribution and use in source and binary forms, with or without
650027Speter * modification, are permitted provided that the following conditions
750027Speter * are met:
850027Speter * 1. Redistributions of source code must retain the above copyright
950027Speter *    notice, this list of conditions and the following disclaimer.
1050027Speter * 2. Redistributions in binary form must reproduce the above copyright
1150027Speter *    notice, this list of conditions and the following disclaimer in the
1250027Speter *    documentation and/or other materials provided with the distribution.
1350027Speter *
1450027Speter * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1550027Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1650027Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1750027Speter * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1850027Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1950027Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2050027Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2150027Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2250027Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2350027Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2450027Speter * SUCH DAMAGE.
2550027Speter *
2650027Speter * Bridge MIB implementation for SNMPd.
2750027Speter * Bridge interface objects.
2850027Speter *
2999072Sjulian * $FreeBSD: stable/10/usr.sbin/bsnmpd/modules/snmp_bridge/bridge_if.c 310903 2016-12-31 10:34:09Z ngie $
3099072Sjulian */
3199072Sjulian
3299072Sjulian#include <sys/queue.h>
3399072Sjulian#include <sys/socket.h>
3499072Sjulian#include <sys/time.h>
3599072Sjulian#include <sys/types.h>
3699072Sjulian
3799072Sjulian#include <net/ethernet.h>
3899072Sjulian#include <net/if.h>
3999072Sjulian#include <net/if_mib.h>
4099072Sjulian#include <net/if_types.h>
4199072Sjulian
4299072Sjulian#include <errno.h>
4399072Sjulian#include <stdarg.h>
4499072Sjulian#include <stdlib.h>
4599072Sjulian#include <string.h>
4699072Sjulian#include <syslog.h>
4799072Sjulian
4899072Sjulian#include <bsnmp/snmpmod.h>
4999072Sjulian#include <bsnmp/snmp_mibII.h>
5099072Sjulian
5199072Sjulian#include "bridge_tree.h"
5299072Sjulian#include "bridge_snmp.h"
5399072Sjulian#include "bridge_oid.h"
5499072Sjulian
5599072Sjulianstatic const struct asn_oid oid_newRoot = OIDX_newRoot;
5699072Sjulianstatic const struct asn_oid oid_TopologyChange = OIDX_topologyChange;
5799072Sjulianstatic const struct asn_oid oid_begemotBrigeName = \
5899072Sjulian			OIDX_begemotBridgeBaseName;
5999072Sjulianstatic const struct asn_oid oid_begemotNewRoot = OIDX_begemotBridgeNewRoot;
6099072Sjulianstatic const struct asn_oid oid_begemotTopologyChange = \
6199072Sjulian			OIDX_begemotBridgeTopologyChange;
6299072Sjulian
6399072SjulianTAILQ_HEAD(bridge_ifs, bridge_if);
6499072Sjulian
6599072Sjulian/*
6699072Sjulian * Free the bridge interface list.
6799072Sjulian */
6899072Sjulianstatic void
6999072Sjulianbridge_ifs_free(struct bridge_ifs *headp)
7099072Sjulian{
7199072Sjulian	struct bridge_if *b;
7299072Sjulian
7399072Sjulian	while ((b = TAILQ_FIRST(headp)) != NULL) {
7499072Sjulian		TAILQ_REMOVE(headp, b, b_if);
7599072Sjulian		free(b);
7699072Sjulian	}
7799072Sjulian}
7899072Sjulian
7999072Sjulian/*
8099072Sjulian * Insert an entry in the bridge interface TAILQ. Keep the
8199072Sjulian * TAILQ sorted by the bridge's interface name.
8299072Sjulian */
8399072Sjulianstatic void
8499072Sjulianbridge_ifs_insert(struct bridge_ifs *headp,
8599072Sjulian	struct bridge_if *b)
8699072Sjulian{
8799072Sjulian	struct bridge_if *temp;
8899072Sjulian
8999072Sjulian	if ((temp = TAILQ_FIRST(headp)) == NULL ||
9099072Sjulian	    strcmp(b->bif_name, temp->bif_name) < 0) {
9199072Sjulian		TAILQ_INSERT_HEAD(headp, b, b_if);
9250027Speter		return;
9350027Speter	}
9450027Speter
9565557Sjasone	TAILQ_FOREACH(temp, headp, b_if)
9674914Sjhb		if(strcmp(b->bif_name, temp->bif_name) < 0)
9767365Sjhb			TAILQ_INSERT_BEFORE(temp, b, b_if);
9850027Speter
9950027Speter	TAILQ_INSERT_TAIL(headp, b, b_if);
10093607Sdillon}
10150027Speter
10297261Sjake/* The global bridge interface list. */
10397261Sjakestatic struct bridge_ifs bridge_ifs = TAILQ_HEAD_INITIALIZER(bridge_ifs);
10450027Speterstatic time_t bridge_list_age;
10572376Sjake
10650027Speter/*
10772376Sjake * Free the global list.
10872376Sjake */
10950027Spetervoid
11099072Sjulianbridge_ifs_fini(void)
11199072Sjulian{
11299072Sjulian	bridge_ifs_free(&bridge_ifs);
11399072Sjulian}
11499072Sjulian
11550027Speter/*
11699072Sjulian * Find a bridge interface entry by the bridge interface system index.
11799072Sjulian */
11899072Sjulianstruct bridge_if *
11950027Speterbridge_if_find_ifs(uint32_t sysindex)
12083366Sjulian{
12183366Sjulian	struct bridge_if *b;
12250027Speter
12399072Sjulian	TAILQ_FOREACH(b, &bridge_ifs, b_if)
12499072Sjulian		if (b->sysindex == sysindex)
12599072Sjulian			return (b);
12699072Sjulian
127100209Sgallatin	return (NULL);
12899072Sjulian}
12999072Sjulian
13099072Sjulian/*
13199072Sjulian * Find a bridge interface entry by the bridge interface name.
13299072Sjulian */
13399072Sjulianstruct bridge_if *
13499072Sjulianbridge_if_find_ifname(const char *b_name)
13599072Sjulian{
13699072Sjulian	struct bridge_if *b;
13799072Sjulian
13899072Sjulian	TAILQ_FOREACH(b, &bridge_ifs, b_if)
13999072Sjulian		if (strcmp(b_name, b->bif_name) == 0)
14099072Sjulian			return (b);
14199072Sjulian
14299072Sjulian	return (NULL);
14399072Sjulian}
14499072Sjulian
14599072Sjulian/*
14699072Sjulian * Find a bridge name by the bridge interface system index.
14799072Sjulian */
14899072Sjulianconst char *
14999072Sjulianbridge_if_find_name(uint32_t sysindex)
15099072Sjulian{
15199072Sjulian	struct bridge_if *b;
15299072Sjulian
15399072Sjulian	TAILQ_FOREACH(b, &bridge_ifs, b_if)
15499072Sjulian		if (b->sysindex == sysindex)
15599072Sjulian			return (b->bif_name);
15699072Sjulian
15799889Sjulian	return (NULL);
15899072Sjulian}
159102592Sjulian
16099072Sjulian/*
16199072Sjulian * Given two bridge interfaces' system indexes, find their
162102592Sjulian * corresponding names and return the result of the name
163100209Sgallatin * comparison. Returns:
164100209Sgallatin * error : -2
165100209Sgallatin * i1 < i2 : -1
166103216Sjulian * i1 > i2 : +1
16799072Sjulian * i1 = i2 : 0
16872376Sjake */
16950027Speterint
17099072Sjulianbridge_compare_sysidx(uint32_t i1, uint32_t i2)
17199072Sjulian{
17299072Sjulian	int c;
17399072Sjulian	const char *b1, *b2;
17499072Sjulian
17599072Sjulian	if (i1 == i2)
17699072Sjulian		return (0);
17799072Sjulian
17899072Sjulian	if ((b1 = bridge_if_find_name(i1)) == NULL) {
17999072Sjulian		syslog(LOG_ERR, "Bridge interface %d does not exist", i1);
18099072Sjulian		return (-2);
18199072Sjulian	}
18299072Sjulian
18399072Sjulian	if ((b2 = bridge_if_find_name(i2)) == NULL) {
18499072Sjulian		syslog(LOG_ERR, "Bridge interface %d does not exist", i2);
18599072Sjulian		return (-2);
18699072Sjulian	}
18799072Sjulian
18899072Sjulian	if ((c = strcmp(b1, b2)) < 0)
18999072Sjulian		return (-1);
19099072Sjulian	else if (c > 0)
19199072Sjulian		return (1);
19299072Sjulian
19399072Sjulian	return (0);
19499072Sjulian}
19599072Sjulian
19699072Sjulian/*
19799072Sjulian * Fetch the first bridge interface from the list.
19899072Sjulian */
19999072Sjulianstruct bridge_if *
20099072Sjulianbridge_first_bif(void)
20199072Sjulian{
20299072Sjulian	return (TAILQ_FIRST(&bridge_ifs));
20399072Sjulian}
20499072Sjulian
20599072Sjulian/*
20699072Sjulian * Fetch the next bridge interface from the list.
20799072Sjulian */
20899072Sjulianstruct bridge_if *
20999072Sjulianbridge_next_bif(struct bridge_if *b_pr)
21099072Sjulian{
21199072Sjulian	return (TAILQ_NEXT(b_pr, b_if));
21272376Sjake}
21399072Sjulian
21472376Sjake/*
21572376Sjake * Create a new entry for a bridge interface and insert
21650027Speter * it in the list.
21750027Speter */
21899072Sjulianstatic struct bridge_if *
21999072Sjulianbridge_new_bif(const char *bif_n, uint32_t sysindex, const u_char *physaddr)
22099072Sjulian{
22199072Sjulian	struct bridge_if *bif;
22299072Sjulian
22399072Sjulian	if ((bif = (struct bridge_if *) malloc(sizeof(*bif)))== NULL) {
22450027Speter		syslog(LOG_ERR, "bridge new interface failed: %s",
22583366Sjulian		    strerror(errno));
22672376Sjake		return (NULL);
22799072Sjulian	}
22899072Sjulian
22999072Sjulian	bzero(bif, sizeof(struct bridge_if));
23099072Sjulian	strlcpy(bif->bif_name, bif_n, IFNAMSIZ);
23199072Sjulian	bcopy(physaddr, bif->br_addr.octet, ETHER_ADDR_LEN);
232103216Sjulian	bif->sysindex = sysindex;
23399072Sjulian	bif->br_type = BaseType_transparent_only;
23499072Sjulian	/* 1 - all bridges default hold time * 100 - centi-seconds */
23599072Sjulian	bif->hold_time = 1 * 100;
23699072Sjulian	bif->prot_spec = dot1dStpProtocolSpecification_ieee8021d;
23799072Sjulian	bridge_ifs_insert(&bridge_ifs, bif);
23899072Sjulian
23999072Sjulian	return (bif);
24099072Sjulian}
241103216Sjulian
24299072Sjulian/*
24399072Sjulian * Remove a bridge interface from the list, freeing all it's ports
24499072Sjulian * and address entries.
24599942Sjulian */
24699072Sjulianvoid
24799072Sjulianbridge_remove_bif(struct bridge_if *bif)
24899072Sjulian{
24999072Sjulian	bridge_members_free(bif);
25099072Sjulian	bridge_addrs_free(bif);
25199072Sjulian	TAILQ_REMOVE(&bridge_ifs, bif, b_if);
25299072Sjulian	free(bif);
25399072Sjulian}
25499072Sjulian
25599072Sjulian
25699072Sjulian/*
25799072Sjulian * Prepare the variable (bridge interface name) for the private
25899072Sjulian * begemot notifications.
25999072Sjulian */
26099072Sjulianstatic struct snmp_value*
26199072Sjulianbridge_basename_var(struct bridge_if *bif, struct snmp_value* b_val)
26299072Sjulian{
26399072Sjulian	uint i;
26499072Sjulian
26599072Sjulian	b_val->var = oid_begemotBrigeName;
26699072Sjulian	b_val->var.subs[b_val->var.len++] = strlen(bif->bif_name);
26799072Sjulian
26899072Sjulian	if ((b_val->v.octetstring.octets = (u_char *)
26999072Sjulian	    malloc(strlen(bif->bif_name))) == NULL)
27099072Sjulian		return (NULL);
27199072Sjulian
27299072Sjulian	for (i = 0; i < strlen(bif->bif_name); i++)
27399072Sjulian		b_val->var.subs[b_val->var.len++] = bif->bif_name[i];
27499072Sjulian
27599072Sjulian	b_val->v.octetstring.len = strlen(bif->bif_name);
27699072Sjulian	bcopy(bif->bif_name, b_val->v.octetstring.octets,
27799072Sjulian	    strlen(bif->bif_name));
27899072Sjulian	b_val->syntax = SNMP_SYNTAX_OCTETSTRING;
27999072Sjulian
28099072Sjulian	return (b_val);
28199072Sjulian}
28299072Sjulian
28399072Sjulian/*
28499072Sjulian * Compare the values of the old and the new root port and
28599072Sjulian * send a new root notification, if they are not matching.
28699072Sjulian */
28799072Sjulianstatic void
28899072Sjulianbridge_new_root(struct bridge_if *bif)
28999072Sjulian{
29072376Sjake	struct snmp_value bif_idx;
29172376Sjake
29272376Sjake	if (bridge_get_default() == bif)
29383366Sjulian		snmp_send_trap(&oid_newRoot, (struct snmp_value *) NULL);
29450027Speter
29599072Sjulian	if (bridge_basename_var(bif, &bif_idx) == NULL)
29699072Sjulian		return;
29799072Sjulian
29899072Sjulian	snmp_send_trap(&oid_begemotTopologyChange,
29999072Sjulian	    &bif_idx, (struct snmp_value *) NULL);
30099072Sjulian}
30199072Sjulian
302103216Sjulian/*
303103216Sjulian * Compare the new and old topology change times and send a
304103216Sjulian * topology change notification if necessary.
30599072Sjulian */
30699072Sjulianstatic void
30799072Sjulianbridge_top_change(struct bridge_if *bif)
30899072Sjulian{
30999072Sjulian	struct snmp_value bif_idx;
31099072Sjulian
31199072Sjulian	if (bridge_get_default() == bif)
31299072Sjulian		snmp_send_trap(&oid_TopologyChange,
31399072Sjulian		    (struct snmp_value *) NULL);
31499072Sjulian
31599072Sjulian	if (bridge_basename_var(bif, &bif_idx) == NULL)
31699072Sjulian		return;
31799072Sjulian
31899072Sjulian	snmp_send_trap(&oid_begemotNewRoot,
31999072Sjulian	    &bif_idx, (struct snmp_value *) NULL);
32099072Sjulian}
32199072Sjulian
32299072Sjulianstatic int
32399072Sjulianbridge_if_create(const char* b_name, int8_t up)
32499072Sjulian{
32599072Sjulian	if (bridge_create(b_name) < 0)
32699072Sjulian		return (-1);
32799072Sjulian
32899072Sjulian	if (up == 1 && (bridge_set_if_up(b_name, 1) < 0))
32999072Sjulian		return (-1);
33099072Sjulian
33199072Sjulian	/*
33299072Sjulian	 * Do not create a new bridge entry here -
33399072Sjulian	 * wait until the mibII module notifies us.
33499072Sjulian	 */
33599072Sjulian	return (0);
33699942Sjulian}
33799072Sjulian
33899072Sjulianstatic int
33999072Sjulianbridge_if_destroy(struct bridge_if *bif)
34099072Sjulian{
34199072Sjulian	if (bridge_destroy(bif->bif_name) < 0)
34299072Sjulian		return (-1);
34399072Sjulian
34499072Sjulian	bridge_remove_bif(bif);
34599072Sjulian
34699072Sjulian	return (0);
34799072Sjulian}
34899072Sjulian
34999072Sjulian/*
35099942Sjulian * Calculate the timeticks since the last topology change.
35199942Sjulian */
35299942Sjulianstatic int
35399072Sjulianbridge_get_time_since_tc(struct bridge_if *bif, uint32_t *ticks)
35499072Sjulian{
35599072Sjulian	struct timeval ct;
35699072Sjulian
35799072Sjulian	if (gettimeofday(&ct, NULL) < 0) {
35899072Sjulian		syslog(LOG_ERR, "bridge get time since last TC:"
35999072Sjulian		    "getttimeofday failed: %s", strerror(errno));
36099072Sjulian		return (-1);
36199072Sjulian	}
36299072Sjulian
36399072Sjulian	if (ct.tv_usec - bif->last_tc_time.tv_usec < 0) {
36499072Sjulian		ct.tv_sec -= 1;
36599072Sjulian		ct.tv_usec += 1000000;
36699072Sjulian	}
36799072Sjulian
36899072Sjulian	ct.tv_sec -= bif->last_tc_time.tv_sec;
36999072Sjulian	ct.tv_usec -= bif->last_tc_time.tv_usec;
37099072Sjulian
37199072Sjulian	*ticks = ct.tv_sec * 100 + ct.tv_usec/10000;
37299072Sjulian
37399072Sjulian	return (0);
37499072Sjulian}
37599072Sjulian
37699072Sjulian/*
37799072Sjulian * Update the info we have for a single bridge interface.
37899072Sjulian * Return:
37999072Sjulian * 1, if successful
38099942Sjulian * 0, if the interface was deleted
38199072Sjulian * -1, error occurred while fetching the info from the kernel.
38299072Sjulian */
38399072Sjulianstatic int
38499072Sjulianbridge_update_bif(struct bridge_if *bif)
38599072Sjulian{
38699072Sjulian	struct mibif *ifp;
38799072Sjulian
38899072Sjulian	/* Walk through the mibII interface list. */
38999072Sjulian	for (ifp = mib_first_if(); ifp != NULL; ifp = mib_next_if(ifp))
39099072Sjulian		if (strcmp(ifp->name, bif->bif_name) == 0)
39199072Sjulian			break;
39299072Sjulian
39399072Sjulian	if (ifp == NULL) {
39499072Sjulian		/* Ops, we do not exist anymore. */
39599072Sjulian		bridge_remove_bif(bif);
39699072Sjulian		return (0);
39799072Sjulian	}
39899072Sjulian
39999072Sjulian	if (ifp->physaddr != NULL )
40099072Sjulian		bcopy(ifp->physaddr, bif->br_addr.octet, ETHER_ADDR_LEN);
40199072Sjulian	else
40299072Sjulian		bridge_get_basemac(bif->bif_name, bif->br_addr.octet,
40399072Sjulian		    ETHER_ADDR_LEN);
40499072Sjulian
40599072Sjulian	if (ifp->mib.ifmd_flags & IFF_RUNNING)
40699072Sjulian		bif->if_status = RowStatus_active;
40799072Sjulian	else
40872376Sjake		bif->if_status = RowStatus_notInService;
40950027Speter
41099072Sjulian	switch (bridge_getinfo_bif(bif)) {
41199072Sjulian		case 2:
41299072Sjulian			bridge_new_root(bif);
41388088Sjhb			break;
41488088Sjhb		case 1:
41588088Sjhb			bridge_top_change(bif);
41688088Sjhb			break;
41788088Sjhb		case -1:
41888088Sjhb			bridge_remove_bif(bif);
41988088Sjhb			return (-1);
42088088Sjhb		default:
42193264Sdillon			break;
42288088Sjhb	}
42388088Sjhb
42488088Sjhb	/*
42588088Sjhb	 * The number of ports is accessible via SNMP -
42688088Sjhb	 * update the ports each time the bridge interface data
42788088Sjhb	 * is refreshed too.
42888088Sjhb	 */
42988088Sjhb	bif->num_ports = bridge_update_memif(bif);
43088088Sjhb	bif->entry_age = time(NULL);
43188088Sjhb
43288088Sjhb	return (1);
43393264Sdillon}
43493264Sdillon
43588088Sjhb/*
43693264Sdillon * Update all bridge interfaces' ports only -
43788088Sjhb * make sure each bridge interface exists first.
43888088Sjhb */
43999072Sjulianvoid
44099072Sjulianbridge_update_all_ports(void)
44199072Sjulian{
44299072Sjulian	struct mibif *ifp;
44372376Sjake	struct bridge_if *bif, *t_bif;
44499072Sjulian
44599072Sjulian	for (bif = bridge_first_bif(); bif != NULL; bif = t_bif) {
44699072Sjulian		t_bif = bridge_next_bif(bif);
44799072Sjulian
44899072Sjulian		for (ifp = mib_first_if(); ifp != NULL;
44999072Sjulian		    ifp = mib_next_if(ifp))
45099072Sjulian			if (strcmp(ifp->name, bif->bif_name) == 0)
45199072Sjulian				break;
45299072Sjulian
45399072Sjulian		if (ifp != NULL)
45499072Sjulian			bif->num_ports = bridge_update_memif(bif);
45599072Sjulian		else  /* Ops, we do not exist anymore. */
45699072Sjulian			bridge_remove_bif(bif);
45772376Sjake	}
45872376Sjake
45972376Sjake	bridge_ports_update_listage();
46072376Sjake}
46172376Sjake
46272376Sjake/*
46372376Sjake * Update all addresses only.
46465557Sjasone */
46572376Sjakevoid
46672376Sjakebridge_update_all_addrs(void)
46772376Sjake{
46872376Sjake	struct mibif *ifp;
46972376Sjake	struct bridge_if *bif, *t_bif;
47072376Sjake
47150027Speter	for (bif = bridge_first_bif(); bif != NULL; bif = t_bif) {
47250027Speter		t_bif = bridge_next_bif(bif);
47350027Speter
47472376Sjake		for (ifp = mib_first_if(); ifp != NULL;
47572376Sjake		    ifp = mib_next_if(ifp))
47650027Speter			if (strcmp(ifp->name, bif->bif_name) == 0)
47772376Sjake				break;
47872376Sjake
47972376Sjake		if (ifp != NULL)
48072376Sjake			bif->num_addrs = bridge_update_addrs(bif);
48172376Sjake		else  /* Ops, we don't exist anymore. */
48272376Sjake			bridge_remove_bif(bif);
48372376Sjake	}
48472376Sjake
48572376Sjake	bridge_addrs_update_listage();
48672376Sjake}
48798469Speter
48872376Sjake/*
48972376Sjake * Update only the bridge interfaces' data - skip addresses.
49072376Sjake */
49172376Sjakevoid
49272376Sjakebridge_update_all_ifs(void)
49372376Sjake{
49472376Sjake	struct bridge_if *bif, *t_bif;
49572376Sjake
49672376Sjake	for (bif = bridge_first_bif(); bif != NULL; bif = t_bif) {
49772376Sjake		t_bif = bridge_next_bif(bif);
49872376Sjake		bridge_update_bif(bif);
49972376Sjake	}
50072376Sjake
50172376Sjake	bridge_ports_update_listage();
50272376Sjake	bridge_list_age = time(NULL);
50372376Sjake}
50472376Sjake
50572376Sjake/*
50672376Sjake * Update all info we have for all bridges.
50772376Sjake */
50872376Sjakevoid
50972376Sjakebridge_update_all(void *arg __unused)
51072376Sjake{
51172376Sjake	struct bridge_if *bif, *t_bif;
51272376Sjake
51372376Sjake	for (bif = bridge_first_bif(); bif != NULL; bif = t_bif) {
51499072Sjulian		t_bif = bridge_next_bif(bif);
51572376Sjake		if (bridge_update_bif(bif) <= 0)
51672376Sjake			continue;
51750027Speter
51883366Sjulian		/* Update our learnt addresses. */
51950027Speter		bif->num_addrs = bridge_update_addrs(bif);
52072376Sjake	}
52172376Sjake
52250027Speter	bridge_list_age = time(NULL);
52399072Sjulian	bridge_ports_update_listage();
52499072Sjulian	bridge_addrs_update_listage();
52599942Sjulian}
52699942Sjulian
52799072Sjulian/*
52899072Sjulian * Callback for polling our last topology change time -
52999072Sjulian * check whether we are root or whether a TC was detected once every
530100913Stanimura * 30 seconds, so that we can send the newRoot and TopologyChange traps
531100913Stanimura * on time. The rest of the data is polled only once every 5 min.
53290538Sjulian */
53383366Sjulianvoid
53472376Sjakebridge_update_tc_time(void *arg __unused)
53572376Sjake{
53672376Sjake	struct bridge_if *bif;
53790538Sjulian	struct mibif *ifp;
53883366Sjulian
53999072Sjulian	TAILQ_FOREACH(bif, &bridge_ifs, b_if) {
54099072Sjulian		/* Walk through the mibII interface list. */
54150027Speter		for (ifp = mib_first_if(); ifp != NULL; ifp = mib_next_if(ifp))
54250027Speter			if (strcmp(ifp->name, bif->bif_name) == 0)
54350027Speter				break;
54472376Sjake
54572376Sjake		if (ifp == NULL) {
54672376Sjake			bridge_remove_bif(bif);
54750027Speter			continue;
54872376Sjake		}
54972376Sjake
55050027Speter		switch (bridge_get_op_param(bif)) {
55172376Sjake			case 2:
55272376Sjake				bridge_new_root(bif);
55372376Sjake				break;
55472376Sjake			case 1:
55572376Sjake				bridge_top_change(bif);
55672376Sjake				break;
55772376Sjake		}
55872376Sjake	}
55972376Sjake}
56072376Sjake
56172376Sjake/*
56272376Sjake * Callback for handling new bridge interface creation.
56372376Sjake */
56450027Speterint
56550027Speterbridge_attach_newif(struct mibif *ifp)
56650027Speter{
56772376Sjake	u_char mac[ETHER_ADDR_LEN];
56872376Sjake	struct bridge_if *bif;
56972376Sjake
57050027Speter	if (ifp->mib.ifmd_data.ifi_type != IFT_BRIDGE)
57183366Sjulian		return (0);
57272376Sjake
57350027Speter	/* Make sure it does not exist in our list. */
57472376Sjake	TAILQ_FOREACH(bif, &bridge_ifs, b_if)
57583366Sjulian		if(strcmp(bif->bif_name, ifp->name) == 0) {
57672376Sjake			syslog(LOG_ERR, "bridge interface %s already "
57750027Speter			    "in list", bif->bif_name);
57865557Sjasone			return (-1);
57999072Sjulian		}
58072376Sjake
58183366Sjulian	if (ifp->physaddr == NULL) {
58283366Sjulian		if (bridge_get_basemac(ifp->name, mac, sizeof(mac)) == NULL) {
58399072Sjulian			syslog(LOG_ERR, "bridge attach new %s failed - "
58499072Sjulian			    "no bridge mac address", ifp->name);
58583366Sjulian			return (-1);
58699072Sjulian		}
58772376Sjake	} else
58872376Sjake		bcopy(ifp->physaddr, &mac, sizeof(mac));
58972376Sjake
59050027Speter	if ((bif = bridge_new_bif(ifp->name, ifp->sysindex, mac)) == NULL)
59199072Sjulian		return (-1);
59299942Sjulian
59399072Sjulian	if (ifp->mib.ifmd_flags & IFF_RUNNING)
59499072Sjulian		bif->if_status = RowStatus_active;
59599072Sjulian	else
59699072Sjulian		bif->if_status = RowStatus_notInService;
597100913Stanimura
598100913Stanimura	/* Skip sending notifications if the interface was just created. */
59983366Sjulian	if (bridge_getinfo_bif(bif) < 0 ||
60050027Speter	    (bif->num_ports = bridge_getinfo_bif_ports(bif)) < 0 ||
60172376Sjake	    (bif->num_addrs = bridge_getinfo_bif_addrs(bif)) < 0) {
60272376Sjake		bridge_remove_bif(bif);
60399072Sjulian		return (-1);
60450027Speter	}
60572376Sjake
60672376Sjake	/* Check whether we are the default bridge interface. */
60799072Sjulian	if (strcmp(ifp->name, bridge_get_default_name()) == 0)
60872376Sjake		bridge_set_default(bif);
60999072Sjulian
61072376Sjake	return (0);
61172376Sjake}
61283366Sjulian
61372376Sjakevoid
61472376Sjakebridge_ifs_dump(void)
61572376Sjake{
61672376Sjake	struct bridge_if *bif;
61799072Sjulian
61872376Sjake	for (bif = bridge_first_bif(); bif != NULL;
619100913Stanimura		bif = bridge_next_bif(bif)) {
620100913Stanimura		syslog(LOG_ERR, "Bridge %s, index - %d", bif->bif_name,
62183366Sjulian		    bif->sysindex);
62272376Sjake		bridge_ports_dump(bif);
62372376Sjake		bridge_addrs_dump(bif);
62490538Sjulian	}
62583366Sjulian}
62683366Sjulian
62772376Sjake/*
62872376Sjake * RFC4188 specifics.
62972376Sjake */
63072376Sjakeint
63199942Sjulianop_dot1d_base(struct snmp_context *ctx __unused, struct snmp_value *value,
63299072Sjulian	uint sub, uint iidx __unused, enum snmp_op op)
63372376Sjake{
63499072Sjulian	struct bridge_if *bif;
63599072Sjulian
63699072Sjulian	if ((bif = bridge_get_default()) == NULL)
63799072Sjulian		return (SNMP_ERR_NOSUCHNAME);
63899072Sjulian
63999072Sjulian	if (time(NULL) - bif->entry_age > bridge_get_data_maxage() &&
64099072Sjulian	    bridge_update_bif(bif) <= 0) /* It was just deleted. */
64199072Sjulian		return (SNMP_ERR_NOSUCHNAME);
64299072Sjulian
64399072Sjulian	switch (op) {
64499072Sjulian	    case SNMP_OP_GET:
64599834Sjulian		switch (value->var.subs[sub - 1]) {
64699072Sjulian		    case LEAF_dot1dBaseBridgeAddress:
64799072Sjulian			return (string_get(value, bif->br_addr.octet,
64899072Sjulian			    ETHER_ADDR_LEN));
64999072Sjulian		    case LEAF_dot1dBaseNumPorts:
65099072Sjulian			value->v.integer = bif->num_ports;
65199072Sjulian			return (SNMP_ERR_NOERROR);
65299072Sjulian		    case LEAF_dot1dBaseType:
65399072Sjulian			value->v.integer = bif->br_type;
65499072Sjulian			return (SNMP_ERR_NOERROR);
65599072Sjulian		}
65699072Sjulian		abort();
65799072Sjulian
65899072Sjulian		case SNMP_OP_SET:
65999072Sjulian		    return (SNMP_ERR_NOT_WRITEABLE);
66099072Sjulian
66199072Sjulian		case SNMP_OP_GETNEXT:
66299072Sjulian		case SNMP_OP_ROLLBACK:
66399072Sjulian		case SNMP_OP_COMMIT:
66499072Sjulian		   break;
66599072Sjulian	}
66699072Sjulian
66799072Sjulian	abort();
66899072Sjulian}
66999072Sjulian
67099072Sjulianint
67199072Sjulianop_dot1d_stp(struct snmp_context *ctx, struct snmp_value *val, uint sub,
67299072Sjulian    uint iidx __unused, enum snmp_op op)
67399072Sjulian{
67499072Sjulian	struct bridge_if *bif;
67599072Sjulian
67699072Sjulian	if ((bif = bridge_get_default()) == NULL)
67799072Sjulian		return (SNMP_ERR_NOSUCHNAME);
67899072Sjulian
67999072Sjulian	if (time(NULL) - bif->entry_age > bridge_get_data_maxage() &&
68099072Sjulian	    bridge_update_bif(bif) <= 0) /* It was just deleted. */
68199072Sjulian		return (SNMP_ERR_NOSUCHNAME);
68299072Sjulian
68399072Sjulian	switch (op) {
68499072Sjulian	    case SNMP_OP_GET:
68599072Sjulian		switch (val->var.subs[sub - 1]) {
68699072Sjulian		    case LEAF_dot1dStpProtocolSpecification:
68799072Sjulian			val->v.integer = bif->prot_spec;
68899072Sjulian			return (SNMP_ERR_NOERROR);
68999072Sjulian
69099072Sjulian		    case LEAF_dot1dStpPriority:
69199072Sjulian			val->v.integer = bif->priority;
69299072Sjulian			return (SNMP_ERR_NOERROR);
69399072Sjulian
69499072Sjulian		    case LEAF_dot1dStpTimeSinceTopologyChange:
69599072Sjulian			if (bridge_get_time_since_tc(bif,
69699072Sjulian			    &(val->v.uint32)) < 0)
69799072Sjulian				return (SNMP_ERR_GENERR);
69899072Sjulian			return (SNMP_ERR_NOERROR);
69999072Sjulian
70099072Sjulian		    case LEAF_dot1dStpTopChanges:
70199072Sjulian			val->v.uint32 = bif->top_changes;
70299072Sjulian			return (SNMP_ERR_NOERROR);
70399072Sjulian
70499072Sjulian		    case LEAF_dot1dStpDesignatedRoot:
70599072Sjulian			return (string_get(val, bif->design_root,
70699072Sjulian			    SNMP_BRIDGE_ID_LEN));
70799072Sjulian
70899072Sjulian		    case LEAF_dot1dStpRootCost:
70999072Sjulian			val->v.integer = bif->root_cost;
71099072Sjulian			return (SNMP_ERR_NOERROR);
71199072Sjulian
71299072Sjulian		    case LEAF_dot1dStpRootPort:
71399072Sjulian			val->v.integer = bif->root_port;
71499072Sjulian			return (SNMP_ERR_NOERROR);
71599072Sjulian
71699072Sjulian		    case LEAF_dot1dStpMaxAge:
71799072Sjulian			val->v.integer = bif->max_age;
718103216Sjulian			return (SNMP_ERR_NOERROR);
71999072Sjulian
72099072Sjulian		    case LEAF_dot1dStpHelloTime:
72199072Sjulian			val->v.integer = bif->hello_time;
72299072Sjulian			return (SNMP_ERR_NOERROR);
72399072Sjulian
72499072Sjulian		    case LEAF_dot1dStpHoldTime:
72599072Sjulian			val->v.integer = bif->hold_time;
72699072Sjulian			return (SNMP_ERR_NOERROR);
72799072Sjulian
72899072Sjulian		    case LEAF_dot1dStpForwardDelay:
72999072Sjulian			val->v.integer = bif->fwd_delay;
73099072Sjulian			return (SNMP_ERR_NOERROR);
73199072Sjulian
73299834Sjulian		    case LEAF_dot1dStpBridgeMaxAge:
73399072Sjulian			val->v.integer = bif->bridge_max_age;
734			return (SNMP_ERR_NOERROR);
735
736		    case LEAF_dot1dStpBridgeHelloTime:
737			val->v.integer = bif->bridge_hello_time;
738			return (SNMP_ERR_NOERROR);
739
740		    case LEAF_dot1dStpBridgeForwardDelay:
741			val->v.integer = bif->bridge_fwd_delay;
742			return (SNMP_ERR_NOERROR);
743
744		    case LEAF_dot1dStpVersion:
745			val->v.integer = bif->stp_version;
746			return (SNMP_ERR_NOERROR);
747
748		    case LEAF_dot1dStpTxHoldCount:
749			val->v.integer = bif->tx_hold_count;
750			return (SNMP_ERR_NOERROR);
751		}
752		abort();
753
754	    case SNMP_OP_GETNEXT:
755		abort();
756
757	    case SNMP_OP_SET:
758		switch (val->var.subs[sub - 1]) {
759		    case LEAF_dot1dStpPriority:
760			if (val->v.integer > SNMP_BRIDGE_MAX_PRIORITY ||
761			    val->v.integer % 4096 != 0)
762			    return (SNMP_ERR_WRONG_VALUE);
763
764			ctx->scratch->int1 = bif->priority;
765			if (bridge_set_priority(bif, val->v.integer) < 0)
766			    return (SNMP_ERR_GENERR);
767			return (SNMP_ERR_NOERROR);
768
769		    case LEAF_dot1dStpBridgeMaxAge:
770			if (val->v.integer < SNMP_BRIDGE_MIN_MAGE ||
771			    val->v.integer > SNMP_BRIDGE_MAX_MAGE)
772			    return (SNMP_ERR_WRONG_VALUE);
773
774			ctx->scratch->int1 = bif->bridge_max_age;
775			if (bridge_set_maxage(bif, val->v.integer) < 0)
776			    return (SNMP_ERR_GENERR);
777			return (SNMP_ERR_NOERROR);
778
779		    case LEAF_dot1dStpBridgeHelloTime:
780			if (val->v.integer < SNMP_BRIDGE_MIN_HTIME ||
781			    val->v.integer > SNMP_BRIDGE_MAX_HTIME)
782			    return (SNMP_ERR_WRONG_VALUE);
783
784			ctx->scratch->int1 = bif->bridge_hello_time;
785			if (bridge_set_hello_time(bif, val->v.integer) < 0)
786			    return (SNMP_ERR_GENERR);
787			return (SNMP_ERR_NOERROR);
788
789		    case LEAF_dot1dStpBridgeForwardDelay:
790			if (val->v.integer < SNMP_BRIDGE_MIN_FDELAY ||
791			    val->v.integer > SNMP_BRIDGE_MAX_FDELAY)
792			    return (SNMP_ERR_WRONG_VALUE);
793
794			ctx->scratch->int1 = bif->bridge_fwd_delay;
795			if (bridge_set_forward_delay(bif, val->v.integer) < 0)
796			    return (SNMP_ERR_GENERR);
797			return (SNMP_ERR_NOERROR);
798
799		    case LEAF_dot1dStpVersion:
800			if (val->v.integer != dot1dStpVersion_stpCompatible &&
801			    val->v.integer != dot1dStpVersion_rstp)
802			    return (SNMP_ERR_WRONG_VALUE);
803
804			ctx->scratch->int1 = bif->stp_version;
805			if (bridge_set_stp_version(bif, val->v.integer) < 0)
806			    return (SNMP_ERR_GENERR);
807			return (SNMP_ERR_NOERROR);
808
809		    case LEAF_dot1dStpTxHoldCount:
810			if (val->v.integer < SNMP_BRIDGE_MIN_TXHC ||
811			    val->v.integer > SNMP_BRIDGE_MAX_TXHC)
812			    return (SNMP_ERR_WRONG_VALUE);
813
814			ctx->scratch->int1 = bif->tx_hold_count;
815			if (bridge_set_tx_hold_count(bif, val->v.integer) < 0)
816			    return (SNMP_ERR_GENERR);
817			return (SNMP_ERR_NOERROR);
818
819		    case LEAF_dot1dStpProtocolSpecification:
820		    case LEAF_dot1dStpTimeSinceTopologyChange:
821		    case LEAF_dot1dStpTopChanges:
822		    case LEAF_dot1dStpDesignatedRoot:
823		    case LEAF_dot1dStpRootCost:
824		    case LEAF_dot1dStpRootPort:
825		    case LEAF_dot1dStpMaxAge:
826		    case LEAF_dot1dStpHelloTime:
827		    case LEAF_dot1dStpHoldTime:
828		    case LEAF_dot1dStpForwardDelay:
829			return (SNMP_ERR_NOT_WRITEABLE);
830		}
831		abort();
832
833	    case SNMP_OP_ROLLBACK:
834		switch (val->var.subs[sub - 1]) {
835		    case LEAF_dot1dStpPriority:
836			bridge_set_priority(bif, ctx->scratch->int1);
837			break;
838		    case LEAF_dot1dStpBridgeMaxAge:
839			bridge_set_maxage(bif, ctx->scratch->int1);
840			break;
841		    case LEAF_dot1dStpBridgeHelloTime:
842			bridge_set_hello_time(bif, ctx->scratch->int1);
843			break;
844		    case LEAF_dot1dStpBridgeForwardDelay:
845			bridge_set_forward_delay(bif, ctx->scratch->int1);
846			break;
847		    case LEAF_dot1dStpVersion:
848			bridge_set_stp_version(bif, ctx->scratch->int1);
849			break;
850		    case LEAF_dot1dStpTxHoldCount:
851			bridge_set_tx_hold_count(bif, ctx->scratch->int1);
852			break;
853		}
854		return (SNMP_ERR_NOERROR);
855
856	    case SNMP_OP_COMMIT:
857		return (SNMP_ERR_NOERROR);
858	}
859
860	abort();
861}
862
863int
864op_dot1d_tp(struct snmp_context *ctx, struct snmp_value *value,
865	uint sub, uint iidx __unused, enum snmp_op op)
866{
867	struct bridge_if *bif;
868
869	if ((bif = bridge_get_default()) == NULL)
870		return (SNMP_ERR_NOSUCHNAME);
871
872	if (time(NULL) - bif->entry_age > bridge_get_data_maxage() &&
873	    bridge_update_bif(bif) <= 0) /* It was just deleted. */
874		return (SNMP_ERR_NOSUCHNAME);
875
876	switch (op) {
877	    case SNMP_OP_GET:
878		switch (value->var.subs[sub - 1]) {
879		    case LEAF_dot1dTpLearnedEntryDiscards:
880			value->v.uint32 = bif->lrnt_drops;
881			return (SNMP_ERR_NOERROR);
882		    case LEAF_dot1dTpAgingTime:
883			value->v.integer = bif->age_time;
884			return (SNMP_ERR_NOERROR);
885		}
886		abort();
887
888	    case SNMP_OP_GETNEXT:
889		abort();
890
891	    case SNMP_OP_SET:
892		switch (value->var.subs[sub - 1]) {
893		    case LEAF_dot1dTpLearnedEntryDiscards:
894			return (SNMP_ERR_NOT_WRITEABLE);
895
896		    case LEAF_dot1dTpAgingTime:
897			if (value->v.integer < SNMP_BRIDGE_MIN_AGE_TIME ||
898			    value->v.integer > SNMP_BRIDGE_MAX_AGE_TIME)
899			    return (SNMP_ERR_WRONG_VALUE);
900
901			ctx->scratch->int1 = bif->age_time;
902			if (bridge_set_aging_time(bif, value->v.integer) < 0)
903			    return (SNMP_ERR_GENERR);
904			return (SNMP_ERR_NOERROR);
905		}
906		abort();
907
908	    case SNMP_OP_ROLLBACK:
909		if (value->var.subs[sub - 1] == LEAF_dot1dTpAgingTime)
910		    bridge_set_aging_time(bif, ctx->scratch->int1);
911		return (SNMP_ERR_NOERROR);
912
913	    case SNMP_OP_COMMIT:
914		return (SNMP_ERR_NOERROR);
915	}
916
917	abort();
918}
919
920/*
921 * Private BEGEMOT-BRIDGE-MIB specifics.
922 */
923
924/*
925 * Get the bridge name from an OID index.
926 */
927static char *
928bridge_name_index_get(const struct asn_oid *oid, uint sub, char *b_name)
929{
930	uint i;
931
932	if (oid->len - sub != oid->subs[sub] + 1 || oid->subs[sub] >= IFNAMSIZ)
933		return (NULL);
934
935	for (i = 0; i < oid->subs[sub]; i++)
936		b_name[i] = oid->subs[sub + i + 1];
937	b_name[i] = '\0';
938
939	return (b_name);
940}
941
942static void
943bridge_if_index_append(struct asn_oid *oid, uint sub,
944	const struct bridge_if *bif)
945{
946	uint i;
947
948	oid->len = sub + strlen(bif->bif_name) + 1;
949	oid->subs[sub] = strlen(bif->bif_name);
950
951	for (i = 1; i <= strlen(bif->bif_name); i++)
952		oid->subs[sub + i] = bif->bif_name[i - 1];
953}
954
955static struct bridge_if *
956bridge_if_index_get(const struct asn_oid *oid, uint sub)
957{
958	uint i;
959	char bif_name[IFNAMSIZ];
960
961	if (oid->len - sub != oid->subs[sub] + 1 || oid->subs[sub] >= IFNAMSIZ)
962		return (NULL);
963
964	for (i = 0; i < oid->subs[sub]; i++)
965		bif_name[i] = oid->subs[sub + i + 1];
966	bif_name[i] = '\0';
967
968	return (bridge_if_find_ifname(bif_name));
969}
970
971static struct bridge_if *
972bridge_if_index_getnext(const struct asn_oid *oid, uint sub)
973{
974	uint i;
975	char bif_name[IFNAMSIZ];
976	struct bridge_if *bif;
977
978	if (oid->len - sub == 0)
979		return (bridge_first_bif());
980
981	if (oid->len - sub != oid->subs[sub] + 1 || oid->subs[sub] >= IFNAMSIZ)
982		return (NULL);
983
984	for (i = 0; i < oid->subs[sub]; i++)
985		bif_name[i] = oid->subs[sub + i + 1];
986	bif_name[i] = '\0';
987
988	if ((bif = bridge_if_find_ifname(bif_name)) == NULL)
989		return (NULL);
990
991	return (bridge_next_bif(bif));
992}
993
994static int
995bridge_set_if_status(struct snmp_context *ctx,
996	struct snmp_value *val, uint sub)
997{
998	struct bridge_if *bif;
999	char bif_name[IFNAMSIZ];
1000
1001	bif = bridge_if_index_get(&val->var, sub);
1002
1003	switch (val->v.integer) {
1004	    case RowStatus_active:
1005		if (bif == NULL)
1006		    return (SNMP_ERR_INCONS_VALUE);
1007
1008		ctx->scratch->int1 = bif->if_status;
1009
1010		switch (bif->if_status) {
1011		    case RowStatus_active:
1012			return (SNMP_ERR_NOERROR);
1013		    case RowStatus_notInService:
1014			if (bridge_set_if_up(bif->bif_name, 1) < 0)
1015			    return (SNMP_ERR_GENERR);
1016			return (SNMP_ERR_NOERROR);
1017		    default:
1018			break;
1019		}
1020		return (SNMP_ERR_INCONS_VALUE);
1021
1022	    case RowStatus_notInService:
1023		if (bif == NULL)
1024		    return (SNMP_ERR_INCONS_VALUE);
1025
1026		ctx->scratch->int1 = bif->if_status;
1027
1028		switch (bif->if_status) {
1029		    case RowStatus_active:
1030			if (bridge_set_if_up(bif->bif_name, 1) < 0)
1031			    return (SNMP_ERR_GENERR);
1032			return (SNMP_ERR_NOERROR);
1033		    case RowStatus_notInService:
1034			return (SNMP_ERR_NOERROR);
1035		    default:
1036			break;
1037		}
1038		return (SNMP_ERR_INCONS_VALUE);
1039
1040	    case RowStatus_notReady:
1041		return (SNMP_ERR_INCONS_VALUE);
1042
1043	    case RowStatus_createAndGo:
1044		if (bif != NULL)
1045		    return (SNMP_ERR_INCONS_VALUE);
1046
1047		ctx->scratch->int1 = RowStatus_destroy;
1048
1049		if (bridge_name_index_get(&val->var, sub, bif_name) == NULL)
1050		    return (SNMP_ERR_BADVALUE);
1051		if (bridge_if_create(bif_name, 1) < 0)
1052		    return (SNMP_ERR_GENERR);
1053		return (SNMP_ERR_NOERROR);
1054
1055	    case RowStatus_createAndWait:
1056		if (bif != NULL)
1057		    return (SNMP_ERR_INCONS_VALUE);
1058
1059		if (bridge_name_index_get(&val->var, sub, bif_name) == NULL)
1060		    return (SNMP_ERR_BADVALUE);
1061
1062		ctx->scratch->int1 = RowStatus_destroy;
1063
1064		if (bridge_if_create(bif_name, 0) < 0)
1065		    return (SNMP_ERR_GENERR);
1066		return (SNMP_ERR_NOERROR);
1067
1068	    case RowStatus_destroy:
1069		if (bif == NULL)
1070		    return (SNMP_ERR_NOSUCHNAME);
1071
1072		ctx->scratch->int1 = bif->if_status;
1073		bif->if_status = RowStatus_destroy;
1074	}
1075
1076	return (SNMP_ERR_NOERROR);
1077}
1078
1079static int
1080bridge_rollback_if_status(struct snmp_context *ctx,
1081	struct snmp_value *val, uint sub)
1082{
1083	struct bridge_if *bif;
1084
1085	if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1086		return (SNMP_ERR_GENERR);
1087
1088	switch (ctx->scratch->int1) {
1089		case RowStatus_destroy:
1090			bridge_if_destroy(bif);
1091			return (SNMP_ERR_NOERROR);
1092
1093		case RowStatus_notInService:
1094			if (bif->if_status != ctx->scratch->int1)
1095				bridge_set_if_up(bif->bif_name, 0);
1096			bif->if_status = RowStatus_notInService;
1097			return (SNMP_ERR_NOERROR);
1098
1099		case RowStatus_active:
1100			if (bif->if_status != ctx->scratch->int1)
1101				bridge_set_if_up(bif->bif_name, 1);
1102			bif->if_status = RowStatus_active;
1103			return (SNMP_ERR_NOERROR);
1104	}
1105
1106	abort();
1107}
1108
1109static int
1110bridge_commit_if_status(struct snmp_value *val, uint sub)
1111{
1112	struct bridge_if *bif;
1113
1114	if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1115		return (SNMP_ERR_GENERR);
1116
1117	if (bif->if_status == RowStatus_destroy &&
1118	    bridge_if_destroy(bif) < 0)
1119		return (SNMP_ERR_COMMIT_FAILED);
1120
1121	return (SNMP_ERR_NOERROR);
1122}
1123
1124int
1125op_begemot_base_bridge(struct snmp_context *ctx, struct snmp_value *val,
1126	uint sub, uint iidx __unused, enum snmp_op op)
1127{
1128	struct bridge_if *bif;
1129
1130	if (time(NULL) - bridge_list_age > bridge_get_data_maxage())
1131		bridge_update_all_ifs();
1132
1133	switch (op) {
1134	    case SNMP_OP_GET:
1135		if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1136		    return (SNMP_ERR_NOSUCHNAME);
1137		goto get;
1138
1139	    case SNMP_OP_GETNEXT:
1140		if ((bif = bridge_if_index_getnext(&val->var, sub)) == NULL)
1141		    return (SNMP_ERR_NOSUCHNAME);
1142		bridge_if_index_append(&val->var, sub, bif);
1143		goto get;
1144
1145	    case SNMP_OP_SET:
1146		switch (val->var.subs[sub - 1]) {
1147		    case LEAF_begemotBridgeBaseStatus:
1148			return (bridge_set_if_status(ctx, val, sub));
1149		    case LEAF_begemotBridgeBaseName:
1150		    case LEAF_begemotBridgeBaseAddress:
1151		    case LEAF_begemotBridgeBaseNumPorts:
1152		    case LEAF_begemotBridgeBaseType:
1153			return (SNMP_ERR_NOT_WRITEABLE);
1154		}
1155		abort();
1156
1157	    case SNMP_OP_ROLLBACK:
1158		return (bridge_rollback_if_status(ctx, val, sub));
1159
1160	    case SNMP_OP_COMMIT:
1161		return (bridge_commit_if_status(val, sub));
1162	}
1163	abort();
1164
1165get:
1166	switch (val->var.subs[sub - 1]) {
1167	    case LEAF_begemotBridgeBaseName:
1168		return (string_get(val, bif->bif_name, -1));
1169
1170	    case LEAF_begemotBridgeBaseAddress:
1171		return (string_get(val, bif->br_addr.octet, ETHER_ADDR_LEN));
1172
1173	    case LEAF_begemotBridgeBaseNumPorts:
1174		val->v.integer = bif->num_ports;
1175		return (SNMP_ERR_NOERROR);
1176
1177	    case LEAF_begemotBridgeBaseType:
1178		val->v.integer = bif->br_type;
1179		return (SNMP_ERR_NOERROR);
1180
1181	    case LEAF_begemotBridgeBaseStatus:
1182		val->v.integer = bif->if_status;
1183		return (SNMP_ERR_NOERROR);
1184	}
1185
1186	abort();
1187}
1188
1189int
1190op_begemot_stp(struct snmp_context *ctx, struct snmp_value *val,
1191	uint sub, uint iidx __unused, enum snmp_op op)
1192{
1193	struct bridge_if *bif;
1194
1195	if (time(NULL) - bridge_list_age > bridge_get_data_maxage())
1196		bridge_update_all_ifs();
1197
1198	switch (op) {
1199	    case SNMP_OP_GET:
1200		if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1201		    return (SNMP_ERR_NOSUCHNAME);
1202		goto get;
1203
1204	    case SNMP_OP_GETNEXT:
1205		if ((bif = bridge_if_index_getnext(&val->var, sub)) == NULL)
1206		    return (SNMP_ERR_NOSUCHNAME);
1207		bridge_if_index_append(&val->var, sub, bif);
1208		goto get;
1209
1210	    case SNMP_OP_SET:
1211		if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1212		    return (SNMP_ERR_NOSUCHNAME);
1213
1214		switch (val->var.subs[sub - 1]) {
1215		    case LEAF_begemotBridgeStpPriority:
1216			if (val->v.integer > SNMP_BRIDGE_MAX_PRIORITY ||
1217			    val->v.integer % 4096 != 0)
1218			    return (SNMP_ERR_WRONG_VALUE);
1219
1220			ctx->scratch->int1 = bif->priority;
1221			if (bridge_set_priority(bif, val->v.integer) < 0)
1222			    return (SNMP_ERR_GENERR);
1223			return (SNMP_ERR_NOERROR);
1224
1225		    case LEAF_begemotBridgeStpBridgeMaxAge:
1226			if (val->v.integer < SNMP_BRIDGE_MIN_MAGE ||
1227			    val->v.integer > SNMP_BRIDGE_MAX_MAGE)
1228			    return (SNMP_ERR_WRONG_VALUE);
1229
1230			ctx->scratch->int1 = bif->bridge_max_age;
1231			if (bridge_set_maxage(bif, val->v.integer) < 0)
1232			    return (SNMP_ERR_GENERR);
1233			return (SNMP_ERR_NOERROR);
1234
1235		    case LEAF_begemotBridgeStpBridgeHelloTime:
1236			if (val->v.integer < SNMP_BRIDGE_MIN_HTIME ||
1237			    val->v.integer > SNMP_BRIDGE_MAX_HTIME)
1238			    return (SNMP_ERR_WRONG_VALUE);
1239
1240			ctx->scratch->int1 = bif->bridge_hello_time;
1241			if (bridge_set_hello_time(bif, val->v.integer) < 0)
1242			    return (SNMP_ERR_GENERR);
1243			return (SNMP_ERR_NOERROR);
1244
1245		    case LEAF_begemotBridgeStpBridgeForwardDelay:
1246			if (val->v.integer < SNMP_BRIDGE_MIN_FDELAY ||
1247			    val->v.integer > SNMP_BRIDGE_MAX_FDELAY)
1248			    return (SNMP_ERR_WRONG_VALUE);
1249
1250			ctx->scratch->int1 = bif->bridge_fwd_delay;
1251			if (bridge_set_forward_delay(bif, val->v.integer) < 0)
1252			    return (SNMP_ERR_GENERR);
1253			return (SNMP_ERR_NOERROR);
1254
1255		    case LEAF_begemotBridgeStpVersion:
1256			if (val->v.integer !=
1257			    begemotBridgeStpVersion_stpCompatible &&
1258			    val->v.integer != begemotBridgeStpVersion_rstp)
1259			    return (SNMP_ERR_WRONG_VALUE);
1260
1261			ctx->scratch->int1 = bif->stp_version;
1262			if (bridge_set_stp_version(bif, val->v.integer) < 0)
1263			    return (SNMP_ERR_GENERR);
1264			return (SNMP_ERR_NOERROR);
1265
1266		    case LEAF_begemotBridgeStpTxHoldCount:
1267			if (val->v.integer < SNMP_BRIDGE_MIN_TXHC ||
1268			    val->v.integer > SNMP_BRIDGE_MAX_TXHC)
1269			    return (SNMP_ERR_WRONG_VALUE);
1270
1271			ctx->scratch->int1 = bif->tx_hold_count;
1272			if (bridge_set_tx_hold_count(bif, val->v.integer) < 0)
1273			    return (SNMP_ERR_GENERR);
1274			return (SNMP_ERR_NOERROR);
1275
1276		    case LEAF_begemotBridgeStpProtocolSpecification:
1277		    case LEAF_begemotBridgeStpTimeSinceTopologyChange:
1278		    case LEAF_begemotBridgeStpTopChanges:
1279		    case LEAF_begemotBridgeStpDesignatedRoot:
1280		    case LEAF_begemotBridgeStpRootCost:
1281		    case LEAF_begemotBridgeStpRootPort:
1282		    case LEAF_begemotBridgeStpMaxAge:
1283		    case LEAF_begemotBridgeStpHelloTime:
1284		    case LEAF_begemotBridgeStpHoldTime:
1285		    case LEAF_begemotBridgeStpForwardDelay:
1286			return (SNMP_ERR_NOT_WRITEABLE);
1287		}
1288		abort();
1289
1290	    case SNMP_OP_ROLLBACK:
1291		if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1292		    return (SNMP_ERR_NOSUCHNAME);
1293
1294		switch (val->var.subs[sub - 1]) {
1295		    case LEAF_begemotBridgeStpPriority:
1296			bridge_set_priority(bif, ctx->scratch->int1);
1297			break;
1298
1299		    case LEAF_begemotBridgeStpBridgeMaxAge:
1300			bridge_set_maxage(bif, ctx->scratch->int1);
1301			break;
1302
1303		    case LEAF_begemotBridgeStpBridgeHelloTime:
1304			bridge_set_hello_time(bif, ctx->scratch->int1);
1305			break;
1306
1307		    case LEAF_begemotBridgeStpBridgeForwardDelay:
1308			bridge_set_forward_delay(bif, ctx->scratch->int1);
1309			break;
1310
1311		    case LEAF_begemotBridgeStpVersion:
1312			bridge_set_stp_version(bif, ctx->scratch->int1);
1313			break;
1314
1315		    case LEAF_begemotBridgeStpTxHoldCount:
1316			bridge_set_tx_hold_count(bif, ctx->scratch->int1);
1317			break;
1318		}
1319		return (SNMP_ERR_NOERROR);
1320
1321	    case SNMP_OP_COMMIT:
1322		return (SNMP_ERR_NOERROR);
1323	}
1324	abort();
1325
1326get:
1327	switch (val->var.subs[sub - 1]) {
1328	    case LEAF_begemotBridgeStpProtocolSpecification:
1329		val->v.integer = bif->prot_spec;
1330		return (SNMP_ERR_NOERROR);
1331
1332	    case LEAF_begemotBridgeStpPriority:
1333		val->v.integer = bif->priority;
1334		return (SNMP_ERR_NOERROR);
1335
1336	    case LEAF_begemotBridgeStpTimeSinceTopologyChange:
1337		if (bridge_get_time_since_tc(bif, &(val->v.uint32)) < 0)
1338		    return (SNMP_ERR_GENERR);
1339		return (SNMP_ERR_NOERROR);
1340
1341	    case LEAF_begemotBridgeStpTopChanges:
1342		val->v.uint32 = bif->top_changes;
1343		return (SNMP_ERR_NOERROR);
1344
1345	    case LEAF_begemotBridgeStpDesignatedRoot:
1346		return (string_get(val, bif->design_root, SNMP_BRIDGE_ID_LEN));
1347
1348	    case LEAF_begemotBridgeStpRootCost:
1349		val->v.integer = bif->root_cost;
1350		return (SNMP_ERR_NOERROR);
1351
1352	    case LEAF_begemotBridgeStpRootPort:
1353		val->v.integer = bif->root_port;
1354		return (SNMP_ERR_NOERROR);
1355
1356	    case LEAF_begemotBridgeStpMaxAge:
1357		val->v.integer = bif->max_age;
1358		return (SNMP_ERR_NOERROR);
1359
1360	    case LEAF_begemotBridgeStpHelloTime:
1361		val->v.integer = bif->hello_time;
1362		return (SNMP_ERR_NOERROR);
1363
1364	    case LEAF_begemotBridgeStpHoldTime:
1365		val->v.integer = bif->hold_time;
1366		return (SNMP_ERR_NOERROR);
1367
1368	    case LEAF_begemotBridgeStpForwardDelay:
1369		val->v.integer = bif->fwd_delay;
1370		return (SNMP_ERR_NOERROR);
1371
1372	    case LEAF_begemotBridgeStpBridgeMaxAge:
1373		val->v.integer = bif->bridge_max_age;
1374		return (SNMP_ERR_NOERROR);
1375
1376	    case LEAF_begemotBridgeStpBridgeHelloTime:
1377		val->v.integer = bif->bridge_hello_time;
1378		return (SNMP_ERR_NOERROR);
1379
1380	    case LEAF_begemotBridgeStpBridgeForwardDelay:
1381		val->v.integer = bif->bridge_fwd_delay;
1382		return (SNMP_ERR_NOERROR);
1383
1384	    case LEAF_begemotBridgeStpVersion:
1385		val->v.integer = bif->stp_version;
1386		return (SNMP_ERR_NOERROR);
1387
1388	    case LEAF_begemotBridgeStpTxHoldCount:
1389		val->v.integer = bif->tx_hold_count;
1390		return (SNMP_ERR_NOERROR);
1391	}
1392
1393	abort();
1394}
1395
1396int
1397op_begemot_tp(struct snmp_context *ctx, struct snmp_value *val,
1398	uint sub, uint iidx __unused, enum snmp_op op)
1399{
1400	struct bridge_if *bif;
1401
1402	if (time(NULL) - bridge_list_age > bridge_get_data_maxage())
1403		bridge_update_all_ifs();
1404
1405	switch (op) {
1406	    case SNMP_OP_GET:
1407		if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1408		    return (SNMP_ERR_NOSUCHNAME);
1409		goto get;
1410
1411	    case SNMP_OP_GETNEXT:
1412		if ((bif = bridge_if_index_getnext(&val->var, sub)) == NULL)
1413		    return (SNMP_ERR_NOSUCHNAME);
1414		bridge_if_index_append(&val->var, sub, bif);
1415		goto get;
1416
1417	    case SNMP_OP_SET:
1418		if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1419		    return (SNMP_ERR_NOSUCHNAME);
1420
1421		switch (val->var.subs[sub - 1]) {
1422		    case LEAF_begemotBridgeTpAgingTime:
1423			if (val->v.integer < SNMP_BRIDGE_MIN_AGE_TIME ||
1424			    val->v.integer > SNMP_BRIDGE_MAX_AGE_TIME)
1425			    return (SNMP_ERR_WRONG_VALUE);
1426
1427			ctx->scratch->int1 = bif->age_time;
1428			if (bridge_set_aging_time(bif, val->v.integer) < 0)
1429			    return (SNMP_ERR_GENERR);
1430			return (SNMP_ERR_NOERROR);
1431
1432		    case LEAF_begemotBridgeTpMaxAddresses:
1433			ctx->scratch->int1 = bif->max_addrs;
1434			if (bridge_set_max_cache(bif, val->v.integer) < 0)
1435			    return (SNMP_ERR_GENERR);
1436			return (SNMP_ERR_NOERROR);
1437
1438		    case LEAF_begemotBridgeTpLearnedEntryDiscards:
1439			return (SNMP_ERR_NOT_WRITEABLE);
1440		}
1441		abort();
1442
1443	    case SNMP_OP_ROLLBACK:
1444		if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1445		    return (SNMP_ERR_GENERR);
1446
1447		switch (val->var.subs[sub - 1]) {
1448		    case LEAF_begemotBridgeTpAgingTime:
1449			bridge_set_aging_time(bif, ctx->scratch->int1);
1450			break;
1451
1452		    case LEAF_begemotBridgeTpMaxAddresses:
1453			bridge_set_max_cache(bif, ctx->scratch->int1);
1454			break;
1455		}
1456		return (SNMP_ERR_NOERROR);
1457
1458	    case SNMP_OP_COMMIT:
1459		return (SNMP_ERR_NOERROR);
1460	}
1461	abort();
1462
1463get:
1464	switch (val->var.subs[sub - 1]) {
1465	    case LEAF_begemotBridgeTpLearnedEntryDiscards:
1466		val->v.uint32 = bif->lrnt_drops;
1467		return (SNMP_ERR_NOERROR);
1468
1469	    case LEAF_begemotBridgeTpAgingTime:
1470		val->v.integer = bif->age_time;
1471		return (SNMP_ERR_NOERROR);
1472
1473	    case LEAF_begemotBridgeTpMaxAddresses:
1474		val->v.integer = bif->max_addrs;
1475		return (SNMP_ERR_NOERROR);
1476	}
1477
1478	abort();
1479}
1480