1164410Ssyrinx/*-
2164410Ssyrinx * Copyright (c) 2006 Shteryana Shopova <syrinx@FreeBSD.org>
3164410Ssyrinx * All rights reserved.
4164410Ssyrinx *
5164410Ssyrinx * Redistribution and use in source and binary forms, with or without
6164410Ssyrinx * modification, are permitted provided that the following conditions
7164410Ssyrinx * are met:
8164410Ssyrinx * 1. Redistributions of source code must retain the above copyright
9164410Ssyrinx *    notice, this list of conditions and the following disclaimer.
10164410Ssyrinx * 2. Redistributions in binary form must reproduce the above copyright
11164410Ssyrinx *    notice, this list of conditions and the following disclaimer in the
12164410Ssyrinx *    documentation and/or other materials provided with the distribution.
13164410Ssyrinx *
14164410Ssyrinx * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15164410Ssyrinx * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16164410Ssyrinx * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17164410Ssyrinx * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18164410Ssyrinx * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19164410Ssyrinx * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20164410Ssyrinx * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21164410Ssyrinx * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22164410Ssyrinx * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23164410Ssyrinx * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24164410Ssyrinx * SUCH DAMAGE.
25164410Ssyrinx *
26164410Ssyrinx * Bridge MIB implementation for SNMPd.
27164410Ssyrinx * Bridge interface objects.
28164410Ssyrinx *
29164410Ssyrinx * $FreeBSD$
30164410Ssyrinx */
31164410Ssyrinx
32164410Ssyrinx#include <sys/queue.h>
33164410Ssyrinx#include <sys/socket.h>
34164410Ssyrinx#include <sys/time.h>
35164410Ssyrinx#include <sys/types.h>
36164410Ssyrinx
37164410Ssyrinx#include <net/ethernet.h>
38164410Ssyrinx#include <net/if.h>
39164410Ssyrinx#include <net/if_mib.h>
40164410Ssyrinx#include <net/if_types.h>
41164410Ssyrinx
42164410Ssyrinx#include <errno.h>
43164410Ssyrinx#include <stdarg.h>
44164410Ssyrinx#include <stdlib.h>
45164410Ssyrinx#include <string.h>
46164410Ssyrinx#include <syslog.h>
47164410Ssyrinx
48164410Ssyrinx#include <bsnmp/snmpmod.h>
49164410Ssyrinx#include <bsnmp/snmp_mibII.h>
50164410Ssyrinx
51164410Ssyrinx#include "bridge_tree.h"
52164410Ssyrinx#include "bridge_snmp.h"
53164410Ssyrinx#include "bridge_oid.h"
54164410Ssyrinx
55164410Ssyrinxstatic const struct asn_oid oid_newRoot = OIDX_newRoot;
56164410Ssyrinxstatic const struct asn_oid oid_TopologyChange = OIDX_topologyChange;
57164410Ssyrinxstatic const struct asn_oid oid_begemotBrigeName = \
58164410Ssyrinx			OIDX_begemotBridgeBaseName;
59164410Ssyrinxstatic const struct asn_oid oid_begemotNewRoot = OIDX_begemotBridgeNewRoot;
60164410Ssyrinxstatic const struct asn_oid oid_begemotTopologyChange = \
61164410Ssyrinx			OIDX_begemotBridgeTopologyChange;
62164410Ssyrinx
63164410SsyrinxTAILQ_HEAD(bridge_ifs, bridge_if);
64164410Ssyrinx
65164410Ssyrinx/*
66164410Ssyrinx * Free the bridge interface list.
67164410Ssyrinx */
68164410Ssyrinxstatic void
69164410Ssyrinxbridge_ifs_free(struct bridge_ifs *headp)
70164410Ssyrinx{
71164410Ssyrinx	struct bridge_if *b;
72164410Ssyrinx
73164410Ssyrinx	while ((b = TAILQ_FIRST(headp)) != NULL) {
74164410Ssyrinx		TAILQ_REMOVE(headp, b, b_if);
75164410Ssyrinx		free(b);
76164410Ssyrinx	}
77164410Ssyrinx}
78164410Ssyrinx
79164410Ssyrinx/*
80164410Ssyrinx * Insert an entry in the bridge interface TAILQ. Keep the
81164410Ssyrinx * TAILQ sorted by the bridge's interface name.
82164410Ssyrinx */
83164410Ssyrinxstatic void
84164410Ssyrinxbridge_ifs_insert(struct bridge_ifs *headp,
85164410Ssyrinx	struct bridge_if *b)
86164410Ssyrinx{
87164410Ssyrinx	struct bridge_if *temp;
88164410Ssyrinx
89164410Ssyrinx	if ((temp = TAILQ_FIRST(headp)) == NULL ||
90164410Ssyrinx	    strcmp(b->bif_name, temp->bif_name) < 0) {
91164410Ssyrinx		TAILQ_INSERT_HEAD(headp, b, b_if);
92164410Ssyrinx		return;
93164410Ssyrinx	}
94164410Ssyrinx
95164410Ssyrinx	TAILQ_FOREACH(temp, headp, b_if)
96164410Ssyrinx		if(strcmp(b->bif_name, temp->bif_name) < 0)
97164410Ssyrinx			TAILQ_INSERT_BEFORE(temp, b, b_if);
98164410Ssyrinx
99164410Ssyrinx	TAILQ_INSERT_TAIL(headp, b, b_if);
100164410Ssyrinx}
101164410Ssyrinx
102164410Ssyrinx/* The global bridge interface list. */
103164410Ssyrinxstatic struct bridge_ifs bridge_ifs = TAILQ_HEAD_INITIALIZER(bridge_ifs);
104164410Ssyrinxstatic time_t bridge_list_age;
105164410Ssyrinx
106164410Ssyrinx/*
107164410Ssyrinx * Free the global list.
108164410Ssyrinx */
109164410Ssyrinxvoid
110164410Ssyrinxbridge_ifs_fini(void)
111164410Ssyrinx{
112164410Ssyrinx	bridge_ifs_free(&bridge_ifs);
113164410Ssyrinx}
114164410Ssyrinx
115164410Ssyrinx/*
116164410Ssyrinx * Find a bridge interface entry by the bridge interface system index.
117164410Ssyrinx */
118164410Ssyrinxstruct bridge_if *
119164410Ssyrinxbridge_if_find_ifs(uint32_t sysindex)
120164410Ssyrinx{
121164410Ssyrinx	struct bridge_if *b;
122164410Ssyrinx
123164410Ssyrinx	TAILQ_FOREACH(b, &bridge_ifs, b_if)
124164410Ssyrinx		if (b->sysindex == sysindex)
125164410Ssyrinx			return (b);
126164410Ssyrinx
127164410Ssyrinx	return (NULL);
128164410Ssyrinx}
129164410Ssyrinx
130164410Ssyrinx/*
131164410Ssyrinx * Find a bridge interface entry by the bridge interface name.
132164410Ssyrinx */
133164410Ssyrinxstruct bridge_if *
134164410Ssyrinxbridge_if_find_ifname(const char *b_name)
135164410Ssyrinx{
136164410Ssyrinx	struct bridge_if *b;
137164410Ssyrinx
138164410Ssyrinx	TAILQ_FOREACH(b, &bridge_ifs, b_if)
139164410Ssyrinx		if (strcmp(b_name, b->bif_name) == 0)
140164410Ssyrinx			return (b);
141164410Ssyrinx
142164410Ssyrinx	return (NULL);
143164410Ssyrinx}
144164410Ssyrinx
145164410Ssyrinx/*
146164410Ssyrinx * Find a bridge name by the bridge interface system index.
147164410Ssyrinx */
148164410Ssyrinxconst char *
149164410Ssyrinxbridge_if_find_name(uint32_t sysindex)
150164410Ssyrinx{
151164410Ssyrinx	struct bridge_if *b;
152164410Ssyrinx
153164410Ssyrinx	TAILQ_FOREACH(b, &bridge_ifs, b_if)
154164410Ssyrinx		if (b->sysindex == sysindex)
155164410Ssyrinx			return (b->bif_name);
156164410Ssyrinx
157164410Ssyrinx	return (NULL);
158164410Ssyrinx}
159164410Ssyrinx
160164410Ssyrinx/*
161164410Ssyrinx * Given two bridge interfaces' system indexes, find their
162164410Ssyrinx * corresponding names and return the result of the name
163164410Ssyrinx * comparison. Returns:
164164410Ssyrinx * error : -2
165164410Ssyrinx * i1 < i2 : -1
166164410Ssyrinx * i1 > i2 : +1
167164410Ssyrinx * i1 = i2 : 0
168164410Ssyrinx */
169164410Ssyrinxint
170164410Ssyrinxbridge_compare_sysidx(uint32_t i1, uint32_t i2)
171164410Ssyrinx{
172164410Ssyrinx	int c;
173164410Ssyrinx	const char *b1, *b2;
174164410Ssyrinx
175164410Ssyrinx	if (i1 == i2)
176164410Ssyrinx		return (0);
177164410Ssyrinx
178164410Ssyrinx	if ((b1 = bridge_if_find_name(i1)) == NULL) {
179164410Ssyrinx		syslog(LOG_ERR, "Bridge interface %d does not exist", i1);
180164410Ssyrinx		return (-2);
181164410Ssyrinx	}
182164410Ssyrinx
183164410Ssyrinx	if ((b2 = bridge_if_find_name(i2)) == NULL) {
184164410Ssyrinx		syslog(LOG_ERR, "Bridge interface %d does not exist", i2);
185164410Ssyrinx		return (-2);
186164410Ssyrinx	}
187164410Ssyrinx
188164410Ssyrinx	if ((c = strcmp(b1, b2)) < 0)
189164410Ssyrinx		return (-1);
190164410Ssyrinx	else if (c > 0)
191164410Ssyrinx		return (1);
192164410Ssyrinx
193164410Ssyrinx	return (0);
194164410Ssyrinx}
195164410Ssyrinx
196164410Ssyrinx/*
197164410Ssyrinx * Fetch the first bridge interface from the list.
198164410Ssyrinx */
199164410Ssyrinxstruct bridge_if *
200164410Ssyrinxbridge_first_bif(void)
201164410Ssyrinx{
202164410Ssyrinx	return (TAILQ_FIRST(&bridge_ifs));
203164410Ssyrinx}
204164410Ssyrinx
205164410Ssyrinx/*
206164410Ssyrinx * Fetch the next bridge interface from the list.
207164410Ssyrinx */
208164410Ssyrinxstruct bridge_if *
209164410Ssyrinxbridge_next_bif(struct bridge_if *b_pr)
210164410Ssyrinx{
211164410Ssyrinx	return (TAILQ_NEXT(b_pr, b_if));
212164410Ssyrinx}
213164410Ssyrinx
214164410Ssyrinx/*
215164410Ssyrinx * Create a new entry for a bridge interface and insert
216164410Ssyrinx * it in the list.
217164410Ssyrinx */
218164410Ssyrinxstatic struct bridge_if *
219164410Ssyrinxbridge_new_bif(const char *bif_n, uint32_t sysindex, const u_char *physaddr)
220164410Ssyrinx{
221164410Ssyrinx	struct bridge_if *bif;
222164410Ssyrinx
223164410Ssyrinx	if ((bif = (struct bridge_if *) malloc(sizeof(*bif)))== NULL) {
224164410Ssyrinx		syslog(LOG_ERR, "bridge new interface failed: %s",
225164410Ssyrinx		    strerror(errno));
226164410Ssyrinx		return (NULL);
227164410Ssyrinx	}
228164410Ssyrinx
229164410Ssyrinx	bzero(bif, sizeof(struct bridge_if));
230164410Ssyrinx	strlcpy(bif->bif_name, bif_n, IFNAMSIZ);
231164410Ssyrinx	bcopy(physaddr, bif->br_addr.octet, ETHER_ADDR_LEN);
232164410Ssyrinx	bif->sysindex = sysindex;
233164410Ssyrinx	bif->br_type = BaseType_transparent_only;
234164410Ssyrinx	/* 1 - all bridges default hold time * 100 - centi-seconds */
235164410Ssyrinx	bif->hold_time = 1 * 100;
236164410Ssyrinx	bif->prot_spec = dot1dStpProtocolSpecification_ieee8021d;
237164410Ssyrinx	bridge_ifs_insert(&bridge_ifs, bif);
238164410Ssyrinx
239164410Ssyrinx	return (bif);
240164410Ssyrinx}
241164410Ssyrinx
242164410Ssyrinx/*
243164410Ssyrinx * Remove a bridge interface from the list, freeing all it's ports
244164410Ssyrinx * and address entries.
245164410Ssyrinx */
246164410Ssyrinxvoid
247164410Ssyrinxbridge_remove_bif(struct bridge_if *bif)
248164410Ssyrinx{
249164410Ssyrinx	bridge_members_free(bif);
250164410Ssyrinx	bridge_addrs_free(bif);
251164410Ssyrinx	TAILQ_REMOVE(&bridge_ifs, bif, b_if);
252164410Ssyrinx	free(bif);
253164410Ssyrinx}
254164410Ssyrinx
255164410Ssyrinx
256164410Ssyrinx/*
257164410Ssyrinx * Prepare the variable (bridge interface name) for the private
258164410Ssyrinx * begemot notifications.
259164410Ssyrinx */
260164410Ssyrinxstatic struct snmp_value*
261164410Ssyrinxbridge_basename_var(struct bridge_if *bif, struct snmp_value* b_val)
262164410Ssyrinx{
263164410Ssyrinx	uint i;
264164410Ssyrinx
265164410Ssyrinx	b_val->var = oid_begemotBrigeName;
266164410Ssyrinx	b_val->var.subs[b_val->var.len++] = strlen(bif->bif_name);
267164410Ssyrinx
268164410Ssyrinx	if ((b_val->v.octetstring.octets = (u_char *)
269164410Ssyrinx	    malloc(strlen(bif->bif_name))) == NULL)
270164410Ssyrinx		return (NULL);
271164410Ssyrinx
272164410Ssyrinx	for (i = 0; i < strlen(bif->bif_name); i++)
273164410Ssyrinx		b_val->var.subs[b_val->var.len++] = bif->bif_name[i];
274164410Ssyrinx
275164410Ssyrinx	b_val->v.octetstring.len = strlen(bif->bif_name);
276164410Ssyrinx	bcopy(bif->bif_name, b_val->v.octetstring.octets,
277164410Ssyrinx	    strlen(bif->bif_name));
278164410Ssyrinx	b_val->syntax = SNMP_SYNTAX_OCTETSTRING;
279164410Ssyrinx
280164410Ssyrinx	return (b_val);
281164410Ssyrinx}
282164410Ssyrinx
283164410Ssyrinx/*
284164410Ssyrinx * Compare the values of the old and the new root port and
285164410Ssyrinx * send a new root notification, if they are not matching.
286164410Ssyrinx */
287164410Ssyrinxstatic void
288164410Ssyrinxbridge_new_root(struct bridge_if *bif)
289164410Ssyrinx{
290164410Ssyrinx	struct snmp_value bif_idx;
291164410Ssyrinx
292164410Ssyrinx	if (bridge_get_default() == bif)
293164410Ssyrinx		snmp_send_trap(&oid_newRoot, (struct snmp_value *) NULL);
294164410Ssyrinx
295164410Ssyrinx	if (bridge_basename_var(bif, &bif_idx) == NULL)
296164410Ssyrinx		return;
297164410Ssyrinx
298164410Ssyrinx	snmp_send_trap(&oid_begemotTopologyChange,
299164410Ssyrinx	    &bif_idx, (struct snmp_value *) NULL);
300164410Ssyrinx}
301164410Ssyrinx
302164410Ssyrinx/*
303164410Ssyrinx * Compare the new and old topology change times and send a
304164410Ssyrinx * topology change notification if necessary.
305164410Ssyrinx */
306164410Ssyrinxstatic void
307164410Ssyrinxbridge_top_change(struct bridge_if *bif)
308164410Ssyrinx{
309164410Ssyrinx	struct snmp_value bif_idx;
310164410Ssyrinx
311164410Ssyrinx	if (bridge_get_default() == bif)
312164410Ssyrinx		snmp_send_trap(&oid_TopologyChange,
313164410Ssyrinx		    (struct snmp_value *) NULL);
314164410Ssyrinx
315164410Ssyrinx	if (bridge_basename_var(bif, &bif_idx) == NULL)
316164410Ssyrinx		return;
317164410Ssyrinx
318164410Ssyrinx	snmp_send_trap(&oid_begemotNewRoot,
319164410Ssyrinx	    &bif_idx, (struct snmp_value *) NULL);
320164410Ssyrinx}
321164410Ssyrinx
322164410Ssyrinxstatic int
323164410Ssyrinxbridge_if_create(const char* b_name, int8_t up)
324164410Ssyrinx{
325164410Ssyrinx	if (bridge_create(b_name) < 0)
326164410Ssyrinx		return (-1);
327164410Ssyrinx
328164410Ssyrinx	if (up == 1 && (bridge_set_if_up(b_name, 1) < 0))
329164410Ssyrinx		return (-1);
330164410Ssyrinx
331164410Ssyrinx	/*
332164410Ssyrinx	 * Do not create a new bridge entry here -
333164410Ssyrinx	 * wait until the mibII module notifies us.
334164410Ssyrinx	 */
335164410Ssyrinx	return (0);
336164410Ssyrinx}
337164410Ssyrinx
338164410Ssyrinxstatic int
339164410Ssyrinxbridge_if_destroy(struct bridge_if *bif)
340164410Ssyrinx{
341164410Ssyrinx	if (bridge_destroy(bif->bif_name) < 0)
342164410Ssyrinx		return (-1);
343164410Ssyrinx
344164410Ssyrinx	bridge_remove_bif(bif);
345164410Ssyrinx
346164410Ssyrinx	return (0);
347164410Ssyrinx}
348164410Ssyrinx
349164410Ssyrinx/*
350164410Ssyrinx * Calculate the timeticks since the last topology change.
351164410Ssyrinx */
352164410Ssyrinxstatic int
353164410Ssyrinxbridge_get_time_since_tc(struct bridge_if *bif, uint32_t *ticks)
354164410Ssyrinx{
355164410Ssyrinx	struct timeval ct;
356164410Ssyrinx
357164410Ssyrinx	if (gettimeofday(&ct, NULL) < 0) {
358164410Ssyrinx		syslog(LOG_ERR, "bridge get time since last TC:"
359164410Ssyrinx		    "getttimeofday failed: %s", strerror(errno));
360164410Ssyrinx		return (-1);
361164410Ssyrinx	}
362164410Ssyrinx
363164410Ssyrinx	if (ct.tv_usec - bif->last_tc_time.tv_usec < 0) {
364164410Ssyrinx		ct.tv_sec -= 1;
365164410Ssyrinx		ct.tv_usec += 1000000;
366164410Ssyrinx	}
367164410Ssyrinx
368164410Ssyrinx	ct.tv_sec -= bif->last_tc_time.tv_sec;
369164410Ssyrinx	ct.tv_usec -= bif->last_tc_time.tv_usec;
370164410Ssyrinx
371164410Ssyrinx	*ticks = ct.tv_sec * 100 + ct.tv_usec/10000;
372164410Ssyrinx
373164410Ssyrinx	return (0);
374164410Ssyrinx}
375164410Ssyrinx
376164410Ssyrinx/*
377164410Ssyrinx * Update the info we have for a single bridge interface.
378164410Ssyrinx * Return:
379164410Ssyrinx * 1, if successful
380164410Ssyrinx * 0, if the interface was deleted
381164410Ssyrinx * -1, error occured while fetching the info from the kernel.
382164410Ssyrinx */
383164410Ssyrinxstatic int
384164410Ssyrinxbridge_update_bif(struct bridge_if *bif)
385164410Ssyrinx{
386164410Ssyrinx	struct mibif *ifp;
387164410Ssyrinx
388164410Ssyrinx	/* Walk through the mibII interface list. */
389164410Ssyrinx	for (ifp = mib_first_if(); ifp != NULL; ifp = mib_next_if(ifp))
390164410Ssyrinx		if (strcmp(ifp->name, bif->bif_name) == 0)
391164410Ssyrinx			break;
392164410Ssyrinx
393164410Ssyrinx	if (ifp == NULL) {
394164410Ssyrinx		/* Ops, we do not exist anymore. */
395164410Ssyrinx		bridge_remove_bif(bif);
396164410Ssyrinx		return (0);
397164410Ssyrinx	}
398164410Ssyrinx
399164410Ssyrinx	if (ifp->physaddr != NULL )
400164410Ssyrinx		bcopy(ifp->physaddr, bif->br_addr.octet, ETHER_ADDR_LEN);
401164410Ssyrinx	else
402165642Sbz		bridge_get_basemac(bif->bif_name, bif->br_addr.octet,
403165642Sbz		    ETHER_ADDR_LEN);
404164410Ssyrinx
405164410Ssyrinx	if (ifp->mib.ifmd_flags & IFF_RUNNING)
406164410Ssyrinx		bif->if_status = RowStatus_active;
407164410Ssyrinx	else
408164410Ssyrinx		bif->if_status = RowStatus_notInService;
409164410Ssyrinx
410164410Ssyrinx	switch (bridge_getinfo_bif(bif)) {
411164410Ssyrinx		case 2:
412164410Ssyrinx			bridge_new_root(bif);
413164410Ssyrinx			break;
414164410Ssyrinx		case 1:
415164410Ssyrinx			bridge_top_change(bif);
416164410Ssyrinx			break;
417164410Ssyrinx		case -1:
418164410Ssyrinx			bridge_remove_bif(bif);
419164410Ssyrinx			return (-1);
420164410Ssyrinx		default:
421164410Ssyrinx			break;
422164410Ssyrinx	}
423164410Ssyrinx
424164410Ssyrinx	/*
425164410Ssyrinx	 * The number of ports is accessible via SNMP -
426164410Ssyrinx	 * update the ports each time the bridge interface data
427164410Ssyrinx	 * is refreshed too.
428164410Ssyrinx	 */
429164410Ssyrinx	bif->num_ports = bridge_update_memif(bif);
430164410Ssyrinx	bif->entry_age = time(NULL);
431164410Ssyrinx
432164410Ssyrinx	return (1);
433164410Ssyrinx}
434164410Ssyrinx
435164410Ssyrinx/*
436164410Ssyrinx * Update all bridge interfaces' ports only -
437164410Ssyrinx * make sure each bridge interface exists first.
438164410Ssyrinx */
439164410Ssyrinxvoid
440164410Ssyrinxbridge_update_all_ports(void)
441164410Ssyrinx{
442164410Ssyrinx	struct mibif *ifp;
443164410Ssyrinx	struct bridge_if *bif, *t_bif;
444164410Ssyrinx
445164410Ssyrinx	for (bif = bridge_first_bif(); bif != NULL; bif = t_bif) {
446164410Ssyrinx		t_bif = bridge_next_bif(bif);
447164410Ssyrinx
448164410Ssyrinx		for (ifp = mib_first_if(); ifp != NULL;
449164410Ssyrinx		    ifp = mib_next_if(ifp))
450164410Ssyrinx			if (strcmp(ifp->name, bif->bif_name) == 0)
451164410Ssyrinx				break;
452164410Ssyrinx
453164410Ssyrinx		if (ifp != NULL)
454164410Ssyrinx			bif->num_ports = bridge_update_memif(bif);
455164410Ssyrinx		else  /* Ops, we do not exist anymore. */
456164410Ssyrinx			bridge_remove_bif(bif);
457164410Ssyrinx	}
458164410Ssyrinx
459164410Ssyrinx	bridge_ports_update_listage();
460164410Ssyrinx}
461164410Ssyrinx
462164410Ssyrinx/*
463164410Ssyrinx * Update all addresses only.
464164410Ssyrinx */
465164410Ssyrinxvoid
466164410Ssyrinxbridge_update_all_addrs(void)
467164410Ssyrinx{
468164410Ssyrinx	struct mibif *ifp;
469164410Ssyrinx	struct bridge_if *bif, *t_bif;
470164410Ssyrinx
471164410Ssyrinx	for (bif = bridge_first_bif(); bif != NULL; bif = t_bif) {
472164410Ssyrinx		t_bif = bridge_next_bif(bif);
473164410Ssyrinx
474164410Ssyrinx		for (ifp = mib_first_if(); ifp != NULL;
475164410Ssyrinx		    ifp = mib_next_if(ifp))
476164410Ssyrinx			if (strcmp(ifp->name, bif->bif_name) == 0)
477164410Ssyrinx				break;
478164410Ssyrinx
479164410Ssyrinx		if (ifp != NULL)
480164410Ssyrinx			bif->num_addrs = bridge_update_addrs(bif);
481164410Ssyrinx		else  /* Ops, we don't exist anymore. */
482164410Ssyrinx			bridge_remove_bif(bif);
483164410Ssyrinx	}
484164410Ssyrinx
485164410Ssyrinx	bridge_addrs_update_listage();
486164410Ssyrinx}
487164410Ssyrinx
488164410Ssyrinx/*
489164410Ssyrinx * Update only the bridge interfaces' data - skip addresses.
490164410Ssyrinx */
491164410Ssyrinxvoid
492164410Ssyrinxbridge_update_all_ifs(void)
493164410Ssyrinx{
494164410Ssyrinx	struct bridge_if *bif, *t_bif;
495164410Ssyrinx
496164410Ssyrinx	for (bif = bridge_first_bif(); bif != NULL; bif = t_bif) {
497164410Ssyrinx		t_bif = bridge_next_bif(bif);
498164410Ssyrinx		bridge_update_bif(bif);
499164410Ssyrinx	}
500164410Ssyrinx
501164410Ssyrinx	bridge_ports_update_listage();
502164410Ssyrinx	bridge_list_age = time(NULL);
503164410Ssyrinx}
504164410Ssyrinx
505164410Ssyrinx/*
506164410Ssyrinx * Update all info we have for all bridges.
507164410Ssyrinx */
508164410Ssyrinxvoid
509164410Ssyrinxbridge_update_all(void *arg __unused)
510164410Ssyrinx{
511164410Ssyrinx	struct bridge_if *bif, *t_bif;
512164410Ssyrinx
513164410Ssyrinx	for (bif = bridge_first_bif(); bif != NULL; bif = t_bif) {
514164410Ssyrinx		t_bif = bridge_next_bif(bif);
515164410Ssyrinx		if (bridge_update_bif(bif) <= 0)
516164410Ssyrinx			continue;
517164410Ssyrinx
518164410Ssyrinx		/* Update our learnt addresses. */
519164410Ssyrinx		bif->num_addrs = bridge_update_addrs(bif);
520164410Ssyrinx	}
521164410Ssyrinx
522164410Ssyrinx	bridge_list_age = time(NULL);
523164410Ssyrinx	bridge_ports_update_listage();
524164410Ssyrinx	bridge_addrs_update_listage();
525164410Ssyrinx}
526164410Ssyrinx
527164410Ssyrinx/*
528164410Ssyrinx * Callback for polling our last topology change time -
529164410Ssyrinx * check whether we are root or whether a TC was detected once every
530164410Ssyrinx * 30 seconds, so that we can send the newRoot and TopologyChange traps
531164410Ssyrinx * on time. The rest of the data is polled only once every 5 min.
532164410Ssyrinx */
533164410Ssyrinxvoid
534164410Ssyrinxbridge_update_tc_time(void *arg __unused)
535164410Ssyrinx{
536164410Ssyrinx	struct bridge_if *bif;
537164410Ssyrinx	struct mibif *ifp;
538164410Ssyrinx
539164410Ssyrinx	TAILQ_FOREACH(bif, &bridge_ifs, b_if) {
540164410Ssyrinx		/* Walk through the mibII interface list. */
541164410Ssyrinx		for (ifp = mib_first_if(); ifp != NULL; ifp = mib_next_if(ifp))
542164410Ssyrinx			if (strcmp(ifp->name, bif->bif_name) == 0)
543164410Ssyrinx				break;
544164410Ssyrinx
545164410Ssyrinx		if (ifp == NULL) {
546164410Ssyrinx			bridge_remove_bif(bif);
547164410Ssyrinx			continue;
548164410Ssyrinx		}
549164410Ssyrinx
550164410Ssyrinx		switch (bridge_get_op_param(bif)) {
551164410Ssyrinx			case 2:
552164410Ssyrinx				bridge_new_root(bif);
553164410Ssyrinx				break;
554164410Ssyrinx			case 1:
555164410Ssyrinx				bridge_top_change(bif);
556164410Ssyrinx				break;
557164410Ssyrinx		}
558164410Ssyrinx	}
559164410Ssyrinx}
560164410Ssyrinx
561164410Ssyrinx/*
562164410Ssyrinx * Callback for handling new bridge interface creation.
563164410Ssyrinx */
564164410Ssyrinxint
565164410Ssyrinxbridge_attach_newif(struct mibif *ifp)
566164410Ssyrinx{
567165642Sbz	u_char mac[ETHER_ADDR_LEN];
568164410Ssyrinx	struct bridge_if *bif;
569164410Ssyrinx
570164410Ssyrinx	if (ifp->mib.ifmd_data.ifi_type != IFT_BRIDGE)
571164410Ssyrinx		return (0);
572164410Ssyrinx
573164410Ssyrinx	/* Make sure it does not exist in our list. */
574164410Ssyrinx	TAILQ_FOREACH(bif, &bridge_ifs, b_if)
575164410Ssyrinx		if(strcmp(bif->bif_name, ifp->name) == 0) {
576164410Ssyrinx			syslog(LOG_ERR, "bridge interface %s already "
577164410Ssyrinx			    "in list", bif->bif_name);
578164410Ssyrinx			return (-1);
579164410Ssyrinx		}
580164410Ssyrinx
581165642Sbz	if (ifp->physaddr == NULL) {
582165642Sbz		if (bridge_get_basemac(ifp->name, mac, sizeof(mac)) == NULL) {
583165642Sbz			syslog(LOG_ERR, "bridge attach new %s failed - "
584165642Sbz			    "no bridge mac address", ifp->name);
585165642Sbz			return (-1);
586165642Sbz		}
587165642Sbz	} else
588165642Sbz		bcopy(ifp->physaddr, &mac, sizeof(mac));
589164410Ssyrinx
590165642Sbz	if ((bif = bridge_new_bif(ifp->name, ifp->sysindex, mac)) == NULL)
591164410Ssyrinx		return (-1);
592164410Ssyrinx
593164410Ssyrinx	if (ifp->mib.ifmd_flags & IFF_RUNNING)
594164410Ssyrinx		bif->if_status = RowStatus_active;
595164410Ssyrinx	else
596164410Ssyrinx		bif->if_status = RowStatus_notInService;
597164410Ssyrinx
598164410Ssyrinx	/* Skip sending notifications if the interface was just created. */
599164410Ssyrinx	if (bridge_getinfo_bif(bif) < 0 ||
600164410Ssyrinx	    (bif->num_ports = bridge_getinfo_bif_ports(bif)) < 0 ||
601164410Ssyrinx	    (bif->num_addrs = bridge_getinfo_bif_addrs(bif)) < 0) {
602164410Ssyrinx		bridge_remove_bif(bif);
603164410Ssyrinx		return (-1);
604164410Ssyrinx	}
605164410Ssyrinx
606164410Ssyrinx	/* Check whether we are the default bridge interface. */
607164410Ssyrinx	if (strcmp(ifp->name, bridge_get_default_name()) == 0)
608164410Ssyrinx		bridge_set_default(bif);
609164410Ssyrinx
610164410Ssyrinx	return (0);
611164410Ssyrinx}
612164410Ssyrinx
613164410Ssyrinxvoid
614164410Ssyrinxbridge_ifs_dump(void)
615164410Ssyrinx{
616164410Ssyrinx	struct bridge_if *bif;
617164410Ssyrinx
618164410Ssyrinx	for (bif = bridge_first_bif(); bif != NULL;
619164410Ssyrinx		bif = bridge_next_bif(bif)) {
620164410Ssyrinx		syslog(LOG_ERR, "Bridge %s, index - %d", bif->bif_name,
621164410Ssyrinx		    bif->sysindex);
622164410Ssyrinx		bridge_ports_dump(bif);
623164410Ssyrinx		bridge_addrs_dump(bif);
624164410Ssyrinx	}
625164410Ssyrinx}
626164410Ssyrinx
627164410Ssyrinx/*
628164410Ssyrinx * RFC4188 specifics.
629164410Ssyrinx */
630164410Ssyrinxint
631164410Ssyrinxop_dot1d_base(struct snmp_context *ctx __unused, struct snmp_value *value,
632164410Ssyrinx	uint sub, uint iidx __unused, enum snmp_op op)
633164410Ssyrinx{
634164410Ssyrinx	struct bridge_if *bif;
635164410Ssyrinx
636164410Ssyrinx	if ((bif = bridge_get_default()) == NULL)
637164410Ssyrinx		return (SNMP_ERR_NOSUCHNAME);
638164410Ssyrinx
639164410Ssyrinx	if (time(NULL) - bif->entry_age > bridge_get_data_maxage() &&
640164410Ssyrinx	    bridge_update_bif(bif) <= 0) /* It was just deleted. */
641164410Ssyrinx		return (SNMP_ERR_NOSUCHNAME);
642164410Ssyrinx
643164410Ssyrinx	switch (op) {
644164410Ssyrinx	    case SNMP_OP_GET:
645164410Ssyrinx		switch (value->var.subs[sub - 1]) {
646164410Ssyrinx		    case LEAF_dot1dBaseBridgeAddress:
647165253Ssyrinx			return (string_get(value, bif->br_addr.octet,
648165253Ssyrinx			    ETHER_ADDR_LEN));
649164410Ssyrinx		    case LEAF_dot1dBaseNumPorts:
650164410Ssyrinx			value->v.integer = bif->num_ports;
651165253Ssyrinx			return (SNMP_ERR_NOERROR);
652164410Ssyrinx		    case LEAF_dot1dBaseType:
653164410Ssyrinx			value->v.integer = bif->br_type;
654165253Ssyrinx			return (SNMP_ERR_NOERROR);
655164410Ssyrinx		}
656165253Ssyrinx		abort();
657164410Ssyrinx
658164410Ssyrinx		case SNMP_OP_SET:
659165253Ssyrinx		    return (SNMP_ERR_NOT_WRITEABLE);
660164410Ssyrinx
661164410Ssyrinx		case SNMP_OP_GETNEXT:
662164410Ssyrinx		case SNMP_OP_ROLLBACK:
663164410Ssyrinx		case SNMP_OP_COMMIT:
664165253Ssyrinx		   break;
665164410Ssyrinx	}
666164410Ssyrinx
667165253Ssyrinx	abort();
668164410Ssyrinx}
669164410Ssyrinx
670164410Ssyrinxint
671165253Ssyrinxop_dot1d_stp(struct snmp_context *ctx, struct snmp_value *val, uint sub,
672165253Ssyrinx    uint iidx __unused, enum snmp_op op)
673164410Ssyrinx{
674164410Ssyrinx	struct bridge_if *bif;
675164410Ssyrinx
676164410Ssyrinx	if ((bif = bridge_get_default()) == NULL)
677164410Ssyrinx		return (SNMP_ERR_NOSUCHNAME);
678164410Ssyrinx
679164410Ssyrinx	if (time(NULL) - bif->entry_age > bridge_get_data_maxage() &&
680164410Ssyrinx	    bridge_update_bif(bif) <= 0) /* It was just deleted. */
681164410Ssyrinx		return (SNMP_ERR_NOSUCHNAME);
682164410Ssyrinx
683164410Ssyrinx	switch (op) {
684164410Ssyrinx	    case SNMP_OP_GET:
685165253Ssyrinx		switch (val->var.subs[sub - 1]) {
686164410Ssyrinx		    case LEAF_dot1dStpProtocolSpecification:
687165253Ssyrinx			val->v.integer = bif->prot_spec;
688165253Ssyrinx			return (SNMP_ERR_NOERROR);
689164410Ssyrinx
690164410Ssyrinx		    case LEAF_dot1dStpPriority:
691165253Ssyrinx			val->v.integer = bif->priority;
692165253Ssyrinx			return (SNMP_ERR_NOERROR);
693164410Ssyrinx
694164410Ssyrinx		    case LEAF_dot1dStpTimeSinceTopologyChange:
695164410Ssyrinx			if (bridge_get_time_since_tc(bif,
696165253Ssyrinx			    &(val->v.uint32)) < 0)
697164410Ssyrinx				return (SNMP_ERR_GENERR);
698165253Ssyrinx			return (SNMP_ERR_NOERROR);
699164410Ssyrinx
700164410Ssyrinx		    case LEAF_dot1dStpTopChanges:
701165253Ssyrinx			val->v.uint32 = bif->top_changes;
702165253Ssyrinx			return (SNMP_ERR_NOERROR);
703164410Ssyrinx
704164410Ssyrinx		    case LEAF_dot1dStpDesignatedRoot:
705165253Ssyrinx			return (string_get(val, bif->design_root,
706164410Ssyrinx			    SNMP_BRIDGE_ID_LEN));
707164410Ssyrinx
708164410Ssyrinx		    case LEAF_dot1dStpRootCost:
709165253Ssyrinx			val->v.integer = bif->root_cost;
710165253Ssyrinx			return (SNMP_ERR_NOERROR);
711164410Ssyrinx
712164410Ssyrinx		    case LEAF_dot1dStpRootPort:
713165253Ssyrinx			val->v.integer = bif->root_port;
714165253Ssyrinx			return (SNMP_ERR_NOERROR);
715164410Ssyrinx
716164410Ssyrinx		    case LEAF_dot1dStpMaxAge:
717165253Ssyrinx			val->v.integer = bif->max_age;
718165253Ssyrinx			return (SNMP_ERR_NOERROR);
719164410Ssyrinx
720164410Ssyrinx		    case LEAF_dot1dStpHelloTime:
721165253Ssyrinx			val->v.integer = bif->hello_time;
722165253Ssyrinx			return (SNMP_ERR_NOERROR);
723164410Ssyrinx
724164410Ssyrinx		    case LEAF_dot1dStpHoldTime:
725165253Ssyrinx			val->v.integer = bif->hold_time;
726165253Ssyrinx			return (SNMP_ERR_NOERROR);
727164410Ssyrinx
728164410Ssyrinx		    case LEAF_dot1dStpForwardDelay:
729165253Ssyrinx			val->v.integer = bif->fwd_delay;
730165253Ssyrinx			return (SNMP_ERR_NOERROR);
731164410Ssyrinx
732164410Ssyrinx		    case LEAF_dot1dStpBridgeMaxAge:
733165253Ssyrinx			val->v.integer = bif->bridge_max_age;
734165253Ssyrinx			return (SNMP_ERR_NOERROR);
735164410Ssyrinx
736164410Ssyrinx		    case LEAF_dot1dStpBridgeHelloTime:
737165253Ssyrinx			val->v.integer = bif->bridge_hello_time;
738165253Ssyrinx			return (SNMP_ERR_NOERROR);
739164410Ssyrinx
740164410Ssyrinx		    case LEAF_dot1dStpBridgeForwardDelay:
741165253Ssyrinx			val->v.integer = bif->bridge_fwd_delay;
742165253Ssyrinx			return (SNMP_ERR_NOERROR);
743165253Ssyrinx
744164997Ssyrinx		    case LEAF_dot1dStpVersion:
745165253Ssyrinx			val->v.integer = bif->stp_version;
746165253Ssyrinx			return (SNMP_ERR_NOERROR);
747165253Ssyrinx
748164997Ssyrinx		    case LEAF_dot1dStpTxHoldCount:
749165253Ssyrinx			val->v.integer = bif->tx_hold_count;
750165253Ssyrinx			return (SNMP_ERR_NOERROR);
751164410Ssyrinx		}
752165253Ssyrinx		abort();
753164410Ssyrinx
754164410Ssyrinx	    case SNMP_OP_GETNEXT:
755164410Ssyrinx		abort();
756164410Ssyrinx
757164410Ssyrinx	    case SNMP_OP_SET:
758165253Ssyrinx		switch (val->var.subs[sub - 1]) {
759164410Ssyrinx		    case LEAF_dot1dStpPriority:
760165253Ssyrinx			if (val->v.integer > SNMP_BRIDGE_MAX_PRIORITY ||
761165253Ssyrinx			    val->v.integer % 4096 != 0)
762165253Ssyrinx			    return (SNMP_ERR_WRONG_VALUE);
763165253Ssyrinx
764164410Ssyrinx			ctx->scratch->int1 = bif->priority;
765165253Ssyrinx			if (bridge_set_priority(bif, val->v.integer) < 0)
766165253Ssyrinx			    return (SNMP_ERR_GENERR);
767165253Ssyrinx			return (SNMP_ERR_NOERROR);
768164410Ssyrinx
769164410Ssyrinx		    case LEAF_dot1dStpBridgeMaxAge:
770165253Ssyrinx			if (val->v.integer < SNMP_BRIDGE_MIN_MAGE ||
771165253Ssyrinx			    val->v.integer > SNMP_BRIDGE_MAX_MAGE)
772165253Ssyrinx			    return (SNMP_ERR_WRONG_VALUE);
773165253Ssyrinx
774164410Ssyrinx			ctx->scratch->int1 = bif->bridge_max_age;
775165253Ssyrinx			if (bridge_set_maxage(bif, val->v.integer) < 0)
776165253Ssyrinx			    return (SNMP_ERR_GENERR);
777165253Ssyrinx			return (SNMP_ERR_NOERROR);
778164410Ssyrinx
779164410Ssyrinx		    case LEAF_dot1dStpBridgeHelloTime:
780165253Ssyrinx			if (val->v.integer < SNMP_BRIDGE_MIN_HTIME ||
781165253Ssyrinx			    val->v.integer > SNMP_BRIDGE_MAX_HTIME)
782165253Ssyrinx			    return (SNMP_ERR_WRONG_VALUE);
783165253Ssyrinx
784164410Ssyrinx			ctx->scratch->int1 = bif->bridge_hello_time;
785165253Ssyrinx			if (bridge_set_hello_time(bif, val->v.integer) < 0)
786165253Ssyrinx			    return (SNMP_ERR_GENERR);
787165253Ssyrinx			return (SNMP_ERR_NOERROR);
788164410Ssyrinx
789164410Ssyrinx		    case LEAF_dot1dStpBridgeForwardDelay:
790165253Ssyrinx			if (val->v.integer < SNMP_BRIDGE_MIN_FDELAY ||
791165253Ssyrinx			    val->v.integer > SNMP_BRIDGE_MAX_FDELAY)
792165253Ssyrinx			    return (SNMP_ERR_WRONG_VALUE);
793165253Ssyrinx
794164410Ssyrinx			ctx->scratch->int1 = bif->bridge_fwd_delay;
795165253Ssyrinx			if (bridge_set_forward_delay(bif, val->v.integer) < 0)
796165253Ssyrinx			    return (SNMP_ERR_GENERR);
797165253Ssyrinx			return (SNMP_ERR_NOERROR);
798164410Ssyrinx
799164997Ssyrinx		    case LEAF_dot1dStpVersion:
800165253Ssyrinx			if (val->v.integer != dot1dStpVersion_stpCompatible &&
801165253Ssyrinx			    val->v.integer != dot1dStpVersion_rstp)
802165253Ssyrinx			    return (SNMP_ERR_WRONG_VALUE);
803165253Ssyrinx
804164997Ssyrinx			ctx->scratch->int1 = bif->stp_version;
805165253Ssyrinx			if (bridge_set_stp_version(bif, val->v.integer) < 0)
806165253Ssyrinx			    return (SNMP_ERR_GENERR);
807165253Ssyrinx			return (SNMP_ERR_NOERROR);
808164997Ssyrinx
809164997Ssyrinx		    case LEAF_dot1dStpTxHoldCount:
810165253Ssyrinx			if (val->v.integer < SNMP_BRIDGE_MIN_TXHC ||
811165253Ssyrinx			    val->v.integer > SNMP_BRIDGE_MAX_TXHC)
812165253Ssyrinx			    return (SNMP_ERR_WRONG_VALUE);
813165253Ssyrinx
814164997Ssyrinx			ctx->scratch->int1 = bif->tx_hold_count;
815165253Ssyrinx			if (bridge_set_tx_hold_count(bif, val->v.integer) < 0)
816165253Ssyrinx			    return (SNMP_ERR_GENERR);
817165253Ssyrinx			return (SNMP_ERR_NOERROR);
818164997Ssyrinx
819164410Ssyrinx		    case LEAF_dot1dStpProtocolSpecification:
820164410Ssyrinx		    case LEAF_dot1dStpTimeSinceTopologyChange:
821164410Ssyrinx		    case LEAF_dot1dStpTopChanges:
822164410Ssyrinx		    case LEAF_dot1dStpDesignatedRoot:
823164410Ssyrinx		    case LEAF_dot1dStpRootCost:
824164410Ssyrinx		    case LEAF_dot1dStpRootPort:
825164410Ssyrinx		    case LEAF_dot1dStpMaxAge:
826164410Ssyrinx		    case LEAF_dot1dStpHelloTime:
827164410Ssyrinx		    case LEAF_dot1dStpHoldTime:
828164410Ssyrinx		    case LEAF_dot1dStpForwardDelay:
829164410Ssyrinx			return (SNMP_ERR_NOT_WRITEABLE);
830164410Ssyrinx		}
831165253Ssyrinx		abort();
832164410Ssyrinx
833164410Ssyrinx	    case SNMP_OP_ROLLBACK:
834165253Ssyrinx		switch (val->var.subs[sub - 1]) {
835164410Ssyrinx		    case LEAF_dot1dStpPriority:
836164997Ssyrinx			bridge_set_priority(bif, ctx->scratch->int1);
837164410Ssyrinx			break;
838164410Ssyrinx		    case LEAF_dot1dStpBridgeMaxAge:
839164997Ssyrinx			bridge_set_maxage(bif, ctx->scratch->int1);
840164410Ssyrinx			break;
841164410Ssyrinx		    case LEAF_dot1dStpBridgeHelloTime:
842164997Ssyrinx			bridge_set_hello_time(bif, ctx->scratch->int1);
843164410Ssyrinx			break;
844164410Ssyrinx		    case LEAF_dot1dStpBridgeForwardDelay:
845164997Ssyrinx			bridge_set_forward_delay(bif, ctx->scratch->int1);
846164410Ssyrinx			break;
847164997Ssyrinx		    case LEAF_dot1dStpVersion:
848164997Ssyrinx			bridge_set_stp_version(bif, ctx->scratch->int1);
849164997Ssyrinx			break;
850164997Ssyrinx		    case LEAF_dot1dStpTxHoldCount:
851164997Ssyrinx			bridge_set_tx_hold_count(bif, ctx->scratch->int1);
852164997Ssyrinx			break;
853164410Ssyrinx		}
854164410Ssyrinx		return (SNMP_ERR_NOERROR);
855164410Ssyrinx
856164410Ssyrinx	    case SNMP_OP_COMMIT:
857164410Ssyrinx		return (SNMP_ERR_NOERROR);
858164410Ssyrinx	}
859164410Ssyrinx
860165253Ssyrinx	abort();
861164410Ssyrinx}
862164410Ssyrinx
863164410Ssyrinxint
864164410Ssyrinxop_dot1d_tp(struct snmp_context *ctx, struct snmp_value *value,
865164410Ssyrinx	uint sub, uint iidx __unused, enum snmp_op op)
866164410Ssyrinx{
867164410Ssyrinx	struct bridge_if *bif;
868164410Ssyrinx
869164410Ssyrinx	if ((bif = bridge_get_default()) == NULL)
870164410Ssyrinx		return (SNMP_ERR_NOSUCHNAME);
871164410Ssyrinx
872164410Ssyrinx	if (time(NULL) - bif->entry_age > bridge_get_data_maxage() &&
873164410Ssyrinx	    bridge_update_bif(bif) <= 0) /* It was just deleted. */
874164410Ssyrinx		return (SNMP_ERR_NOSUCHNAME);
875164410Ssyrinx
876164410Ssyrinx	switch (op) {
877164410Ssyrinx	    case SNMP_OP_GET:
878164410Ssyrinx		switch (value->var.subs[sub - 1]) {
879164410Ssyrinx		    case LEAF_dot1dTpLearnedEntryDiscards:
880164410Ssyrinx			value->v.uint32 = bif->lrnt_drops;
881165253Ssyrinx			return (SNMP_ERR_NOERROR);
882164410Ssyrinx		    case LEAF_dot1dTpAgingTime:
883164410Ssyrinx			value->v.integer = bif->age_time;
884165253Ssyrinx			return (SNMP_ERR_NOERROR);
885164410Ssyrinx		}
886165253Ssyrinx		abort();
887164410Ssyrinx
888164410Ssyrinx	    case SNMP_OP_GETNEXT:
889164410Ssyrinx		abort();
890164410Ssyrinx
891164410Ssyrinx	    case SNMP_OP_SET:
892165253Ssyrinx		switch (value->var.subs[sub - 1]) {
893165253Ssyrinx		    case LEAF_dot1dTpLearnedEntryDiscards:
894165253Ssyrinx			return (SNMP_ERR_NOT_WRITEABLE);
895165253Ssyrinx
896165253Ssyrinx		    case LEAF_dot1dTpAgingTime:
897165253Ssyrinx			if (value->v.integer < SNMP_BRIDGE_MIN_AGE_TIME ||
898165253Ssyrinx			    value->v.integer > SNMP_BRIDGE_MAX_AGE_TIME)
899165253Ssyrinx			    return (SNMP_ERR_WRONG_VALUE);
900165253Ssyrinx
901165253Ssyrinx			ctx->scratch->int1 = bif->age_time;
902165253Ssyrinx			if (bridge_set_aging_time(bif, value->v.integer) < 0)
903165253Ssyrinx			    return (SNMP_ERR_GENERR);
904165253Ssyrinx			return (SNMP_ERR_NOERROR);
905164410Ssyrinx		}
906165253Ssyrinx		abort();
907164410Ssyrinx
908164410Ssyrinx	    case SNMP_OP_ROLLBACK:
909164410Ssyrinx		if (value->var.subs[sub - 1] == LEAF_dot1dTpAgingTime)
910164997Ssyrinx		    bridge_set_aging_time(bif, ctx->scratch->int1);
911164410Ssyrinx		return (SNMP_ERR_NOERROR);
912164410Ssyrinx
913164410Ssyrinx	    case SNMP_OP_COMMIT:
914164410Ssyrinx		return (SNMP_ERR_NOERROR);
915164410Ssyrinx	}
916164410Ssyrinx
917165253Ssyrinx	abort();
918164410Ssyrinx}
919164410Ssyrinx
920164410Ssyrinx/*
921164410Ssyrinx * Private BEGEMOT-BRIDGE-MIB specifics.
922164410Ssyrinx */
923164410Ssyrinx
924164410Ssyrinx/*
925164410Ssyrinx * Get the bridge name from an OID index.
926164410Ssyrinx */
927164410Ssyrinxstatic char *
928164410Ssyrinxbridge_name_index_get(const struct asn_oid *oid, uint sub, char *b_name)
929164410Ssyrinx{
930164410Ssyrinx	uint i;
931164410Ssyrinx
932164410Ssyrinx	if (oid->len - sub != oid->subs[sub] + 1 || oid->subs[sub] >= IFNAMSIZ)
933164410Ssyrinx		return (NULL);
934164410Ssyrinx
935164410Ssyrinx	for (i = 0; i < oid->subs[sub]; i++)
936164410Ssyrinx		b_name[i] = oid->subs[sub + i + 1];
937164410Ssyrinx	b_name[i] = '\0';
938164410Ssyrinx
939164410Ssyrinx	return (b_name);
940164410Ssyrinx}
941164410Ssyrinx
942164410Ssyrinxstatic void
943164410Ssyrinxbridge_if_index_append(struct asn_oid *oid, uint sub,
944164410Ssyrinx	const struct bridge_if *bif)
945164410Ssyrinx{
946164410Ssyrinx	uint i;
947164410Ssyrinx
948164410Ssyrinx	oid->len = sub + strlen(bif->bif_name) + 1;
949164410Ssyrinx	oid->subs[sub] = strlen(bif->bif_name);
950164410Ssyrinx
951164410Ssyrinx	for (i = 1; i <= strlen(bif->bif_name); i++)
952164410Ssyrinx		oid->subs[sub + i] = bif->bif_name[i - 1];
953164410Ssyrinx}
954164410Ssyrinx
955164410Ssyrinxstatic struct bridge_if *
956164410Ssyrinxbridge_if_index_get(const struct asn_oid *oid, uint sub)
957164410Ssyrinx{
958164410Ssyrinx	uint i;
959164410Ssyrinx	char bif_name[IFNAMSIZ];
960164410Ssyrinx
961164410Ssyrinx	if (oid->len - sub != oid->subs[sub] + 1 || oid->subs[sub] >= IFNAMSIZ)
962164410Ssyrinx		return (NULL);
963164410Ssyrinx
964164410Ssyrinx	for (i = 0; i < oid->subs[sub]; i++)
965164410Ssyrinx		bif_name[i] = oid->subs[sub + i + 1];
966164410Ssyrinx	bif_name[i] = '\0';
967164410Ssyrinx
968164410Ssyrinx	return (bridge_if_find_ifname(bif_name));
969164410Ssyrinx}
970164410Ssyrinx
971164410Ssyrinxstatic struct bridge_if *
972164410Ssyrinxbridge_if_index_getnext(const struct asn_oid *oid, uint sub)
973164410Ssyrinx{
974164410Ssyrinx	uint i;
975164410Ssyrinx	char bif_name[IFNAMSIZ];
976164410Ssyrinx	struct bridge_if *bif;
977164410Ssyrinx
978164410Ssyrinx	if (oid->len - sub == 0)
979164410Ssyrinx		return (bridge_first_bif());
980164410Ssyrinx
981164410Ssyrinx	if (oid->len - sub != oid->subs[sub] + 1 || oid->subs[sub] >= IFNAMSIZ)
982164410Ssyrinx		return (NULL);
983164410Ssyrinx
984164410Ssyrinx	for (i = 0; i < oid->subs[sub]; i++)
985164410Ssyrinx		bif_name[i] = oid->subs[sub + i + 1];
986164410Ssyrinx	bif_name[i] = '\0';
987164410Ssyrinx
988164410Ssyrinx	if ((bif = bridge_if_find_ifname(bif_name)) == NULL)
989164410Ssyrinx		return (NULL);
990164410Ssyrinx
991164410Ssyrinx	return (bridge_next_bif(bif));
992164410Ssyrinx}
993164410Ssyrinx
994164410Ssyrinxstatic int
995164410Ssyrinxbridge_set_if_status(struct snmp_context *ctx,
996164410Ssyrinx	struct snmp_value *val, uint sub)
997164410Ssyrinx{
998164410Ssyrinx	struct bridge_if *bif;
999164410Ssyrinx	char bif_name[IFNAMSIZ];
1000164410Ssyrinx
1001164410Ssyrinx	bif = bridge_if_index_get(&val->var, sub);
1002164410Ssyrinx
1003164410Ssyrinx	switch (val->v.integer) {
1004164410Ssyrinx	    case RowStatus_active:
1005164410Ssyrinx		if (bif == NULL)
1006164410Ssyrinx		    return (SNMP_ERR_INCONS_VALUE);
1007164410Ssyrinx
1008164410Ssyrinx		ctx->scratch->int1 = bif->if_status;
1009164410Ssyrinx
1010164410Ssyrinx		switch (bif->if_status) {
1011164410Ssyrinx		    case RowStatus_active:
1012164410Ssyrinx			return (SNMP_ERR_NOERROR);
1013164410Ssyrinx		    case RowStatus_notInService:
1014164410Ssyrinx			if (bridge_set_if_up(bif->bif_name, 1) < 0)
1015164410Ssyrinx			    return (SNMP_ERR_GENERR);
1016164410Ssyrinx			return (SNMP_ERR_NOERROR);
1017164410Ssyrinx		    default:
1018164410Ssyrinx			break;
1019164410Ssyrinx		}
1020164410Ssyrinx		return (SNMP_ERR_INCONS_VALUE);
1021164410Ssyrinx
1022164410Ssyrinx	    case RowStatus_notInService:
1023164410Ssyrinx		if (bif == NULL)
1024164410Ssyrinx		    return (SNMP_ERR_INCONS_VALUE);
1025164410Ssyrinx
1026164410Ssyrinx		ctx->scratch->int1 = bif->if_status;
1027164410Ssyrinx
1028164410Ssyrinx		switch (bif->if_status) {
1029164410Ssyrinx		    case RowStatus_active:
1030164410Ssyrinx			if (bridge_set_if_up(bif->bif_name, 1) < 0)
1031164410Ssyrinx			    return (SNMP_ERR_GENERR);
1032164410Ssyrinx			return (SNMP_ERR_NOERROR);
1033164410Ssyrinx		    case RowStatus_notInService:
1034164410Ssyrinx			return (SNMP_ERR_NOERROR);
1035164410Ssyrinx		    default:
1036164410Ssyrinx			break;
1037164410Ssyrinx		}
1038164410Ssyrinx		return (SNMP_ERR_INCONS_VALUE);
1039164410Ssyrinx
1040164410Ssyrinx	    case RowStatus_notReady:
1041164410Ssyrinx		return (SNMP_ERR_INCONS_VALUE);
1042164410Ssyrinx
1043164410Ssyrinx	    case RowStatus_createAndGo:
1044164410Ssyrinx		if (bif != NULL)
1045164410Ssyrinx		    return (SNMP_ERR_INCONS_VALUE);
1046164410Ssyrinx
1047164410Ssyrinx		ctx->scratch->int1 = RowStatus_destroy;
1048164410Ssyrinx
1049164410Ssyrinx		if (bridge_name_index_get(&val->var, sub, bif_name) == NULL)
1050164410Ssyrinx		    return (SNMP_ERR_BADVALUE);
1051164410Ssyrinx		if (bridge_if_create(bif_name, 1) < 0)
1052164410Ssyrinx		    return (SNMP_ERR_GENERR);
1053164410Ssyrinx		return (SNMP_ERR_NOERROR);
1054164410Ssyrinx
1055164410Ssyrinx	    case RowStatus_createAndWait:
1056164410Ssyrinx		if (bif != NULL)
1057164410Ssyrinx		    return (SNMP_ERR_INCONS_VALUE);
1058164410Ssyrinx
1059164410Ssyrinx		if (bridge_name_index_get(&val->var, sub, bif_name) == NULL)
1060164410Ssyrinx		    return (SNMP_ERR_BADVALUE);
1061164410Ssyrinx
1062164410Ssyrinx		ctx->scratch->int1 = RowStatus_destroy;
1063164410Ssyrinx
1064164410Ssyrinx		if (bridge_if_create(bif_name, 0) < 0)
1065164410Ssyrinx		    return (SNMP_ERR_GENERR);
1066164410Ssyrinx		return (SNMP_ERR_NOERROR);
1067164410Ssyrinx
1068164410Ssyrinx	    case RowStatus_destroy:
1069164410Ssyrinx		if (bif == NULL)
1070164410Ssyrinx		    return (SNMP_ERR_NOSUCHNAME);
1071164410Ssyrinx
1072164410Ssyrinx		ctx->scratch->int1 = bif->if_status;
1073164410Ssyrinx		bif->if_status = RowStatus_destroy;
1074164410Ssyrinx	}
1075164410Ssyrinx
1076164410Ssyrinx	return (SNMP_ERR_NOERROR);
1077164410Ssyrinx}
1078164410Ssyrinx
1079164410Ssyrinxstatic int
1080164410Ssyrinxbridge_rollback_if_status(struct snmp_context *ctx,
1081164410Ssyrinx	struct snmp_value *val, uint sub)
1082164410Ssyrinx{
1083164410Ssyrinx	struct bridge_if *bif;
1084164410Ssyrinx
1085164410Ssyrinx	if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1086164410Ssyrinx		return (SNMP_ERR_GENERR);
1087164410Ssyrinx
1088164410Ssyrinx	switch (ctx->scratch->int1) {
1089164410Ssyrinx		case RowStatus_destroy:
1090164410Ssyrinx			bridge_if_destroy(bif);
1091164410Ssyrinx			return (SNMP_ERR_NOERROR);
1092164410Ssyrinx
1093164410Ssyrinx		case RowStatus_notInService:
1094164410Ssyrinx			if (bif->if_status != ctx->scratch->int1)
1095164410Ssyrinx				bridge_set_if_up(bif->bif_name, 0);
1096164410Ssyrinx			bif->if_status = RowStatus_notInService;
1097164410Ssyrinx			return (SNMP_ERR_NOERROR);
1098164410Ssyrinx
1099164410Ssyrinx		case RowStatus_active:
1100164410Ssyrinx			if (bif->if_status != ctx->scratch->int1)
1101164410Ssyrinx				bridge_set_if_up(bif->bif_name, 1);
1102164410Ssyrinx			bif->if_status = RowStatus_active;
1103164410Ssyrinx			return (SNMP_ERR_NOERROR);
1104164410Ssyrinx	}
1105164410Ssyrinx
1106164410Ssyrinx	abort();
1107164410Ssyrinx}
1108164410Ssyrinx
1109164410Ssyrinxstatic int
1110164410Ssyrinxbridge_commit_if_status(struct snmp_value *val, uint sub)
1111164410Ssyrinx{
1112164410Ssyrinx	struct bridge_if *bif;
1113164410Ssyrinx
1114164410Ssyrinx	if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1115164410Ssyrinx		return (SNMP_ERR_GENERR);
1116164410Ssyrinx
1117164410Ssyrinx	if (bif->if_status == RowStatus_destroy &&
1118164410Ssyrinx	    bridge_if_destroy(bif) < 0)
1119164410Ssyrinx		return (SNMP_ERR_COMMIT_FAILED);
1120164410Ssyrinx
1121164410Ssyrinx	return (SNMP_ERR_NOERROR);
1122164410Ssyrinx}
1123164410Ssyrinx
1124164410Ssyrinxint
1125164410Ssyrinxop_begemot_base_bridge(struct snmp_context *ctx, struct snmp_value *val,
1126164410Ssyrinx	uint sub, uint iidx __unused, enum snmp_op op)
1127164410Ssyrinx{
1128165046Ssyrinx	struct bridge_if *bif;
1129164410Ssyrinx
1130164410Ssyrinx	if (time(NULL) - bridge_list_age > bridge_get_data_maxage())
1131164410Ssyrinx		bridge_update_all_ifs();
1132164410Ssyrinx
1133164410Ssyrinx	switch (op) {
1134164410Ssyrinx	    case SNMP_OP_GET:
1135164410Ssyrinx		if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1136164410Ssyrinx		    return (SNMP_ERR_NOSUCHNAME);
1137165253Ssyrinx		goto get;
1138164410Ssyrinx
1139164410Ssyrinx	    case SNMP_OP_GETNEXT:
1140164410Ssyrinx		if ((bif = bridge_if_index_getnext(&val->var, sub)) == NULL)
1141164410Ssyrinx		    return (SNMP_ERR_NOSUCHNAME);
1142164410Ssyrinx		bridge_if_index_append(&val->var, sub, bif);
1143165253Ssyrinx		goto get;
1144164410Ssyrinx
1145164410Ssyrinx	    case SNMP_OP_SET:
1146164410Ssyrinx		switch (val->var.subs[sub - 1]) {
1147164410Ssyrinx		    case LEAF_begemotBridgeBaseStatus:
1148164410Ssyrinx			return (bridge_set_if_status(ctx, val, sub));
1149164410Ssyrinx		    case LEAF_begemotBridgeBaseName:
1150164410Ssyrinx		    case LEAF_begemotBridgeBaseAddress:
1151164410Ssyrinx		    case LEAF_begemotBridgeBaseNumPorts:
1152164410Ssyrinx		    case LEAF_begemotBridgeBaseType:
1153164410Ssyrinx			return (SNMP_ERR_NOT_WRITEABLE);
1154164410Ssyrinx		}
1155164410Ssyrinx		abort();
1156164410Ssyrinx
1157164410Ssyrinx	    case SNMP_OP_ROLLBACK:
1158164410Ssyrinx		return (bridge_rollback_if_status(ctx, val, sub));
1159165046Ssyrinx
1160164410Ssyrinx	    case SNMP_OP_COMMIT:
1161164410Ssyrinx		return (bridge_commit_if_status(val, sub));
1162164410Ssyrinx	}
1163165253Ssyrinx	abort();
1164164410Ssyrinx
1165165253Ssyrinxget:
1166164410Ssyrinx	switch (val->var.subs[sub - 1]) {
1167164410Ssyrinx	    case LEAF_begemotBridgeBaseName:
1168165253Ssyrinx		return (string_get(val, bif->bif_name, -1));
1169164410Ssyrinx
1170164410Ssyrinx	    case LEAF_begemotBridgeBaseAddress:
1171165253Ssyrinx		return (string_get(val, bif->br_addr.octet, ETHER_ADDR_LEN));
1172164410Ssyrinx
1173164410Ssyrinx	    case LEAF_begemotBridgeBaseNumPorts:
1174164410Ssyrinx		val->v.integer = bif->num_ports;
1175165253Ssyrinx		return (SNMP_ERR_NOERROR);
1176164410Ssyrinx
1177164410Ssyrinx	    case LEAF_begemotBridgeBaseType:
1178164410Ssyrinx		val->v.integer = bif->br_type;
1179165253Ssyrinx		return (SNMP_ERR_NOERROR);
1180164410Ssyrinx
1181164410Ssyrinx	    case LEAF_begemotBridgeBaseStatus:
1182164410Ssyrinx		val->v.integer = bif->if_status;
1183165253Ssyrinx		return (SNMP_ERR_NOERROR);
1184164410Ssyrinx	}
1185164410Ssyrinx
1186165253Ssyrinx	abort();
1187164410Ssyrinx}
1188164410Ssyrinx
1189164410Ssyrinxint
1190164410Ssyrinxop_begemot_stp(struct snmp_context *ctx, struct snmp_value *val,
1191164410Ssyrinx	uint sub, uint iidx __unused, enum snmp_op op)
1192164410Ssyrinx{
1193165046Ssyrinx	struct bridge_if *bif;
1194164410Ssyrinx
1195164410Ssyrinx	if (time(NULL) - bridge_list_age > bridge_get_data_maxage())
1196164410Ssyrinx		bridge_update_all_ifs();
1197164410Ssyrinx
1198164410Ssyrinx	switch (op) {
1199164410Ssyrinx	    case SNMP_OP_GET:
1200164410Ssyrinx		if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1201164410Ssyrinx		    return (SNMP_ERR_NOSUCHNAME);
1202165253Ssyrinx		goto get;
1203164410Ssyrinx
1204164410Ssyrinx	    case SNMP_OP_GETNEXT:
1205164410Ssyrinx		if ((bif = bridge_if_index_getnext(&val->var, sub)) == NULL)
1206164410Ssyrinx		    return (SNMP_ERR_NOSUCHNAME);
1207164410Ssyrinx		bridge_if_index_append(&val->var, sub, bif);
1208165253Ssyrinx		goto get;
1209164410Ssyrinx
1210164410Ssyrinx	    case SNMP_OP_SET:
1211164410Ssyrinx		if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1212164410Ssyrinx		    return (SNMP_ERR_NOSUCHNAME);
1213164410Ssyrinx
1214164410Ssyrinx		switch (val->var.subs[sub - 1]) {
1215164410Ssyrinx		    case LEAF_begemotBridgeStpPriority:
1216165253Ssyrinx			if (val->v.integer > SNMP_BRIDGE_MAX_PRIORITY ||
1217165253Ssyrinx			    val->v.integer % 4096 != 0)
1218165253Ssyrinx			    return (SNMP_ERR_WRONG_VALUE);
1219165253Ssyrinx
1220164410Ssyrinx			ctx->scratch->int1 = bif->priority;
1221165253Ssyrinx			if (bridge_set_priority(bif, val->v.integer) < 0)
1222165253Ssyrinx			    return (SNMP_ERR_GENERR);
1223165253Ssyrinx			return (SNMP_ERR_NOERROR);
1224164410Ssyrinx
1225164410Ssyrinx		    case LEAF_begemotBridgeStpBridgeMaxAge:
1226165253Ssyrinx			if (val->v.integer < SNMP_BRIDGE_MIN_MAGE ||
1227165253Ssyrinx			    val->v.integer > SNMP_BRIDGE_MAX_MAGE)
1228165253Ssyrinx			    return (SNMP_ERR_WRONG_VALUE);
1229165253Ssyrinx
1230164410Ssyrinx			ctx->scratch->int1 = bif->bridge_max_age;
1231165253Ssyrinx			if (bridge_set_maxage(bif, val->v.integer) < 0)
1232165253Ssyrinx			    return (SNMP_ERR_GENERR);
1233165253Ssyrinx			return (SNMP_ERR_NOERROR);
1234164410Ssyrinx
1235164410Ssyrinx		    case LEAF_begemotBridgeStpBridgeHelloTime:
1236165253Ssyrinx			if (val->v.integer < SNMP_BRIDGE_MIN_HTIME ||
1237165253Ssyrinx			    val->v.integer > SNMP_BRIDGE_MAX_HTIME)
1238165253Ssyrinx			    return (SNMP_ERR_WRONG_VALUE);
1239165253Ssyrinx
1240164410Ssyrinx			ctx->scratch->int1 = bif->bridge_hello_time;
1241165253Ssyrinx			if (bridge_set_hello_time(bif, val->v.integer) < 0)
1242165253Ssyrinx			    return (SNMP_ERR_GENERR);
1243165253Ssyrinx			return (SNMP_ERR_NOERROR);
1244164410Ssyrinx
1245164410Ssyrinx		    case LEAF_begemotBridgeStpBridgeForwardDelay:
1246165253Ssyrinx			if (val->v.integer < SNMP_BRIDGE_MIN_FDELAY ||
1247165253Ssyrinx			    val->v.integer > SNMP_BRIDGE_MAX_FDELAY)
1248165253Ssyrinx			    return (SNMP_ERR_WRONG_VALUE);
1249165253Ssyrinx
1250164410Ssyrinx			ctx->scratch->int1 = bif->bridge_fwd_delay;
1251165253Ssyrinx			if (bridge_set_forward_delay(bif, val->v.integer) < 0)
1252165253Ssyrinx			    return (SNMP_ERR_GENERR);
1253165253Ssyrinx			return (SNMP_ERR_NOERROR);
1254164410Ssyrinx
1255164997Ssyrinx		    case LEAF_begemotBridgeStpVersion:
1256165253Ssyrinx			if (val->v.integer !=
1257165253Ssyrinx			    begemotBridgeStpVersion_stpCompatible &&
1258165253Ssyrinx			    val->v.integer != begemotBridgeStpVersion_rstp)
1259165253Ssyrinx			    return (SNMP_ERR_WRONG_VALUE);
1260165253Ssyrinx
1261164997Ssyrinx			ctx->scratch->int1 = bif->stp_version;
1262165253Ssyrinx			if (bridge_set_stp_version(bif, val->v.integer) < 0)
1263165253Ssyrinx			    return (SNMP_ERR_GENERR);
1264165253Ssyrinx			return (SNMP_ERR_NOERROR);
1265164997Ssyrinx
1266164997Ssyrinx		    case LEAF_begemotBridgeStpTxHoldCount:
1267165253Ssyrinx			if (val->v.integer < SNMP_BRIDGE_MIN_TXHC ||
1268165253Ssyrinx			    val->v.integer > SNMP_BRIDGE_MAX_TXHC)
1269165253Ssyrinx			    return (SNMP_ERR_WRONG_VALUE);
1270165253Ssyrinx
1271164997Ssyrinx			ctx->scratch->int1 = bif->tx_hold_count;
1272165253Ssyrinx			if (bridge_set_tx_hold_count(bif, val->v.integer) < 0)
1273165253Ssyrinx			    return (SNMP_ERR_GENERR);
1274165253Ssyrinx			return (SNMP_ERR_NOERROR);
1275164997Ssyrinx
1276164410Ssyrinx		    case LEAF_begemotBridgeStpProtocolSpecification:
1277164410Ssyrinx		    case LEAF_begemotBridgeStpTimeSinceTopologyChange:
1278164410Ssyrinx		    case LEAF_begemotBridgeStpTopChanges:
1279164410Ssyrinx		    case LEAF_begemotBridgeStpDesignatedRoot:
1280164410Ssyrinx		    case LEAF_begemotBridgeStpRootCost:
1281164410Ssyrinx		    case LEAF_begemotBridgeStpRootPort:
1282164410Ssyrinx		    case LEAF_begemotBridgeStpMaxAge:
1283164410Ssyrinx		    case LEAF_begemotBridgeStpHelloTime:
1284164410Ssyrinx		    case LEAF_begemotBridgeStpHoldTime:
1285164410Ssyrinx		    case LEAF_begemotBridgeStpForwardDelay:
1286164410Ssyrinx			return (SNMP_ERR_NOT_WRITEABLE);
1287164410Ssyrinx		}
1288165253Ssyrinx		abort();
1289164410Ssyrinx
1290164410Ssyrinx	    case SNMP_OP_ROLLBACK:
1291164410Ssyrinx		if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1292164410Ssyrinx		    return (SNMP_ERR_NOSUCHNAME);
1293164410Ssyrinx
1294164410Ssyrinx		switch (val->var.subs[sub - 1]) {
1295164410Ssyrinx		    case LEAF_begemotBridgeStpPriority:
1296164410Ssyrinx			bridge_set_priority(bif, ctx->scratch->int1);
1297164410Ssyrinx			break;
1298164410Ssyrinx
1299164410Ssyrinx		    case LEAF_begemotBridgeStpBridgeMaxAge:
1300164410Ssyrinx			bridge_set_maxage(bif, ctx->scratch->int1);
1301164410Ssyrinx			break;
1302164410Ssyrinx
1303164410Ssyrinx		    case LEAF_begemotBridgeStpBridgeHelloTime:
1304164410Ssyrinx			bridge_set_hello_time(bif, ctx->scratch->int1);
1305164410Ssyrinx			break;
1306164410Ssyrinx
1307164410Ssyrinx		    case LEAF_begemotBridgeStpBridgeForwardDelay:
1308164410Ssyrinx			bridge_set_forward_delay(bif, ctx->scratch->int1);
1309164410Ssyrinx			break;
1310164997Ssyrinx
1311164997Ssyrinx		    case LEAF_begemotBridgeStpVersion:
1312164997Ssyrinx			bridge_set_stp_version(bif, ctx->scratch->int1);
1313164997Ssyrinx			break;
1314164997Ssyrinx
1315164997Ssyrinx		    case LEAF_begemotBridgeStpTxHoldCount:
1316164997Ssyrinx			bridge_set_tx_hold_count(bif, ctx->scratch->int1);
1317164997Ssyrinx			break;
1318164410Ssyrinx		}
1319164410Ssyrinx		return (SNMP_ERR_NOERROR);
1320164410Ssyrinx
1321164410Ssyrinx	    case SNMP_OP_COMMIT:
1322164410Ssyrinx		return (SNMP_ERR_NOERROR);
1323164410Ssyrinx	}
1324165253Ssyrinx	abort();
1325164410Ssyrinx
1326165253Ssyrinxget:
1327164410Ssyrinx	switch (val->var.subs[sub - 1]) {
1328164410Ssyrinx	    case LEAF_begemotBridgeStpProtocolSpecification:
1329164410Ssyrinx		val->v.integer = bif->prot_spec;
1330165253Ssyrinx		return (SNMP_ERR_NOERROR);
1331164410Ssyrinx
1332164410Ssyrinx	    case LEAF_begemotBridgeStpPriority:
1333164410Ssyrinx		val->v.integer = bif->priority;
1334165253Ssyrinx		return (SNMP_ERR_NOERROR);
1335164410Ssyrinx
1336164410Ssyrinx	    case LEAF_begemotBridgeStpTimeSinceTopologyChange:
1337164410Ssyrinx		if (bridge_get_time_since_tc(bif, &(val->v.uint32)) < 0)
1338164410Ssyrinx		    return (SNMP_ERR_GENERR);
1339165253Ssyrinx		return (SNMP_ERR_NOERROR);
1340164410Ssyrinx
1341164410Ssyrinx	    case LEAF_begemotBridgeStpTopChanges:
1342164410Ssyrinx		val->v.uint32 = bif->top_changes;
1343165253Ssyrinx		return (SNMP_ERR_NOERROR);
1344164410Ssyrinx
1345164410Ssyrinx	    case LEAF_begemotBridgeStpDesignatedRoot:
1346165253Ssyrinx		return (string_get(val, bif->design_root, SNMP_BRIDGE_ID_LEN));
1347164410Ssyrinx
1348164410Ssyrinx	    case LEAF_begemotBridgeStpRootCost:
1349164410Ssyrinx		val->v.integer = bif->root_cost;
1350165253Ssyrinx		return (SNMP_ERR_NOERROR);
1351164410Ssyrinx
1352164410Ssyrinx	    case LEAF_begemotBridgeStpRootPort:
1353164410Ssyrinx		val->v.integer = bif->root_port;
1354165253Ssyrinx		return (SNMP_ERR_NOERROR);
1355164410Ssyrinx
1356164410Ssyrinx	    case LEAF_begemotBridgeStpMaxAge:
1357164410Ssyrinx		val->v.integer = bif->max_age;
1358165253Ssyrinx		return (SNMP_ERR_NOERROR);
1359164410Ssyrinx
1360164410Ssyrinx	    case LEAF_begemotBridgeStpHelloTime:
1361164410Ssyrinx		val->v.integer = bif->hello_time;
1362165253Ssyrinx		return (SNMP_ERR_NOERROR);
1363164410Ssyrinx
1364164410Ssyrinx	    case LEAF_begemotBridgeStpHoldTime:
1365164410Ssyrinx		val->v.integer = bif->hold_time;
1366165253Ssyrinx		return (SNMP_ERR_NOERROR);
1367164410Ssyrinx
1368164410Ssyrinx	    case LEAF_begemotBridgeStpForwardDelay:
1369164410Ssyrinx		val->v.integer = bif->fwd_delay;
1370165253Ssyrinx		return (SNMP_ERR_NOERROR);
1371164410Ssyrinx
1372164410Ssyrinx	    case LEAF_begemotBridgeStpBridgeMaxAge:
1373164410Ssyrinx		val->v.integer = bif->bridge_max_age;
1374165253Ssyrinx		return (SNMP_ERR_NOERROR);
1375164410Ssyrinx
1376164410Ssyrinx	    case LEAF_begemotBridgeStpBridgeHelloTime:
1377164410Ssyrinx		val->v.integer = bif->bridge_hello_time;
1378165253Ssyrinx		return (SNMP_ERR_NOERROR);
1379164410Ssyrinx
1380164410Ssyrinx	    case LEAF_begemotBridgeStpBridgeForwardDelay:
1381164410Ssyrinx		val->v.integer = bif->bridge_fwd_delay;
1382165253Ssyrinx		return (SNMP_ERR_NOERROR);
1383164997Ssyrinx
1384164997Ssyrinx	    case LEAF_begemotBridgeStpVersion:
1385164997Ssyrinx		val->v.integer = bif->stp_version;
1386165253Ssyrinx		return (SNMP_ERR_NOERROR);
1387164997Ssyrinx
1388164997Ssyrinx	    case LEAF_begemotBridgeStpTxHoldCount:
1389164997Ssyrinx		val->v.integer = bif->tx_hold_count;
1390165253Ssyrinx		return (SNMP_ERR_NOERROR);
1391164410Ssyrinx	}
1392164410Ssyrinx
1393165253Ssyrinx	abort();
1394164410Ssyrinx}
1395164410Ssyrinx
1396164410Ssyrinxint
1397164410Ssyrinxop_begemot_tp(struct snmp_context *ctx, struct snmp_value *val,
1398164410Ssyrinx	uint sub, uint iidx __unused, enum snmp_op op)
1399164410Ssyrinx{
1400165046Ssyrinx	struct bridge_if *bif;
1401164410Ssyrinx
1402164410Ssyrinx	if (time(NULL) - bridge_list_age > bridge_get_data_maxage())
1403164410Ssyrinx		bridge_update_all_ifs();
1404164410Ssyrinx
1405164410Ssyrinx	switch (op) {
1406164410Ssyrinx	    case SNMP_OP_GET:
1407164410Ssyrinx		if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1408164410Ssyrinx		    return (SNMP_ERR_NOSUCHNAME);
1409165253Ssyrinx		goto get;
1410164410Ssyrinx
1411164410Ssyrinx	    case SNMP_OP_GETNEXT:
1412164410Ssyrinx		if ((bif = bridge_if_index_getnext(&val->var, sub)) == NULL)
1413164410Ssyrinx		    return (SNMP_ERR_NOSUCHNAME);
1414164410Ssyrinx		bridge_if_index_append(&val->var, sub, bif);
1415165253Ssyrinx		goto get;
1416164410Ssyrinx
1417164410Ssyrinx	    case SNMP_OP_SET:
1418164410Ssyrinx		if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1419164410Ssyrinx		    return (SNMP_ERR_NOSUCHNAME);
1420164410Ssyrinx
1421164410Ssyrinx		switch (val->var.subs[sub - 1]) {
1422164410Ssyrinx		    case LEAF_begemotBridgeTpAgingTime:
1423165253Ssyrinx			if (val->v.integer < SNMP_BRIDGE_MIN_AGE_TIME ||
1424165253Ssyrinx			    val->v.integer > SNMP_BRIDGE_MAX_AGE_TIME)
1425165253Ssyrinx			    return (SNMP_ERR_WRONG_VALUE);
1426165253Ssyrinx
1427164410Ssyrinx			ctx->scratch->int1 = bif->age_time;
1428164410Ssyrinx			if (bridge_set_aging_time(bif, val->v.integer) < 0)
1429164410Ssyrinx			    return (SNMP_ERR_GENERR);
1430164410Ssyrinx			return (SNMP_ERR_NOERROR);
1431164410Ssyrinx
1432164410Ssyrinx		    case LEAF_begemotBridgeTpMaxAddresses:
1433164410Ssyrinx			ctx->scratch->int1 = bif->max_addrs;
1434164410Ssyrinx			if (bridge_set_max_cache(bif, val->v.integer) < 0)
1435164410Ssyrinx			    return (SNMP_ERR_GENERR);
1436164410Ssyrinx			return (SNMP_ERR_NOERROR);
1437164410Ssyrinx
1438164410Ssyrinx		    case LEAF_begemotBridgeTpLearnedEntryDiscards:
1439164410Ssyrinx			return (SNMP_ERR_NOT_WRITEABLE);
1440164410Ssyrinx		}
1441164410Ssyrinx		abort();
1442164410Ssyrinx
1443164410Ssyrinx	    case SNMP_OP_ROLLBACK:
1444164410Ssyrinx		if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1445164410Ssyrinx		    return (SNMP_ERR_GENERR);
1446164410Ssyrinx
1447164410Ssyrinx		switch (val->var.subs[sub - 1]) {
1448164410Ssyrinx		    case LEAF_begemotBridgeTpAgingTime:
1449164410Ssyrinx			bridge_set_aging_time(bif, ctx->scratch->int1);
1450164410Ssyrinx			break;
1451164410Ssyrinx
1452164410Ssyrinx		    case LEAF_begemotBridgeTpMaxAddresses:
1453164410Ssyrinx			bridge_set_max_cache(bif, ctx->scratch->int1);
1454164410Ssyrinx			break;
1455164410Ssyrinx		}
1456164410Ssyrinx		return (SNMP_ERR_NOERROR);
1457164410Ssyrinx
1458164410Ssyrinx	    case SNMP_OP_COMMIT:
1459164410Ssyrinx		return (SNMP_ERR_NOERROR);
1460164410Ssyrinx	}
1461165253Ssyrinx	abort();
1462164410Ssyrinx
1463165253Ssyrinxget:
1464164410Ssyrinx	switch (val->var.subs[sub - 1]) {
1465164410Ssyrinx	    case LEAF_begemotBridgeTpLearnedEntryDiscards:
1466164410Ssyrinx		val->v.uint32 = bif->lrnt_drops;
1467165253Ssyrinx		return (SNMP_ERR_NOERROR);
1468164410Ssyrinx
1469164410Ssyrinx	    case LEAF_begemotBridgeTpAgingTime:
1470164410Ssyrinx		val->v.integer = bif->age_time;
1471165253Ssyrinx		return (SNMP_ERR_NOERROR);
1472164410Ssyrinx
1473164410Ssyrinx	    case LEAF_begemotBridgeTpMaxAddresses:
1474164410Ssyrinx		val->v.integer = bif->max_addrs;
1475165253Ssyrinx		return (SNMP_ERR_NOERROR);
1476164410Ssyrinx	}
1477164410Ssyrinx
1478165253Ssyrinx	abort();
1479164410Ssyrinx}
1480