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