1164410Ssyrinx/*-
2330449Seadler * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3330449Seadler *
4164410Ssyrinx * Copyright (c) 2006 Shteryana Shopova <syrinx@FreeBSD.org>
5164410Ssyrinx * All rights reserved.
6164410Ssyrinx *
7164410Ssyrinx * Redistribution and use in source and binary forms, with or without
8164410Ssyrinx * modification, are permitted provided that the following conditions
9164410Ssyrinx * are met:
10164410Ssyrinx * 1. Redistributions of source code must retain the above copyright
11164410Ssyrinx *    notice, this list of conditions and the following disclaimer.
12164410Ssyrinx * 2. Redistributions in binary form must reproduce the above copyright
13164410Ssyrinx *    notice, this list of conditions and the following disclaimer in the
14164410Ssyrinx *    documentation and/or other materials provided with the distribution.
15164410Ssyrinx *
16164410Ssyrinx * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17164410Ssyrinx * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18164410Ssyrinx * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19164410Ssyrinx * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20164410Ssyrinx * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21164410Ssyrinx * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22164410Ssyrinx * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23164410Ssyrinx * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24164410Ssyrinx * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25164410Ssyrinx * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26164410Ssyrinx * SUCH DAMAGE.
27164410Ssyrinx *
28164410Ssyrinx * Bridge MIB implementation for SNMPd.
29164410Ssyrinx * Bridge interface objects.
30164410Ssyrinx *
31164410Ssyrinx * $FreeBSD: stable/11/usr.sbin/bsnmpd/modules/snmp_bridge/bridge_if.c 330449 2018-03-05 07:26:05Z eadler $
32164410Ssyrinx */
33164410Ssyrinx
34164410Ssyrinx#include <sys/queue.h>
35164410Ssyrinx#include <sys/socket.h>
36164410Ssyrinx#include <sys/time.h>
37164410Ssyrinx#include <sys/types.h>
38164410Ssyrinx
39164410Ssyrinx#include <net/ethernet.h>
40164410Ssyrinx#include <net/if.h>
41164410Ssyrinx#include <net/if_mib.h>
42164410Ssyrinx#include <net/if_types.h>
43164410Ssyrinx
44164410Ssyrinx#include <errno.h>
45164410Ssyrinx#include <stdarg.h>
46164410Ssyrinx#include <stdlib.h>
47164410Ssyrinx#include <string.h>
48164410Ssyrinx#include <syslog.h>
49164410Ssyrinx
50164410Ssyrinx#include <bsnmp/snmpmod.h>
51164410Ssyrinx#include <bsnmp/snmp_mibII.h>
52164410Ssyrinx
53164410Ssyrinx#include "bridge_tree.h"
54164410Ssyrinx#include "bridge_snmp.h"
55164410Ssyrinx#include "bridge_oid.h"
56164410Ssyrinx
57164410Ssyrinxstatic const struct asn_oid oid_newRoot = OIDX_newRoot;
58164410Ssyrinxstatic const struct asn_oid oid_TopologyChange = OIDX_topologyChange;
59164410Ssyrinxstatic const struct asn_oid oid_begemotBrigeName = \
60164410Ssyrinx			OIDX_begemotBridgeBaseName;
61164410Ssyrinxstatic const struct asn_oid oid_begemotNewRoot = OIDX_begemotBridgeNewRoot;
62164410Ssyrinxstatic const struct asn_oid oid_begemotTopologyChange = \
63164410Ssyrinx			OIDX_begemotBridgeTopologyChange;
64164410Ssyrinx
65164410SsyrinxTAILQ_HEAD(bridge_ifs, bridge_if);
66164410Ssyrinx
67164410Ssyrinx/*
68164410Ssyrinx * Free the bridge interface list.
69164410Ssyrinx */
70164410Ssyrinxstatic void
71164410Ssyrinxbridge_ifs_free(struct bridge_ifs *headp)
72164410Ssyrinx{
73164410Ssyrinx	struct bridge_if *b;
74164410Ssyrinx
75164410Ssyrinx	while ((b = TAILQ_FIRST(headp)) != NULL) {
76164410Ssyrinx		TAILQ_REMOVE(headp, b, b_if);
77164410Ssyrinx		free(b);
78164410Ssyrinx	}
79164410Ssyrinx}
80164410Ssyrinx
81164410Ssyrinx/*
82164410Ssyrinx * Insert an entry in the bridge interface TAILQ. Keep the
83164410Ssyrinx * TAILQ sorted by the bridge's interface name.
84164410Ssyrinx */
85164410Ssyrinxstatic void
86164410Ssyrinxbridge_ifs_insert(struct bridge_ifs *headp,
87164410Ssyrinx	struct bridge_if *b)
88164410Ssyrinx{
89164410Ssyrinx	struct bridge_if *temp;
90164410Ssyrinx
91164410Ssyrinx	if ((temp = TAILQ_FIRST(headp)) == NULL ||
92164410Ssyrinx	    strcmp(b->bif_name, temp->bif_name) < 0) {
93164410Ssyrinx		TAILQ_INSERT_HEAD(headp, b, b_if);
94164410Ssyrinx		return;
95164410Ssyrinx	}
96164410Ssyrinx
97164410Ssyrinx	TAILQ_FOREACH(temp, headp, b_if)
98164410Ssyrinx		if(strcmp(b->bif_name, temp->bif_name) < 0)
99164410Ssyrinx			TAILQ_INSERT_BEFORE(temp, b, b_if);
100164410Ssyrinx
101164410Ssyrinx	TAILQ_INSERT_TAIL(headp, b, b_if);
102164410Ssyrinx}
103164410Ssyrinx
104164410Ssyrinx/* The global bridge interface list. */
105164410Ssyrinxstatic struct bridge_ifs bridge_ifs = TAILQ_HEAD_INITIALIZER(bridge_ifs);
106164410Ssyrinxstatic time_t bridge_list_age;
107164410Ssyrinx
108164410Ssyrinx/*
109164410Ssyrinx * Free the global list.
110164410Ssyrinx */
111164410Ssyrinxvoid
112164410Ssyrinxbridge_ifs_fini(void)
113164410Ssyrinx{
114164410Ssyrinx	bridge_ifs_free(&bridge_ifs);
115164410Ssyrinx}
116164410Ssyrinx
117164410Ssyrinx/*
118164410Ssyrinx * Find a bridge interface entry by the bridge interface system index.
119164410Ssyrinx */
120164410Ssyrinxstruct bridge_if *
121164410Ssyrinxbridge_if_find_ifs(uint32_t sysindex)
122164410Ssyrinx{
123164410Ssyrinx	struct bridge_if *b;
124164410Ssyrinx
125164410Ssyrinx	TAILQ_FOREACH(b, &bridge_ifs, b_if)
126164410Ssyrinx		if (b->sysindex == sysindex)
127164410Ssyrinx			return (b);
128164410Ssyrinx
129164410Ssyrinx	return (NULL);
130164410Ssyrinx}
131164410Ssyrinx
132164410Ssyrinx/*
133164410Ssyrinx * Find a bridge interface entry by the bridge interface name.
134164410Ssyrinx */
135164410Ssyrinxstruct bridge_if *
136164410Ssyrinxbridge_if_find_ifname(const char *b_name)
137164410Ssyrinx{
138164410Ssyrinx	struct bridge_if *b;
139164410Ssyrinx
140164410Ssyrinx	TAILQ_FOREACH(b, &bridge_ifs, b_if)
141164410Ssyrinx		if (strcmp(b_name, b->bif_name) == 0)
142164410Ssyrinx			return (b);
143164410Ssyrinx
144164410Ssyrinx	return (NULL);
145164410Ssyrinx}
146164410Ssyrinx
147164410Ssyrinx/*
148164410Ssyrinx * Find a bridge name by the bridge interface system index.
149164410Ssyrinx */
150164410Ssyrinxconst char *
151164410Ssyrinxbridge_if_find_name(uint32_t sysindex)
152164410Ssyrinx{
153164410Ssyrinx	struct bridge_if *b;
154164410Ssyrinx
155164410Ssyrinx	TAILQ_FOREACH(b, &bridge_ifs, b_if)
156164410Ssyrinx		if (b->sysindex == sysindex)
157164410Ssyrinx			return (b->bif_name);
158164410Ssyrinx
159164410Ssyrinx	return (NULL);
160164410Ssyrinx}
161164410Ssyrinx
162164410Ssyrinx/*
163164410Ssyrinx * Given two bridge interfaces' system indexes, find their
164164410Ssyrinx * corresponding names and return the result of the name
165164410Ssyrinx * comparison. Returns:
166164410Ssyrinx * error : -2
167164410Ssyrinx * i1 < i2 : -1
168164410Ssyrinx * i1 > i2 : +1
169164410Ssyrinx * i1 = i2 : 0
170164410Ssyrinx */
171164410Ssyrinxint
172164410Ssyrinxbridge_compare_sysidx(uint32_t i1, uint32_t i2)
173164410Ssyrinx{
174164410Ssyrinx	int c;
175164410Ssyrinx	const char *b1, *b2;
176164410Ssyrinx
177164410Ssyrinx	if (i1 == i2)
178164410Ssyrinx		return (0);
179164410Ssyrinx
180164410Ssyrinx	if ((b1 = bridge_if_find_name(i1)) == NULL) {
181164410Ssyrinx		syslog(LOG_ERR, "Bridge interface %d does not exist", i1);
182164410Ssyrinx		return (-2);
183164410Ssyrinx	}
184164410Ssyrinx
185164410Ssyrinx	if ((b2 = bridge_if_find_name(i2)) == NULL) {
186164410Ssyrinx		syslog(LOG_ERR, "Bridge interface %d does not exist", i2);
187164410Ssyrinx		return (-2);
188164410Ssyrinx	}
189164410Ssyrinx
190164410Ssyrinx	if ((c = strcmp(b1, b2)) < 0)
191164410Ssyrinx		return (-1);
192164410Ssyrinx	else if (c > 0)
193164410Ssyrinx		return (1);
194164410Ssyrinx
195164410Ssyrinx	return (0);
196164410Ssyrinx}
197164410Ssyrinx
198164410Ssyrinx/*
199164410Ssyrinx * Fetch the first bridge interface from the list.
200164410Ssyrinx */
201164410Ssyrinxstruct bridge_if *
202164410Ssyrinxbridge_first_bif(void)
203164410Ssyrinx{
204164410Ssyrinx	return (TAILQ_FIRST(&bridge_ifs));
205164410Ssyrinx}
206164410Ssyrinx
207164410Ssyrinx/*
208164410Ssyrinx * Fetch the next bridge interface from the list.
209164410Ssyrinx */
210164410Ssyrinxstruct bridge_if *
211164410Ssyrinxbridge_next_bif(struct bridge_if *b_pr)
212164410Ssyrinx{
213164410Ssyrinx	return (TAILQ_NEXT(b_pr, b_if));
214164410Ssyrinx}
215164410Ssyrinx
216164410Ssyrinx/*
217164410Ssyrinx * Create a new entry for a bridge interface and insert
218164410Ssyrinx * it in the list.
219164410Ssyrinx */
220164410Ssyrinxstatic struct bridge_if *
221164410Ssyrinxbridge_new_bif(const char *bif_n, uint32_t sysindex, const u_char *physaddr)
222164410Ssyrinx{
223164410Ssyrinx	struct bridge_if *bif;
224164410Ssyrinx
225164410Ssyrinx	if ((bif = (struct bridge_if *) malloc(sizeof(*bif)))== NULL) {
226164410Ssyrinx		syslog(LOG_ERR, "bridge new interface failed: %s",
227164410Ssyrinx		    strerror(errno));
228164410Ssyrinx		return (NULL);
229164410Ssyrinx	}
230164410Ssyrinx
231164410Ssyrinx	bzero(bif, sizeof(struct bridge_if));
232164410Ssyrinx	strlcpy(bif->bif_name, bif_n, IFNAMSIZ);
233164410Ssyrinx	bcopy(physaddr, bif->br_addr.octet, ETHER_ADDR_LEN);
234164410Ssyrinx	bif->sysindex = sysindex;
235164410Ssyrinx	bif->br_type = BaseType_transparent_only;
236164410Ssyrinx	/* 1 - all bridges default hold time * 100 - centi-seconds */
237164410Ssyrinx	bif->hold_time = 1 * 100;
238164410Ssyrinx	bif->prot_spec = dot1dStpProtocolSpecification_ieee8021d;
239164410Ssyrinx	bridge_ifs_insert(&bridge_ifs, bif);
240164410Ssyrinx
241164410Ssyrinx	return (bif);
242164410Ssyrinx}
243164410Ssyrinx
244164410Ssyrinx/*
245164410Ssyrinx * Remove a bridge interface from the list, freeing all it's ports
246164410Ssyrinx * and address entries.
247164410Ssyrinx */
248164410Ssyrinxvoid
249164410Ssyrinxbridge_remove_bif(struct bridge_if *bif)
250164410Ssyrinx{
251164410Ssyrinx	bridge_members_free(bif);
252164410Ssyrinx	bridge_addrs_free(bif);
253164410Ssyrinx	TAILQ_REMOVE(&bridge_ifs, bif, b_if);
254164410Ssyrinx	free(bif);
255164410Ssyrinx}
256164410Ssyrinx
257164410Ssyrinx
258164410Ssyrinx/*
259164410Ssyrinx * Prepare the variable (bridge interface name) for the private
260164410Ssyrinx * begemot notifications.
261164410Ssyrinx */
262164410Ssyrinxstatic struct snmp_value*
263164410Ssyrinxbridge_basename_var(struct bridge_if *bif, struct snmp_value* b_val)
264164410Ssyrinx{
265164410Ssyrinx	uint i;
266164410Ssyrinx
267164410Ssyrinx	b_val->var = oid_begemotBrigeName;
268164410Ssyrinx	b_val->var.subs[b_val->var.len++] = strlen(bif->bif_name);
269164410Ssyrinx
270164410Ssyrinx	if ((b_val->v.octetstring.octets = (u_char *)
271164410Ssyrinx	    malloc(strlen(bif->bif_name))) == NULL)
272164410Ssyrinx		return (NULL);
273164410Ssyrinx
274164410Ssyrinx	for (i = 0; i < strlen(bif->bif_name); i++)
275164410Ssyrinx		b_val->var.subs[b_val->var.len++] = bif->bif_name[i];
276164410Ssyrinx
277164410Ssyrinx	b_val->v.octetstring.len = strlen(bif->bif_name);
278164410Ssyrinx	bcopy(bif->bif_name, b_val->v.octetstring.octets,
279164410Ssyrinx	    strlen(bif->bif_name));
280164410Ssyrinx	b_val->syntax = SNMP_SYNTAX_OCTETSTRING;
281164410Ssyrinx
282164410Ssyrinx	return (b_val);
283164410Ssyrinx}
284164410Ssyrinx
285164410Ssyrinx/*
286164410Ssyrinx * Compare the values of the old and the new root port and
287164410Ssyrinx * send a new root notification, if they are not matching.
288164410Ssyrinx */
289164410Ssyrinxstatic void
290164410Ssyrinxbridge_new_root(struct bridge_if *bif)
291164410Ssyrinx{
292164410Ssyrinx	struct snmp_value bif_idx;
293164410Ssyrinx
294164410Ssyrinx	if (bridge_get_default() == bif)
295164410Ssyrinx		snmp_send_trap(&oid_newRoot, (struct snmp_value *) NULL);
296164410Ssyrinx
297164410Ssyrinx	if (bridge_basename_var(bif, &bif_idx) == NULL)
298164410Ssyrinx		return;
299164410Ssyrinx
300164410Ssyrinx	snmp_send_trap(&oid_begemotTopologyChange,
301164410Ssyrinx	    &bif_idx, (struct snmp_value *) NULL);
302164410Ssyrinx}
303164410Ssyrinx
304164410Ssyrinx/*
305164410Ssyrinx * Compare the new and old topology change times and send a
306164410Ssyrinx * topology change notification if necessary.
307164410Ssyrinx */
308164410Ssyrinxstatic void
309164410Ssyrinxbridge_top_change(struct bridge_if *bif)
310164410Ssyrinx{
311164410Ssyrinx	struct snmp_value bif_idx;
312164410Ssyrinx
313164410Ssyrinx	if (bridge_get_default() == bif)
314164410Ssyrinx		snmp_send_trap(&oid_TopologyChange,
315164410Ssyrinx		    (struct snmp_value *) NULL);
316164410Ssyrinx
317164410Ssyrinx	if (bridge_basename_var(bif, &bif_idx) == NULL)
318164410Ssyrinx		return;
319164410Ssyrinx
320164410Ssyrinx	snmp_send_trap(&oid_begemotNewRoot,
321164410Ssyrinx	    &bif_idx, (struct snmp_value *) NULL);
322164410Ssyrinx}
323164410Ssyrinx
324164410Ssyrinxstatic int
325164410Ssyrinxbridge_if_create(const char* b_name, int8_t up)
326164410Ssyrinx{
327164410Ssyrinx	if (bridge_create(b_name) < 0)
328164410Ssyrinx		return (-1);
329164410Ssyrinx
330164410Ssyrinx	if (up == 1 && (bridge_set_if_up(b_name, 1) < 0))
331164410Ssyrinx		return (-1);
332164410Ssyrinx
333164410Ssyrinx	/*
334164410Ssyrinx	 * Do not create a new bridge entry here -
335164410Ssyrinx	 * wait until the mibII module notifies us.
336164410Ssyrinx	 */
337164410Ssyrinx	return (0);
338164410Ssyrinx}
339164410Ssyrinx
340164410Ssyrinxstatic int
341164410Ssyrinxbridge_if_destroy(struct bridge_if *bif)
342164410Ssyrinx{
343164410Ssyrinx	if (bridge_destroy(bif->bif_name) < 0)
344164410Ssyrinx		return (-1);
345164410Ssyrinx
346164410Ssyrinx	bridge_remove_bif(bif);
347164410Ssyrinx
348164410Ssyrinx	return (0);
349164410Ssyrinx}
350164410Ssyrinx
351164410Ssyrinx/*
352164410Ssyrinx * Calculate the timeticks since the last topology change.
353164410Ssyrinx */
354164410Ssyrinxstatic int
355164410Ssyrinxbridge_get_time_since_tc(struct bridge_if *bif, uint32_t *ticks)
356164410Ssyrinx{
357164410Ssyrinx	struct timeval ct;
358164410Ssyrinx
359164410Ssyrinx	if (gettimeofday(&ct, NULL) < 0) {
360164410Ssyrinx		syslog(LOG_ERR, "bridge get time since last TC:"
361164410Ssyrinx		    "getttimeofday failed: %s", strerror(errno));
362164410Ssyrinx		return (-1);
363164410Ssyrinx	}
364164410Ssyrinx
365164410Ssyrinx	if (ct.tv_usec - bif->last_tc_time.tv_usec < 0) {
366164410Ssyrinx		ct.tv_sec -= 1;
367164410Ssyrinx		ct.tv_usec += 1000000;
368164410Ssyrinx	}
369164410Ssyrinx
370164410Ssyrinx	ct.tv_sec -= bif->last_tc_time.tv_sec;
371164410Ssyrinx	ct.tv_usec -= bif->last_tc_time.tv_usec;
372164410Ssyrinx
373164410Ssyrinx	*ticks = ct.tv_sec * 100 + ct.tv_usec/10000;
374164410Ssyrinx
375164410Ssyrinx	return (0);
376164410Ssyrinx}
377164410Ssyrinx
378164410Ssyrinx/*
379164410Ssyrinx * Update the info we have for a single bridge interface.
380164410Ssyrinx * Return:
381164410Ssyrinx * 1, if successful
382164410Ssyrinx * 0, if the interface was deleted
383228990Suqs * -1, error occurred while fetching the info from the kernel.
384164410Ssyrinx */
385164410Ssyrinxstatic int
386164410Ssyrinxbridge_update_bif(struct bridge_if *bif)
387164410Ssyrinx{
388164410Ssyrinx	struct mibif *ifp;
389164410Ssyrinx
390164410Ssyrinx	/* Walk through the mibII interface list. */
391164410Ssyrinx	for (ifp = mib_first_if(); ifp != NULL; ifp = mib_next_if(ifp))
392164410Ssyrinx		if (strcmp(ifp->name, bif->bif_name) == 0)
393164410Ssyrinx			break;
394164410Ssyrinx
395164410Ssyrinx	if (ifp == NULL) {
396164410Ssyrinx		/* Ops, we do not exist anymore. */
397164410Ssyrinx		bridge_remove_bif(bif);
398164410Ssyrinx		return (0);
399164410Ssyrinx	}
400164410Ssyrinx
401164410Ssyrinx	if (ifp->physaddr != NULL )
402164410Ssyrinx		bcopy(ifp->physaddr, bif->br_addr.octet, ETHER_ADDR_LEN);
403164410Ssyrinx	else
404165642Sbz		bridge_get_basemac(bif->bif_name, bif->br_addr.octet,
405165642Sbz		    ETHER_ADDR_LEN);
406164410Ssyrinx
407164410Ssyrinx	if (ifp->mib.ifmd_flags & IFF_RUNNING)
408164410Ssyrinx		bif->if_status = RowStatus_active;
409164410Ssyrinx	else
410164410Ssyrinx		bif->if_status = RowStatus_notInService;
411164410Ssyrinx
412164410Ssyrinx	switch (bridge_getinfo_bif(bif)) {
413164410Ssyrinx		case 2:
414164410Ssyrinx			bridge_new_root(bif);
415164410Ssyrinx			break;
416164410Ssyrinx		case 1:
417164410Ssyrinx			bridge_top_change(bif);
418164410Ssyrinx			break;
419164410Ssyrinx		case -1:
420164410Ssyrinx			bridge_remove_bif(bif);
421164410Ssyrinx			return (-1);
422164410Ssyrinx		default:
423164410Ssyrinx			break;
424164410Ssyrinx	}
425164410Ssyrinx
426164410Ssyrinx	/*
427164410Ssyrinx	 * The number of ports is accessible via SNMP -
428164410Ssyrinx	 * update the ports each time the bridge interface data
429164410Ssyrinx	 * is refreshed too.
430164410Ssyrinx	 */
431164410Ssyrinx	bif->num_ports = bridge_update_memif(bif);
432164410Ssyrinx	bif->entry_age = time(NULL);
433164410Ssyrinx
434164410Ssyrinx	return (1);
435164410Ssyrinx}
436164410Ssyrinx
437164410Ssyrinx/*
438310901Sngie * Update all bridge interfaces' ports only -
439164410Ssyrinx * make sure each bridge interface exists first.
440164410Ssyrinx */
441164410Ssyrinxvoid
442164410Ssyrinxbridge_update_all_ports(void)
443164410Ssyrinx{
444164410Ssyrinx	struct mibif *ifp;
445164410Ssyrinx	struct bridge_if *bif, *t_bif;
446164410Ssyrinx
447164410Ssyrinx	for (bif = bridge_first_bif(); bif != NULL; bif = t_bif) {
448164410Ssyrinx		t_bif = bridge_next_bif(bif);
449164410Ssyrinx
450164410Ssyrinx		for (ifp = mib_first_if(); ifp != NULL;
451164410Ssyrinx		    ifp = mib_next_if(ifp))
452164410Ssyrinx			if (strcmp(ifp->name, bif->bif_name) == 0)
453164410Ssyrinx				break;
454164410Ssyrinx
455164410Ssyrinx		if (ifp != NULL)
456164410Ssyrinx			bif->num_ports = bridge_update_memif(bif);
457164410Ssyrinx		else  /* Ops, we do not exist anymore. */
458164410Ssyrinx			bridge_remove_bif(bif);
459164410Ssyrinx	}
460164410Ssyrinx
461164410Ssyrinx	bridge_ports_update_listage();
462164410Ssyrinx}
463164410Ssyrinx
464164410Ssyrinx/*
465164410Ssyrinx * Update all addresses only.
466164410Ssyrinx */
467164410Ssyrinxvoid
468164410Ssyrinxbridge_update_all_addrs(void)
469164410Ssyrinx{
470164410Ssyrinx	struct mibif *ifp;
471164410Ssyrinx	struct bridge_if *bif, *t_bif;
472164410Ssyrinx
473164410Ssyrinx	for (bif = bridge_first_bif(); bif != NULL; bif = t_bif) {
474164410Ssyrinx		t_bif = bridge_next_bif(bif);
475164410Ssyrinx
476164410Ssyrinx		for (ifp = mib_first_if(); ifp != NULL;
477164410Ssyrinx		    ifp = mib_next_if(ifp))
478164410Ssyrinx			if (strcmp(ifp->name, bif->bif_name) == 0)
479164410Ssyrinx				break;
480164410Ssyrinx
481164410Ssyrinx		if (ifp != NULL)
482164410Ssyrinx			bif->num_addrs = bridge_update_addrs(bif);
483164410Ssyrinx		else  /* Ops, we don't exist anymore. */
484164410Ssyrinx			bridge_remove_bif(bif);
485164410Ssyrinx	}
486164410Ssyrinx
487164410Ssyrinx	bridge_addrs_update_listage();
488164410Ssyrinx}
489164410Ssyrinx
490164410Ssyrinx/*
491164410Ssyrinx * Update only the bridge interfaces' data - skip addresses.
492164410Ssyrinx */
493164410Ssyrinxvoid
494164410Ssyrinxbridge_update_all_ifs(void)
495164410Ssyrinx{
496164410Ssyrinx	struct bridge_if *bif, *t_bif;
497164410Ssyrinx
498164410Ssyrinx	for (bif = bridge_first_bif(); bif != NULL; bif = t_bif) {
499164410Ssyrinx		t_bif = bridge_next_bif(bif);
500164410Ssyrinx		bridge_update_bif(bif);
501164410Ssyrinx	}
502164410Ssyrinx
503164410Ssyrinx	bridge_ports_update_listage();
504164410Ssyrinx	bridge_list_age = time(NULL);
505164410Ssyrinx}
506164410Ssyrinx
507164410Ssyrinx/*
508164410Ssyrinx * Update all info we have for all bridges.
509164410Ssyrinx */
510164410Ssyrinxvoid
511164410Ssyrinxbridge_update_all(void *arg __unused)
512164410Ssyrinx{
513164410Ssyrinx	struct bridge_if *bif, *t_bif;
514164410Ssyrinx
515164410Ssyrinx	for (bif = bridge_first_bif(); bif != NULL; bif = t_bif) {
516164410Ssyrinx		t_bif = bridge_next_bif(bif);
517164410Ssyrinx		if (bridge_update_bif(bif) <= 0)
518164410Ssyrinx			continue;
519164410Ssyrinx
520164410Ssyrinx		/* Update our learnt addresses. */
521164410Ssyrinx		bif->num_addrs = bridge_update_addrs(bif);
522164410Ssyrinx	}
523164410Ssyrinx
524164410Ssyrinx	bridge_list_age = time(NULL);
525164410Ssyrinx	bridge_ports_update_listage();
526164410Ssyrinx	bridge_addrs_update_listage();
527164410Ssyrinx}
528164410Ssyrinx
529164410Ssyrinx/*
530164410Ssyrinx * Callback for polling our last topology change time -
531164410Ssyrinx * check whether we are root or whether a TC was detected once every
532164410Ssyrinx * 30 seconds, so that we can send the newRoot and TopologyChange traps
533164410Ssyrinx * on time. The rest of the data is polled only once every 5 min.
534164410Ssyrinx */
535164410Ssyrinxvoid
536164410Ssyrinxbridge_update_tc_time(void *arg __unused)
537164410Ssyrinx{
538164410Ssyrinx	struct bridge_if *bif;
539164410Ssyrinx	struct mibif *ifp;
540164410Ssyrinx
541164410Ssyrinx	TAILQ_FOREACH(bif, &bridge_ifs, b_if) {
542164410Ssyrinx		/* Walk through the mibII interface list. */
543164410Ssyrinx		for (ifp = mib_first_if(); ifp != NULL; ifp = mib_next_if(ifp))
544164410Ssyrinx			if (strcmp(ifp->name, bif->bif_name) == 0)
545164410Ssyrinx				break;
546164410Ssyrinx
547164410Ssyrinx		if (ifp == NULL) {
548164410Ssyrinx			bridge_remove_bif(bif);
549164410Ssyrinx			continue;
550164410Ssyrinx		}
551164410Ssyrinx
552164410Ssyrinx		switch (bridge_get_op_param(bif)) {
553164410Ssyrinx			case 2:
554164410Ssyrinx				bridge_new_root(bif);
555164410Ssyrinx				break;
556164410Ssyrinx			case 1:
557164410Ssyrinx				bridge_top_change(bif);
558164410Ssyrinx				break;
559164410Ssyrinx		}
560164410Ssyrinx	}
561164410Ssyrinx}
562164410Ssyrinx
563164410Ssyrinx/*
564164410Ssyrinx * Callback for handling new bridge interface creation.
565164410Ssyrinx */
566164410Ssyrinxint
567164410Ssyrinxbridge_attach_newif(struct mibif *ifp)
568164410Ssyrinx{
569165642Sbz	u_char mac[ETHER_ADDR_LEN];
570164410Ssyrinx	struct bridge_if *bif;
571164410Ssyrinx
572164410Ssyrinx	if (ifp->mib.ifmd_data.ifi_type != IFT_BRIDGE)
573164410Ssyrinx		return (0);
574164410Ssyrinx
575164410Ssyrinx	/* Make sure it does not exist in our list. */
576164410Ssyrinx	TAILQ_FOREACH(bif, &bridge_ifs, b_if)
577164410Ssyrinx		if(strcmp(bif->bif_name, ifp->name) == 0) {
578164410Ssyrinx			syslog(LOG_ERR, "bridge interface %s already "
579164410Ssyrinx			    "in list", bif->bif_name);
580164410Ssyrinx			return (-1);
581164410Ssyrinx		}
582164410Ssyrinx
583165642Sbz	if (ifp->physaddr == NULL) {
584165642Sbz		if (bridge_get_basemac(ifp->name, mac, sizeof(mac)) == NULL) {
585165642Sbz			syslog(LOG_ERR, "bridge attach new %s failed - "
586165642Sbz			    "no bridge mac address", ifp->name);
587165642Sbz			return (-1);
588165642Sbz		}
589165642Sbz	} else
590165642Sbz		bcopy(ifp->physaddr, &mac, sizeof(mac));
591164410Ssyrinx
592165642Sbz	if ((bif = bridge_new_bif(ifp->name, ifp->sysindex, mac)) == NULL)
593164410Ssyrinx		return (-1);
594164410Ssyrinx
595164410Ssyrinx	if (ifp->mib.ifmd_flags & IFF_RUNNING)
596164410Ssyrinx		bif->if_status = RowStatus_active;
597164410Ssyrinx	else
598164410Ssyrinx		bif->if_status = RowStatus_notInService;
599164410Ssyrinx
600164410Ssyrinx	/* Skip sending notifications if the interface was just created. */
601164410Ssyrinx	if (bridge_getinfo_bif(bif) < 0 ||
602164410Ssyrinx	    (bif->num_ports = bridge_getinfo_bif_ports(bif)) < 0 ||
603164410Ssyrinx	    (bif->num_addrs = bridge_getinfo_bif_addrs(bif)) < 0) {
604164410Ssyrinx		bridge_remove_bif(bif);
605164410Ssyrinx		return (-1);
606164410Ssyrinx	}
607164410Ssyrinx
608164410Ssyrinx	/* Check whether we are the default bridge interface. */
609164410Ssyrinx	if (strcmp(ifp->name, bridge_get_default_name()) == 0)
610164410Ssyrinx		bridge_set_default(bif);
611164410Ssyrinx
612164410Ssyrinx	return (0);
613164410Ssyrinx}
614164410Ssyrinx
615164410Ssyrinxvoid
616164410Ssyrinxbridge_ifs_dump(void)
617164410Ssyrinx{
618164410Ssyrinx	struct bridge_if *bif;
619164410Ssyrinx
620164410Ssyrinx	for (bif = bridge_first_bif(); bif != NULL;
621164410Ssyrinx		bif = bridge_next_bif(bif)) {
622164410Ssyrinx		syslog(LOG_ERR, "Bridge %s, index - %d", bif->bif_name,
623164410Ssyrinx		    bif->sysindex);
624164410Ssyrinx		bridge_ports_dump(bif);
625164410Ssyrinx		bridge_addrs_dump(bif);
626164410Ssyrinx	}
627164410Ssyrinx}
628164410Ssyrinx
629164410Ssyrinx/*
630164410Ssyrinx * RFC4188 specifics.
631164410Ssyrinx */
632164410Ssyrinxint
633164410Ssyrinxop_dot1d_base(struct snmp_context *ctx __unused, struct snmp_value *value,
634164410Ssyrinx	uint sub, uint iidx __unused, enum snmp_op op)
635164410Ssyrinx{
636164410Ssyrinx	struct bridge_if *bif;
637164410Ssyrinx
638164410Ssyrinx	if ((bif = bridge_get_default()) == NULL)
639164410Ssyrinx		return (SNMP_ERR_NOSUCHNAME);
640164410Ssyrinx
641164410Ssyrinx	if (time(NULL) - bif->entry_age > bridge_get_data_maxage() &&
642164410Ssyrinx	    bridge_update_bif(bif) <= 0) /* It was just deleted. */
643164410Ssyrinx		return (SNMP_ERR_NOSUCHNAME);
644164410Ssyrinx
645164410Ssyrinx	switch (op) {
646164410Ssyrinx	    case SNMP_OP_GET:
647164410Ssyrinx		switch (value->var.subs[sub - 1]) {
648164410Ssyrinx		    case LEAF_dot1dBaseBridgeAddress:
649165253Ssyrinx			return (string_get(value, bif->br_addr.octet,
650165253Ssyrinx			    ETHER_ADDR_LEN));
651164410Ssyrinx		    case LEAF_dot1dBaseNumPorts:
652164410Ssyrinx			value->v.integer = bif->num_ports;
653165253Ssyrinx			return (SNMP_ERR_NOERROR);
654164410Ssyrinx		    case LEAF_dot1dBaseType:
655164410Ssyrinx			value->v.integer = bif->br_type;
656165253Ssyrinx			return (SNMP_ERR_NOERROR);
657164410Ssyrinx		}
658165253Ssyrinx		abort();
659164410Ssyrinx
660164410Ssyrinx		case SNMP_OP_SET:
661165253Ssyrinx		    return (SNMP_ERR_NOT_WRITEABLE);
662164410Ssyrinx
663164410Ssyrinx		case SNMP_OP_GETNEXT:
664164410Ssyrinx		case SNMP_OP_ROLLBACK:
665164410Ssyrinx		case SNMP_OP_COMMIT:
666165253Ssyrinx		   break;
667164410Ssyrinx	}
668164410Ssyrinx
669165253Ssyrinx	abort();
670164410Ssyrinx}
671164410Ssyrinx
672164410Ssyrinxint
673165253Ssyrinxop_dot1d_stp(struct snmp_context *ctx, struct snmp_value *val, uint sub,
674165253Ssyrinx    uint iidx __unused, enum snmp_op op)
675164410Ssyrinx{
676164410Ssyrinx	struct bridge_if *bif;
677164410Ssyrinx
678164410Ssyrinx	if ((bif = bridge_get_default()) == NULL)
679164410Ssyrinx		return (SNMP_ERR_NOSUCHNAME);
680164410Ssyrinx
681164410Ssyrinx	if (time(NULL) - bif->entry_age > bridge_get_data_maxage() &&
682164410Ssyrinx	    bridge_update_bif(bif) <= 0) /* It was just deleted. */
683164410Ssyrinx		return (SNMP_ERR_NOSUCHNAME);
684164410Ssyrinx
685164410Ssyrinx	switch (op) {
686164410Ssyrinx	    case SNMP_OP_GET:
687165253Ssyrinx		switch (val->var.subs[sub - 1]) {
688164410Ssyrinx		    case LEAF_dot1dStpProtocolSpecification:
689165253Ssyrinx			val->v.integer = bif->prot_spec;
690165253Ssyrinx			return (SNMP_ERR_NOERROR);
691164410Ssyrinx
692164410Ssyrinx		    case LEAF_dot1dStpPriority:
693165253Ssyrinx			val->v.integer = bif->priority;
694165253Ssyrinx			return (SNMP_ERR_NOERROR);
695164410Ssyrinx
696164410Ssyrinx		    case LEAF_dot1dStpTimeSinceTopologyChange:
697164410Ssyrinx			if (bridge_get_time_since_tc(bif,
698165253Ssyrinx			    &(val->v.uint32)) < 0)
699164410Ssyrinx				return (SNMP_ERR_GENERR);
700165253Ssyrinx			return (SNMP_ERR_NOERROR);
701164410Ssyrinx
702164410Ssyrinx		    case LEAF_dot1dStpTopChanges:
703165253Ssyrinx			val->v.uint32 = bif->top_changes;
704165253Ssyrinx			return (SNMP_ERR_NOERROR);
705164410Ssyrinx
706164410Ssyrinx		    case LEAF_dot1dStpDesignatedRoot:
707165253Ssyrinx			return (string_get(val, bif->design_root,
708164410Ssyrinx			    SNMP_BRIDGE_ID_LEN));
709164410Ssyrinx
710164410Ssyrinx		    case LEAF_dot1dStpRootCost:
711165253Ssyrinx			val->v.integer = bif->root_cost;
712165253Ssyrinx			return (SNMP_ERR_NOERROR);
713164410Ssyrinx
714164410Ssyrinx		    case LEAF_dot1dStpRootPort:
715165253Ssyrinx			val->v.integer = bif->root_port;
716165253Ssyrinx			return (SNMP_ERR_NOERROR);
717164410Ssyrinx
718164410Ssyrinx		    case LEAF_dot1dStpMaxAge:
719165253Ssyrinx			val->v.integer = bif->max_age;
720165253Ssyrinx			return (SNMP_ERR_NOERROR);
721164410Ssyrinx
722164410Ssyrinx		    case LEAF_dot1dStpHelloTime:
723165253Ssyrinx			val->v.integer = bif->hello_time;
724165253Ssyrinx			return (SNMP_ERR_NOERROR);
725164410Ssyrinx
726164410Ssyrinx		    case LEAF_dot1dStpHoldTime:
727165253Ssyrinx			val->v.integer = bif->hold_time;
728165253Ssyrinx			return (SNMP_ERR_NOERROR);
729164410Ssyrinx
730164410Ssyrinx		    case LEAF_dot1dStpForwardDelay:
731165253Ssyrinx			val->v.integer = bif->fwd_delay;
732165253Ssyrinx			return (SNMP_ERR_NOERROR);
733164410Ssyrinx
734164410Ssyrinx		    case LEAF_dot1dStpBridgeMaxAge:
735165253Ssyrinx			val->v.integer = bif->bridge_max_age;
736165253Ssyrinx			return (SNMP_ERR_NOERROR);
737164410Ssyrinx
738164410Ssyrinx		    case LEAF_dot1dStpBridgeHelloTime:
739165253Ssyrinx			val->v.integer = bif->bridge_hello_time;
740165253Ssyrinx			return (SNMP_ERR_NOERROR);
741164410Ssyrinx
742164410Ssyrinx		    case LEAF_dot1dStpBridgeForwardDelay:
743165253Ssyrinx			val->v.integer = bif->bridge_fwd_delay;
744165253Ssyrinx			return (SNMP_ERR_NOERROR);
745165253Ssyrinx
746164997Ssyrinx		    case LEAF_dot1dStpVersion:
747165253Ssyrinx			val->v.integer = bif->stp_version;
748165253Ssyrinx			return (SNMP_ERR_NOERROR);
749165253Ssyrinx
750164997Ssyrinx		    case LEAF_dot1dStpTxHoldCount:
751165253Ssyrinx			val->v.integer = bif->tx_hold_count;
752165253Ssyrinx			return (SNMP_ERR_NOERROR);
753164410Ssyrinx		}
754165253Ssyrinx		abort();
755164410Ssyrinx
756164410Ssyrinx	    case SNMP_OP_GETNEXT:
757164410Ssyrinx		abort();
758164410Ssyrinx
759164410Ssyrinx	    case SNMP_OP_SET:
760165253Ssyrinx		switch (val->var.subs[sub - 1]) {
761164410Ssyrinx		    case LEAF_dot1dStpPriority:
762165253Ssyrinx			if (val->v.integer > SNMP_BRIDGE_MAX_PRIORITY ||
763165253Ssyrinx			    val->v.integer % 4096 != 0)
764165253Ssyrinx			    return (SNMP_ERR_WRONG_VALUE);
765165253Ssyrinx
766164410Ssyrinx			ctx->scratch->int1 = bif->priority;
767165253Ssyrinx			if (bridge_set_priority(bif, val->v.integer) < 0)
768165253Ssyrinx			    return (SNMP_ERR_GENERR);
769165253Ssyrinx			return (SNMP_ERR_NOERROR);
770164410Ssyrinx
771164410Ssyrinx		    case LEAF_dot1dStpBridgeMaxAge:
772165253Ssyrinx			if (val->v.integer < SNMP_BRIDGE_MIN_MAGE ||
773165253Ssyrinx			    val->v.integer > SNMP_BRIDGE_MAX_MAGE)
774165253Ssyrinx			    return (SNMP_ERR_WRONG_VALUE);
775165253Ssyrinx
776164410Ssyrinx			ctx->scratch->int1 = bif->bridge_max_age;
777165253Ssyrinx			if (bridge_set_maxage(bif, val->v.integer) < 0)
778165253Ssyrinx			    return (SNMP_ERR_GENERR);
779165253Ssyrinx			return (SNMP_ERR_NOERROR);
780164410Ssyrinx
781164410Ssyrinx		    case LEAF_dot1dStpBridgeHelloTime:
782165253Ssyrinx			if (val->v.integer < SNMP_BRIDGE_MIN_HTIME ||
783165253Ssyrinx			    val->v.integer > SNMP_BRIDGE_MAX_HTIME)
784165253Ssyrinx			    return (SNMP_ERR_WRONG_VALUE);
785165253Ssyrinx
786164410Ssyrinx			ctx->scratch->int1 = bif->bridge_hello_time;
787165253Ssyrinx			if (bridge_set_hello_time(bif, val->v.integer) < 0)
788165253Ssyrinx			    return (SNMP_ERR_GENERR);
789165253Ssyrinx			return (SNMP_ERR_NOERROR);
790164410Ssyrinx
791164410Ssyrinx		    case LEAF_dot1dStpBridgeForwardDelay:
792165253Ssyrinx			if (val->v.integer < SNMP_BRIDGE_MIN_FDELAY ||
793165253Ssyrinx			    val->v.integer > SNMP_BRIDGE_MAX_FDELAY)
794165253Ssyrinx			    return (SNMP_ERR_WRONG_VALUE);
795165253Ssyrinx
796164410Ssyrinx			ctx->scratch->int1 = bif->bridge_fwd_delay;
797165253Ssyrinx			if (bridge_set_forward_delay(bif, val->v.integer) < 0)
798165253Ssyrinx			    return (SNMP_ERR_GENERR);
799165253Ssyrinx			return (SNMP_ERR_NOERROR);
800164410Ssyrinx
801164997Ssyrinx		    case LEAF_dot1dStpVersion:
802165253Ssyrinx			if (val->v.integer != dot1dStpVersion_stpCompatible &&
803165253Ssyrinx			    val->v.integer != dot1dStpVersion_rstp)
804165253Ssyrinx			    return (SNMP_ERR_WRONG_VALUE);
805165253Ssyrinx
806164997Ssyrinx			ctx->scratch->int1 = bif->stp_version;
807165253Ssyrinx			if (bridge_set_stp_version(bif, val->v.integer) < 0)
808165253Ssyrinx			    return (SNMP_ERR_GENERR);
809165253Ssyrinx			return (SNMP_ERR_NOERROR);
810164997Ssyrinx
811164997Ssyrinx		    case LEAF_dot1dStpTxHoldCount:
812165253Ssyrinx			if (val->v.integer < SNMP_BRIDGE_MIN_TXHC ||
813165253Ssyrinx			    val->v.integer > SNMP_BRIDGE_MAX_TXHC)
814165253Ssyrinx			    return (SNMP_ERR_WRONG_VALUE);
815165253Ssyrinx
816164997Ssyrinx			ctx->scratch->int1 = bif->tx_hold_count;
817165253Ssyrinx			if (bridge_set_tx_hold_count(bif, val->v.integer) < 0)
818165253Ssyrinx			    return (SNMP_ERR_GENERR);
819165253Ssyrinx			return (SNMP_ERR_NOERROR);
820164997Ssyrinx
821164410Ssyrinx		    case LEAF_dot1dStpProtocolSpecification:
822164410Ssyrinx		    case LEAF_dot1dStpTimeSinceTopologyChange:
823164410Ssyrinx		    case LEAF_dot1dStpTopChanges:
824164410Ssyrinx		    case LEAF_dot1dStpDesignatedRoot:
825164410Ssyrinx		    case LEAF_dot1dStpRootCost:
826164410Ssyrinx		    case LEAF_dot1dStpRootPort:
827164410Ssyrinx		    case LEAF_dot1dStpMaxAge:
828164410Ssyrinx		    case LEAF_dot1dStpHelloTime:
829164410Ssyrinx		    case LEAF_dot1dStpHoldTime:
830164410Ssyrinx		    case LEAF_dot1dStpForwardDelay:
831164410Ssyrinx			return (SNMP_ERR_NOT_WRITEABLE);
832164410Ssyrinx		}
833165253Ssyrinx		abort();
834164410Ssyrinx
835164410Ssyrinx	    case SNMP_OP_ROLLBACK:
836165253Ssyrinx		switch (val->var.subs[sub - 1]) {
837164410Ssyrinx		    case LEAF_dot1dStpPriority:
838164997Ssyrinx			bridge_set_priority(bif, ctx->scratch->int1);
839164410Ssyrinx			break;
840164410Ssyrinx		    case LEAF_dot1dStpBridgeMaxAge:
841164997Ssyrinx			bridge_set_maxage(bif, ctx->scratch->int1);
842164410Ssyrinx			break;
843164410Ssyrinx		    case LEAF_dot1dStpBridgeHelloTime:
844164997Ssyrinx			bridge_set_hello_time(bif, ctx->scratch->int1);
845164410Ssyrinx			break;
846164410Ssyrinx		    case LEAF_dot1dStpBridgeForwardDelay:
847164997Ssyrinx			bridge_set_forward_delay(bif, ctx->scratch->int1);
848164410Ssyrinx			break;
849164997Ssyrinx		    case LEAF_dot1dStpVersion:
850164997Ssyrinx			bridge_set_stp_version(bif, ctx->scratch->int1);
851164997Ssyrinx			break;
852164997Ssyrinx		    case LEAF_dot1dStpTxHoldCount:
853164997Ssyrinx			bridge_set_tx_hold_count(bif, ctx->scratch->int1);
854164997Ssyrinx			break;
855164410Ssyrinx		}
856164410Ssyrinx		return (SNMP_ERR_NOERROR);
857164410Ssyrinx
858164410Ssyrinx	    case SNMP_OP_COMMIT:
859164410Ssyrinx		return (SNMP_ERR_NOERROR);
860164410Ssyrinx	}
861164410Ssyrinx
862165253Ssyrinx	abort();
863164410Ssyrinx}
864164410Ssyrinx
865164410Ssyrinxint
866164410Ssyrinxop_dot1d_tp(struct snmp_context *ctx, struct snmp_value *value,
867164410Ssyrinx	uint sub, uint iidx __unused, enum snmp_op op)
868164410Ssyrinx{
869164410Ssyrinx	struct bridge_if *bif;
870164410Ssyrinx
871164410Ssyrinx	if ((bif = bridge_get_default()) == NULL)
872164410Ssyrinx		return (SNMP_ERR_NOSUCHNAME);
873164410Ssyrinx
874164410Ssyrinx	if (time(NULL) - bif->entry_age > bridge_get_data_maxage() &&
875164410Ssyrinx	    bridge_update_bif(bif) <= 0) /* It was just deleted. */
876164410Ssyrinx		return (SNMP_ERR_NOSUCHNAME);
877164410Ssyrinx
878164410Ssyrinx	switch (op) {
879164410Ssyrinx	    case SNMP_OP_GET:
880164410Ssyrinx		switch (value->var.subs[sub - 1]) {
881164410Ssyrinx		    case LEAF_dot1dTpLearnedEntryDiscards:
882164410Ssyrinx			value->v.uint32 = bif->lrnt_drops;
883165253Ssyrinx			return (SNMP_ERR_NOERROR);
884164410Ssyrinx		    case LEAF_dot1dTpAgingTime:
885164410Ssyrinx			value->v.integer = bif->age_time;
886165253Ssyrinx			return (SNMP_ERR_NOERROR);
887164410Ssyrinx		}
888165253Ssyrinx		abort();
889164410Ssyrinx
890164410Ssyrinx	    case SNMP_OP_GETNEXT:
891164410Ssyrinx		abort();
892164410Ssyrinx
893164410Ssyrinx	    case SNMP_OP_SET:
894165253Ssyrinx		switch (value->var.subs[sub - 1]) {
895165253Ssyrinx		    case LEAF_dot1dTpLearnedEntryDiscards:
896165253Ssyrinx			return (SNMP_ERR_NOT_WRITEABLE);
897165253Ssyrinx
898165253Ssyrinx		    case LEAF_dot1dTpAgingTime:
899165253Ssyrinx			if (value->v.integer < SNMP_BRIDGE_MIN_AGE_TIME ||
900165253Ssyrinx			    value->v.integer > SNMP_BRIDGE_MAX_AGE_TIME)
901165253Ssyrinx			    return (SNMP_ERR_WRONG_VALUE);
902165253Ssyrinx
903165253Ssyrinx			ctx->scratch->int1 = bif->age_time;
904165253Ssyrinx			if (bridge_set_aging_time(bif, value->v.integer) < 0)
905165253Ssyrinx			    return (SNMP_ERR_GENERR);
906165253Ssyrinx			return (SNMP_ERR_NOERROR);
907164410Ssyrinx		}
908165253Ssyrinx		abort();
909164410Ssyrinx
910164410Ssyrinx	    case SNMP_OP_ROLLBACK:
911164410Ssyrinx		if (value->var.subs[sub - 1] == LEAF_dot1dTpAgingTime)
912164997Ssyrinx		    bridge_set_aging_time(bif, ctx->scratch->int1);
913164410Ssyrinx		return (SNMP_ERR_NOERROR);
914164410Ssyrinx
915164410Ssyrinx	    case SNMP_OP_COMMIT:
916164410Ssyrinx		return (SNMP_ERR_NOERROR);
917164410Ssyrinx	}
918164410Ssyrinx
919165253Ssyrinx	abort();
920164410Ssyrinx}
921164410Ssyrinx
922164410Ssyrinx/*
923164410Ssyrinx * Private BEGEMOT-BRIDGE-MIB specifics.
924164410Ssyrinx */
925164410Ssyrinx
926164410Ssyrinx/*
927164410Ssyrinx * Get the bridge name from an OID index.
928164410Ssyrinx */
929164410Ssyrinxstatic char *
930164410Ssyrinxbridge_name_index_get(const struct asn_oid *oid, uint sub, char *b_name)
931164410Ssyrinx{
932164410Ssyrinx	uint i;
933164410Ssyrinx
934164410Ssyrinx	if (oid->len - sub != oid->subs[sub] + 1 || oid->subs[sub] >= IFNAMSIZ)
935164410Ssyrinx		return (NULL);
936164410Ssyrinx
937164410Ssyrinx	for (i = 0; i < oid->subs[sub]; i++)
938164410Ssyrinx		b_name[i] = oid->subs[sub + i + 1];
939164410Ssyrinx	b_name[i] = '\0';
940164410Ssyrinx
941164410Ssyrinx	return (b_name);
942164410Ssyrinx}
943164410Ssyrinx
944164410Ssyrinxstatic void
945164410Ssyrinxbridge_if_index_append(struct asn_oid *oid, uint sub,
946164410Ssyrinx	const struct bridge_if *bif)
947164410Ssyrinx{
948164410Ssyrinx	uint i;
949164410Ssyrinx
950164410Ssyrinx	oid->len = sub + strlen(bif->bif_name) + 1;
951164410Ssyrinx	oid->subs[sub] = strlen(bif->bif_name);
952164410Ssyrinx
953164410Ssyrinx	for (i = 1; i <= strlen(bif->bif_name); i++)
954164410Ssyrinx		oid->subs[sub + i] = bif->bif_name[i - 1];
955164410Ssyrinx}
956164410Ssyrinx
957164410Ssyrinxstatic struct bridge_if *
958164410Ssyrinxbridge_if_index_get(const struct asn_oid *oid, uint sub)
959164410Ssyrinx{
960164410Ssyrinx	uint i;
961164410Ssyrinx	char bif_name[IFNAMSIZ];
962164410Ssyrinx
963164410Ssyrinx	if (oid->len - sub != oid->subs[sub] + 1 || oid->subs[sub] >= IFNAMSIZ)
964164410Ssyrinx		return (NULL);
965164410Ssyrinx
966164410Ssyrinx	for (i = 0; i < oid->subs[sub]; i++)
967164410Ssyrinx		bif_name[i] = oid->subs[sub + i + 1];
968164410Ssyrinx	bif_name[i] = '\0';
969164410Ssyrinx
970164410Ssyrinx	return (bridge_if_find_ifname(bif_name));
971164410Ssyrinx}
972164410Ssyrinx
973164410Ssyrinxstatic struct bridge_if *
974164410Ssyrinxbridge_if_index_getnext(const struct asn_oid *oid, uint sub)
975164410Ssyrinx{
976164410Ssyrinx	uint i;
977164410Ssyrinx	char bif_name[IFNAMSIZ];
978164410Ssyrinx	struct bridge_if *bif;
979164410Ssyrinx
980164410Ssyrinx	if (oid->len - sub == 0)
981164410Ssyrinx		return (bridge_first_bif());
982164410Ssyrinx
983164410Ssyrinx	if (oid->len - sub != oid->subs[sub] + 1 || oid->subs[sub] >= IFNAMSIZ)
984164410Ssyrinx		return (NULL);
985164410Ssyrinx
986164410Ssyrinx	for (i = 0; i < oid->subs[sub]; i++)
987164410Ssyrinx		bif_name[i] = oid->subs[sub + i + 1];
988164410Ssyrinx	bif_name[i] = '\0';
989164410Ssyrinx
990164410Ssyrinx	if ((bif = bridge_if_find_ifname(bif_name)) == NULL)
991164410Ssyrinx		return (NULL);
992164410Ssyrinx
993164410Ssyrinx	return (bridge_next_bif(bif));
994164410Ssyrinx}
995164410Ssyrinx
996164410Ssyrinxstatic int
997164410Ssyrinxbridge_set_if_status(struct snmp_context *ctx,
998164410Ssyrinx	struct snmp_value *val, uint sub)
999164410Ssyrinx{
1000164410Ssyrinx	struct bridge_if *bif;
1001164410Ssyrinx	char bif_name[IFNAMSIZ];
1002164410Ssyrinx
1003164410Ssyrinx	bif = bridge_if_index_get(&val->var, sub);
1004164410Ssyrinx
1005164410Ssyrinx	switch (val->v.integer) {
1006164410Ssyrinx	    case RowStatus_active:
1007164410Ssyrinx		if (bif == NULL)
1008164410Ssyrinx		    return (SNMP_ERR_INCONS_VALUE);
1009164410Ssyrinx
1010164410Ssyrinx		ctx->scratch->int1 = bif->if_status;
1011164410Ssyrinx
1012164410Ssyrinx		switch (bif->if_status) {
1013164410Ssyrinx		    case RowStatus_active:
1014164410Ssyrinx			return (SNMP_ERR_NOERROR);
1015164410Ssyrinx		    case RowStatus_notInService:
1016164410Ssyrinx			if (bridge_set_if_up(bif->bif_name, 1) < 0)
1017164410Ssyrinx			    return (SNMP_ERR_GENERR);
1018164410Ssyrinx			return (SNMP_ERR_NOERROR);
1019164410Ssyrinx		    default:
1020164410Ssyrinx			break;
1021164410Ssyrinx		}
1022164410Ssyrinx		return (SNMP_ERR_INCONS_VALUE);
1023164410Ssyrinx
1024164410Ssyrinx	    case RowStatus_notInService:
1025164410Ssyrinx		if (bif == NULL)
1026164410Ssyrinx		    return (SNMP_ERR_INCONS_VALUE);
1027164410Ssyrinx
1028164410Ssyrinx		ctx->scratch->int1 = bif->if_status;
1029164410Ssyrinx
1030164410Ssyrinx		switch (bif->if_status) {
1031164410Ssyrinx		    case RowStatus_active:
1032164410Ssyrinx			if (bridge_set_if_up(bif->bif_name, 1) < 0)
1033164410Ssyrinx			    return (SNMP_ERR_GENERR);
1034164410Ssyrinx			return (SNMP_ERR_NOERROR);
1035164410Ssyrinx		    case RowStatus_notInService:
1036164410Ssyrinx			return (SNMP_ERR_NOERROR);
1037164410Ssyrinx		    default:
1038164410Ssyrinx			break;
1039164410Ssyrinx		}
1040164410Ssyrinx		return (SNMP_ERR_INCONS_VALUE);
1041164410Ssyrinx
1042164410Ssyrinx	    case RowStatus_notReady:
1043164410Ssyrinx		return (SNMP_ERR_INCONS_VALUE);
1044164410Ssyrinx
1045164410Ssyrinx	    case RowStatus_createAndGo:
1046164410Ssyrinx		if (bif != NULL)
1047164410Ssyrinx		    return (SNMP_ERR_INCONS_VALUE);
1048164410Ssyrinx
1049164410Ssyrinx		ctx->scratch->int1 = RowStatus_destroy;
1050164410Ssyrinx
1051164410Ssyrinx		if (bridge_name_index_get(&val->var, sub, bif_name) == NULL)
1052164410Ssyrinx		    return (SNMP_ERR_BADVALUE);
1053164410Ssyrinx		if (bridge_if_create(bif_name, 1) < 0)
1054164410Ssyrinx		    return (SNMP_ERR_GENERR);
1055164410Ssyrinx		return (SNMP_ERR_NOERROR);
1056164410Ssyrinx
1057164410Ssyrinx	    case RowStatus_createAndWait:
1058164410Ssyrinx		if (bif != NULL)
1059164410Ssyrinx		    return (SNMP_ERR_INCONS_VALUE);
1060164410Ssyrinx
1061164410Ssyrinx		if (bridge_name_index_get(&val->var, sub, bif_name) == NULL)
1062164410Ssyrinx		    return (SNMP_ERR_BADVALUE);
1063164410Ssyrinx
1064164410Ssyrinx		ctx->scratch->int1 = RowStatus_destroy;
1065164410Ssyrinx
1066164410Ssyrinx		if (bridge_if_create(bif_name, 0) < 0)
1067164410Ssyrinx		    return (SNMP_ERR_GENERR);
1068164410Ssyrinx		return (SNMP_ERR_NOERROR);
1069164410Ssyrinx
1070164410Ssyrinx	    case RowStatus_destroy:
1071164410Ssyrinx		if (bif == NULL)
1072164410Ssyrinx		    return (SNMP_ERR_NOSUCHNAME);
1073164410Ssyrinx
1074164410Ssyrinx		ctx->scratch->int1 = bif->if_status;
1075164410Ssyrinx		bif->if_status = RowStatus_destroy;
1076164410Ssyrinx	}
1077164410Ssyrinx
1078164410Ssyrinx	return (SNMP_ERR_NOERROR);
1079164410Ssyrinx}
1080164410Ssyrinx
1081164410Ssyrinxstatic int
1082164410Ssyrinxbridge_rollback_if_status(struct snmp_context *ctx,
1083164410Ssyrinx	struct snmp_value *val, uint sub)
1084164410Ssyrinx{
1085164410Ssyrinx	struct bridge_if *bif;
1086164410Ssyrinx
1087164410Ssyrinx	if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1088164410Ssyrinx		return (SNMP_ERR_GENERR);
1089164410Ssyrinx
1090164410Ssyrinx	switch (ctx->scratch->int1) {
1091164410Ssyrinx		case RowStatus_destroy:
1092164410Ssyrinx			bridge_if_destroy(bif);
1093164410Ssyrinx			return (SNMP_ERR_NOERROR);
1094164410Ssyrinx
1095164410Ssyrinx		case RowStatus_notInService:
1096164410Ssyrinx			if (bif->if_status != ctx->scratch->int1)
1097164410Ssyrinx				bridge_set_if_up(bif->bif_name, 0);
1098164410Ssyrinx			bif->if_status = RowStatus_notInService;
1099164410Ssyrinx			return (SNMP_ERR_NOERROR);
1100164410Ssyrinx
1101164410Ssyrinx		case RowStatus_active:
1102164410Ssyrinx			if (bif->if_status != ctx->scratch->int1)
1103164410Ssyrinx				bridge_set_if_up(bif->bif_name, 1);
1104164410Ssyrinx			bif->if_status = RowStatus_active;
1105164410Ssyrinx			return (SNMP_ERR_NOERROR);
1106164410Ssyrinx	}
1107164410Ssyrinx
1108164410Ssyrinx	abort();
1109164410Ssyrinx}
1110164410Ssyrinx
1111164410Ssyrinxstatic int
1112164410Ssyrinxbridge_commit_if_status(struct snmp_value *val, uint sub)
1113164410Ssyrinx{
1114164410Ssyrinx	struct bridge_if *bif;
1115164410Ssyrinx
1116164410Ssyrinx	if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1117164410Ssyrinx		return (SNMP_ERR_GENERR);
1118164410Ssyrinx
1119164410Ssyrinx	if (bif->if_status == RowStatus_destroy &&
1120164410Ssyrinx	    bridge_if_destroy(bif) < 0)
1121164410Ssyrinx		return (SNMP_ERR_COMMIT_FAILED);
1122164410Ssyrinx
1123164410Ssyrinx	return (SNMP_ERR_NOERROR);
1124164410Ssyrinx}
1125164410Ssyrinx
1126164410Ssyrinxint
1127164410Ssyrinxop_begemot_base_bridge(struct snmp_context *ctx, struct snmp_value *val,
1128164410Ssyrinx	uint sub, uint iidx __unused, enum snmp_op op)
1129164410Ssyrinx{
1130165046Ssyrinx	struct bridge_if *bif;
1131164410Ssyrinx
1132164410Ssyrinx	if (time(NULL) - bridge_list_age > bridge_get_data_maxage())
1133164410Ssyrinx		bridge_update_all_ifs();
1134164410Ssyrinx
1135164410Ssyrinx	switch (op) {
1136164410Ssyrinx	    case SNMP_OP_GET:
1137164410Ssyrinx		if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1138164410Ssyrinx		    return (SNMP_ERR_NOSUCHNAME);
1139165253Ssyrinx		goto get;
1140164410Ssyrinx
1141164410Ssyrinx	    case SNMP_OP_GETNEXT:
1142164410Ssyrinx		if ((bif = bridge_if_index_getnext(&val->var, sub)) == NULL)
1143164410Ssyrinx		    return (SNMP_ERR_NOSUCHNAME);
1144164410Ssyrinx		bridge_if_index_append(&val->var, sub, bif);
1145165253Ssyrinx		goto get;
1146164410Ssyrinx
1147164410Ssyrinx	    case SNMP_OP_SET:
1148164410Ssyrinx		switch (val->var.subs[sub - 1]) {
1149164410Ssyrinx		    case LEAF_begemotBridgeBaseStatus:
1150164410Ssyrinx			return (bridge_set_if_status(ctx, val, sub));
1151164410Ssyrinx		    case LEAF_begemotBridgeBaseName:
1152164410Ssyrinx		    case LEAF_begemotBridgeBaseAddress:
1153164410Ssyrinx		    case LEAF_begemotBridgeBaseNumPorts:
1154164410Ssyrinx		    case LEAF_begemotBridgeBaseType:
1155164410Ssyrinx			return (SNMP_ERR_NOT_WRITEABLE);
1156164410Ssyrinx		}
1157164410Ssyrinx		abort();
1158164410Ssyrinx
1159164410Ssyrinx	    case SNMP_OP_ROLLBACK:
1160164410Ssyrinx		return (bridge_rollback_if_status(ctx, val, sub));
1161165046Ssyrinx
1162164410Ssyrinx	    case SNMP_OP_COMMIT:
1163164410Ssyrinx		return (bridge_commit_if_status(val, sub));
1164164410Ssyrinx	}
1165165253Ssyrinx	abort();
1166164410Ssyrinx
1167165253Ssyrinxget:
1168164410Ssyrinx	switch (val->var.subs[sub - 1]) {
1169164410Ssyrinx	    case LEAF_begemotBridgeBaseName:
1170165253Ssyrinx		return (string_get(val, bif->bif_name, -1));
1171164410Ssyrinx
1172164410Ssyrinx	    case LEAF_begemotBridgeBaseAddress:
1173165253Ssyrinx		return (string_get(val, bif->br_addr.octet, ETHER_ADDR_LEN));
1174164410Ssyrinx
1175164410Ssyrinx	    case LEAF_begemotBridgeBaseNumPorts:
1176164410Ssyrinx		val->v.integer = bif->num_ports;
1177165253Ssyrinx		return (SNMP_ERR_NOERROR);
1178164410Ssyrinx
1179164410Ssyrinx	    case LEAF_begemotBridgeBaseType:
1180164410Ssyrinx		val->v.integer = bif->br_type;
1181165253Ssyrinx		return (SNMP_ERR_NOERROR);
1182164410Ssyrinx
1183164410Ssyrinx	    case LEAF_begemotBridgeBaseStatus:
1184164410Ssyrinx		val->v.integer = bif->if_status;
1185165253Ssyrinx		return (SNMP_ERR_NOERROR);
1186164410Ssyrinx	}
1187164410Ssyrinx
1188165253Ssyrinx	abort();
1189164410Ssyrinx}
1190164410Ssyrinx
1191164410Ssyrinxint
1192164410Ssyrinxop_begemot_stp(struct snmp_context *ctx, struct snmp_value *val,
1193164410Ssyrinx	uint sub, uint iidx __unused, enum snmp_op op)
1194164410Ssyrinx{
1195165046Ssyrinx	struct bridge_if *bif;
1196164410Ssyrinx
1197164410Ssyrinx	if (time(NULL) - bridge_list_age > bridge_get_data_maxage())
1198164410Ssyrinx		bridge_update_all_ifs();
1199164410Ssyrinx
1200164410Ssyrinx	switch (op) {
1201164410Ssyrinx	    case SNMP_OP_GET:
1202164410Ssyrinx		if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1203164410Ssyrinx		    return (SNMP_ERR_NOSUCHNAME);
1204165253Ssyrinx		goto get;
1205164410Ssyrinx
1206164410Ssyrinx	    case SNMP_OP_GETNEXT:
1207164410Ssyrinx		if ((bif = bridge_if_index_getnext(&val->var, sub)) == NULL)
1208164410Ssyrinx		    return (SNMP_ERR_NOSUCHNAME);
1209164410Ssyrinx		bridge_if_index_append(&val->var, sub, bif);
1210165253Ssyrinx		goto get;
1211164410Ssyrinx
1212164410Ssyrinx	    case SNMP_OP_SET:
1213164410Ssyrinx		if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1214164410Ssyrinx		    return (SNMP_ERR_NOSUCHNAME);
1215164410Ssyrinx
1216164410Ssyrinx		switch (val->var.subs[sub - 1]) {
1217164410Ssyrinx		    case LEAF_begemotBridgeStpPriority:
1218165253Ssyrinx			if (val->v.integer > SNMP_BRIDGE_MAX_PRIORITY ||
1219165253Ssyrinx			    val->v.integer % 4096 != 0)
1220165253Ssyrinx			    return (SNMP_ERR_WRONG_VALUE);
1221165253Ssyrinx
1222164410Ssyrinx			ctx->scratch->int1 = bif->priority;
1223165253Ssyrinx			if (bridge_set_priority(bif, val->v.integer) < 0)
1224165253Ssyrinx			    return (SNMP_ERR_GENERR);
1225165253Ssyrinx			return (SNMP_ERR_NOERROR);
1226164410Ssyrinx
1227164410Ssyrinx		    case LEAF_begemotBridgeStpBridgeMaxAge:
1228165253Ssyrinx			if (val->v.integer < SNMP_BRIDGE_MIN_MAGE ||
1229165253Ssyrinx			    val->v.integer > SNMP_BRIDGE_MAX_MAGE)
1230165253Ssyrinx			    return (SNMP_ERR_WRONG_VALUE);
1231165253Ssyrinx
1232164410Ssyrinx			ctx->scratch->int1 = bif->bridge_max_age;
1233165253Ssyrinx			if (bridge_set_maxage(bif, val->v.integer) < 0)
1234165253Ssyrinx			    return (SNMP_ERR_GENERR);
1235165253Ssyrinx			return (SNMP_ERR_NOERROR);
1236164410Ssyrinx
1237164410Ssyrinx		    case LEAF_begemotBridgeStpBridgeHelloTime:
1238165253Ssyrinx			if (val->v.integer < SNMP_BRIDGE_MIN_HTIME ||
1239165253Ssyrinx			    val->v.integer > SNMP_BRIDGE_MAX_HTIME)
1240165253Ssyrinx			    return (SNMP_ERR_WRONG_VALUE);
1241165253Ssyrinx
1242164410Ssyrinx			ctx->scratch->int1 = bif->bridge_hello_time;
1243165253Ssyrinx			if (bridge_set_hello_time(bif, val->v.integer) < 0)
1244165253Ssyrinx			    return (SNMP_ERR_GENERR);
1245165253Ssyrinx			return (SNMP_ERR_NOERROR);
1246164410Ssyrinx
1247164410Ssyrinx		    case LEAF_begemotBridgeStpBridgeForwardDelay:
1248165253Ssyrinx			if (val->v.integer < SNMP_BRIDGE_MIN_FDELAY ||
1249165253Ssyrinx			    val->v.integer > SNMP_BRIDGE_MAX_FDELAY)
1250165253Ssyrinx			    return (SNMP_ERR_WRONG_VALUE);
1251165253Ssyrinx
1252164410Ssyrinx			ctx->scratch->int1 = bif->bridge_fwd_delay;
1253165253Ssyrinx			if (bridge_set_forward_delay(bif, val->v.integer) < 0)
1254165253Ssyrinx			    return (SNMP_ERR_GENERR);
1255165253Ssyrinx			return (SNMP_ERR_NOERROR);
1256164410Ssyrinx
1257164997Ssyrinx		    case LEAF_begemotBridgeStpVersion:
1258165253Ssyrinx			if (val->v.integer !=
1259165253Ssyrinx			    begemotBridgeStpVersion_stpCompatible &&
1260165253Ssyrinx			    val->v.integer != begemotBridgeStpVersion_rstp)
1261165253Ssyrinx			    return (SNMP_ERR_WRONG_VALUE);
1262165253Ssyrinx
1263164997Ssyrinx			ctx->scratch->int1 = bif->stp_version;
1264165253Ssyrinx			if (bridge_set_stp_version(bif, val->v.integer) < 0)
1265165253Ssyrinx			    return (SNMP_ERR_GENERR);
1266165253Ssyrinx			return (SNMP_ERR_NOERROR);
1267164997Ssyrinx
1268164997Ssyrinx		    case LEAF_begemotBridgeStpTxHoldCount:
1269165253Ssyrinx			if (val->v.integer < SNMP_BRIDGE_MIN_TXHC ||
1270165253Ssyrinx			    val->v.integer > SNMP_BRIDGE_MAX_TXHC)
1271165253Ssyrinx			    return (SNMP_ERR_WRONG_VALUE);
1272165253Ssyrinx
1273164997Ssyrinx			ctx->scratch->int1 = bif->tx_hold_count;
1274165253Ssyrinx			if (bridge_set_tx_hold_count(bif, val->v.integer) < 0)
1275165253Ssyrinx			    return (SNMP_ERR_GENERR);
1276165253Ssyrinx			return (SNMP_ERR_NOERROR);
1277164997Ssyrinx
1278164410Ssyrinx		    case LEAF_begemotBridgeStpProtocolSpecification:
1279164410Ssyrinx		    case LEAF_begemotBridgeStpTimeSinceTopologyChange:
1280164410Ssyrinx		    case LEAF_begemotBridgeStpTopChanges:
1281164410Ssyrinx		    case LEAF_begemotBridgeStpDesignatedRoot:
1282164410Ssyrinx		    case LEAF_begemotBridgeStpRootCost:
1283164410Ssyrinx		    case LEAF_begemotBridgeStpRootPort:
1284164410Ssyrinx		    case LEAF_begemotBridgeStpMaxAge:
1285164410Ssyrinx		    case LEAF_begemotBridgeStpHelloTime:
1286164410Ssyrinx		    case LEAF_begemotBridgeStpHoldTime:
1287164410Ssyrinx		    case LEAF_begemotBridgeStpForwardDelay:
1288164410Ssyrinx			return (SNMP_ERR_NOT_WRITEABLE);
1289164410Ssyrinx		}
1290165253Ssyrinx		abort();
1291164410Ssyrinx
1292164410Ssyrinx	    case SNMP_OP_ROLLBACK:
1293164410Ssyrinx		if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1294164410Ssyrinx		    return (SNMP_ERR_NOSUCHNAME);
1295164410Ssyrinx
1296164410Ssyrinx		switch (val->var.subs[sub - 1]) {
1297164410Ssyrinx		    case LEAF_begemotBridgeStpPriority:
1298164410Ssyrinx			bridge_set_priority(bif, ctx->scratch->int1);
1299164410Ssyrinx			break;
1300164410Ssyrinx
1301164410Ssyrinx		    case LEAF_begemotBridgeStpBridgeMaxAge:
1302164410Ssyrinx			bridge_set_maxage(bif, ctx->scratch->int1);
1303164410Ssyrinx			break;
1304164410Ssyrinx
1305164410Ssyrinx		    case LEAF_begemotBridgeStpBridgeHelloTime:
1306164410Ssyrinx			bridge_set_hello_time(bif, ctx->scratch->int1);
1307164410Ssyrinx			break;
1308164410Ssyrinx
1309164410Ssyrinx		    case LEAF_begemotBridgeStpBridgeForwardDelay:
1310164410Ssyrinx			bridge_set_forward_delay(bif, ctx->scratch->int1);
1311164410Ssyrinx			break;
1312164997Ssyrinx
1313164997Ssyrinx		    case LEAF_begemotBridgeStpVersion:
1314164997Ssyrinx			bridge_set_stp_version(bif, ctx->scratch->int1);
1315164997Ssyrinx			break;
1316164997Ssyrinx
1317164997Ssyrinx		    case LEAF_begemotBridgeStpTxHoldCount:
1318164997Ssyrinx			bridge_set_tx_hold_count(bif, ctx->scratch->int1);
1319164997Ssyrinx			break;
1320164410Ssyrinx		}
1321164410Ssyrinx		return (SNMP_ERR_NOERROR);
1322164410Ssyrinx
1323164410Ssyrinx	    case SNMP_OP_COMMIT:
1324164410Ssyrinx		return (SNMP_ERR_NOERROR);
1325164410Ssyrinx	}
1326165253Ssyrinx	abort();
1327164410Ssyrinx
1328165253Ssyrinxget:
1329164410Ssyrinx	switch (val->var.subs[sub - 1]) {
1330164410Ssyrinx	    case LEAF_begemotBridgeStpProtocolSpecification:
1331164410Ssyrinx		val->v.integer = bif->prot_spec;
1332165253Ssyrinx		return (SNMP_ERR_NOERROR);
1333164410Ssyrinx
1334164410Ssyrinx	    case LEAF_begemotBridgeStpPriority:
1335164410Ssyrinx		val->v.integer = bif->priority;
1336165253Ssyrinx		return (SNMP_ERR_NOERROR);
1337164410Ssyrinx
1338164410Ssyrinx	    case LEAF_begemotBridgeStpTimeSinceTopologyChange:
1339164410Ssyrinx		if (bridge_get_time_since_tc(bif, &(val->v.uint32)) < 0)
1340164410Ssyrinx		    return (SNMP_ERR_GENERR);
1341165253Ssyrinx		return (SNMP_ERR_NOERROR);
1342164410Ssyrinx
1343164410Ssyrinx	    case LEAF_begemotBridgeStpTopChanges:
1344164410Ssyrinx		val->v.uint32 = bif->top_changes;
1345165253Ssyrinx		return (SNMP_ERR_NOERROR);
1346164410Ssyrinx
1347164410Ssyrinx	    case LEAF_begemotBridgeStpDesignatedRoot:
1348165253Ssyrinx		return (string_get(val, bif->design_root, SNMP_BRIDGE_ID_LEN));
1349164410Ssyrinx
1350164410Ssyrinx	    case LEAF_begemotBridgeStpRootCost:
1351164410Ssyrinx		val->v.integer = bif->root_cost;
1352165253Ssyrinx		return (SNMP_ERR_NOERROR);
1353164410Ssyrinx
1354164410Ssyrinx	    case LEAF_begemotBridgeStpRootPort:
1355164410Ssyrinx		val->v.integer = bif->root_port;
1356165253Ssyrinx		return (SNMP_ERR_NOERROR);
1357164410Ssyrinx
1358164410Ssyrinx	    case LEAF_begemotBridgeStpMaxAge:
1359164410Ssyrinx		val->v.integer = bif->max_age;
1360165253Ssyrinx		return (SNMP_ERR_NOERROR);
1361164410Ssyrinx
1362164410Ssyrinx	    case LEAF_begemotBridgeStpHelloTime:
1363164410Ssyrinx		val->v.integer = bif->hello_time;
1364165253Ssyrinx		return (SNMP_ERR_NOERROR);
1365164410Ssyrinx
1366164410Ssyrinx	    case LEAF_begemotBridgeStpHoldTime:
1367164410Ssyrinx		val->v.integer = bif->hold_time;
1368165253Ssyrinx		return (SNMP_ERR_NOERROR);
1369164410Ssyrinx
1370164410Ssyrinx	    case LEAF_begemotBridgeStpForwardDelay:
1371164410Ssyrinx		val->v.integer = bif->fwd_delay;
1372165253Ssyrinx		return (SNMP_ERR_NOERROR);
1373164410Ssyrinx
1374164410Ssyrinx	    case LEAF_begemotBridgeStpBridgeMaxAge:
1375164410Ssyrinx		val->v.integer = bif->bridge_max_age;
1376165253Ssyrinx		return (SNMP_ERR_NOERROR);
1377164410Ssyrinx
1378164410Ssyrinx	    case LEAF_begemotBridgeStpBridgeHelloTime:
1379164410Ssyrinx		val->v.integer = bif->bridge_hello_time;
1380165253Ssyrinx		return (SNMP_ERR_NOERROR);
1381164410Ssyrinx
1382164410Ssyrinx	    case LEAF_begemotBridgeStpBridgeForwardDelay:
1383164410Ssyrinx		val->v.integer = bif->bridge_fwd_delay;
1384165253Ssyrinx		return (SNMP_ERR_NOERROR);
1385164997Ssyrinx
1386164997Ssyrinx	    case LEAF_begemotBridgeStpVersion:
1387164997Ssyrinx		val->v.integer = bif->stp_version;
1388165253Ssyrinx		return (SNMP_ERR_NOERROR);
1389164997Ssyrinx
1390164997Ssyrinx	    case LEAF_begemotBridgeStpTxHoldCount:
1391164997Ssyrinx		val->v.integer = bif->tx_hold_count;
1392165253Ssyrinx		return (SNMP_ERR_NOERROR);
1393164410Ssyrinx	}
1394164410Ssyrinx
1395165253Ssyrinx	abort();
1396164410Ssyrinx}
1397164410Ssyrinx
1398164410Ssyrinxint
1399164410Ssyrinxop_begemot_tp(struct snmp_context *ctx, struct snmp_value *val,
1400164410Ssyrinx	uint sub, uint iidx __unused, enum snmp_op op)
1401164410Ssyrinx{
1402165046Ssyrinx	struct bridge_if *bif;
1403164410Ssyrinx
1404164410Ssyrinx	if (time(NULL) - bridge_list_age > bridge_get_data_maxage())
1405164410Ssyrinx		bridge_update_all_ifs();
1406164410Ssyrinx
1407164410Ssyrinx	switch (op) {
1408164410Ssyrinx	    case SNMP_OP_GET:
1409164410Ssyrinx		if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1410164410Ssyrinx		    return (SNMP_ERR_NOSUCHNAME);
1411165253Ssyrinx		goto get;
1412164410Ssyrinx
1413164410Ssyrinx	    case SNMP_OP_GETNEXT:
1414164410Ssyrinx		if ((bif = bridge_if_index_getnext(&val->var, sub)) == NULL)
1415164410Ssyrinx		    return (SNMP_ERR_NOSUCHNAME);
1416164410Ssyrinx		bridge_if_index_append(&val->var, sub, bif);
1417165253Ssyrinx		goto get;
1418164410Ssyrinx
1419164410Ssyrinx	    case SNMP_OP_SET:
1420164410Ssyrinx		if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1421164410Ssyrinx		    return (SNMP_ERR_NOSUCHNAME);
1422164410Ssyrinx
1423164410Ssyrinx		switch (val->var.subs[sub - 1]) {
1424164410Ssyrinx		    case LEAF_begemotBridgeTpAgingTime:
1425165253Ssyrinx			if (val->v.integer < SNMP_BRIDGE_MIN_AGE_TIME ||
1426165253Ssyrinx			    val->v.integer > SNMP_BRIDGE_MAX_AGE_TIME)
1427165253Ssyrinx			    return (SNMP_ERR_WRONG_VALUE);
1428165253Ssyrinx
1429164410Ssyrinx			ctx->scratch->int1 = bif->age_time;
1430164410Ssyrinx			if (bridge_set_aging_time(bif, val->v.integer) < 0)
1431164410Ssyrinx			    return (SNMP_ERR_GENERR);
1432164410Ssyrinx			return (SNMP_ERR_NOERROR);
1433164410Ssyrinx
1434164410Ssyrinx		    case LEAF_begemotBridgeTpMaxAddresses:
1435164410Ssyrinx			ctx->scratch->int1 = bif->max_addrs;
1436164410Ssyrinx			if (bridge_set_max_cache(bif, val->v.integer) < 0)
1437164410Ssyrinx			    return (SNMP_ERR_GENERR);
1438164410Ssyrinx			return (SNMP_ERR_NOERROR);
1439164410Ssyrinx
1440164410Ssyrinx		    case LEAF_begemotBridgeTpLearnedEntryDiscards:
1441164410Ssyrinx			return (SNMP_ERR_NOT_WRITEABLE);
1442164410Ssyrinx		}
1443164410Ssyrinx		abort();
1444164410Ssyrinx
1445164410Ssyrinx	    case SNMP_OP_ROLLBACK:
1446164410Ssyrinx		if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1447164410Ssyrinx		    return (SNMP_ERR_GENERR);
1448164410Ssyrinx
1449164410Ssyrinx		switch (val->var.subs[sub - 1]) {
1450164410Ssyrinx		    case LEAF_begemotBridgeTpAgingTime:
1451164410Ssyrinx			bridge_set_aging_time(bif, ctx->scratch->int1);
1452164410Ssyrinx			break;
1453164410Ssyrinx
1454164410Ssyrinx		    case LEAF_begemotBridgeTpMaxAddresses:
1455164410Ssyrinx			bridge_set_max_cache(bif, ctx->scratch->int1);
1456164410Ssyrinx			break;
1457164410Ssyrinx		}
1458164410Ssyrinx		return (SNMP_ERR_NOERROR);
1459164410Ssyrinx
1460164410Ssyrinx	    case SNMP_OP_COMMIT:
1461164410Ssyrinx		return (SNMP_ERR_NOERROR);
1462164410Ssyrinx	}
1463165253Ssyrinx	abort();
1464164410Ssyrinx
1465165253Ssyrinxget:
1466164410Ssyrinx	switch (val->var.subs[sub - 1]) {
1467164410Ssyrinx	    case LEAF_begemotBridgeTpLearnedEntryDiscards:
1468164410Ssyrinx		val->v.uint32 = bif->lrnt_drops;
1469165253Ssyrinx		return (SNMP_ERR_NOERROR);
1470164410Ssyrinx
1471164410Ssyrinx	    case LEAF_begemotBridgeTpAgingTime:
1472164410Ssyrinx		val->v.integer = bif->age_time;
1473165253Ssyrinx		return (SNMP_ERR_NOERROR);
1474164410Ssyrinx
1475164410Ssyrinx	    case LEAF_begemotBridgeTpMaxAddresses:
1476164410Ssyrinx		val->v.integer = bif->max_addrs;
1477165253Ssyrinx		return (SNMP_ERR_NOERROR);
1478164410Ssyrinx	}
1479164410Ssyrinx
1480165253Ssyrinx	abort();
1481164410Ssyrinx}
1482