]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/bsnmpd/modules/snmp_bridge/bridge_if.c
MFV r316893:
[FreeBSD/FreeBSD.git] / usr.sbin / bsnmpd / modules / snmp_bridge / bridge_if.c
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 }