Deleted Added
full compact
bridge_if.c (164997) bridge_if.c (165046)
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 *
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: head/usr.sbin/bsnmpd/modules/snmp_bridge/bridge_if.c 164997 2006-12-07 22:36:17Z syrinx $
29 * $FreeBSD: head/usr.sbin/bsnmpd/modules/snmp_bridge/bridge_if.c 165046 2006-12-09 20:58:26Z syrinx $
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
55static const struct asn_oid oid_newRoot = OIDX_newRoot;
56static const struct asn_oid oid_TopologyChange = OIDX_topologyChange;
57static const struct asn_oid oid_begemotBrigeName = \
58 OIDX_begemotBridgeBaseName;
59static const struct asn_oid oid_begemotNewRoot = OIDX_begemotBridgeNewRoot;
60static const struct asn_oid oid_begemotTopologyChange = \
61 OIDX_begemotBridgeTopologyChange;
62
63TAILQ_HEAD(bridge_ifs, bridge_if);
64
65/*
66 * Free the bridge interface list.
67 */
68static void
69bridge_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 */
83static void
84bridge_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. */
103static struct bridge_ifs bridge_ifs = TAILQ_HEAD_INITIALIZER(bridge_ifs);
104static time_t bridge_list_age;
105
106/*
107 * Free the global list.
108 */
109void
110bridge_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 */
118struct bridge_if *
119bridge_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 */
133struct bridge_if *
134bridge_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 */
148const char *
149bridge_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 */
169int
170bridge_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 */
199struct bridge_if *
200bridge_first_bif(void)
201{
202 return (TAILQ_FIRST(&bridge_ifs));
203}
204
205/*
206 * Fetch the next bridge interface from the list.
207 */
208struct bridge_if *
209bridge_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 */
218static struct bridge_if *
219bridge_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 */
246void
247bridge_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 */
260static struct snmp_value*
261bridge_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 */
287static void
288bridge_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 */
306static void
307bridge_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
322static int
323bridge_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
338static int
339bridge_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 */
352static int
353bridge_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 occured while fetching the info from the kernel.
382 */
383static int
384bridge_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
404 if (ifp->mib.ifmd_flags & IFF_RUNNING)
405 bif->if_status = RowStatus_active;
406 else
407 bif->if_status = RowStatus_notInService;
408
409 switch (bridge_getinfo_bif(bif)) {
410 case 2:
411 bridge_new_root(bif);
412 break;
413 case 1:
414 bridge_top_change(bif);
415 break;
416 case -1:
417 bridge_remove_bif(bif);
418 return (-1);
419 default:
420 break;
421 }
422
423 /*
424 * The number of ports is accessible via SNMP -
425 * update the ports each time the bridge interface data
426 * is refreshed too.
427 */
428 bif->num_ports = bridge_update_memif(bif);
429 bif->entry_age = time(NULL);
430
431 return (1);
432}
433
434/*
435 * Update all bridge interfaces' ports only -
436 * make sure each bridge interface exists first.
437 */
438void
439bridge_update_all_ports(void)
440{
441 struct mibif *ifp;
442 struct bridge_if *bif, *t_bif;
443
444 for (bif = bridge_first_bif(); bif != NULL; bif = t_bif) {
445 t_bif = bridge_next_bif(bif);
446
447 for (ifp = mib_first_if(); ifp != NULL;
448 ifp = mib_next_if(ifp))
449 if (strcmp(ifp->name, bif->bif_name) == 0)
450 break;
451
452 if (ifp != NULL)
453 bif->num_ports = bridge_update_memif(bif);
454 else /* Ops, we do not exist anymore. */
455 bridge_remove_bif(bif);
456 }
457
458 bridge_ports_update_listage();
459}
460
461/*
462 * Update all addresses only.
463 */
464void
465bridge_update_all_addrs(void)
466{
467 struct mibif *ifp;
468 struct bridge_if *bif, *t_bif;
469
470 for (bif = bridge_first_bif(); bif != NULL; bif = t_bif) {
471 t_bif = bridge_next_bif(bif);
472
473 for (ifp = mib_first_if(); ifp != NULL;
474 ifp = mib_next_if(ifp))
475 if (strcmp(ifp->name, bif->bif_name) == 0)
476 break;
477
478 if (ifp != NULL)
479 bif->num_addrs = bridge_update_addrs(bif);
480 else /* Ops, we don't exist anymore. */
481 bridge_remove_bif(bif);
482 }
483
484 bridge_addrs_update_listage();
485}
486
487/*
488 * Update only the bridge interfaces' data - skip addresses.
489 */
490void
491bridge_update_all_ifs(void)
492{
493 struct bridge_if *bif, *t_bif;
494
495 for (bif = bridge_first_bif(); bif != NULL; bif = t_bif) {
496 t_bif = bridge_next_bif(bif);
497 bridge_update_bif(bif);
498 }
499
500 bridge_ports_update_listage();
501 bridge_list_age = time(NULL);
502}
503
504/*
505 * Update all info we have for all bridges.
506 */
507void
508bridge_update_all(void *arg __unused)
509{
510 struct bridge_if *bif, *t_bif;
511
512 for (bif = bridge_first_bif(); bif != NULL; bif = t_bif) {
513 t_bif = bridge_next_bif(bif);
514 if (bridge_update_bif(bif) <= 0)
515 continue;
516
517 /* Update our learnt addresses. */
518 bif->num_addrs = bridge_update_addrs(bif);
519 }
520
521 bridge_list_age = time(NULL);
522 bridge_ports_update_listage();
523 bridge_addrs_update_listage();
524}
525
526/*
527 * Callback for polling our last topology change time -
528 * check whether we are root or whether a TC was detected once every
529 * 30 seconds, so that we can send the newRoot and TopologyChange traps
530 * on time. The rest of the data is polled only once every 5 min.
531 */
532void
533bridge_update_tc_time(void *arg __unused)
534{
535 struct bridge_if *bif;
536 struct mibif *ifp;
537
538 TAILQ_FOREACH(bif, &bridge_ifs, b_if) {
539 /* Walk through the mibII interface list. */
540 for (ifp = mib_first_if(); ifp != NULL; ifp = mib_next_if(ifp))
541 if (strcmp(ifp->name, bif->bif_name) == 0)
542 break;
543
544 if (ifp == NULL) {
545 bridge_remove_bif(bif);
546 continue;
547 }
548
549 switch (bridge_get_op_param(bif)) {
550 case 2:
551 bridge_new_root(bif);
552 break;
553 case 1:
554 bridge_top_change(bif);
555 break;
556 }
557 }
558}
559
560/*
561 * Callback for handling new bridge interface creation.
562 */
563int
564bridge_attach_newif(struct mibif *ifp)
565{
566 u_char *p_mac, mac[ETHER_ADDR_LEN];
567 struct bridge_if *bif;
568
569 if (ifp->mib.ifmd_data.ifi_type != IFT_BRIDGE)
570 return (0);
571
572 /* Make sure it does not exist in our list. */
573 TAILQ_FOREACH(bif, &bridge_ifs, b_if)
574 if(strcmp(bif->bif_name, ifp->name) == 0) {
575 syslog(LOG_ERR, "bridge interface %s already "
576 "in list", bif->bif_name);
577 return (-1);
578 }
579
580 if ((p_mac = ifp->physaddr) == NULL &&
581 (p_mac = bridge_get_basemac(ifp->name, mac)) == NULL) {
582 syslog(LOG_ERR, "bridge attach new %s failed - "
583 "no bridge mac address", ifp->name);
584 return (-1);
585 }
586
587 if ((bif = bridge_new_bif(ifp->name, ifp->sysindex, p_mac)) == NULL)
588 return (-1);
589
590 if (ifp->mib.ifmd_flags & IFF_RUNNING)
591 bif->if_status = RowStatus_active;
592 else
593 bif->if_status = RowStatus_notInService;
594
595 /* Skip sending notifications if the interface was just created. */
596 if (bridge_getinfo_bif(bif) < 0 ||
597 (bif->num_ports = bridge_getinfo_bif_ports(bif)) < 0 ||
598 (bif->num_addrs = bridge_getinfo_bif_addrs(bif)) < 0) {
599 bridge_remove_bif(bif);
600 return (-1);
601 }
602
603 /* Check whether we are the default bridge interface. */
604 if (strcmp(ifp->name, bridge_get_default_name()) == 0)
605 bridge_set_default(bif);
606
607 return (0);
608}
609
610void
611bridge_ifs_dump(void)
612{
613 struct bridge_if *bif;
614
615 for (bif = bridge_first_bif(); bif != NULL;
616 bif = bridge_next_bif(bif)) {
617 syslog(LOG_ERR, "Bridge %s, index - %d", bif->bif_name,
618 bif->sysindex);
619 bridge_ports_dump(bif);
620 bridge_addrs_dump(bif);
621 }
622}
623
624/*
625 * RFC4188 specifics.
626 */
627int
628op_dot1d_base(struct snmp_context *ctx __unused, struct snmp_value *value,
629 uint sub, uint iidx __unused, enum snmp_op op)
630{
631 int ret;
632 struct bridge_if *bif;
633
634 if ((bif = bridge_get_default()) == NULL)
635 return (SNMP_ERR_NOSUCHNAME);
636
637 if (time(NULL) - bif->entry_age > bridge_get_data_maxage() &&
638 bridge_update_bif(bif) <= 0) /* It was just deleted. */
639 return (SNMP_ERR_NOSUCHNAME);
640
641 ret = SNMP_ERR_NOERROR;
642
643 switch (op) {
644 case SNMP_OP_GET:
645 switch (value->var.subs[sub - 1]) {
646 case LEAF_dot1dBaseBridgeAddress:
647 ret = string_get(value, bif->br_addr.octet,
648 ETHER_ADDR_LEN);
649 break;
650 case LEAF_dot1dBaseNumPorts:
651 value->v.integer = bif->num_ports;
652 break;
653 case LEAF_dot1dBaseType:
654 value->v.integer = bif->br_type;
655 break;
656 abort();
657 }
658 break;
659
660 case SNMP_OP_SET:
661 ret = SNMP_ERR_NOT_WRITEABLE;
662 break;
663
664 case SNMP_OP_GETNEXT:
665 case SNMP_OP_ROLLBACK:
666 case SNMP_OP_COMMIT:
667 abort();
668 }
669
670 return (ret);
671}
672
673int
674op_dot1d_stp(struct snmp_context *ctx, struct snmp_value *value,
675 uint sub, uint iidx __unused, enum snmp_op op)
676{
677 int ret;
678 struct bridge_if *bif;
679
680 if ((bif = bridge_get_default()) == NULL)
681 return (SNMP_ERR_NOSUCHNAME);
682
683 if (time(NULL) - bif->entry_age > bridge_get_data_maxage() &&
684 bridge_update_bif(bif) <= 0) /* It was just deleted. */
685 return (SNMP_ERR_NOSUCHNAME);
686
687 switch (op) {
688 case SNMP_OP_GET:
689 switch (value->var.subs[sub - 1]) {
690 case LEAF_dot1dStpProtocolSpecification:
691 value->v.integer = bif->prot_spec;
692 break;
693
694 case LEAF_dot1dStpPriority:
695 value->v.integer = bif->priority;
696 break;
697
698 case LEAF_dot1dStpTimeSinceTopologyChange:
699 if (bridge_get_time_since_tc(bif,
700 &(value->v.uint32)) < 0)
701 return (SNMP_ERR_GENERR);
702 break;
703
704 case LEAF_dot1dStpTopChanges:
705 value->v.uint32 = bif->top_changes;
706 break;
707
708 case LEAF_dot1dStpDesignatedRoot:
709 return (string_get(value, bif->design_root,
710 SNMP_BRIDGE_ID_LEN));
711
712 case LEAF_dot1dStpRootCost:
713 value->v.integer = bif->root_cost;
714 break;
715
716 case LEAF_dot1dStpRootPort:
717 value->v.integer = bif->root_port;
718 break;
719
720 case LEAF_dot1dStpMaxAge:
721 value->v.integer = bif->max_age;
722 break;
723
724 case LEAF_dot1dStpHelloTime:
725 value->v.integer = bif->hello_time;
726 break;
727
728 case LEAF_dot1dStpHoldTime:
729 value->v.integer = bif->hold_time;
730 break;
731
732 case LEAF_dot1dStpForwardDelay:
733 value->v.integer = bif->fwd_delay;
734 break;
735
736 case LEAF_dot1dStpBridgeMaxAge:
737 value->v.integer = bif->bridge_max_age;
738 break;
739
740 case LEAF_dot1dStpBridgeHelloTime:
741 value->v.integer = bif->bridge_hello_time;
742 break;
743
744 case LEAF_dot1dStpBridgeForwardDelay:
745 value->v.integer = bif->bridge_fwd_delay;
746 break;
747 case LEAF_dot1dStpVersion:
748 value->v.integer = bif->stp_version;
749 break;
750 case LEAF_dot1dStpTxHoldCount:
751 value->v.integer = bif->tx_hold_count;
752 }
753
754 return (SNMP_ERR_NOERROR);
755
756 case SNMP_OP_GETNEXT:
757 abort();
758
759 case SNMP_OP_SET:
760 switch (value->var.subs[sub - 1]) {
761 case LEAF_dot1dStpPriority:
762 ctx->scratch->int1 = bif->priority;
763 ret = bridge_set_priority(bif, value->v.integer);
764 break;
765
766 case LEAF_dot1dStpBridgeMaxAge:
767 ctx->scratch->int1 = bif->bridge_max_age;
768 ret = bridge_set_maxage(bif, value->v.integer);
769 break;
770
771 case LEAF_dot1dStpBridgeHelloTime:
772 ctx->scratch->int1 = bif->bridge_hello_time;
773 ret = bridge_set_hello_time(bif, value->v.integer);
774 break;
775
776 case LEAF_dot1dStpBridgeForwardDelay:
777 ctx->scratch->int1 = bif->bridge_fwd_delay;
778 ret = bridge_set_forward_delay(bif, value->v.integer);
779 break;
780
781 case LEAF_dot1dStpVersion:
782 ctx->scratch->int1 = bif->stp_version;
783 ret = bridge_set_stp_version(bif, value->v.integer);
784 break;
785
786 case LEAF_dot1dStpTxHoldCount:
787 ctx->scratch->int1 = bif->tx_hold_count;
788 ret = bridge_set_tx_hold_count(bif, value->v.integer);
789 break;
790
791 case LEAF_dot1dStpProtocolSpecification:
792 case LEAF_dot1dStpTimeSinceTopologyChange:
793 case LEAF_dot1dStpTopChanges:
794 case LEAF_dot1dStpDesignatedRoot:
795 case LEAF_dot1dStpRootCost:
796 case LEAF_dot1dStpRootPort:
797 case LEAF_dot1dStpMaxAge:
798 case LEAF_dot1dStpHelloTime:
799 case LEAF_dot1dStpHoldTime:
800 case LEAF_dot1dStpForwardDelay:
801 return (SNMP_ERR_NOT_WRITEABLE);
802 default:
803 return (SNMP_ERR_NOSUCHNAME);
804 }
805
806 if (ret == -2)
807 return (SNMP_ERR_WRONG_VALUE);
808 else if (ret < 0)
809 return (SNMP_ERR_GENERR);
810 return (SNMP_ERR_NOERROR);
811
812 case SNMP_OP_ROLLBACK:
813 switch (value->var.subs[sub - 1]) {
814 case LEAF_dot1dStpPriority:
815 bridge_set_priority(bif, ctx->scratch->int1);
816 break;
817 case LEAF_dot1dStpBridgeMaxAge:
818 bridge_set_maxage(bif, ctx->scratch->int1);
819 break;
820 case LEAF_dot1dStpBridgeHelloTime:
821 bridge_set_hello_time(bif, ctx->scratch->int1);
822 break;
823 case LEAF_dot1dStpBridgeForwardDelay:
824 bridge_set_forward_delay(bif, ctx->scratch->int1);
825 break;
826 case LEAF_dot1dStpVersion:
827 bridge_set_stp_version(bif, ctx->scratch->int1);
828 break;
829 case LEAF_dot1dStpTxHoldCount:
830 bridge_set_tx_hold_count(bif, ctx->scratch->int1);
831 break;
832 }
833 return (SNMP_ERR_NOERROR);
834
835 case SNMP_OP_COMMIT:
836 return (SNMP_ERR_NOERROR);
837 }
838
839 return (SNMP_ERR_NOERROR);
840}
841
842int
843op_dot1d_tp(struct snmp_context *ctx, struct snmp_value *value,
844 uint sub, uint iidx __unused, enum snmp_op op)
845{
846 struct bridge_if *bif;
847
848 if ((bif = bridge_get_default()) == NULL)
849 return (SNMP_ERR_NOSUCHNAME);
850
851 if (time(NULL) - bif->entry_age > bridge_get_data_maxage() &&
852 bridge_update_bif(bif) <= 0) /* It was just deleted. */
853 return (SNMP_ERR_NOSUCHNAME);
854
855 switch (op) {
856 case SNMP_OP_GET:
857 switch (value->var.subs[sub - 1]) {
858 case LEAF_dot1dTpLearnedEntryDiscards:
859 value->v.uint32 = bif->lrnt_drops;
860 break;
861 case LEAF_dot1dTpAgingTime:
862 value->v.integer = bif->age_time;
863 break;
864 }
865 return (SNMP_ERR_NOERROR);
866
867 case SNMP_OP_GETNEXT:
868 abort();
869
870 case SNMP_OP_SET:
871 if (value->var.subs[sub - 1] == LEAF_dot1dTpAgingTime) {
872 ctx->scratch->int1 = bif->age_time;
873 if (bridge_set_aging_time(bif, value->v.integer) < 0)
874 return (SNMP_ERR_GENERR);
875 }
876 return (SNMP_ERR_NOERROR);
877
878 case SNMP_OP_ROLLBACK:
879 if (value->var.subs[sub - 1] == LEAF_dot1dTpAgingTime)
880 bridge_set_aging_time(bif, ctx->scratch->int1);
881 return (SNMP_ERR_NOERROR);
882
883 case SNMP_OP_COMMIT:
884 return (SNMP_ERR_NOERROR);
885 }
886
887 return (SNMP_ERR_NOERROR);
888}
889
890/*
891 * Private BEGEMOT-BRIDGE-MIB specifics.
892 */
893
894/*
895 * Get the bridge name from an OID index.
896 */
897static char *
898bridge_name_index_get(const struct asn_oid *oid, uint sub, char *b_name)
899{
900 uint i;
901
902 if (oid->len - sub != oid->subs[sub] + 1 || oid->subs[sub] >= IFNAMSIZ)
903 return (NULL);
904
905 for (i = 0; i < oid->subs[sub]; i++)
906 b_name[i] = oid->subs[sub + i + 1];
907 b_name[i] = '\0';
908
909 return (b_name);
910}
911
912static void
913bridge_if_index_append(struct asn_oid *oid, uint sub,
914 const struct bridge_if *bif)
915{
916 uint i;
917
918 oid->len = sub + strlen(bif->bif_name) + 1;
919 oid->subs[sub] = strlen(bif->bif_name);
920
921 for (i = 1; i <= strlen(bif->bif_name); i++)
922 oid->subs[sub + i] = bif->bif_name[i - 1];
923}
924
925static struct bridge_if *
926bridge_if_index_get(const struct asn_oid *oid, uint sub)
927{
928 uint i;
929 char bif_name[IFNAMSIZ];
930
931 if (oid->len - sub != oid->subs[sub] + 1 || oid->subs[sub] >= IFNAMSIZ)
932 return (NULL);
933
934 for (i = 0; i < oid->subs[sub]; i++)
935 bif_name[i] = oid->subs[sub + i + 1];
936 bif_name[i] = '\0';
937
938 return (bridge_if_find_ifname(bif_name));
939}
940
941static struct bridge_if *
942bridge_if_index_getnext(const struct asn_oid *oid, uint sub)
943{
944 uint i;
945 char bif_name[IFNAMSIZ];
946 struct bridge_if *bif;
947
948 if (oid->len - sub == 0)
949 return (bridge_first_bif());
950
951 if (oid->len - sub != oid->subs[sub] + 1 || oid->subs[sub] >= IFNAMSIZ)
952 return (NULL);
953
954 for (i = 0; i < oid->subs[sub]; i++)
955 bif_name[i] = oid->subs[sub + i + 1];
956 bif_name[i] = '\0';
957
958 if ((bif = bridge_if_find_ifname(bif_name)) == NULL)
959 return (NULL);
960
961 return (bridge_next_bif(bif));
962}
963
964static int
965bridge_set_if_status(struct snmp_context *ctx,
966 struct snmp_value *val, uint sub)
967{
968 struct bridge_if *bif;
969 char bif_name[IFNAMSIZ];
970
971 bif = bridge_if_index_get(&val->var, sub);
972
973 switch (val->v.integer) {
974 case RowStatus_active:
975 if (bif == NULL)
976 return (SNMP_ERR_INCONS_VALUE);
977
978 ctx->scratch->int1 = bif->if_status;
979
980 switch (bif->if_status) {
981 case RowStatus_active:
982 return (SNMP_ERR_NOERROR);
983 case RowStatus_notInService:
984 if (bridge_set_if_up(bif->bif_name, 1) < 0)
985 return (SNMP_ERR_GENERR);
986 return (SNMP_ERR_NOERROR);
987 default:
988 break;
989 }
990 return (SNMP_ERR_INCONS_VALUE);
991
992 case RowStatus_notInService:
993 if (bif == NULL)
994 return (SNMP_ERR_INCONS_VALUE);
995
996 ctx->scratch->int1 = bif->if_status;
997
998 switch (bif->if_status) {
999 case RowStatus_active:
1000 if (bridge_set_if_up(bif->bif_name, 1) < 0)
1001 return (SNMP_ERR_GENERR);
1002 return (SNMP_ERR_NOERROR);
1003 case RowStatus_notInService:
1004 return (SNMP_ERR_NOERROR);
1005 default:
1006 break;
1007 }
1008 return (SNMP_ERR_INCONS_VALUE);
1009
1010 case RowStatus_notReady:
1011 return (SNMP_ERR_INCONS_VALUE);
1012
1013 case RowStatus_createAndGo:
1014 if (bif != NULL)
1015 return (SNMP_ERR_INCONS_VALUE);
1016
1017 ctx->scratch->int1 = RowStatus_destroy;
1018
1019 if (bridge_name_index_get(&val->var, sub, bif_name) == NULL)
1020 return (SNMP_ERR_BADVALUE);
1021 if (bridge_if_create(bif_name, 1) < 0)
1022 return (SNMP_ERR_GENERR);
1023 return (SNMP_ERR_NOERROR);
1024
1025 case RowStatus_createAndWait:
1026 if (bif != NULL)
1027 return (SNMP_ERR_INCONS_VALUE);
1028
1029 if (bridge_name_index_get(&val->var, sub, bif_name) == NULL)
1030 return (SNMP_ERR_BADVALUE);
1031
1032 ctx->scratch->int1 = RowStatus_destroy;
1033
1034 if (bridge_if_create(bif_name, 0) < 0)
1035 return (SNMP_ERR_GENERR);
1036 return (SNMP_ERR_NOERROR);
1037
1038 case RowStatus_destroy:
1039 if (bif == NULL)
1040 return (SNMP_ERR_NOSUCHNAME);
1041
1042 ctx->scratch->int1 = bif->if_status;
1043 bif->if_status = RowStatus_destroy;
1044 }
1045
1046 return (SNMP_ERR_NOERROR);
1047}
1048
1049static int
1050bridge_rollback_if_status(struct snmp_context *ctx,
1051 struct snmp_value *val, uint sub)
1052{
1053 struct bridge_if *bif;
1054
1055 if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1056 return (SNMP_ERR_GENERR);
1057
1058 switch (ctx->scratch->int1) {
1059 case RowStatus_destroy:
1060 bridge_if_destroy(bif);
1061 return (SNMP_ERR_NOERROR);
1062
1063 case RowStatus_notInService:
1064 if (bif->if_status != ctx->scratch->int1)
1065 bridge_set_if_up(bif->bif_name, 0);
1066 bif->if_status = RowStatus_notInService;
1067 return (SNMP_ERR_NOERROR);
1068
1069 case RowStatus_active:
1070 if (bif->if_status != ctx->scratch->int1)
1071 bridge_set_if_up(bif->bif_name, 1);
1072 bif->if_status = RowStatus_active;
1073 return (SNMP_ERR_NOERROR);
1074 }
1075
1076 abort();
1077}
1078
1079static int
1080bridge_commit_if_status(struct snmp_value *val, uint sub)
1081{
1082 struct bridge_if *bif;
1083
1084 if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1085 return (SNMP_ERR_GENERR);
1086
1087 if (bif->if_status == RowStatus_destroy &&
1088 bridge_if_destroy(bif) < 0)
1089 return (SNMP_ERR_COMMIT_FAILED);
1090
1091 return (SNMP_ERR_NOERROR);
1092}
1093
1094int
1095op_begemot_base_bridge(struct snmp_context *ctx, struct snmp_value *val,
1096 uint sub, uint iidx __unused, enum snmp_op op)
1097{
1098 int ret;
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
55static const struct asn_oid oid_newRoot = OIDX_newRoot;
56static const struct asn_oid oid_TopologyChange = OIDX_topologyChange;
57static const struct asn_oid oid_begemotBrigeName = \
58 OIDX_begemotBridgeBaseName;
59static const struct asn_oid oid_begemotNewRoot = OIDX_begemotBridgeNewRoot;
60static const struct asn_oid oid_begemotTopologyChange = \
61 OIDX_begemotBridgeTopologyChange;
62
63TAILQ_HEAD(bridge_ifs, bridge_if);
64
65/*
66 * Free the bridge interface list.
67 */
68static void
69bridge_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 */
83static void
84bridge_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. */
103static struct bridge_ifs bridge_ifs = TAILQ_HEAD_INITIALIZER(bridge_ifs);
104static time_t bridge_list_age;
105
106/*
107 * Free the global list.
108 */
109void
110bridge_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 */
118struct bridge_if *
119bridge_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 */
133struct bridge_if *
134bridge_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 */
148const char *
149bridge_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 */
169int
170bridge_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 */
199struct bridge_if *
200bridge_first_bif(void)
201{
202 return (TAILQ_FIRST(&bridge_ifs));
203}
204
205/*
206 * Fetch the next bridge interface from the list.
207 */
208struct bridge_if *
209bridge_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 */
218static struct bridge_if *
219bridge_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 */
246void
247bridge_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 */
260static struct snmp_value*
261bridge_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 */
287static void
288bridge_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 */
306static void
307bridge_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
322static int
323bridge_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
338static int
339bridge_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 */
352static int
353bridge_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 occured while fetching the info from the kernel.
382 */
383static int
384bridge_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
404 if (ifp->mib.ifmd_flags & IFF_RUNNING)
405 bif->if_status = RowStatus_active;
406 else
407 bif->if_status = RowStatus_notInService;
408
409 switch (bridge_getinfo_bif(bif)) {
410 case 2:
411 bridge_new_root(bif);
412 break;
413 case 1:
414 bridge_top_change(bif);
415 break;
416 case -1:
417 bridge_remove_bif(bif);
418 return (-1);
419 default:
420 break;
421 }
422
423 /*
424 * The number of ports is accessible via SNMP -
425 * update the ports each time the bridge interface data
426 * is refreshed too.
427 */
428 bif->num_ports = bridge_update_memif(bif);
429 bif->entry_age = time(NULL);
430
431 return (1);
432}
433
434/*
435 * Update all bridge interfaces' ports only -
436 * make sure each bridge interface exists first.
437 */
438void
439bridge_update_all_ports(void)
440{
441 struct mibif *ifp;
442 struct bridge_if *bif, *t_bif;
443
444 for (bif = bridge_first_bif(); bif != NULL; bif = t_bif) {
445 t_bif = bridge_next_bif(bif);
446
447 for (ifp = mib_first_if(); ifp != NULL;
448 ifp = mib_next_if(ifp))
449 if (strcmp(ifp->name, bif->bif_name) == 0)
450 break;
451
452 if (ifp != NULL)
453 bif->num_ports = bridge_update_memif(bif);
454 else /* Ops, we do not exist anymore. */
455 bridge_remove_bif(bif);
456 }
457
458 bridge_ports_update_listage();
459}
460
461/*
462 * Update all addresses only.
463 */
464void
465bridge_update_all_addrs(void)
466{
467 struct mibif *ifp;
468 struct bridge_if *bif, *t_bif;
469
470 for (bif = bridge_first_bif(); bif != NULL; bif = t_bif) {
471 t_bif = bridge_next_bif(bif);
472
473 for (ifp = mib_first_if(); ifp != NULL;
474 ifp = mib_next_if(ifp))
475 if (strcmp(ifp->name, bif->bif_name) == 0)
476 break;
477
478 if (ifp != NULL)
479 bif->num_addrs = bridge_update_addrs(bif);
480 else /* Ops, we don't exist anymore. */
481 bridge_remove_bif(bif);
482 }
483
484 bridge_addrs_update_listage();
485}
486
487/*
488 * Update only the bridge interfaces' data - skip addresses.
489 */
490void
491bridge_update_all_ifs(void)
492{
493 struct bridge_if *bif, *t_bif;
494
495 for (bif = bridge_first_bif(); bif != NULL; bif = t_bif) {
496 t_bif = bridge_next_bif(bif);
497 bridge_update_bif(bif);
498 }
499
500 bridge_ports_update_listage();
501 bridge_list_age = time(NULL);
502}
503
504/*
505 * Update all info we have for all bridges.
506 */
507void
508bridge_update_all(void *arg __unused)
509{
510 struct bridge_if *bif, *t_bif;
511
512 for (bif = bridge_first_bif(); bif != NULL; bif = t_bif) {
513 t_bif = bridge_next_bif(bif);
514 if (bridge_update_bif(bif) <= 0)
515 continue;
516
517 /* Update our learnt addresses. */
518 bif->num_addrs = bridge_update_addrs(bif);
519 }
520
521 bridge_list_age = time(NULL);
522 bridge_ports_update_listage();
523 bridge_addrs_update_listage();
524}
525
526/*
527 * Callback for polling our last topology change time -
528 * check whether we are root or whether a TC was detected once every
529 * 30 seconds, so that we can send the newRoot and TopologyChange traps
530 * on time. The rest of the data is polled only once every 5 min.
531 */
532void
533bridge_update_tc_time(void *arg __unused)
534{
535 struct bridge_if *bif;
536 struct mibif *ifp;
537
538 TAILQ_FOREACH(bif, &bridge_ifs, b_if) {
539 /* Walk through the mibII interface list. */
540 for (ifp = mib_first_if(); ifp != NULL; ifp = mib_next_if(ifp))
541 if (strcmp(ifp->name, bif->bif_name) == 0)
542 break;
543
544 if (ifp == NULL) {
545 bridge_remove_bif(bif);
546 continue;
547 }
548
549 switch (bridge_get_op_param(bif)) {
550 case 2:
551 bridge_new_root(bif);
552 break;
553 case 1:
554 bridge_top_change(bif);
555 break;
556 }
557 }
558}
559
560/*
561 * Callback for handling new bridge interface creation.
562 */
563int
564bridge_attach_newif(struct mibif *ifp)
565{
566 u_char *p_mac, mac[ETHER_ADDR_LEN];
567 struct bridge_if *bif;
568
569 if (ifp->mib.ifmd_data.ifi_type != IFT_BRIDGE)
570 return (0);
571
572 /* Make sure it does not exist in our list. */
573 TAILQ_FOREACH(bif, &bridge_ifs, b_if)
574 if(strcmp(bif->bif_name, ifp->name) == 0) {
575 syslog(LOG_ERR, "bridge interface %s already "
576 "in list", bif->bif_name);
577 return (-1);
578 }
579
580 if ((p_mac = ifp->physaddr) == NULL &&
581 (p_mac = bridge_get_basemac(ifp->name, mac)) == NULL) {
582 syslog(LOG_ERR, "bridge attach new %s failed - "
583 "no bridge mac address", ifp->name);
584 return (-1);
585 }
586
587 if ((bif = bridge_new_bif(ifp->name, ifp->sysindex, p_mac)) == NULL)
588 return (-1);
589
590 if (ifp->mib.ifmd_flags & IFF_RUNNING)
591 bif->if_status = RowStatus_active;
592 else
593 bif->if_status = RowStatus_notInService;
594
595 /* Skip sending notifications if the interface was just created. */
596 if (bridge_getinfo_bif(bif) < 0 ||
597 (bif->num_ports = bridge_getinfo_bif_ports(bif)) < 0 ||
598 (bif->num_addrs = bridge_getinfo_bif_addrs(bif)) < 0) {
599 bridge_remove_bif(bif);
600 return (-1);
601 }
602
603 /* Check whether we are the default bridge interface. */
604 if (strcmp(ifp->name, bridge_get_default_name()) == 0)
605 bridge_set_default(bif);
606
607 return (0);
608}
609
610void
611bridge_ifs_dump(void)
612{
613 struct bridge_if *bif;
614
615 for (bif = bridge_first_bif(); bif != NULL;
616 bif = bridge_next_bif(bif)) {
617 syslog(LOG_ERR, "Bridge %s, index - %d", bif->bif_name,
618 bif->sysindex);
619 bridge_ports_dump(bif);
620 bridge_addrs_dump(bif);
621 }
622}
623
624/*
625 * RFC4188 specifics.
626 */
627int
628op_dot1d_base(struct snmp_context *ctx __unused, struct snmp_value *value,
629 uint sub, uint iidx __unused, enum snmp_op op)
630{
631 int ret;
632 struct bridge_if *bif;
633
634 if ((bif = bridge_get_default()) == NULL)
635 return (SNMP_ERR_NOSUCHNAME);
636
637 if (time(NULL) - bif->entry_age > bridge_get_data_maxage() &&
638 bridge_update_bif(bif) <= 0) /* It was just deleted. */
639 return (SNMP_ERR_NOSUCHNAME);
640
641 ret = SNMP_ERR_NOERROR;
642
643 switch (op) {
644 case SNMP_OP_GET:
645 switch (value->var.subs[sub - 1]) {
646 case LEAF_dot1dBaseBridgeAddress:
647 ret = string_get(value, bif->br_addr.octet,
648 ETHER_ADDR_LEN);
649 break;
650 case LEAF_dot1dBaseNumPorts:
651 value->v.integer = bif->num_ports;
652 break;
653 case LEAF_dot1dBaseType:
654 value->v.integer = bif->br_type;
655 break;
656 abort();
657 }
658 break;
659
660 case SNMP_OP_SET:
661 ret = SNMP_ERR_NOT_WRITEABLE;
662 break;
663
664 case SNMP_OP_GETNEXT:
665 case SNMP_OP_ROLLBACK:
666 case SNMP_OP_COMMIT:
667 abort();
668 }
669
670 return (ret);
671}
672
673int
674op_dot1d_stp(struct snmp_context *ctx, struct snmp_value *value,
675 uint sub, uint iidx __unused, enum snmp_op op)
676{
677 int ret;
678 struct bridge_if *bif;
679
680 if ((bif = bridge_get_default()) == NULL)
681 return (SNMP_ERR_NOSUCHNAME);
682
683 if (time(NULL) - bif->entry_age > bridge_get_data_maxage() &&
684 bridge_update_bif(bif) <= 0) /* It was just deleted. */
685 return (SNMP_ERR_NOSUCHNAME);
686
687 switch (op) {
688 case SNMP_OP_GET:
689 switch (value->var.subs[sub - 1]) {
690 case LEAF_dot1dStpProtocolSpecification:
691 value->v.integer = bif->prot_spec;
692 break;
693
694 case LEAF_dot1dStpPriority:
695 value->v.integer = bif->priority;
696 break;
697
698 case LEAF_dot1dStpTimeSinceTopologyChange:
699 if (bridge_get_time_since_tc(bif,
700 &(value->v.uint32)) < 0)
701 return (SNMP_ERR_GENERR);
702 break;
703
704 case LEAF_dot1dStpTopChanges:
705 value->v.uint32 = bif->top_changes;
706 break;
707
708 case LEAF_dot1dStpDesignatedRoot:
709 return (string_get(value, bif->design_root,
710 SNMP_BRIDGE_ID_LEN));
711
712 case LEAF_dot1dStpRootCost:
713 value->v.integer = bif->root_cost;
714 break;
715
716 case LEAF_dot1dStpRootPort:
717 value->v.integer = bif->root_port;
718 break;
719
720 case LEAF_dot1dStpMaxAge:
721 value->v.integer = bif->max_age;
722 break;
723
724 case LEAF_dot1dStpHelloTime:
725 value->v.integer = bif->hello_time;
726 break;
727
728 case LEAF_dot1dStpHoldTime:
729 value->v.integer = bif->hold_time;
730 break;
731
732 case LEAF_dot1dStpForwardDelay:
733 value->v.integer = bif->fwd_delay;
734 break;
735
736 case LEAF_dot1dStpBridgeMaxAge:
737 value->v.integer = bif->bridge_max_age;
738 break;
739
740 case LEAF_dot1dStpBridgeHelloTime:
741 value->v.integer = bif->bridge_hello_time;
742 break;
743
744 case LEAF_dot1dStpBridgeForwardDelay:
745 value->v.integer = bif->bridge_fwd_delay;
746 break;
747 case LEAF_dot1dStpVersion:
748 value->v.integer = bif->stp_version;
749 break;
750 case LEAF_dot1dStpTxHoldCount:
751 value->v.integer = bif->tx_hold_count;
752 }
753
754 return (SNMP_ERR_NOERROR);
755
756 case SNMP_OP_GETNEXT:
757 abort();
758
759 case SNMP_OP_SET:
760 switch (value->var.subs[sub - 1]) {
761 case LEAF_dot1dStpPriority:
762 ctx->scratch->int1 = bif->priority;
763 ret = bridge_set_priority(bif, value->v.integer);
764 break;
765
766 case LEAF_dot1dStpBridgeMaxAge:
767 ctx->scratch->int1 = bif->bridge_max_age;
768 ret = bridge_set_maxage(bif, value->v.integer);
769 break;
770
771 case LEAF_dot1dStpBridgeHelloTime:
772 ctx->scratch->int1 = bif->bridge_hello_time;
773 ret = bridge_set_hello_time(bif, value->v.integer);
774 break;
775
776 case LEAF_dot1dStpBridgeForwardDelay:
777 ctx->scratch->int1 = bif->bridge_fwd_delay;
778 ret = bridge_set_forward_delay(bif, value->v.integer);
779 break;
780
781 case LEAF_dot1dStpVersion:
782 ctx->scratch->int1 = bif->stp_version;
783 ret = bridge_set_stp_version(bif, value->v.integer);
784 break;
785
786 case LEAF_dot1dStpTxHoldCount:
787 ctx->scratch->int1 = bif->tx_hold_count;
788 ret = bridge_set_tx_hold_count(bif, value->v.integer);
789 break;
790
791 case LEAF_dot1dStpProtocolSpecification:
792 case LEAF_dot1dStpTimeSinceTopologyChange:
793 case LEAF_dot1dStpTopChanges:
794 case LEAF_dot1dStpDesignatedRoot:
795 case LEAF_dot1dStpRootCost:
796 case LEAF_dot1dStpRootPort:
797 case LEAF_dot1dStpMaxAge:
798 case LEAF_dot1dStpHelloTime:
799 case LEAF_dot1dStpHoldTime:
800 case LEAF_dot1dStpForwardDelay:
801 return (SNMP_ERR_NOT_WRITEABLE);
802 default:
803 return (SNMP_ERR_NOSUCHNAME);
804 }
805
806 if (ret == -2)
807 return (SNMP_ERR_WRONG_VALUE);
808 else if (ret < 0)
809 return (SNMP_ERR_GENERR);
810 return (SNMP_ERR_NOERROR);
811
812 case SNMP_OP_ROLLBACK:
813 switch (value->var.subs[sub - 1]) {
814 case LEAF_dot1dStpPriority:
815 bridge_set_priority(bif, ctx->scratch->int1);
816 break;
817 case LEAF_dot1dStpBridgeMaxAge:
818 bridge_set_maxage(bif, ctx->scratch->int1);
819 break;
820 case LEAF_dot1dStpBridgeHelloTime:
821 bridge_set_hello_time(bif, ctx->scratch->int1);
822 break;
823 case LEAF_dot1dStpBridgeForwardDelay:
824 bridge_set_forward_delay(bif, ctx->scratch->int1);
825 break;
826 case LEAF_dot1dStpVersion:
827 bridge_set_stp_version(bif, ctx->scratch->int1);
828 break;
829 case LEAF_dot1dStpTxHoldCount:
830 bridge_set_tx_hold_count(bif, ctx->scratch->int1);
831 break;
832 }
833 return (SNMP_ERR_NOERROR);
834
835 case SNMP_OP_COMMIT:
836 return (SNMP_ERR_NOERROR);
837 }
838
839 return (SNMP_ERR_NOERROR);
840}
841
842int
843op_dot1d_tp(struct snmp_context *ctx, struct snmp_value *value,
844 uint sub, uint iidx __unused, enum snmp_op op)
845{
846 struct bridge_if *bif;
847
848 if ((bif = bridge_get_default()) == NULL)
849 return (SNMP_ERR_NOSUCHNAME);
850
851 if (time(NULL) - bif->entry_age > bridge_get_data_maxage() &&
852 bridge_update_bif(bif) <= 0) /* It was just deleted. */
853 return (SNMP_ERR_NOSUCHNAME);
854
855 switch (op) {
856 case SNMP_OP_GET:
857 switch (value->var.subs[sub - 1]) {
858 case LEAF_dot1dTpLearnedEntryDiscards:
859 value->v.uint32 = bif->lrnt_drops;
860 break;
861 case LEAF_dot1dTpAgingTime:
862 value->v.integer = bif->age_time;
863 break;
864 }
865 return (SNMP_ERR_NOERROR);
866
867 case SNMP_OP_GETNEXT:
868 abort();
869
870 case SNMP_OP_SET:
871 if (value->var.subs[sub - 1] == LEAF_dot1dTpAgingTime) {
872 ctx->scratch->int1 = bif->age_time;
873 if (bridge_set_aging_time(bif, value->v.integer) < 0)
874 return (SNMP_ERR_GENERR);
875 }
876 return (SNMP_ERR_NOERROR);
877
878 case SNMP_OP_ROLLBACK:
879 if (value->var.subs[sub - 1] == LEAF_dot1dTpAgingTime)
880 bridge_set_aging_time(bif, ctx->scratch->int1);
881 return (SNMP_ERR_NOERROR);
882
883 case SNMP_OP_COMMIT:
884 return (SNMP_ERR_NOERROR);
885 }
886
887 return (SNMP_ERR_NOERROR);
888}
889
890/*
891 * Private BEGEMOT-BRIDGE-MIB specifics.
892 */
893
894/*
895 * Get the bridge name from an OID index.
896 */
897static char *
898bridge_name_index_get(const struct asn_oid *oid, uint sub, char *b_name)
899{
900 uint i;
901
902 if (oid->len - sub != oid->subs[sub] + 1 || oid->subs[sub] >= IFNAMSIZ)
903 return (NULL);
904
905 for (i = 0; i < oid->subs[sub]; i++)
906 b_name[i] = oid->subs[sub + i + 1];
907 b_name[i] = '\0';
908
909 return (b_name);
910}
911
912static void
913bridge_if_index_append(struct asn_oid *oid, uint sub,
914 const struct bridge_if *bif)
915{
916 uint i;
917
918 oid->len = sub + strlen(bif->bif_name) + 1;
919 oid->subs[sub] = strlen(bif->bif_name);
920
921 for (i = 1; i <= strlen(bif->bif_name); i++)
922 oid->subs[sub + i] = bif->bif_name[i - 1];
923}
924
925static struct bridge_if *
926bridge_if_index_get(const struct asn_oid *oid, uint sub)
927{
928 uint i;
929 char bif_name[IFNAMSIZ];
930
931 if (oid->len - sub != oid->subs[sub] + 1 || oid->subs[sub] >= IFNAMSIZ)
932 return (NULL);
933
934 for (i = 0; i < oid->subs[sub]; i++)
935 bif_name[i] = oid->subs[sub + i + 1];
936 bif_name[i] = '\0';
937
938 return (bridge_if_find_ifname(bif_name));
939}
940
941static struct bridge_if *
942bridge_if_index_getnext(const struct asn_oid *oid, uint sub)
943{
944 uint i;
945 char bif_name[IFNAMSIZ];
946 struct bridge_if *bif;
947
948 if (oid->len - sub == 0)
949 return (bridge_first_bif());
950
951 if (oid->len - sub != oid->subs[sub] + 1 || oid->subs[sub] >= IFNAMSIZ)
952 return (NULL);
953
954 for (i = 0; i < oid->subs[sub]; i++)
955 bif_name[i] = oid->subs[sub + i + 1];
956 bif_name[i] = '\0';
957
958 if ((bif = bridge_if_find_ifname(bif_name)) == NULL)
959 return (NULL);
960
961 return (bridge_next_bif(bif));
962}
963
964static int
965bridge_set_if_status(struct snmp_context *ctx,
966 struct snmp_value *val, uint sub)
967{
968 struct bridge_if *bif;
969 char bif_name[IFNAMSIZ];
970
971 bif = bridge_if_index_get(&val->var, sub);
972
973 switch (val->v.integer) {
974 case RowStatus_active:
975 if (bif == NULL)
976 return (SNMP_ERR_INCONS_VALUE);
977
978 ctx->scratch->int1 = bif->if_status;
979
980 switch (bif->if_status) {
981 case RowStatus_active:
982 return (SNMP_ERR_NOERROR);
983 case RowStatus_notInService:
984 if (bridge_set_if_up(bif->bif_name, 1) < 0)
985 return (SNMP_ERR_GENERR);
986 return (SNMP_ERR_NOERROR);
987 default:
988 break;
989 }
990 return (SNMP_ERR_INCONS_VALUE);
991
992 case RowStatus_notInService:
993 if (bif == NULL)
994 return (SNMP_ERR_INCONS_VALUE);
995
996 ctx->scratch->int1 = bif->if_status;
997
998 switch (bif->if_status) {
999 case RowStatus_active:
1000 if (bridge_set_if_up(bif->bif_name, 1) < 0)
1001 return (SNMP_ERR_GENERR);
1002 return (SNMP_ERR_NOERROR);
1003 case RowStatus_notInService:
1004 return (SNMP_ERR_NOERROR);
1005 default:
1006 break;
1007 }
1008 return (SNMP_ERR_INCONS_VALUE);
1009
1010 case RowStatus_notReady:
1011 return (SNMP_ERR_INCONS_VALUE);
1012
1013 case RowStatus_createAndGo:
1014 if (bif != NULL)
1015 return (SNMP_ERR_INCONS_VALUE);
1016
1017 ctx->scratch->int1 = RowStatus_destroy;
1018
1019 if (bridge_name_index_get(&val->var, sub, bif_name) == NULL)
1020 return (SNMP_ERR_BADVALUE);
1021 if (bridge_if_create(bif_name, 1) < 0)
1022 return (SNMP_ERR_GENERR);
1023 return (SNMP_ERR_NOERROR);
1024
1025 case RowStatus_createAndWait:
1026 if (bif != NULL)
1027 return (SNMP_ERR_INCONS_VALUE);
1028
1029 if (bridge_name_index_get(&val->var, sub, bif_name) == NULL)
1030 return (SNMP_ERR_BADVALUE);
1031
1032 ctx->scratch->int1 = RowStatus_destroy;
1033
1034 if (bridge_if_create(bif_name, 0) < 0)
1035 return (SNMP_ERR_GENERR);
1036 return (SNMP_ERR_NOERROR);
1037
1038 case RowStatus_destroy:
1039 if (bif == NULL)
1040 return (SNMP_ERR_NOSUCHNAME);
1041
1042 ctx->scratch->int1 = bif->if_status;
1043 bif->if_status = RowStatus_destroy;
1044 }
1045
1046 return (SNMP_ERR_NOERROR);
1047}
1048
1049static int
1050bridge_rollback_if_status(struct snmp_context *ctx,
1051 struct snmp_value *val, uint sub)
1052{
1053 struct bridge_if *bif;
1054
1055 if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1056 return (SNMP_ERR_GENERR);
1057
1058 switch (ctx->scratch->int1) {
1059 case RowStatus_destroy:
1060 bridge_if_destroy(bif);
1061 return (SNMP_ERR_NOERROR);
1062
1063 case RowStatus_notInService:
1064 if (bif->if_status != ctx->scratch->int1)
1065 bridge_set_if_up(bif->bif_name, 0);
1066 bif->if_status = RowStatus_notInService;
1067 return (SNMP_ERR_NOERROR);
1068
1069 case RowStatus_active:
1070 if (bif->if_status != ctx->scratch->int1)
1071 bridge_set_if_up(bif->bif_name, 1);
1072 bif->if_status = RowStatus_active;
1073 return (SNMP_ERR_NOERROR);
1074 }
1075
1076 abort();
1077}
1078
1079static int
1080bridge_commit_if_status(struct snmp_value *val, uint sub)
1081{
1082 struct bridge_if *bif;
1083
1084 if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1085 return (SNMP_ERR_GENERR);
1086
1087 if (bif->if_status == RowStatus_destroy &&
1088 bridge_if_destroy(bif) < 0)
1089 return (SNMP_ERR_COMMIT_FAILED);
1090
1091 return (SNMP_ERR_NOERROR);
1092}
1093
1094int
1095op_begemot_base_bridge(struct snmp_context *ctx, struct snmp_value *val,
1096 uint sub, uint iidx __unused, enum snmp_op op)
1097{
1098 int ret;
1099 struct bridge_if *bif = NULL;
1099 struct bridge_if *bif;
1100
1101 if (time(NULL) - bridge_list_age > bridge_get_data_maxage())
1102 bridge_update_all_ifs();
1103
1104 switch (op) {
1105 case SNMP_OP_GET:
1106 if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1107 return (SNMP_ERR_NOSUCHNAME);
1108 break;
1109
1110 case SNMP_OP_GETNEXT:
1111 if ((bif = bridge_if_index_getnext(&val->var, sub)) == NULL)
1112 return (SNMP_ERR_NOSUCHNAME);
1113 bridge_if_index_append(&val->var, sub, bif);
1114 break;
1115
1116 case SNMP_OP_SET:
1117 switch (val->var.subs[sub - 1]) {
1118 case LEAF_begemotBridgeBaseStatus:
1119 return (bridge_set_if_status(ctx, val, sub));
1120 case LEAF_begemotBridgeBaseName:
1121 case LEAF_begemotBridgeBaseAddress:
1122 case LEAF_begemotBridgeBaseNumPorts:
1123 case LEAF_begemotBridgeBaseType:
1124 return (SNMP_ERR_NOT_WRITEABLE);
1125 }
1126 abort();
1127
1128 case SNMP_OP_ROLLBACK:
1129 return (bridge_rollback_if_status(ctx, val, sub));
1100
1101 if (time(NULL) - bridge_list_age > bridge_get_data_maxage())
1102 bridge_update_all_ifs();
1103
1104 switch (op) {
1105 case SNMP_OP_GET:
1106 if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1107 return (SNMP_ERR_NOSUCHNAME);
1108 break;
1109
1110 case SNMP_OP_GETNEXT:
1111 if ((bif = bridge_if_index_getnext(&val->var, sub)) == NULL)
1112 return (SNMP_ERR_NOSUCHNAME);
1113 bridge_if_index_append(&val->var, sub, bif);
1114 break;
1115
1116 case SNMP_OP_SET:
1117 switch (val->var.subs[sub - 1]) {
1118 case LEAF_begemotBridgeBaseStatus:
1119 return (bridge_set_if_status(ctx, val, sub));
1120 case LEAF_begemotBridgeBaseName:
1121 case LEAF_begemotBridgeBaseAddress:
1122 case LEAF_begemotBridgeBaseNumPorts:
1123 case LEAF_begemotBridgeBaseType:
1124 return (SNMP_ERR_NOT_WRITEABLE);
1125 }
1126 abort();
1127
1128 case SNMP_OP_ROLLBACK:
1129 return (bridge_rollback_if_status(ctx, val, sub));
1130
1130 case SNMP_OP_COMMIT:
1131 return (bridge_commit_if_status(val, sub));
1131 case SNMP_OP_COMMIT:
1132 return (bridge_commit_if_status(val, sub));
1133
1134 default:
1135 abort();
1132 }
1133
1134 ret = SNMP_ERR_NOERROR;
1135 switch (val->var.subs[sub - 1]) {
1136 case LEAF_begemotBridgeBaseName:
1137 ret = string_get(val, bif->bif_name, -1);
1138 break;
1139
1140 case LEAF_begemotBridgeBaseAddress:
1141 ret = string_get(val, bif->br_addr.octet, ETHER_ADDR_LEN);
1142 break;
1143
1144 case LEAF_begemotBridgeBaseNumPorts:
1145 val->v.integer = bif->num_ports;
1146 break;
1147
1148 case LEAF_begemotBridgeBaseType:
1149 val->v.integer = bif->br_type;
1150 break;
1151
1152 case LEAF_begemotBridgeBaseStatus:
1153 val->v.integer = bif->if_status;
1154 break;
1155 }
1156
1157 return (ret);
1158}
1159
1160int
1161op_begemot_stp(struct snmp_context *ctx, struct snmp_value *val,
1162 uint sub, uint iidx __unused, enum snmp_op op)
1163{
1136 }
1137
1138 ret = SNMP_ERR_NOERROR;
1139 switch (val->var.subs[sub - 1]) {
1140 case LEAF_begemotBridgeBaseName:
1141 ret = string_get(val, bif->bif_name, -1);
1142 break;
1143
1144 case LEAF_begemotBridgeBaseAddress:
1145 ret = string_get(val, bif->br_addr.octet, ETHER_ADDR_LEN);
1146 break;
1147
1148 case LEAF_begemotBridgeBaseNumPorts:
1149 val->v.integer = bif->num_ports;
1150 break;
1151
1152 case LEAF_begemotBridgeBaseType:
1153 val->v.integer = bif->br_type;
1154 break;
1155
1156 case LEAF_begemotBridgeBaseStatus:
1157 val->v.integer = bif->if_status;
1158 break;
1159 }
1160
1161 return (ret);
1162}
1163
1164int
1165op_begemot_stp(struct snmp_context *ctx, struct snmp_value *val,
1166 uint sub, uint iidx __unused, enum snmp_op op)
1167{
1164 int ret = SNMP_ERR_NOERROR; /* Make the compiler happy. */
1165 struct bridge_if *bif = NULL;
1168 int ret;
1169 struct bridge_if *bif;
1166
1167 if (time(NULL) - bridge_list_age > bridge_get_data_maxage())
1168 bridge_update_all_ifs();
1169
1170 switch (op) {
1171 case SNMP_OP_GET:
1172 if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1173 return (SNMP_ERR_NOSUCHNAME);
1174 break;
1175
1176 case SNMP_OP_GETNEXT:
1177 if ((bif = bridge_if_index_getnext(&val->var, sub)) == NULL)
1178 return (SNMP_ERR_NOSUCHNAME);
1179 bridge_if_index_append(&val->var, sub, bif);
1180 break;
1181
1182 case SNMP_OP_SET:
1183 if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1184 return (SNMP_ERR_NOSUCHNAME);
1185
1186 switch (val->var.subs[sub - 1]) {
1187 case LEAF_begemotBridgeStpPriority:
1188 ctx->scratch->int1 = bif->priority;
1189 ret = bridge_set_priority(bif, val->v.integer);
1190 break;
1191
1192 case LEAF_begemotBridgeStpBridgeMaxAge:
1193 ctx->scratch->int1 = bif->bridge_max_age;
1194 ret = bridge_set_maxage(bif, val->v.integer);
1195 break;
1196
1197 case LEAF_begemotBridgeStpBridgeHelloTime:
1198 ctx->scratch->int1 = bif->bridge_hello_time;
1199 ret = bridge_set_hello_time(bif, val->v.integer);
1200 break;
1201
1202 case LEAF_begemotBridgeStpBridgeForwardDelay:
1203 ctx->scratch->int1 = bif->bridge_fwd_delay;
1204 ret = bridge_set_forward_delay(bif, val->v.integer);
1205 break;
1206
1207 case LEAF_begemotBridgeStpVersion:
1208 ctx->scratch->int1 = bif->stp_version;
1209 ret = bridge_set_stp_version(bif, val->v.integer);
1210 break;
1211
1212 case LEAF_begemotBridgeStpTxHoldCount:
1213 ctx->scratch->int1 = bif->tx_hold_count;
1214 ret = bridge_set_tx_hold_count(bif, val->v.integer);
1215 break;
1216
1217 case LEAF_begemotBridgeStpProtocolSpecification:
1218 case LEAF_begemotBridgeStpTimeSinceTopologyChange:
1219 case LEAF_begemotBridgeStpTopChanges:
1220 case LEAF_begemotBridgeStpDesignatedRoot:
1221 case LEAF_begemotBridgeStpRootCost:
1222 case LEAF_begemotBridgeStpRootPort:
1223 case LEAF_begemotBridgeStpMaxAge:
1224 case LEAF_begemotBridgeStpHelloTime:
1225 case LEAF_begemotBridgeStpHoldTime:
1226 case LEAF_begemotBridgeStpForwardDelay:
1227 return (SNMP_ERR_NOT_WRITEABLE);
1170
1171 if (time(NULL) - bridge_list_age > bridge_get_data_maxage())
1172 bridge_update_all_ifs();
1173
1174 switch (op) {
1175 case SNMP_OP_GET:
1176 if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1177 return (SNMP_ERR_NOSUCHNAME);
1178 break;
1179
1180 case SNMP_OP_GETNEXT:
1181 if ((bif = bridge_if_index_getnext(&val->var, sub)) == NULL)
1182 return (SNMP_ERR_NOSUCHNAME);
1183 bridge_if_index_append(&val->var, sub, bif);
1184 break;
1185
1186 case SNMP_OP_SET:
1187 if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1188 return (SNMP_ERR_NOSUCHNAME);
1189
1190 switch (val->var.subs[sub - 1]) {
1191 case LEAF_begemotBridgeStpPriority:
1192 ctx->scratch->int1 = bif->priority;
1193 ret = bridge_set_priority(bif, val->v.integer);
1194 break;
1195
1196 case LEAF_begemotBridgeStpBridgeMaxAge:
1197 ctx->scratch->int1 = bif->bridge_max_age;
1198 ret = bridge_set_maxage(bif, val->v.integer);
1199 break;
1200
1201 case LEAF_begemotBridgeStpBridgeHelloTime:
1202 ctx->scratch->int1 = bif->bridge_hello_time;
1203 ret = bridge_set_hello_time(bif, val->v.integer);
1204 break;
1205
1206 case LEAF_begemotBridgeStpBridgeForwardDelay:
1207 ctx->scratch->int1 = bif->bridge_fwd_delay;
1208 ret = bridge_set_forward_delay(bif, val->v.integer);
1209 break;
1210
1211 case LEAF_begemotBridgeStpVersion:
1212 ctx->scratch->int1 = bif->stp_version;
1213 ret = bridge_set_stp_version(bif, val->v.integer);
1214 break;
1215
1216 case LEAF_begemotBridgeStpTxHoldCount:
1217 ctx->scratch->int1 = bif->tx_hold_count;
1218 ret = bridge_set_tx_hold_count(bif, val->v.integer);
1219 break;
1220
1221 case LEAF_begemotBridgeStpProtocolSpecification:
1222 case LEAF_begemotBridgeStpTimeSinceTopologyChange:
1223 case LEAF_begemotBridgeStpTopChanges:
1224 case LEAF_begemotBridgeStpDesignatedRoot:
1225 case LEAF_begemotBridgeStpRootCost:
1226 case LEAF_begemotBridgeStpRootPort:
1227 case LEAF_begemotBridgeStpMaxAge:
1228 case LEAF_begemotBridgeStpHelloTime:
1229 case LEAF_begemotBridgeStpHoldTime:
1230 case LEAF_begemotBridgeStpForwardDelay:
1231 return (SNMP_ERR_NOT_WRITEABLE);
1232
1233 default:
1234 return (SNMP_ERR_NOSUCHNAME);
1228 }
1229
1230 if (ret == 0)
1231 return (SNMP_ERR_NOERROR);
1232 else if (ret == -2)
1233 return (SNMP_ERR_WRONG_VALUE);
1234 return (SNMP_ERR_GENERR);
1235
1236 case SNMP_OP_ROLLBACK:
1237 if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1238 return (SNMP_ERR_NOSUCHNAME);
1239
1240 switch (val->var.subs[sub - 1]) {
1241 case LEAF_begemotBridgeStpPriority:
1242 bridge_set_priority(bif, ctx->scratch->int1);
1243 break;
1244
1245 case LEAF_begemotBridgeStpBridgeMaxAge:
1246 bridge_set_maxage(bif, ctx->scratch->int1);
1247 break;
1248
1249 case LEAF_begemotBridgeStpBridgeHelloTime:
1250 bridge_set_hello_time(bif, ctx->scratch->int1);
1251 break;
1252
1253 case LEAF_begemotBridgeStpBridgeForwardDelay:
1254 bridge_set_forward_delay(bif, ctx->scratch->int1);
1255 break;
1256
1257 case LEAF_begemotBridgeStpVersion:
1258 bridge_set_stp_version(bif, ctx->scratch->int1);
1259 break;
1260
1261 case LEAF_begemotBridgeStpTxHoldCount:
1262 bridge_set_tx_hold_count(bif, ctx->scratch->int1);
1263 break;
1264 }
1265 return (SNMP_ERR_NOERROR);
1266
1267 case SNMP_OP_COMMIT:
1268 return (SNMP_ERR_NOERROR);
1235 }
1236
1237 if (ret == 0)
1238 return (SNMP_ERR_NOERROR);
1239 else if (ret == -2)
1240 return (SNMP_ERR_WRONG_VALUE);
1241 return (SNMP_ERR_GENERR);
1242
1243 case SNMP_OP_ROLLBACK:
1244 if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1245 return (SNMP_ERR_NOSUCHNAME);
1246
1247 switch (val->var.subs[sub - 1]) {
1248 case LEAF_begemotBridgeStpPriority:
1249 bridge_set_priority(bif, ctx->scratch->int1);
1250 break;
1251
1252 case LEAF_begemotBridgeStpBridgeMaxAge:
1253 bridge_set_maxage(bif, ctx->scratch->int1);
1254 break;
1255
1256 case LEAF_begemotBridgeStpBridgeHelloTime:
1257 bridge_set_hello_time(bif, ctx->scratch->int1);
1258 break;
1259
1260 case LEAF_begemotBridgeStpBridgeForwardDelay:
1261 bridge_set_forward_delay(bif, ctx->scratch->int1);
1262 break;
1263
1264 case LEAF_begemotBridgeStpVersion:
1265 bridge_set_stp_version(bif, ctx->scratch->int1);
1266 break;
1267
1268 case LEAF_begemotBridgeStpTxHoldCount:
1269 bridge_set_tx_hold_count(bif, ctx->scratch->int1);
1270 break;
1271 }
1272 return (SNMP_ERR_NOERROR);
1273
1274 case SNMP_OP_COMMIT:
1275 return (SNMP_ERR_NOERROR);
1276
1277 default:
1278 abort();
1269 }
1270
1279 }
1280
1281 ret = SNMP_ERR_NOERROR;
1282
1271 switch (val->var.subs[sub - 1]) {
1272 case LEAF_begemotBridgeStpProtocolSpecification:
1273 val->v.integer = bif->prot_spec;
1274 break;
1275
1276 case LEAF_begemotBridgeStpPriority:
1277 val->v.integer = bif->priority;
1278 break;
1279
1280 case LEAF_begemotBridgeStpTimeSinceTopologyChange:
1281 if (bridge_get_time_since_tc(bif, &(val->v.uint32)) < 0)
1282 return (SNMP_ERR_GENERR);
1283 break;
1284
1285 case LEAF_begemotBridgeStpTopChanges:
1286 val->v.uint32 = bif->top_changes;
1287 break;
1288
1289 case LEAF_begemotBridgeStpDesignatedRoot:
1290 ret = string_get(val, bif->design_root, SNMP_BRIDGE_ID_LEN);
1291 break;
1292
1293 case LEAF_begemotBridgeStpRootCost:
1294 val->v.integer = bif->root_cost;
1295 break;
1296
1297 case LEAF_begemotBridgeStpRootPort:
1298 val->v.integer = bif->root_port;
1299 break;
1300
1301 case LEAF_begemotBridgeStpMaxAge:
1302 val->v.integer = bif->max_age;
1303 break;
1304
1305 case LEAF_begemotBridgeStpHelloTime:
1306 val->v.integer = bif->hello_time;
1307 break;
1308
1309 case LEAF_begemotBridgeStpHoldTime:
1310 val->v.integer = bif->hold_time;
1311 break;
1312
1313 case LEAF_begemotBridgeStpForwardDelay:
1314 val->v.integer = bif->fwd_delay;
1315 break;
1316
1317 case LEAF_begemotBridgeStpBridgeMaxAge:
1318 val->v.integer = bif->bridge_max_age;
1319 break;
1320
1321 case LEAF_begemotBridgeStpBridgeHelloTime:
1322 val->v.integer = bif->bridge_hello_time;
1323 break;
1324
1325 case LEAF_begemotBridgeStpBridgeForwardDelay:
1326 val->v.integer = bif->bridge_fwd_delay;
1327 break;
1328
1329 case LEAF_begemotBridgeStpVersion:
1330 val->v.integer = bif->stp_version;
1331 break;
1332
1333 case LEAF_begemotBridgeStpTxHoldCount:
1334 val->v.integer = bif->tx_hold_count;
1335 break;
1336 }
1337
1338 return (ret);
1339}
1340
1341int
1342op_begemot_tp(struct snmp_context *ctx, struct snmp_value *val,
1343 uint sub, uint iidx __unused, enum snmp_op op)
1344{
1283 switch (val->var.subs[sub - 1]) {
1284 case LEAF_begemotBridgeStpProtocolSpecification:
1285 val->v.integer = bif->prot_spec;
1286 break;
1287
1288 case LEAF_begemotBridgeStpPriority:
1289 val->v.integer = bif->priority;
1290 break;
1291
1292 case LEAF_begemotBridgeStpTimeSinceTopologyChange:
1293 if (bridge_get_time_since_tc(bif, &(val->v.uint32)) < 0)
1294 return (SNMP_ERR_GENERR);
1295 break;
1296
1297 case LEAF_begemotBridgeStpTopChanges:
1298 val->v.uint32 = bif->top_changes;
1299 break;
1300
1301 case LEAF_begemotBridgeStpDesignatedRoot:
1302 ret = string_get(val, bif->design_root, SNMP_BRIDGE_ID_LEN);
1303 break;
1304
1305 case LEAF_begemotBridgeStpRootCost:
1306 val->v.integer = bif->root_cost;
1307 break;
1308
1309 case LEAF_begemotBridgeStpRootPort:
1310 val->v.integer = bif->root_port;
1311 break;
1312
1313 case LEAF_begemotBridgeStpMaxAge:
1314 val->v.integer = bif->max_age;
1315 break;
1316
1317 case LEAF_begemotBridgeStpHelloTime:
1318 val->v.integer = bif->hello_time;
1319 break;
1320
1321 case LEAF_begemotBridgeStpHoldTime:
1322 val->v.integer = bif->hold_time;
1323 break;
1324
1325 case LEAF_begemotBridgeStpForwardDelay:
1326 val->v.integer = bif->fwd_delay;
1327 break;
1328
1329 case LEAF_begemotBridgeStpBridgeMaxAge:
1330 val->v.integer = bif->bridge_max_age;
1331 break;
1332
1333 case LEAF_begemotBridgeStpBridgeHelloTime:
1334 val->v.integer = bif->bridge_hello_time;
1335 break;
1336
1337 case LEAF_begemotBridgeStpBridgeForwardDelay:
1338 val->v.integer = bif->bridge_fwd_delay;
1339 break;
1340
1341 case LEAF_begemotBridgeStpVersion:
1342 val->v.integer = bif->stp_version;
1343 break;
1344
1345 case LEAF_begemotBridgeStpTxHoldCount:
1346 val->v.integer = bif->tx_hold_count;
1347 break;
1348 }
1349
1350 return (ret);
1351}
1352
1353int
1354op_begemot_tp(struct snmp_context *ctx, struct snmp_value *val,
1355 uint sub, uint iidx __unused, enum snmp_op op)
1356{
1345 struct bridge_if *bif = NULL;
1357 struct bridge_if *bif;
1346
1347 if (time(NULL) - bridge_list_age > bridge_get_data_maxage())
1348 bridge_update_all_ifs();
1349
1350 switch (op) {
1351 case SNMP_OP_GET:
1352 if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1353 return (SNMP_ERR_NOSUCHNAME);
1354 break;
1355
1356 case SNMP_OP_GETNEXT:
1357 if ((bif = bridge_if_index_getnext(&val->var, sub)) == NULL)
1358 return (SNMP_ERR_NOSUCHNAME);
1359 bridge_if_index_append(&val->var, sub, bif);
1360 break;
1361
1362 case SNMP_OP_SET:
1363 if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1364 return (SNMP_ERR_NOSUCHNAME);
1365
1366 switch (val->var.subs[sub - 1]) {
1367 case LEAF_begemotBridgeTpAgingTime:
1368 ctx->scratch->int1 = bif->age_time;
1369 if (bridge_set_aging_time(bif, val->v.integer) < 0)
1370 return (SNMP_ERR_GENERR);
1371 return (SNMP_ERR_NOERROR);
1372
1373 case LEAF_begemotBridgeTpMaxAddresses:
1374 ctx->scratch->int1 = bif->max_addrs;
1375 if (bridge_set_max_cache(bif, val->v.integer) < 0)
1376 return (SNMP_ERR_GENERR);
1377 return (SNMP_ERR_NOERROR);
1378
1379 case LEAF_begemotBridgeTpLearnedEntryDiscards:
1380 return (SNMP_ERR_NOT_WRITEABLE);
1381 }
1382 abort();
1383
1384 case SNMP_OP_ROLLBACK:
1385 if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1386 return (SNMP_ERR_GENERR);
1387
1388 switch (val->var.subs[sub - 1]) {
1389 case LEAF_begemotBridgeTpAgingTime:
1390 bridge_set_aging_time(bif, ctx->scratch->int1);
1391 break;
1392
1393 case LEAF_begemotBridgeTpMaxAddresses:
1394 bridge_set_max_cache(bif, ctx->scratch->int1);
1395 break;
1396 }
1397 return (SNMP_ERR_NOERROR);
1398
1399 case SNMP_OP_COMMIT:
1400 return (SNMP_ERR_NOERROR);
1358
1359 if (time(NULL) - bridge_list_age > bridge_get_data_maxage())
1360 bridge_update_all_ifs();
1361
1362 switch (op) {
1363 case SNMP_OP_GET:
1364 if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1365 return (SNMP_ERR_NOSUCHNAME);
1366 break;
1367
1368 case SNMP_OP_GETNEXT:
1369 if ((bif = bridge_if_index_getnext(&val->var, sub)) == NULL)
1370 return (SNMP_ERR_NOSUCHNAME);
1371 bridge_if_index_append(&val->var, sub, bif);
1372 break;
1373
1374 case SNMP_OP_SET:
1375 if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1376 return (SNMP_ERR_NOSUCHNAME);
1377
1378 switch (val->var.subs[sub - 1]) {
1379 case LEAF_begemotBridgeTpAgingTime:
1380 ctx->scratch->int1 = bif->age_time;
1381 if (bridge_set_aging_time(bif, val->v.integer) < 0)
1382 return (SNMP_ERR_GENERR);
1383 return (SNMP_ERR_NOERROR);
1384
1385 case LEAF_begemotBridgeTpMaxAddresses:
1386 ctx->scratch->int1 = bif->max_addrs;
1387 if (bridge_set_max_cache(bif, val->v.integer) < 0)
1388 return (SNMP_ERR_GENERR);
1389 return (SNMP_ERR_NOERROR);
1390
1391 case LEAF_begemotBridgeTpLearnedEntryDiscards:
1392 return (SNMP_ERR_NOT_WRITEABLE);
1393 }
1394 abort();
1395
1396 case SNMP_OP_ROLLBACK:
1397 if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1398 return (SNMP_ERR_GENERR);
1399
1400 switch (val->var.subs[sub - 1]) {
1401 case LEAF_begemotBridgeTpAgingTime:
1402 bridge_set_aging_time(bif, ctx->scratch->int1);
1403 break;
1404
1405 case LEAF_begemotBridgeTpMaxAddresses:
1406 bridge_set_max_cache(bif, ctx->scratch->int1);
1407 break;
1408 }
1409 return (SNMP_ERR_NOERROR);
1410
1411 case SNMP_OP_COMMIT:
1412 return (SNMP_ERR_NOERROR);
1413
1414 default:
1415 abort();
1401 }
1402
1403 switch (val->var.subs[sub - 1]) {
1404 case LEAF_begemotBridgeTpLearnedEntryDiscards:
1405 val->v.uint32 = bif->lrnt_drops;
1406 break;
1407
1408 case LEAF_begemotBridgeTpAgingTime:
1409 val->v.integer = bif->age_time;
1410 break;
1411
1412 case LEAF_begemotBridgeTpMaxAddresses:
1413 val->v.integer = bif->max_addrs;
1414 break;
1415 }
1416
1417 return (SNMP_ERR_NOERROR);
1418}
1416 }
1417
1418 switch (val->var.subs[sub - 1]) {
1419 case LEAF_begemotBridgeTpLearnedEntryDiscards:
1420 val->v.uint32 = bif->lrnt_drops;
1421 break;
1422
1423 case LEAF_begemotBridgeTpAgingTime:
1424 val->v.integer = bif->age_time;
1425 break;
1426
1427 case LEAF_begemotBridgeTpMaxAddresses:
1428 val->v.integer = bif->max_addrs;
1429 break;
1430 }
1431
1432 return (SNMP_ERR_NOERROR);
1433}