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