xref: /freebsd/usr.sbin/bsnmpd/modules/snmp_bridge/bridge_if.c (revision f7c32ed617858bcd22f8d1b03199099d50125721)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2006 Shteryana Shopova <syrinx@FreeBSD.org>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  *
28  * Bridge MIB implementation for SNMPd.
29  * Bridge interface objects.
30  *
31  * $FreeBSD$
32  */
33 
34 #include <sys/queue.h>
35 #include <sys/socket.h>
36 #include <sys/time.h>
37 #include <sys/types.h>
38 
39 #include <net/ethernet.h>
40 #include <net/if.h>
41 #include <net/if_mib.h>
42 #include <net/if_types.h>
43 
44 #include <errno.h>
45 #include <stdarg.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <syslog.h>
49 
50 #include <bsnmp/snmpmod.h>
51 #include <bsnmp/snmp_mibII.h>
52 
53 #define	SNMPTREE_TYPES
54 #include "bridge_tree.h"
55 #include "bridge_snmp.h"
56 #include "bridge_oid.h"
57 
58 static const struct asn_oid oid_newRoot = OIDX_newRoot;
59 static const struct asn_oid oid_TopologyChange = OIDX_topologyChange;
60 static const struct asn_oid oid_begemotBrigeName = \
61 			OIDX_begemotBridgeBaseName;
62 static const struct asn_oid oid_begemotNewRoot = OIDX_begemotBridgeNewRoot;
63 static const struct asn_oid oid_begemotTopologyChange = \
64 			OIDX_begemotBridgeTopologyChange;
65 
66 TAILQ_HEAD(bridge_ifs, bridge_if);
67 
68 /*
69  * Free the bridge interface list.
70  */
71 static void
72 bridge_ifs_free(struct bridge_ifs *headp)
73 {
74 	struct bridge_if *b;
75 
76 	while ((b = TAILQ_FIRST(headp)) != NULL) {
77 		TAILQ_REMOVE(headp, b, b_if);
78 		free(b);
79 	}
80 }
81 
82 /*
83  * Insert an entry in the bridge interface TAILQ. Keep the
84  * TAILQ sorted by the bridge's interface name.
85  */
86 static void
87 bridge_ifs_insert(struct bridge_ifs *headp,
88 	struct bridge_if *b)
89 {
90 	struct bridge_if *temp;
91 
92 	if ((temp = TAILQ_FIRST(headp)) == NULL ||
93 	    strcmp(b->bif_name, temp->bif_name) < 0) {
94 		TAILQ_INSERT_HEAD(headp, b, b_if);
95 		return;
96 	}
97 
98 	TAILQ_FOREACH(temp, headp, b_if)
99 		if(strcmp(b->bif_name, temp->bif_name) < 0)
100 			TAILQ_INSERT_BEFORE(temp, b, b_if);
101 
102 	TAILQ_INSERT_TAIL(headp, b, b_if);
103 }
104 
105 /* The global bridge interface list. */
106 static struct bridge_ifs bridge_ifs = TAILQ_HEAD_INITIALIZER(bridge_ifs);
107 static time_t bridge_list_age;
108 
109 /*
110  * Free the global list.
111  */
112 void
113 bridge_ifs_fini(void)
114 {
115 	bridge_ifs_free(&bridge_ifs);
116 }
117 
118 /*
119  * Find a bridge interface entry by the bridge interface system index.
120  */
121 struct bridge_if *
122 bridge_if_find_ifs(uint32_t sysindex)
123 {
124 	struct bridge_if *b;
125 
126 	TAILQ_FOREACH(b, &bridge_ifs, b_if)
127 		if (b->sysindex == sysindex)
128 			return (b);
129 
130 	return (NULL);
131 }
132 
133 /*
134  * Find a bridge interface entry by the bridge interface name.
135  */
136 struct bridge_if *
137 bridge_if_find_ifname(const char *b_name)
138 {
139 	struct bridge_if *b;
140 
141 	TAILQ_FOREACH(b, &bridge_ifs, b_if)
142 		if (strcmp(b_name, b->bif_name) == 0)
143 			return (b);
144 
145 	return (NULL);
146 }
147 
148 /*
149  * Find a bridge name by the bridge interface system index.
150  */
151 const char *
152 bridge_if_find_name(uint32_t sysindex)
153 {
154 	struct bridge_if *b;
155 
156 	TAILQ_FOREACH(b, &bridge_ifs, b_if)
157 		if (b->sysindex == sysindex)
158 			return (b->bif_name);
159 
160 	return (NULL);
161 }
162 
163 /*
164  * Given two bridge interfaces' system indexes, find their
165  * corresponding names and return the result of the name
166  * comparison. Returns:
167  * error : -2
168  * i1 < i2 : -1
169  * i1 > i2 : +1
170  * i1 = i2 : 0
171  */
172 int
173 bridge_compare_sysidx(uint32_t i1, uint32_t i2)
174 {
175 	int c;
176 	const char *b1, *b2;
177 
178 	if (i1 == i2)
179 		return (0);
180 
181 	if ((b1 = bridge_if_find_name(i1)) == NULL) {
182 		syslog(LOG_ERR, "Bridge interface %d does not exist", i1);
183 		return (-2);
184 	}
185 
186 	if ((b2 = bridge_if_find_name(i2)) == NULL) {
187 		syslog(LOG_ERR, "Bridge interface %d does not exist", i2);
188 		return (-2);
189 	}
190 
191 	if ((c = strcmp(b1, b2)) < 0)
192 		return (-1);
193 	else if (c > 0)
194 		return (1);
195 
196 	return (0);
197 }
198 
199 /*
200  * Fetch the first bridge interface from the list.
201  */
202 struct bridge_if *
203 bridge_first_bif(void)
204 {
205 	return (TAILQ_FIRST(&bridge_ifs));
206 }
207 
208 /*
209  * Fetch the next bridge interface from the list.
210  */
211 struct bridge_if *
212 bridge_next_bif(struct bridge_if *b_pr)
213 {
214 	return (TAILQ_NEXT(b_pr, b_if));
215 }
216 
217 /*
218  * Create a new entry for a bridge interface and insert
219  * it in the list.
220  */
221 static struct bridge_if *
222 bridge_new_bif(const char *bif_n, uint32_t sysindex, const u_char *physaddr)
223 {
224 	struct bridge_if *bif;
225 
226 	if ((bif = (struct bridge_if *) malloc(sizeof(*bif)))== NULL) {
227 		syslog(LOG_ERR, "bridge new interface failed: %s",
228 		    strerror(errno));
229 		return (NULL);
230 	}
231 
232 	bzero(bif, sizeof(struct bridge_if));
233 	strlcpy(bif->bif_name, bif_n, IFNAMSIZ);
234 	bcopy(physaddr, bif->br_addr.octet, ETHER_ADDR_LEN);
235 	bif->sysindex = sysindex;
236 	bif->br_type = BaseType_transparent_only;
237 	/* 1 - all bridges default hold time * 100 - centi-seconds */
238 	bif->hold_time = 1 * 100;
239 	bif->prot_spec = dot1dStpProtocolSpecification_ieee8021d;
240 	bridge_ifs_insert(&bridge_ifs, bif);
241 
242 	return (bif);
243 }
244 
245 /*
246  * Remove a bridge interface from the list, freeing all it's ports
247  * and address entries.
248  */
249 void
250 bridge_remove_bif(struct bridge_if *bif)
251 {
252 	bridge_members_free(bif);
253 	bridge_addrs_free(bif);
254 	TAILQ_REMOVE(&bridge_ifs, bif, b_if);
255 	free(bif);
256 }
257 
258 
259 /*
260  * Prepare the variable (bridge interface name) for the private
261  * begemot notifications.
262  */
263 static struct snmp_value*
264 bridge_basename_var(struct bridge_if *bif, struct snmp_value* b_val)
265 {
266 	uint i;
267 
268 	b_val->var = oid_begemotBrigeName;
269 	b_val->var.subs[b_val->var.len++] = strlen(bif->bif_name);
270 
271 	if ((b_val->v.octetstring.octets = (u_char *)
272 	    malloc(strlen(bif->bif_name))) == NULL)
273 		return (NULL);
274 
275 	for (i = 0; i < strlen(bif->bif_name); i++)
276 		b_val->var.subs[b_val->var.len++] = bif->bif_name[i];
277 
278 	b_val->v.octetstring.len = strlen(bif->bif_name);
279 	bcopy(bif->bif_name, b_val->v.octetstring.octets,
280 	    strlen(bif->bif_name));
281 	b_val->syntax = SNMP_SYNTAX_OCTETSTRING;
282 
283 	return (b_val);
284 }
285 
286 /*
287  * Compare the values of the old and the new root port and
288  * send a new root notification, if they are not matching.
289  */
290 static void
291 bridge_new_root(struct bridge_if *bif)
292 {
293 	struct snmp_value bif_idx;
294 
295 	if (bridge_get_default() == bif)
296 		snmp_send_trap(&oid_newRoot, (struct snmp_value *) NULL);
297 
298 	if (bridge_basename_var(bif, &bif_idx) == NULL)
299 		return;
300 
301 	snmp_send_trap(&oid_begemotTopologyChange,
302 	    &bif_idx, (struct snmp_value *) NULL);
303 }
304 
305 /*
306  * Compare the new and old topology change times and send a
307  * topology change notification if necessary.
308  */
309 static void
310 bridge_top_change(struct bridge_if *bif)
311 {
312 	struct snmp_value bif_idx;
313 
314 	if (bridge_get_default() == bif)
315 		snmp_send_trap(&oid_TopologyChange,
316 		    (struct snmp_value *) NULL);
317 
318 	if (bridge_basename_var(bif, &bif_idx) == NULL)
319 		return;
320 
321 	snmp_send_trap(&oid_begemotNewRoot,
322 	    &bif_idx, (struct snmp_value *) NULL);
323 }
324 
325 static int
326 bridge_if_create(const char* b_name, int8_t up)
327 {
328 	if (bridge_create(b_name) < 0)
329 		return (-1);
330 
331 	if (up == 1 && (bridge_set_if_up(b_name, 1) < 0))
332 		return (-1);
333 
334 	/*
335 	 * Do not create a new bridge entry here -
336 	 * wait until the mibII module notifies us.
337 	 */
338 	return (0);
339 }
340 
341 static int
342 bridge_if_destroy(struct bridge_if *bif)
343 {
344 	if (bridge_destroy(bif->bif_name) < 0)
345 		return (-1);
346 
347 	bridge_remove_bif(bif);
348 
349 	return (0);
350 }
351 
352 /*
353  * Calculate the timeticks since the last topology change.
354  */
355 static int
356 bridge_get_time_since_tc(struct bridge_if *bif, uint32_t *ticks)
357 {
358 	struct timeval ct;
359 
360 	if (gettimeofday(&ct, NULL) < 0) {
361 		syslog(LOG_ERR, "bridge get time since last TC:"
362 		    "gettimeofday failed: %s", strerror(errno));
363 		return (-1);
364 	}
365 
366 	if (ct.tv_usec - bif->last_tc_time.tv_usec < 0) {
367 		ct.tv_sec -= 1;
368 		ct.tv_usec += 1000000;
369 	}
370 
371 	ct.tv_sec -= bif->last_tc_time.tv_sec;
372 	ct.tv_usec -= bif->last_tc_time.tv_usec;
373 
374 	*ticks = ct.tv_sec * 100 + ct.tv_usec/10000;
375 
376 	return (0);
377 }
378 
379 /*
380  * Update the info we have for a single bridge interface.
381  * Return:
382  * 1, if successful
383  * 0, if the interface was deleted
384  * -1, error occurred while fetching the info from the kernel.
385  */
386 static int
387 bridge_update_bif(struct bridge_if *bif)
388 {
389 	struct mibif *ifp;
390 
391 	/* Walk through the mibII interface list. */
392 	for (ifp = mib_first_if(); ifp != NULL; ifp = mib_next_if(ifp))
393 		if (strcmp(ifp->name, bif->bif_name) == 0)
394 			break;
395 
396 	if (ifp == NULL) {
397 		/* Ops, we do not exist anymore. */
398 		bridge_remove_bif(bif);
399 		return (0);
400 	}
401 
402 	if (ifp->physaddr != NULL )
403 		bcopy(ifp->physaddr, bif->br_addr.octet, ETHER_ADDR_LEN);
404 	else
405 		bridge_get_basemac(bif->bif_name, bif->br_addr.octet,
406 		    ETHER_ADDR_LEN);
407 
408 	if (ifp->mib.ifmd_flags & IFF_RUNNING)
409 		bif->if_status = RowStatus_active;
410 	else
411 		bif->if_status = RowStatus_notInService;
412 
413 	switch (bridge_getinfo_bif(bif)) {
414 		case 2:
415 			bridge_new_root(bif);
416 			break;
417 		case 1:
418 			bridge_top_change(bif);
419 			break;
420 		case -1:
421 			bridge_remove_bif(bif);
422 			return (-1);
423 		default:
424 			break;
425 	}
426 
427 	/*
428 	 * The number of ports is accessible via SNMP -
429 	 * update the ports each time the bridge interface data
430 	 * is refreshed too.
431 	 */
432 	bif->num_ports = bridge_update_memif(bif);
433 	bif->entry_age = time(NULL);
434 
435 	return (1);
436 }
437 
438 /*
439  * Update all bridge interfaces' ports only -
440  * make sure each bridge interface exists first.
441  */
442 void
443 bridge_update_all_ports(void)
444 {
445 	struct mibif *ifp;
446 	struct bridge_if *bif, *t_bif;
447 
448 	for (bif = bridge_first_bif(); bif != NULL; bif = t_bif) {
449 		t_bif = bridge_next_bif(bif);
450 
451 		for (ifp = mib_first_if(); ifp != NULL;
452 		    ifp = mib_next_if(ifp))
453 			if (strcmp(ifp->name, bif->bif_name) == 0)
454 				break;
455 
456 		if (ifp != NULL)
457 			bif->num_ports = bridge_update_memif(bif);
458 		else  /* Ops, we do not exist anymore. */
459 			bridge_remove_bif(bif);
460 	}
461 
462 	bridge_ports_update_listage();
463 }
464 
465 /*
466  * Update all addresses only.
467  */
468 void
469 bridge_update_all_addrs(void)
470 {
471 	struct mibif *ifp;
472 	struct bridge_if *bif, *t_bif;
473 
474 	for (bif = bridge_first_bif(); bif != NULL; bif = t_bif) {
475 		t_bif = bridge_next_bif(bif);
476 
477 		for (ifp = mib_first_if(); ifp != NULL;
478 		    ifp = mib_next_if(ifp))
479 			if (strcmp(ifp->name, bif->bif_name) == 0)
480 				break;
481 
482 		if (ifp != NULL)
483 			bif->num_addrs = bridge_update_addrs(bif);
484 		else  /* Ops, we don't exist anymore. */
485 			bridge_remove_bif(bif);
486 	}
487 
488 	bridge_addrs_update_listage();
489 }
490 
491 /*
492  * Update only the bridge interfaces' data - skip addresses.
493  */
494 void
495 bridge_update_all_ifs(void)
496 {
497 	struct bridge_if *bif, *t_bif;
498 
499 	for (bif = bridge_first_bif(); bif != NULL; bif = t_bif) {
500 		t_bif = bridge_next_bif(bif);
501 		bridge_update_bif(bif);
502 	}
503 
504 	bridge_ports_update_listage();
505 	bridge_list_age = time(NULL);
506 }
507 
508 /*
509  * Update all info we have for all bridges.
510  */
511 void
512 bridge_update_all(void *arg __unused)
513 {
514 	struct bridge_if *bif, *t_bif;
515 
516 	for (bif = bridge_first_bif(); bif != NULL; bif = t_bif) {
517 		t_bif = bridge_next_bif(bif);
518 		if (bridge_update_bif(bif) <= 0)
519 			continue;
520 
521 		/* Update our learnt addresses. */
522 		bif->num_addrs = bridge_update_addrs(bif);
523 	}
524 
525 	bridge_list_age = time(NULL);
526 	bridge_ports_update_listage();
527 	bridge_addrs_update_listage();
528 }
529 
530 /*
531  * Callback for polling our last topology change time -
532  * check whether we are root or whether a TC was detected once every
533  * 30 seconds, so that we can send the newRoot and TopologyChange traps
534  * on time. The rest of the data is polled only once every 5 min.
535  */
536 void
537 bridge_update_tc_time(void *arg __unused)
538 {
539 	struct bridge_if *bif;
540 	struct mibif *ifp;
541 
542 	TAILQ_FOREACH(bif, &bridge_ifs, b_if) {
543 		/* Walk through the mibII interface list. */
544 		for (ifp = mib_first_if(); ifp != NULL; ifp = mib_next_if(ifp))
545 			if (strcmp(ifp->name, bif->bif_name) == 0)
546 				break;
547 
548 		if (ifp == NULL) {
549 			bridge_remove_bif(bif);
550 			continue;
551 		}
552 
553 		switch (bridge_get_op_param(bif)) {
554 			case 2:
555 				bridge_new_root(bif);
556 				break;
557 			case 1:
558 				bridge_top_change(bif);
559 				break;
560 		}
561 	}
562 }
563 
564 /*
565  * Callback for handling new bridge interface creation.
566  */
567 int
568 bridge_attach_newif(struct mibif *ifp)
569 {
570 	u_char mac[ETHER_ADDR_LEN];
571 	struct bridge_if *bif;
572 
573 	if (ifp->mib.ifmd_data.ifi_type != IFT_BRIDGE)
574 		return (0);
575 
576 	/* Make sure it does not exist in our list. */
577 	TAILQ_FOREACH(bif, &bridge_ifs, b_if)
578 		if(strcmp(bif->bif_name, ifp->name) == 0) {
579 			syslog(LOG_ERR, "bridge interface %s already "
580 			    "in list", bif->bif_name);
581 			return (-1);
582 		}
583 
584 	if (ifp->physaddr == NULL) {
585 		if (bridge_get_basemac(ifp->name, mac, sizeof(mac)) == NULL) {
586 			syslog(LOG_ERR, "bridge attach new %s failed - "
587 			    "no bridge mac address", ifp->name);
588 			return (-1);
589 		}
590 	} else
591 		bcopy(ifp->physaddr, &mac, sizeof(mac));
592 
593 	if ((bif = bridge_new_bif(ifp->name, ifp->sysindex, mac)) == NULL)
594 		return (-1);
595 
596 	if (ifp->mib.ifmd_flags & IFF_RUNNING)
597 		bif->if_status = RowStatus_active;
598 	else
599 		bif->if_status = RowStatus_notInService;
600 
601 	/* Skip sending notifications if the interface was just created. */
602 	if (bridge_getinfo_bif(bif) < 0 ||
603 	    (bif->num_ports = bridge_getinfo_bif_ports(bif)) < 0 ||
604 	    (bif->num_addrs = bridge_getinfo_bif_addrs(bif)) < 0) {
605 		bridge_remove_bif(bif);
606 		return (-1);
607 	}
608 
609 	/* Check whether we are the default bridge interface. */
610 	if (strcmp(ifp->name, bridge_get_default_name()) == 0)
611 		bridge_set_default(bif);
612 
613 	return (0);
614 }
615 
616 void
617 bridge_ifs_dump(void)
618 {
619 	struct bridge_if *bif;
620 
621 	for (bif = bridge_first_bif(); bif != NULL;
622 		bif = bridge_next_bif(bif)) {
623 		syslog(LOG_ERR, "Bridge %s, index - %d", bif->bif_name,
624 		    bif->sysindex);
625 		bridge_ports_dump(bif);
626 		bridge_addrs_dump(bif);
627 	}
628 }
629 
630 /*
631  * RFC4188 specifics.
632  */
633 int
634 op_dot1d_base(struct snmp_context *ctx __unused, struct snmp_value *value,
635 	uint sub, uint iidx __unused, enum snmp_op op)
636 {
637 	struct bridge_if *bif;
638 
639 	if ((bif = bridge_get_default()) == NULL)
640 		return (SNMP_ERR_NOSUCHNAME);
641 
642 	if (time(NULL) - bif->entry_age > bridge_get_data_maxage() &&
643 	    bridge_update_bif(bif) <= 0) /* It was just deleted. */
644 		return (SNMP_ERR_NOSUCHNAME);
645 
646 	switch (op) {
647 	    case SNMP_OP_GET:
648 		switch (value->var.subs[sub - 1]) {
649 		    case LEAF_dot1dBaseBridgeAddress:
650 			return (string_get(value, bif->br_addr.octet,
651 			    ETHER_ADDR_LEN));
652 		    case LEAF_dot1dBaseNumPorts:
653 			value->v.integer = bif->num_ports;
654 			return (SNMP_ERR_NOERROR);
655 		    case LEAF_dot1dBaseType:
656 			value->v.integer = bif->br_type;
657 			return (SNMP_ERR_NOERROR);
658 		}
659 		abort();
660 
661 		case SNMP_OP_SET:
662 		    return (SNMP_ERR_NOT_WRITEABLE);
663 
664 		case SNMP_OP_GETNEXT:
665 		case SNMP_OP_ROLLBACK:
666 		case SNMP_OP_COMMIT:
667 		   break;
668 	}
669 
670 	abort();
671 }
672 
673 int
674 op_dot1d_stp(struct snmp_context *ctx, struct snmp_value *val, uint sub,
675     uint iidx __unused, enum snmp_op op)
676 {
677 	struct bridge_if *bif;
678 
679 	if ((bif = bridge_get_default()) == NULL)
680 		return (SNMP_ERR_NOSUCHNAME);
681 
682 	if (time(NULL) - bif->entry_age > bridge_get_data_maxage() &&
683 	    bridge_update_bif(bif) <= 0) /* It was just deleted. */
684 		return (SNMP_ERR_NOSUCHNAME);
685 
686 	switch (op) {
687 	    case SNMP_OP_GET:
688 		switch (val->var.subs[sub - 1]) {
689 		    case LEAF_dot1dStpProtocolSpecification:
690 			val->v.integer = bif->prot_spec;
691 			return (SNMP_ERR_NOERROR);
692 
693 		    case LEAF_dot1dStpPriority:
694 			val->v.integer = bif->priority;
695 			return (SNMP_ERR_NOERROR);
696 
697 		    case LEAF_dot1dStpTimeSinceTopologyChange:
698 			if (bridge_get_time_since_tc(bif,
699 			    &(val->v.uint32)) < 0)
700 				return (SNMP_ERR_GENERR);
701 			return (SNMP_ERR_NOERROR);
702 
703 		    case LEAF_dot1dStpTopChanges:
704 			val->v.uint32 = bif->top_changes;
705 			return (SNMP_ERR_NOERROR);
706 
707 		    case LEAF_dot1dStpDesignatedRoot:
708 			return (string_get(val, bif->design_root,
709 			    SNMP_BRIDGE_ID_LEN));
710 
711 		    case LEAF_dot1dStpRootCost:
712 			val->v.integer = bif->root_cost;
713 			return (SNMP_ERR_NOERROR);
714 
715 		    case LEAF_dot1dStpRootPort:
716 			val->v.integer = bif->root_port;
717 			return (SNMP_ERR_NOERROR);
718 
719 		    case LEAF_dot1dStpMaxAge:
720 			val->v.integer = bif->max_age;
721 			return (SNMP_ERR_NOERROR);
722 
723 		    case LEAF_dot1dStpHelloTime:
724 			val->v.integer = bif->hello_time;
725 			return (SNMP_ERR_NOERROR);
726 
727 		    case LEAF_dot1dStpHoldTime:
728 			val->v.integer = bif->hold_time;
729 			return (SNMP_ERR_NOERROR);
730 
731 		    case LEAF_dot1dStpForwardDelay:
732 			val->v.integer = bif->fwd_delay;
733 			return (SNMP_ERR_NOERROR);
734 
735 		    case LEAF_dot1dStpBridgeMaxAge:
736 			val->v.integer = bif->bridge_max_age;
737 			return (SNMP_ERR_NOERROR);
738 
739 		    case LEAF_dot1dStpBridgeHelloTime:
740 			val->v.integer = bif->bridge_hello_time;
741 			return (SNMP_ERR_NOERROR);
742 
743 		    case LEAF_dot1dStpBridgeForwardDelay:
744 			val->v.integer = bif->bridge_fwd_delay;
745 			return (SNMP_ERR_NOERROR);
746 
747 		    case LEAF_dot1dStpVersion:
748 			val->v.integer = bif->stp_version;
749 			return (SNMP_ERR_NOERROR);
750 
751 		    case LEAF_dot1dStpTxHoldCount:
752 			val->v.integer = bif->tx_hold_count;
753 			return (SNMP_ERR_NOERROR);
754 		}
755 		abort();
756 
757 	    case SNMP_OP_GETNEXT:
758 		abort();
759 
760 	    case SNMP_OP_SET:
761 		switch (val->var.subs[sub - 1]) {
762 		    case LEAF_dot1dStpPriority:
763 			if (val->v.integer > SNMP_BRIDGE_MAX_PRIORITY ||
764 			    val->v.integer % 4096 != 0)
765 			    return (SNMP_ERR_WRONG_VALUE);
766 
767 			ctx->scratch->int1 = bif->priority;
768 			if (bridge_set_priority(bif, val->v.integer) < 0)
769 			    return (SNMP_ERR_GENERR);
770 			return (SNMP_ERR_NOERROR);
771 
772 		    case LEAF_dot1dStpBridgeMaxAge:
773 			if (val->v.integer < SNMP_BRIDGE_MIN_MAGE ||
774 			    val->v.integer > SNMP_BRIDGE_MAX_MAGE)
775 			    return (SNMP_ERR_WRONG_VALUE);
776 
777 			ctx->scratch->int1 = bif->bridge_max_age;
778 			if (bridge_set_maxage(bif, val->v.integer) < 0)
779 			    return (SNMP_ERR_GENERR);
780 			return (SNMP_ERR_NOERROR);
781 
782 		    case LEAF_dot1dStpBridgeHelloTime:
783 			if (val->v.integer < SNMP_BRIDGE_MIN_HTIME ||
784 			    val->v.integer > SNMP_BRIDGE_MAX_HTIME)
785 			    return (SNMP_ERR_WRONG_VALUE);
786 
787 			ctx->scratch->int1 = bif->bridge_hello_time;
788 			if (bridge_set_hello_time(bif, val->v.integer) < 0)
789 			    return (SNMP_ERR_GENERR);
790 			return (SNMP_ERR_NOERROR);
791 
792 		    case LEAF_dot1dStpBridgeForwardDelay:
793 			if (val->v.integer < SNMP_BRIDGE_MIN_FDELAY ||
794 			    val->v.integer > SNMP_BRIDGE_MAX_FDELAY)
795 			    return (SNMP_ERR_WRONG_VALUE);
796 
797 			ctx->scratch->int1 = bif->bridge_fwd_delay;
798 			if (bridge_set_forward_delay(bif, val->v.integer) < 0)
799 			    return (SNMP_ERR_GENERR);
800 			return (SNMP_ERR_NOERROR);
801 
802 		    case LEAF_dot1dStpVersion:
803 			if (val->v.integer != dot1dStpVersion_stpCompatible &&
804 			    val->v.integer != dot1dStpVersion_rstp)
805 			    return (SNMP_ERR_WRONG_VALUE);
806 
807 			ctx->scratch->int1 = bif->stp_version;
808 			if (bridge_set_stp_version(bif, val->v.integer) < 0)
809 			    return (SNMP_ERR_GENERR);
810 			return (SNMP_ERR_NOERROR);
811 
812 		    case LEAF_dot1dStpTxHoldCount:
813 			if (val->v.integer < SNMP_BRIDGE_MIN_TXHC ||
814 			    val->v.integer > SNMP_BRIDGE_MAX_TXHC)
815 			    return (SNMP_ERR_WRONG_VALUE);
816 
817 			ctx->scratch->int1 = bif->tx_hold_count;
818 			if (bridge_set_tx_hold_count(bif, val->v.integer) < 0)
819 			    return (SNMP_ERR_GENERR);
820 			return (SNMP_ERR_NOERROR);
821 
822 		    case LEAF_dot1dStpProtocolSpecification:
823 		    case LEAF_dot1dStpTimeSinceTopologyChange:
824 		    case LEAF_dot1dStpTopChanges:
825 		    case LEAF_dot1dStpDesignatedRoot:
826 		    case LEAF_dot1dStpRootCost:
827 		    case LEAF_dot1dStpRootPort:
828 		    case LEAF_dot1dStpMaxAge:
829 		    case LEAF_dot1dStpHelloTime:
830 		    case LEAF_dot1dStpHoldTime:
831 		    case LEAF_dot1dStpForwardDelay:
832 			return (SNMP_ERR_NOT_WRITEABLE);
833 		}
834 		abort();
835 
836 	    case SNMP_OP_ROLLBACK:
837 		switch (val->var.subs[sub - 1]) {
838 		    case LEAF_dot1dStpPriority:
839 			bridge_set_priority(bif, ctx->scratch->int1);
840 			break;
841 		    case LEAF_dot1dStpBridgeMaxAge:
842 			bridge_set_maxage(bif, ctx->scratch->int1);
843 			break;
844 		    case LEAF_dot1dStpBridgeHelloTime:
845 			bridge_set_hello_time(bif, ctx->scratch->int1);
846 			break;
847 		    case LEAF_dot1dStpBridgeForwardDelay:
848 			bridge_set_forward_delay(bif, ctx->scratch->int1);
849 			break;
850 		    case LEAF_dot1dStpVersion:
851 			bridge_set_stp_version(bif, ctx->scratch->int1);
852 			break;
853 		    case LEAF_dot1dStpTxHoldCount:
854 			bridge_set_tx_hold_count(bif, ctx->scratch->int1);
855 			break;
856 		}
857 		return (SNMP_ERR_NOERROR);
858 
859 	    case SNMP_OP_COMMIT:
860 		return (SNMP_ERR_NOERROR);
861 	}
862 
863 	abort();
864 }
865 
866 int
867 op_dot1d_tp(struct snmp_context *ctx, struct snmp_value *value,
868 	uint sub, uint iidx __unused, enum snmp_op op)
869 {
870 	struct bridge_if *bif;
871 
872 	if ((bif = bridge_get_default()) == NULL)
873 		return (SNMP_ERR_NOSUCHNAME);
874 
875 	if (time(NULL) - bif->entry_age > bridge_get_data_maxage() &&
876 	    bridge_update_bif(bif) <= 0) /* It was just deleted. */
877 		return (SNMP_ERR_NOSUCHNAME);
878 
879 	switch (op) {
880 	    case SNMP_OP_GET:
881 		switch (value->var.subs[sub - 1]) {
882 		    case LEAF_dot1dTpLearnedEntryDiscards:
883 			value->v.uint32 = bif->lrnt_drops;
884 			return (SNMP_ERR_NOERROR);
885 		    case LEAF_dot1dTpAgingTime:
886 			value->v.integer = bif->age_time;
887 			return (SNMP_ERR_NOERROR);
888 		}
889 		abort();
890 
891 	    case SNMP_OP_GETNEXT:
892 		abort();
893 
894 	    case SNMP_OP_SET:
895 		switch (value->var.subs[sub - 1]) {
896 		    case LEAF_dot1dTpLearnedEntryDiscards:
897 			return (SNMP_ERR_NOT_WRITEABLE);
898 
899 		    case LEAF_dot1dTpAgingTime:
900 			if (value->v.integer < SNMP_BRIDGE_MIN_AGE_TIME ||
901 			    value->v.integer > SNMP_BRIDGE_MAX_AGE_TIME)
902 			    return (SNMP_ERR_WRONG_VALUE);
903 
904 			ctx->scratch->int1 = bif->age_time;
905 			if (bridge_set_aging_time(bif, value->v.integer) < 0)
906 			    return (SNMP_ERR_GENERR);
907 			return (SNMP_ERR_NOERROR);
908 		}
909 		abort();
910 
911 	    case SNMP_OP_ROLLBACK:
912 		if (value->var.subs[sub - 1] == LEAF_dot1dTpAgingTime)
913 		    bridge_set_aging_time(bif, ctx->scratch->int1);
914 		return (SNMP_ERR_NOERROR);
915 
916 	    case SNMP_OP_COMMIT:
917 		return (SNMP_ERR_NOERROR);
918 	}
919 
920 	abort();
921 }
922 
923 /*
924  * Private BEGEMOT-BRIDGE-MIB specifics.
925  */
926 
927 /*
928  * Get the bridge name from an OID index.
929  */
930 static char *
931 bridge_name_index_get(const struct asn_oid *oid, uint sub, char *b_name)
932 {
933 	uint i;
934 
935 	if (oid->len - sub != oid->subs[sub] + 1 || oid->subs[sub] >= IFNAMSIZ)
936 		return (NULL);
937 
938 	for (i = 0; i < oid->subs[sub]; i++)
939 		b_name[i] = oid->subs[sub + i + 1];
940 	b_name[i] = '\0';
941 
942 	return (b_name);
943 }
944 
945 static void
946 bridge_if_index_append(struct asn_oid *oid, uint sub,
947 	const struct bridge_if *bif)
948 {
949 	uint i;
950 
951 	oid->len = sub + strlen(bif->bif_name) + 1;
952 	oid->subs[sub] = strlen(bif->bif_name);
953 
954 	for (i = 1; i <= strlen(bif->bif_name); i++)
955 		oid->subs[sub + i] = bif->bif_name[i - 1];
956 }
957 
958 static struct bridge_if *
959 bridge_if_index_get(const struct asn_oid *oid, uint sub)
960 {
961 	uint i;
962 	char bif_name[IFNAMSIZ];
963 
964 	if (oid->len - sub != oid->subs[sub] + 1 || oid->subs[sub] >= IFNAMSIZ)
965 		return (NULL);
966 
967 	for (i = 0; i < oid->subs[sub]; i++)
968 		bif_name[i] = oid->subs[sub + i + 1];
969 	bif_name[i] = '\0';
970 
971 	return (bridge_if_find_ifname(bif_name));
972 }
973 
974 static struct bridge_if *
975 bridge_if_index_getnext(const struct asn_oid *oid, uint sub)
976 {
977 	uint i;
978 	char bif_name[IFNAMSIZ];
979 	struct bridge_if *bif;
980 
981 	if (oid->len - sub == 0)
982 		return (bridge_first_bif());
983 
984 	if (oid->len - sub != oid->subs[sub] + 1 || oid->subs[sub] >= IFNAMSIZ)
985 		return (NULL);
986 
987 	for (i = 0; i < oid->subs[sub]; i++)
988 		bif_name[i] = oid->subs[sub + i + 1];
989 	bif_name[i] = '\0';
990 
991 	if ((bif = bridge_if_find_ifname(bif_name)) == NULL)
992 		return (NULL);
993 
994 	return (bridge_next_bif(bif));
995 }
996 
997 static int
998 bridge_set_if_status(struct snmp_context *ctx,
999 	struct snmp_value *val, uint sub)
1000 {
1001 	struct bridge_if *bif;
1002 	char bif_name[IFNAMSIZ];
1003 
1004 	bif = bridge_if_index_get(&val->var, sub);
1005 
1006 	switch (val->v.integer) {
1007 	    case RowStatus_active:
1008 		if (bif == NULL)
1009 		    return (SNMP_ERR_INCONS_VALUE);
1010 
1011 		ctx->scratch->int1 = bif->if_status;
1012 
1013 		switch (bif->if_status) {
1014 		    case RowStatus_active:
1015 			return (SNMP_ERR_NOERROR);
1016 		    case RowStatus_notInService:
1017 			if (bridge_set_if_up(bif->bif_name, 1) < 0)
1018 			    return (SNMP_ERR_GENERR);
1019 			return (SNMP_ERR_NOERROR);
1020 		    default:
1021 			break;
1022 		}
1023 		return (SNMP_ERR_INCONS_VALUE);
1024 
1025 	    case RowStatus_notInService:
1026 		if (bif == NULL)
1027 		    return (SNMP_ERR_INCONS_VALUE);
1028 
1029 		ctx->scratch->int1 = bif->if_status;
1030 
1031 		switch (bif->if_status) {
1032 		    case RowStatus_active:
1033 			if (bridge_set_if_up(bif->bif_name, 1) < 0)
1034 			    return (SNMP_ERR_GENERR);
1035 			return (SNMP_ERR_NOERROR);
1036 		    case RowStatus_notInService:
1037 			return (SNMP_ERR_NOERROR);
1038 		    default:
1039 			break;
1040 		}
1041 		return (SNMP_ERR_INCONS_VALUE);
1042 
1043 	    case RowStatus_notReady:
1044 		return (SNMP_ERR_INCONS_VALUE);
1045 
1046 	    case RowStatus_createAndGo:
1047 		if (bif != NULL)
1048 		    return (SNMP_ERR_INCONS_VALUE);
1049 
1050 		ctx->scratch->int1 = RowStatus_destroy;
1051 
1052 		if (bridge_name_index_get(&val->var, sub, bif_name) == NULL)
1053 		    return (SNMP_ERR_BADVALUE);
1054 		if (bridge_if_create(bif_name, 1) < 0)
1055 		    return (SNMP_ERR_GENERR);
1056 		return (SNMP_ERR_NOERROR);
1057 
1058 	    case RowStatus_createAndWait:
1059 		if (bif != NULL)
1060 		    return (SNMP_ERR_INCONS_VALUE);
1061 
1062 		if (bridge_name_index_get(&val->var, sub, bif_name) == NULL)
1063 		    return (SNMP_ERR_BADVALUE);
1064 
1065 		ctx->scratch->int1 = RowStatus_destroy;
1066 
1067 		if (bridge_if_create(bif_name, 0) < 0)
1068 		    return (SNMP_ERR_GENERR);
1069 		return (SNMP_ERR_NOERROR);
1070 
1071 	    case RowStatus_destroy:
1072 		if (bif == NULL)
1073 		    return (SNMP_ERR_NOSUCHNAME);
1074 
1075 		ctx->scratch->int1 = bif->if_status;
1076 		bif->if_status = RowStatus_destroy;
1077 	}
1078 
1079 	return (SNMP_ERR_NOERROR);
1080 }
1081 
1082 static int
1083 bridge_rollback_if_status(struct snmp_context *ctx,
1084 	struct snmp_value *val, uint sub)
1085 {
1086 	struct bridge_if *bif;
1087 
1088 	if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1089 		return (SNMP_ERR_GENERR);
1090 
1091 	switch (ctx->scratch->int1) {
1092 		case RowStatus_destroy:
1093 			bridge_if_destroy(bif);
1094 			return (SNMP_ERR_NOERROR);
1095 
1096 		case RowStatus_notInService:
1097 			if (bif->if_status != ctx->scratch->int1)
1098 				bridge_set_if_up(bif->bif_name, 0);
1099 			bif->if_status = RowStatus_notInService;
1100 			return (SNMP_ERR_NOERROR);
1101 
1102 		case RowStatus_active:
1103 			if (bif->if_status != ctx->scratch->int1)
1104 				bridge_set_if_up(bif->bif_name, 1);
1105 			bif->if_status = RowStatus_active;
1106 			return (SNMP_ERR_NOERROR);
1107 	}
1108 
1109 	abort();
1110 }
1111 
1112 static int
1113 bridge_commit_if_status(struct snmp_value *val, uint sub)
1114 {
1115 	struct bridge_if *bif;
1116 
1117 	if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1118 		return (SNMP_ERR_GENERR);
1119 
1120 	if (bif->if_status == RowStatus_destroy &&
1121 	    bridge_if_destroy(bif) < 0)
1122 		return (SNMP_ERR_COMMIT_FAILED);
1123 
1124 	return (SNMP_ERR_NOERROR);
1125 }
1126 
1127 int
1128 op_begemot_base_bridge(struct snmp_context *ctx, struct snmp_value *val,
1129 	uint sub, uint iidx __unused, enum snmp_op op)
1130 {
1131 	struct bridge_if *bif;
1132 
1133 	if (time(NULL) - bridge_list_age > bridge_get_data_maxage())
1134 		bridge_update_all_ifs();
1135 
1136 	switch (op) {
1137 	    case SNMP_OP_GET:
1138 		if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1139 		    return (SNMP_ERR_NOSUCHNAME);
1140 		goto get;
1141 
1142 	    case SNMP_OP_GETNEXT:
1143 		if ((bif = bridge_if_index_getnext(&val->var, sub)) == NULL)
1144 		    return (SNMP_ERR_NOSUCHNAME);
1145 		bridge_if_index_append(&val->var, sub, bif);
1146 		goto get;
1147 
1148 	    case SNMP_OP_SET:
1149 		switch (val->var.subs[sub - 1]) {
1150 		    case LEAF_begemotBridgeBaseStatus:
1151 			return (bridge_set_if_status(ctx, val, sub));
1152 		    case LEAF_begemotBridgeBaseName:
1153 		    case LEAF_begemotBridgeBaseAddress:
1154 		    case LEAF_begemotBridgeBaseNumPorts:
1155 		    case LEAF_begemotBridgeBaseType:
1156 			return (SNMP_ERR_NOT_WRITEABLE);
1157 		}
1158 		abort();
1159 
1160 	    case SNMP_OP_ROLLBACK:
1161 		return (bridge_rollback_if_status(ctx, val, sub));
1162 
1163 	    case SNMP_OP_COMMIT:
1164 		return (bridge_commit_if_status(val, sub));
1165 	}
1166 	abort();
1167 
1168 get:
1169 	switch (val->var.subs[sub - 1]) {
1170 	    case LEAF_begemotBridgeBaseName:
1171 		return (string_get(val, bif->bif_name, -1));
1172 
1173 	    case LEAF_begemotBridgeBaseAddress:
1174 		return (string_get(val, bif->br_addr.octet, ETHER_ADDR_LEN));
1175 
1176 	    case LEAF_begemotBridgeBaseNumPorts:
1177 		val->v.integer = bif->num_ports;
1178 		return (SNMP_ERR_NOERROR);
1179 
1180 	    case LEAF_begemotBridgeBaseType:
1181 		val->v.integer = bif->br_type;
1182 		return (SNMP_ERR_NOERROR);
1183 
1184 	    case LEAF_begemotBridgeBaseStatus:
1185 		val->v.integer = bif->if_status;
1186 		return (SNMP_ERR_NOERROR);
1187 	}
1188 
1189 	abort();
1190 }
1191 
1192 int
1193 op_begemot_stp(struct snmp_context *ctx, struct snmp_value *val,
1194 	uint sub, uint iidx __unused, enum snmp_op op)
1195 {
1196 	struct bridge_if *bif;
1197 
1198 	if (time(NULL) - bridge_list_age > bridge_get_data_maxage())
1199 		bridge_update_all_ifs();
1200 
1201 	switch (op) {
1202 	    case SNMP_OP_GET:
1203 		if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1204 		    return (SNMP_ERR_NOSUCHNAME);
1205 		goto get;
1206 
1207 	    case SNMP_OP_GETNEXT:
1208 		if ((bif = bridge_if_index_getnext(&val->var, sub)) == NULL)
1209 		    return (SNMP_ERR_NOSUCHNAME);
1210 		bridge_if_index_append(&val->var, sub, bif);
1211 		goto get;
1212 
1213 	    case SNMP_OP_SET:
1214 		if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1215 		    return (SNMP_ERR_NOSUCHNAME);
1216 
1217 		switch (val->var.subs[sub - 1]) {
1218 		    case LEAF_begemotBridgeStpPriority:
1219 			if (val->v.integer > SNMP_BRIDGE_MAX_PRIORITY ||
1220 			    val->v.integer % 4096 != 0)
1221 			    return (SNMP_ERR_WRONG_VALUE);
1222 
1223 			ctx->scratch->int1 = bif->priority;
1224 			if (bridge_set_priority(bif, val->v.integer) < 0)
1225 			    return (SNMP_ERR_GENERR);
1226 			return (SNMP_ERR_NOERROR);
1227 
1228 		    case LEAF_begemotBridgeStpBridgeMaxAge:
1229 			if (val->v.integer < SNMP_BRIDGE_MIN_MAGE ||
1230 			    val->v.integer > SNMP_BRIDGE_MAX_MAGE)
1231 			    return (SNMP_ERR_WRONG_VALUE);
1232 
1233 			ctx->scratch->int1 = bif->bridge_max_age;
1234 			if (bridge_set_maxage(bif, val->v.integer) < 0)
1235 			    return (SNMP_ERR_GENERR);
1236 			return (SNMP_ERR_NOERROR);
1237 
1238 		    case LEAF_begemotBridgeStpBridgeHelloTime:
1239 			if (val->v.integer < SNMP_BRIDGE_MIN_HTIME ||
1240 			    val->v.integer > SNMP_BRIDGE_MAX_HTIME)
1241 			    return (SNMP_ERR_WRONG_VALUE);
1242 
1243 			ctx->scratch->int1 = bif->bridge_hello_time;
1244 			if (bridge_set_hello_time(bif, val->v.integer) < 0)
1245 			    return (SNMP_ERR_GENERR);
1246 			return (SNMP_ERR_NOERROR);
1247 
1248 		    case LEAF_begemotBridgeStpBridgeForwardDelay:
1249 			if (val->v.integer < SNMP_BRIDGE_MIN_FDELAY ||
1250 			    val->v.integer > SNMP_BRIDGE_MAX_FDELAY)
1251 			    return (SNMP_ERR_WRONG_VALUE);
1252 
1253 			ctx->scratch->int1 = bif->bridge_fwd_delay;
1254 			if (bridge_set_forward_delay(bif, val->v.integer) < 0)
1255 			    return (SNMP_ERR_GENERR);
1256 			return (SNMP_ERR_NOERROR);
1257 
1258 		    case LEAF_begemotBridgeStpVersion:
1259 			if (val->v.integer !=
1260 			    begemotBridgeStpVersion_stpCompatible &&
1261 			    val->v.integer != begemotBridgeStpVersion_rstp)
1262 			    return (SNMP_ERR_WRONG_VALUE);
1263 
1264 			ctx->scratch->int1 = bif->stp_version;
1265 			if (bridge_set_stp_version(bif, val->v.integer) < 0)
1266 			    return (SNMP_ERR_GENERR);
1267 			return (SNMP_ERR_NOERROR);
1268 
1269 		    case LEAF_begemotBridgeStpTxHoldCount:
1270 			if (val->v.integer < SNMP_BRIDGE_MIN_TXHC ||
1271 			    val->v.integer > SNMP_BRIDGE_MAX_TXHC)
1272 			    return (SNMP_ERR_WRONG_VALUE);
1273 
1274 			ctx->scratch->int1 = bif->tx_hold_count;
1275 			if (bridge_set_tx_hold_count(bif, val->v.integer) < 0)
1276 			    return (SNMP_ERR_GENERR);
1277 			return (SNMP_ERR_NOERROR);
1278 
1279 		    case LEAF_begemotBridgeStpProtocolSpecification:
1280 		    case LEAF_begemotBridgeStpTimeSinceTopologyChange:
1281 		    case LEAF_begemotBridgeStpTopChanges:
1282 		    case LEAF_begemotBridgeStpDesignatedRoot:
1283 		    case LEAF_begemotBridgeStpRootCost:
1284 		    case LEAF_begemotBridgeStpRootPort:
1285 		    case LEAF_begemotBridgeStpMaxAge:
1286 		    case LEAF_begemotBridgeStpHelloTime:
1287 		    case LEAF_begemotBridgeStpHoldTime:
1288 		    case LEAF_begemotBridgeStpForwardDelay:
1289 			return (SNMP_ERR_NOT_WRITEABLE);
1290 		}
1291 		abort();
1292 
1293 	    case SNMP_OP_ROLLBACK:
1294 		if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1295 		    return (SNMP_ERR_NOSUCHNAME);
1296 
1297 		switch (val->var.subs[sub - 1]) {
1298 		    case LEAF_begemotBridgeStpPriority:
1299 			bridge_set_priority(bif, ctx->scratch->int1);
1300 			break;
1301 
1302 		    case LEAF_begemotBridgeStpBridgeMaxAge:
1303 			bridge_set_maxage(bif, ctx->scratch->int1);
1304 			break;
1305 
1306 		    case LEAF_begemotBridgeStpBridgeHelloTime:
1307 			bridge_set_hello_time(bif, ctx->scratch->int1);
1308 			break;
1309 
1310 		    case LEAF_begemotBridgeStpBridgeForwardDelay:
1311 			bridge_set_forward_delay(bif, ctx->scratch->int1);
1312 			break;
1313 
1314 		    case LEAF_begemotBridgeStpVersion:
1315 			bridge_set_stp_version(bif, ctx->scratch->int1);
1316 			break;
1317 
1318 		    case LEAF_begemotBridgeStpTxHoldCount:
1319 			bridge_set_tx_hold_count(bif, ctx->scratch->int1);
1320 			break;
1321 		}
1322 		return (SNMP_ERR_NOERROR);
1323 
1324 	    case SNMP_OP_COMMIT:
1325 		return (SNMP_ERR_NOERROR);
1326 	}
1327 	abort();
1328 
1329 get:
1330 	switch (val->var.subs[sub - 1]) {
1331 	    case LEAF_begemotBridgeStpProtocolSpecification:
1332 		val->v.integer = bif->prot_spec;
1333 		return (SNMP_ERR_NOERROR);
1334 
1335 	    case LEAF_begemotBridgeStpPriority:
1336 		val->v.integer = bif->priority;
1337 		return (SNMP_ERR_NOERROR);
1338 
1339 	    case LEAF_begemotBridgeStpTimeSinceTopologyChange:
1340 		if (bridge_get_time_since_tc(bif, &(val->v.uint32)) < 0)
1341 		    return (SNMP_ERR_GENERR);
1342 		return (SNMP_ERR_NOERROR);
1343 
1344 	    case LEAF_begemotBridgeStpTopChanges:
1345 		val->v.uint32 = bif->top_changes;
1346 		return (SNMP_ERR_NOERROR);
1347 
1348 	    case LEAF_begemotBridgeStpDesignatedRoot:
1349 		return (string_get(val, bif->design_root, SNMP_BRIDGE_ID_LEN));
1350 
1351 	    case LEAF_begemotBridgeStpRootCost:
1352 		val->v.integer = bif->root_cost;
1353 		return (SNMP_ERR_NOERROR);
1354 
1355 	    case LEAF_begemotBridgeStpRootPort:
1356 		val->v.integer = bif->root_port;
1357 		return (SNMP_ERR_NOERROR);
1358 
1359 	    case LEAF_begemotBridgeStpMaxAge:
1360 		val->v.integer = bif->max_age;
1361 		return (SNMP_ERR_NOERROR);
1362 
1363 	    case LEAF_begemotBridgeStpHelloTime:
1364 		val->v.integer = bif->hello_time;
1365 		return (SNMP_ERR_NOERROR);
1366 
1367 	    case LEAF_begemotBridgeStpHoldTime:
1368 		val->v.integer = bif->hold_time;
1369 		return (SNMP_ERR_NOERROR);
1370 
1371 	    case LEAF_begemotBridgeStpForwardDelay:
1372 		val->v.integer = bif->fwd_delay;
1373 		return (SNMP_ERR_NOERROR);
1374 
1375 	    case LEAF_begemotBridgeStpBridgeMaxAge:
1376 		val->v.integer = bif->bridge_max_age;
1377 		return (SNMP_ERR_NOERROR);
1378 
1379 	    case LEAF_begemotBridgeStpBridgeHelloTime:
1380 		val->v.integer = bif->bridge_hello_time;
1381 		return (SNMP_ERR_NOERROR);
1382 
1383 	    case LEAF_begemotBridgeStpBridgeForwardDelay:
1384 		val->v.integer = bif->bridge_fwd_delay;
1385 		return (SNMP_ERR_NOERROR);
1386 
1387 	    case LEAF_begemotBridgeStpVersion:
1388 		val->v.integer = bif->stp_version;
1389 		return (SNMP_ERR_NOERROR);
1390 
1391 	    case LEAF_begemotBridgeStpTxHoldCount:
1392 		val->v.integer = bif->tx_hold_count;
1393 		return (SNMP_ERR_NOERROR);
1394 	}
1395 
1396 	abort();
1397 }
1398 
1399 int
1400 op_begemot_tp(struct snmp_context *ctx, struct snmp_value *val,
1401 	uint sub, uint iidx __unused, enum snmp_op op)
1402 {
1403 	struct bridge_if *bif;
1404 
1405 	if (time(NULL) - bridge_list_age > bridge_get_data_maxage())
1406 		bridge_update_all_ifs();
1407 
1408 	switch (op) {
1409 	    case SNMP_OP_GET:
1410 		if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1411 		    return (SNMP_ERR_NOSUCHNAME);
1412 		goto get;
1413 
1414 	    case SNMP_OP_GETNEXT:
1415 		if ((bif = bridge_if_index_getnext(&val->var, sub)) == NULL)
1416 		    return (SNMP_ERR_NOSUCHNAME);
1417 		bridge_if_index_append(&val->var, sub, bif);
1418 		goto get;
1419 
1420 	    case SNMP_OP_SET:
1421 		if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1422 		    return (SNMP_ERR_NOSUCHNAME);
1423 
1424 		switch (val->var.subs[sub - 1]) {
1425 		    case LEAF_begemotBridgeTpAgingTime:
1426 			if (val->v.integer < SNMP_BRIDGE_MIN_AGE_TIME ||
1427 			    val->v.integer > SNMP_BRIDGE_MAX_AGE_TIME)
1428 			    return (SNMP_ERR_WRONG_VALUE);
1429 
1430 			ctx->scratch->int1 = bif->age_time;
1431 			if (bridge_set_aging_time(bif, val->v.integer) < 0)
1432 			    return (SNMP_ERR_GENERR);
1433 			return (SNMP_ERR_NOERROR);
1434 
1435 		    case LEAF_begemotBridgeTpMaxAddresses:
1436 			ctx->scratch->int1 = bif->max_addrs;
1437 			if (bridge_set_max_cache(bif, val->v.integer) < 0)
1438 			    return (SNMP_ERR_GENERR);
1439 			return (SNMP_ERR_NOERROR);
1440 
1441 		    case LEAF_begemotBridgeTpLearnedEntryDiscards:
1442 			return (SNMP_ERR_NOT_WRITEABLE);
1443 		}
1444 		abort();
1445 
1446 	    case SNMP_OP_ROLLBACK:
1447 		if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1448 		    return (SNMP_ERR_GENERR);
1449 
1450 		switch (val->var.subs[sub - 1]) {
1451 		    case LEAF_begemotBridgeTpAgingTime:
1452 			bridge_set_aging_time(bif, ctx->scratch->int1);
1453 			break;
1454 
1455 		    case LEAF_begemotBridgeTpMaxAddresses:
1456 			bridge_set_max_cache(bif, ctx->scratch->int1);
1457 			break;
1458 		}
1459 		return (SNMP_ERR_NOERROR);
1460 
1461 	    case SNMP_OP_COMMIT:
1462 		return (SNMP_ERR_NOERROR);
1463 	}
1464 	abort();
1465 
1466 get:
1467 	switch (val->var.subs[sub - 1]) {
1468 	    case LEAF_begemotBridgeTpLearnedEntryDiscards:
1469 		val->v.uint32 = bif->lrnt_drops;
1470 		return (SNMP_ERR_NOERROR);
1471 
1472 	    case LEAF_begemotBridgeTpAgingTime:
1473 		val->v.integer = bif->age_time;
1474 		return (SNMP_ERR_NOERROR);
1475 
1476 	    case LEAF_begemotBridgeTpMaxAddresses:
1477 		val->v.integer = bif->max_addrs;
1478 		return (SNMP_ERR_NOERROR);
1479 	}
1480 
1481 	abort();
1482 }
1483