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: stable/10/usr.sbin/bsnmpd/modules/snmp_bridge/bridge_if.c 310903 2016-12-31 10:34:09Z ngie $
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
bridge_ifs_free(struct bridge_ifs * headp)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
bridge_ifs_insert(struct bridge_ifs * headp,struct bridge_if * b)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
bridge_ifs_fini(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 *
bridge_if_find_ifs(uint32_t sysindex)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 *
bridge_if_find_ifname(const char * b_name)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 *
bridge_if_find_name(uint32_t sysindex)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
bridge_compare_sysidx(uint32_t i1,uint32_t i2)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 *
bridge_first_bif(void)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 *
bridge_next_bif(struct bridge_if * b_pr)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 *
bridge_new_bif(const char * bif_n,uint32_t sysindex,const u_char * physaddr)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
bridge_remove_bif(struct bridge_if * bif)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*
bridge_basename_var(struct bridge_if * bif,struct snmp_value * b_val)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
bridge_new_root(struct bridge_if * bif)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
bridge_top_change(struct bridge_if * bif)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
bridge_if_create(const char * b_name,int8_t up)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
bridge_if_destroy(struct bridge_if * bif)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
bridge_get_time_since_tc(struct bridge_if * bif,uint32_t * ticks)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
bridge_update_bif(struct bridge_if * bif)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
bridge_update_all_ports(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
bridge_update_all_addrs(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
bridge_update_all_ifs(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
bridge_update_all(void * arg __unused)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
bridge_update_tc_time(void * arg __unused)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
bridge_attach_newif(struct mibif * ifp)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
bridge_ifs_dump(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
op_dot1d_base(struct snmp_context * ctx __unused,struct snmp_value * value,uint sub,uint iidx __unused,enum snmp_op op)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
op_dot1d_stp(struct snmp_context * ctx,struct snmp_value * val,uint sub,uint iidx __unused,enum snmp_op op)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
op_dot1d_tp(struct snmp_context * ctx,struct snmp_value * value,uint sub,uint iidx __unused,enum snmp_op op)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 *
bridge_name_index_get(const struct asn_oid * oid,uint sub,char * b_name)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
bridge_if_index_append(struct asn_oid * oid,uint sub,const struct bridge_if * bif)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 *
bridge_if_index_get(const struct asn_oid * oid,uint sub)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 *
bridge_if_index_getnext(const struct asn_oid * oid,uint sub)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
bridge_set_if_status(struct snmp_context * ctx,struct snmp_value * val,uint sub)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
bridge_rollback_if_status(struct snmp_context * ctx,struct snmp_value * val,uint sub)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
bridge_commit_if_status(struct snmp_value * val,uint sub)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
op_begemot_base_bridge(struct snmp_context * ctx,struct snmp_value * val,uint sub,uint iidx __unused,enum snmp_op op)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
op_begemot_stp(struct snmp_context * ctx,struct snmp_value * val,uint sub,uint iidx __unused,enum snmp_op op)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
op_begemot_tp(struct snmp_context * ctx,struct snmp_value * val,uint sub,uint iidx __unused,enum snmp_op op)1397 op_begemot_tp(struct snmp_context *ctx, struct snmp_value *val,
1398 uint sub, uint iidx __unused, enum snmp_op op)
1399 {
1400 struct bridge_if *bif;
1401
1402 if (time(NULL) - bridge_list_age > bridge_get_data_maxage())
1403 bridge_update_all_ifs();
1404
1405 switch (op) {
1406 case SNMP_OP_GET:
1407 if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1408 return (SNMP_ERR_NOSUCHNAME);
1409 goto get;
1410
1411 case SNMP_OP_GETNEXT:
1412 if ((bif = bridge_if_index_getnext(&val->var, sub)) == NULL)
1413 return (SNMP_ERR_NOSUCHNAME);
1414 bridge_if_index_append(&val->var, sub, bif);
1415 goto get;
1416
1417 case SNMP_OP_SET:
1418 if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1419 return (SNMP_ERR_NOSUCHNAME);
1420
1421 switch (val->var.subs[sub - 1]) {
1422 case LEAF_begemotBridgeTpAgingTime:
1423 if (val->v.integer < SNMP_BRIDGE_MIN_AGE_TIME ||
1424 val->v.integer > SNMP_BRIDGE_MAX_AGE_TIME)
1425 return (SNMP_ERR_WRONG_VALUE);
1426
1427 ctx->scratch->int1 = bif->age_time;
1428 if (bridge_set_aging_time(bif, val->v.integer) < 0)
1429 return (SNMP_ERR_GENERR);
1430 return (SNMP_ERR_NOERROR);
1431
1432 case LEAF_begemotBridgeTpMaxAddresses:
1433 ctx->scratch->int1 = bif->max_addrs;
1434 if (bridge_set_max_cache(bif, val->v.integer) < 0)
1435 return (SNMP_ERR_GENERR);
1436 return (SNMP_ERR_NOERROR);
1437
1438 case LEAF_begemotBridgeTpLearnedEntryDiscards:
1439 return (SNMP_ERR_NOT_WRITEABLE);
1440 }
1441 abort();
1442
1443 case SNMP_OP_ROLLBACK:
1444 if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1445 return (SNMP_ERR_GENERR);
1446
1447 switch (val->var.subs[sub - 1]) {
1448 case LEAF_begemotBridgeTpAgingTime:
1449 bridge_set_aging_time(bif, ctx->scratch->int1);
1450 break;
1451
1452 case LEAF_begemotBridgeTpMaxAddresses:
1453 bridge_set_max_cache(bif, ctx->scratch->int1);
1454 break;
1455 }
1456 return (SNMP_ERR_NOERROR);
1457
1458 case SNMP_OP_COMMIT:
1459 return (SNMP_ERR_NOERROR);
1460 }
1461 abort();
1462
1463 get:
1464 switch (val->var.subs[sub - 1]) {
1465 case LEAF_begemotBridgeTpLearnedEntryDiscards:
1466 val->v.uint32 = bif->lrnt_drops;
1467 return (SNMP_ERR_NOERROR);
1468
1469 case LEAF_begemotBridgeTpAgingTime:
1470 val->v.integer = bif->age_time;
1471 return (SNMP_ERR_NOERROR);
1472
1473 case LEAF_begemotBridgeTpMaxAddresses:
1474 val->v.integer = bif->max_addrs;
1475 return (SNMP_ERR_NOERROR);
1476 }
1477
1478 abort();
1479 }
1480