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