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