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