Deleted Added
full compact
bridge_if.c (164410) bridge_if.c (164997)
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 164410 2006-11-19 15:42:48Z syrinx $
29 * $FreeBSD: head/usr.sbin/bsnmpd/modules/snmp_bridge/bridge_if.c 164997 2006-12-07 22:36:17Z 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{
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;
677 struct bridge_if *bif;
678
679 if ((bif = bridge_get_default()) == NULL)
680 return (SNMP_ERR_NOSUCHNAME);
681
682 if (time(NULL) - bif->entry_age > bridge_get_data_maxage() &&
683 bridge_update_bif(bif) <= 0) /* It was just deleted. */
684 return (SNMP_ERR_NOSUCHNAME);
685
686 switch (op) {
687 case SNMP_OP_GET:
688 switch (value->var.subs[sub - 1]) {
689 case LEAF_dot1dStpProtocolSpecification:
690 value->v.integer = bif->prot_spec;
691 break;
692
693 case LEAF_dot1dStpPriority:
694 value->v.integer = bif->priority;
695 break;
696
697 case LEAF_dot1dStpTimeSinceTopologyChange:
698 if (bridge_get_time_since_tc(bif,
699 &(value->v.uint32)) < 0)
700 return (SNMP_ERR_GENERR);
701 break;
702
703 case LEAF_dot1dStpTopChanges:
704 value->v.uint32 = bif->top_changes;
705 break;
706
707 case LEAF_dot1dStpDesignatedRoot:
708 return (string_get(value, bif->design_root,
709 SNMP_BRIDGE_ID_LEN));
710
711 case LEAF_dot1dStpRootCost:
712 value->v.integer = bif->root_cost;
713 break;
714
715 case LEAF_dot1dStpRootPort:
716 value->v.integer = bif->root_port;
717 break;
718
719 case LEAF_dot1dStpMaxAge:
720 value->v.integer = bif->max_age;
721 break;
722
723 case LEAF_dot1dStpHelloTime:
724 value->v.integer = bif->hello_time;
725 break;
726
727 case LEAF_dot1dStpHoldTime:
728 value->v.integer = bif->hold_time;
729 break;
730
731 case LEAF_dot1dStpForwardDelay:
732 value->v.integer = bif->fwd_delay;
733 break;
734
735 case LEAF_dot1dStpBridgeMaxAge:
736 value->v.integer = bif->bridge_max_age;
737 break;
738
739 case LEAF_dot1dStpBridgeHelloTime:
740 value->v.integer = bif->bridge_hello_time;
741 break;
742
743 case LEAF_dot1dStpBridgeForwardDelay:
744 value->v.integer = bif->bridge_fwd_delay;
745 break;
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;
746 }
747
748 return (SNMP_ERR_NOERROR);
749
750 case SNMP_OP_GETNEXT:
751 abort();
752
753 case SNMP_OP_SET:
754 switch (value->var.subs[sub - 1]) {
755 case LEAF_dot1dStpPriority:
756 ctx->scratch->int1 = bif->priority;
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;
757 if (bridge_set_priority(bif, value->v.integer) < 0)
758 return (SNMP_ERR_GENERR);
763 ret = bridge_set_priority(bif, value->v.integer);
759 break;
760
761 case LEAF_dot1dStpBridgeMaxAge:
762 ctx->scratch->int1 = bif->bridge_max_age;
764 break;
765
766 case LEAF_dot1dStpBridgeMaxAge:
767 ctx->scratch->int1 = bif->bridge_max_age;
763 if (bridge_set_maxage(bif, value->v.integer) < 0)
764 return (SNMP_ERR_GENERR);
768 ret = bridge_set_maxage(bif, value->v.integer);
765 break;
766
767 case LEAF_dot1dStpBridgeHelloTime:
768 ctx->scratch->int1 = bif->bridge_hello_time;
769 break;
770
771 case LEAF_dot1dStpBridgeHelloTime:
772 ctx->scratch->int1 = bif->bridge_hello_time;
769 if (bridge_set_hello_time(bif, value->v.integer) < 0)
770 return (SNMP_ERR_GENERR);
773 ret = bridge_set_hello_time(bif, value->v.integer);
771 break;
772
773 case LEAF_dot1dStpBridgeForwardDelay:
774 ctx->scratch->int1 = bif->bridge_fwd_delay;
774 break;
775
776 case LEAF_dot1dStpBridgeForwardDelay:
777 ctx->scratch->int1 = bif->bridge_fwd_delay;
775 if (bridge_set_forward_delay(bif, value->v.integer) < 0)
776 return (SNMP_ERR_GENERR);
778 ret = bridge_set_forward_delay(bif, value->v.integer);
777 break;
778
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
779 case LEAF_dot1dStpProtocolSpecification:
780 case LEAF_dot1dStpTimeSinceTopologyChange:
781 case LEAF_dot1dStpTopChanges:
782 case LEAF_dot1dStpDesignatedRoot:
783 case LEAF_dot1dStpRootCost:
784 case LEAF_dot1dStpRootPort:
785 case LEAF_dot1dStpMaxAge:
786 case LEAF_dot1dStpHelloTime:
787 case LEAF_dot1dStpHoldTime:
788 case LEAF_dot1dStpForwardDelay:
789 return (SNMP_ERR_NOT_WRITEABLE);
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);
790 }
791
804 }
805
806 if (ret == -2)
807 return (SNMP_ERR_WRONG_VALUE);
808 else if (ret < 0)
809 return (SNMP_ERR_GENERR);
792 return (SNMP_ERR_NOERROR);
793
794 case SNMP_OP_ROLLBACK:
795 switch (value->var.subs[sub - 1]) {
796 case LEAF_dot1dStpPriority:
810 return (SNMP_ERR_NOERROR);
811
812 case SNMP_OP_ROLLBACK:
813 switch (value->var.subs[sub - 1]) {
814 case LEAF_dot1dStpPriority:
797 (void) bridge_set_priority(bif, ctx->scratch->int1);
815 bridge_set_priority(bif, ctx->scratch->int1);
798 break;
799 case LEAF_dot1dStpBridgeMaxAge:
816 break;
817 case LEAF_dot1dStpBridgeMaxAge:
800 (void) bridge_set_maxage(bif, ctx->scratch->int1);
818 bridge_set_maxage(bif, ctx->scratch->int1);
801 break;
802 case LEAF_dot1dStpBridgeHelloTime:
819 break;
820 case LEAF_dot1dStpBridgeHelloTime:
803 (void) bridge_set_hello_time(bif, ctx->scratch->int1);
821 bridge_set_hello_time(bif, ctx->scratch->int1);
804 break;
805 case LEAF_dot1dStpBridgeForwardDelay:
822 break;
823 case LEAF_dot1dStpBridgeForwardDelay:
806 (void) bridge_set_forward_delay(bif,
807 ctx->scratch->int1);
824 bridge_set_forward_delay(bif, ctx->scratch->int1);
808 break;
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;
809 }
810 return (SNMP_ERR_NOERROR);
811
812 case SNMP_OP_COMMIT:
813 return (SNMP_ERR_NOERROR);
814 }
815
816 return (SNMP_ERR_NOERROR);
817}
818
819int
820op_dot1d_tp(struct snmp_context *ctx, struct snmp_value *value,
821 uint sub, uint iidx __unused, enum snmp_op op)
822{
823 struct bridge_if *bif;
824
825 if ((bif = bridge_get_default()) == NULL)
826 return (SNMP_ERR_NOSUCHNAME);
827
828 if (time(NULL) - bif->entry_age > bridge_get_data_maxage() &&
829 bridge_update_bif(bif) <= 0) /* It was just deleted. */
830 return (SNMP_ERR_NOSUCHNAME);
831
832 switch (op) {
833 case SNMP_OP_GET:
834 switch (value->var.subs[sub - 1]) {
835 case LEAF_dot1dTpLearnedEntryDiscards:
836 value->v.uint32 = bif->lrnt_drops;
837 break;
838 case LEAF_dot1dTpAgingTime:
839 value->v.integer = bif->age_time;
840 break;
841 }
842 return (SNMP_ERR_NOERROR);
843
844 case SNMP_OP_GETNEXT:
845 abort();
846
847 case SNMP_OP_SET:
848 if (value->var.subs[sub - 1] == LEAF_dot1dTpAgingTime) {
849 ctx->scratch->int1 = bif->age_time;
850 if (bridge_set_aging_time(bif, value->v.integer) < 0)
851 return (SNMP_ERR_GENERR);
852 }
853 return (SNMP_ERR_NOERROR);
854
855 case SNMP_OP_ROLLBACK:
856 if (value->var.subs[sub - 1] == LEAF_dot1dTpAgingTime)
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)
857 (void) bridge_set_aging_time(bif, ctx->scratch->int1);
880 bridge_set_aging_time(bif, ctx->scratch->int1);
858 return (SNMP_ERR_NOERROR);
859
860 case SNMP_OP_COMMIT:
861 return (SNMP_ERR_NOERROR);
862 }
863
864 return (SNMP_ERR_NOERROR);
865}
866
867/*
868 * Private BEGEMOT-BRIDGE-MIB specifics.
869 */
870
871/*
872 * Get the bridge name from an OID index.
873 */
874static char *
875bridge_name_index_get(const struct asn_oid *oid, uint sub, char *b_name)
876{
877 uint i;
878
879 if (oid->len - sub != oid->subs[sub] + 1 || oid->subs[sub] >= IFNAMSIZ)
880 return (NULL);
881
882 for (i = 0; i < oid->subs[sub]; i++)
883 b_name[i] = oid->subs[sub + i + 1];
884 b_name[i] = '\0';
885
886 return (b_name);
887}
888
889static void
890bridge_if_index_append(struct asn_oid *oid, uint sub,
891 const struct bridge_if *bif)
892{
893 uint i;
894
895 oid->len = sub + strlen(bif->bif_name) + 1;
896 oid->subs[sub] = strlen(bif->bif_name);
897
898 for (i = 1; i <= strlen(bif->bif_name); i++)
899 oid->subs[sub + i] = bif->bif_name[i - 1];
900}
901
902static struct bridge_if *
903bridge_if_index_get(const struct asn_oid *oid, uint sub)
904{
905 uint i;
906 char bif_name[IFNAMSIZ];
907
908 if (oid->len - sub != oid->subs[sub] + 1 || oid->subs[sub] >= IFNAMSIZ)
909 return (NULL);
910
911 for (i = 0; i < oid->subs[sub]; i++)
912 bif_name[i] = oid->subs[sub + i + 1];
913 bif_name[i] = '\0';
914
915 return (bridge_if_find_ifname(bif_name));
916}
917
918static struct bridge_if *
919bridge_if_index_getnext(const struct asn_oid *oid, uint sub)
920{
921 uint i;
922 char bif_name[IFNAMSIZ];
923 struct bridge_if *bif;
924
925 if (oid->len - sub == 0)
926 return (bridge_first_bif());
927
928 if (oid->len - sub != oid->subs[sub] + 1 || oid->subs[sub] >= IFNAMSIZ)
929 return (NULL);
930
931 for (i = 0; i < oid->subs[sub]; i++)
932 bif_name[i] = oid->subs[sub + i + 1];
933 bif_name[i] = '\0';
934
935 if ((bif = bridge_if_find_ifname(bif_name)) == NULL)
936 return (NULL);
937
938 return (bridge_next_bif(bif));
939}
940
941static int
942bridge_set_if_status(struct snmp_context *ctx,
943 struct snmp_value *val, uint sub)
944{
945 struct bridge_if *bif;
946 char bif_name[IFNAMSIZ];
947
948 bif = bridge_if_index_get(&val->var, sub);
949
950 switch (val->v.integer) {
951 case RowStatus_active:
952 if (bif == NULL)
953 return (SNMP_ERR_INCONS_VALUE);
954
955 ctx->scratch->int1 = bif->if_status;
956
957 switch (bif->if_status) {
958 case RowStatus_active:
959 return (SNMP_ERR_NOERROR);
960 case RowStatus_notInService:
961 if (bridge_set_if_up(bif->bif_name, 1) < 0)
962 return (SNMP_ERR_GENERR);
963 return (SNMP_ERR_NOERROR);
964 default:
965 break;
966 }
967 return (SNMP_ERR_INCONS_VALUE);
968
969 case RowStatus_notInService:
970 if (bif == NULL)
971 return (SNMP_ERR_INCONS_VALUE);
972
973 ctx->scratch->int1 = bif->if_status;
974
975 switch (bif->if_status) {
976 case RowStatus_active:
977 if (bridge_set_if_up(bif->bif_name, 1) < 0)
978 return (SNMP_ERR_GENERR);
979 return (SNMP_ERR_NOERROR);
980 case RowStatus_notInService:
981 return (SNMP_ERR_NOERROR);
982 default:
983 break;
984 }
985 return (SNMP_ERR_INCONS_VALUE);
986
987 case RowStatus_notReady:
988 return (SNMP_ERR_INCONS_VALUE);
989
990 case RowStatus_createAndGo:
991 if (bif != NULL)
992 return (SNMP_ERR_INCONS_VALUE);
993
994 ctx->scratch->int1 = RowStatus_destroy;
995
996 if (bridge_name_index_get(&val->var, sub, bif_name) == NULL)
997 return (SNMP_ERR_BADVALUE);
998 if (bridge_if_create(bif_name, 1) < 0)
999 return (SNMP_ERR_GENERR);
1000 return (SNMP_ERR_NOERROR);
1001
1002 case RowStatus_createAndWait:
1003 if (bif != NULL)
1004 return (SNMP_ERR_INCONS_VALUE);
1005
1006 if (bridge_name_index_get(&val->var, sub, bif_name) == NULL)
1007 return (SNMP_ERR_BADVALUE);
1008
1009 ctx->scratch->int1 = RowStatus_destroy;
1010
1011 if (bridge_if_create(bif_name, 0) < 0)
1012 return (SNMP_ERR_GENERR);
1013 return (SNMP_ERR_NOERROR);
1014
1015 case RowStatus_destroy:
1016 if (bif == NULL)
1017 return (SNMP_ERR_NOSUCHNAME);
1018
1019 ctx->scratch->int1 = bif->if_status;
1020 bif->if_status = RowStatus_destroy;
1021 }
1022
1023 return (SNMP_ERR_NOERROR);
1024}
1025
1026static int
1027bridge_rollback_if_status(struct snmp_context *ctx,
1028 struct snmp_value *val, uint sub)
1029{
1030 struct bridge_if *bif;
1031
1032 if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1033 return (SNMP_ERR_GENERR);
1034
1035 switch (ctx->scratch->int1) {
1036 case RowStatus_destroy:
1037 bridge_if_destroy(bif);
1038 return (SNMP_ERR_NOERROR);
1039
1040 case RowStatus_notInService:
1041 if (bif->if_status != ctx->scratch->int1)
1042 bridge_set_if_up(bif->bif_name, 0);
1043 bif->if_status = RowStatus_notInService;
1044 return (SNMP_ERR_NOERROR);
1045
1046 case RowStatus_active:
1047 if (bif->if_status != ctx->scratch->int1)
1048 bridge_set_if_up(bif->bif_name, 1);
1049 bif->if_status = RowStatus_active;
1050 return (SNMP_ERR_NOERROR);
1051 }
1052
1053 abort();
1054}
1055
1056static int
1057bridge_commit_if_status(struct snmp_value *val, uint sub)
1058{
1059 struct bridge_if *bif;
1060
1061 if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1062 return (SNMP_ERR_GENERR);
1063
1064 if (bif->if_status == RowStatus_destroy &&
1065 bridge_if_destroy(bif) < 0)
1066 return (SNMP_ERR_COMMIT_FAILED);
1067
1068 return (SNMP_ERR_NOERROR);
1069}
1070
1071int
1072op_begemot_base_bridge(struct snmp_context *ctx, struct snmp_value *val,
1073 uint sub, uint iidx __unused, enum snmp_op op)
1074{
1075 int ret;
1076 struct bridge_if *bif = NULL;
1077
1078 if (time(NULL) - bridge_list_age > bridge_get_data_maxage())
1079 bridge_update_all_ifs();
1080
1081 switch (op) {
1082 case SNMP_OP_GET:
1083 if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1084 return (SNMP_ERR_NOSUCHNAME);
1085 break;
1086
1087 case SNMP_OP_GETNEXT:
1088 if ((bif = bridge_if_index_getnext(&val->var, sub)) == NULL)
1089 return (SNMP_ERR_NOSUCHNAME);
1090 bridge_if_index_append(&val->var, sub, bif);
1091 break;
1092
1093 case SNMP_OP_SET:
1094 switch (val->var.subs[sub - 1]) {
1095 case LEAF_begemotBridgeBaseStatus:
1096 return (bridge_set_if_status(ctx, val, sub));
1097 case LEAF_begemotBridgeBaseName:
1098 case LEAF_begemotBridgeBaseAddress:
1099 case LEAF_begemotBridgeBaseNumPorts:
1100 case LEAF_begemotBridgeBaseType:
1101 return (SNMP_ERR_NOT_WRITEABLE);
1102 }
1103 abort();
1104
1105 case SNMP_OP_ROLLBACK:
1106 return (bridge_rollback_if_status(ctx, val, sub));
1107 case SNMP_OP_COMMIT:
1108 return (bridge_commit_if_status(val, sub));
1109 }
1110
1111 ret = SNMP_ERR_NOERROR;
1112 switch (val->var.subs[sub - 1]) {
1113 case LEAF_begemotBridgeBaseName:
1114 ret = string_get(val, bif->bif_name, -1);
1115 break;
1116
1117 case LEAF_begemotBridgeBaseAddress:
1118 ret = string_get(val, bif->br_addr.octet, ETHER_ADDR_LEN);
1119 break;
1120
1121 case LEAF_begemotBridgeBaseNumPorts:
1122 val->v.integer = bif->num_ports;
1123 break;
1124
1125 case LEAF_begemotBridgeBaseType:
1126 val->v.integer = bif->br_type;
1127 break;
1128
1129 case LEAF_begemotBridgeBaseStatus:
1130 val->v.integer = bif->if_status;
1131 break;
1132 }
1133
1134 return (ret);
1135}
1136
1137int
1138op_begemot_stp(struct snmp_context *ctx, struct snmp_value *val,
1139 uint sub, uint iidx __unused, enum snmp_op op)
1140{
1141 int ret = SNMP_ERR_NOERROR; /* Make the compiler happy. */
1142 struct bridge_if *bif = NULL;
1143
1144 if (time(NULL) - bridge_list_age > bridge_get_data_maxage())
1145 bridge_update_all_ifs();
1146
1147 switch (op) {
1148 case SNMP_OP_GET:
1149 if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1150 return (SNMP_ERR_NOSUCHNAME);
1151 break;
1152
1153 case SNMP_OP_GETNEXT:
1154 if ((bif = bridge_if_index_getnext(&val->var, sub)) == NULL)
1155 return (SNMP_ERR_NOSUCHNAME);
1156 bridge_if_index_append(&val->var, sub, bif);
1157 break;
1158
1159 case SNMP_OP_SET:
1160 if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1161 return (SNMP_ERR_NOSUCHNAME);
1162
1163 switch (val->var.subs[sub - 1]) {
1164 case LEAF_begemotBridgeStpPriority:
1165 ctx->scratch->int1 = bif->priority;
1166 ret = bridge_set_priority(bif, val->v.integer);
1167 break;
1168
1169 case LEAF_begemotBridgeStpBridgeMaxAge:
1170 ctx->scratch->int1 = bif->bridge_max_age;
1171 ret = bridge_set_maxage(bif, val->v.integer);
1172 break;
1173
1174 case LEAF_begemotBridgeStpBridgeHelloTime:
1175 ctx->scratch->int1 = bif->bridge_hello_time;
1176 ret = bridge_set_hello_time(bif, val->v.integer);
1177 break;
1178
1179 case LEAF_begemotBridgeStpBridgeForwardDelay:
1180 ctx->scratch->int1 = bif->bridge_fwd_delay;
1181 ret = bridge_set_forward_delay(bif, val->v.integer);
1182 break;
1183
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;
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 case SNMP_OP_COMMIT:
1131 return (bridge_commit_if_status(val, sub));
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{
1164 int ret = SNMP_ERR_NOERROR; /* Make the compiler happy. */
1165 struct bridge_if *bif = NULL;
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
1184 case LEAF_begemotBridgeStpProtocolSpecification:
1185 case LEAF_begemotBridgeStpTimeSinceTopologyChange:
1186 case LEAF_begemotBridgeStpTopChanges:
1187 case LEAF_begemotBridgeStpDesignatedRoot:
1188 case LEAF_begemotBridgeStpRootCost:
1189 case LEAF_begemotBridgeStpRootPort:
1190 case LEAF_begemotBridgeStpMaxAge:
1191 case LEAF_begemotBridgeStpHelloTime:
1192 case LEAF_begemotBridgeStpHoldTime:
1193 case LEAF_begemotBridgeStpForwardDelay:
1194 return (SNMP_ERR_NOT_WRITEABLE);
1195 }
1196
1197 if (ret == 0)
1198 return (SNMP_ERR_NOERROR);
1199 else if (ret == -2)
1200 return (SNMP_ERR_WRONG_VALUE);
1201 return (SNMP_ERR_GENERR);
1202
1203 case SNMP_OP_ROLLBACK:
1204 if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1205 return (SNMP_ERR_NOSUCHNAME);
1206
1207 switch (val->var.subs[sub - 1]) {
1208 case LEAF_begemotBridgeStpPriority:
1209 bridge_set_priority(bif, ctx->scratch->int1);
1210 break;
1211
1212 case LEAF_begemotBridgeStpBridgeMaxAge:
1213 bridge_set_maxage(bif, ctx->scratch->int1);
1214 break;
1215
1216 case LEAF_begemotBridgeStpBridgeHelloTime:
1217 bridge_set_hello_time(bif, ctx->scratch->int1);
1218 break;
1219
1220 case LEAF_begemotBridgeStpBridgeForwardDelay:
1221 bridge_set_forward_delay(bif, ctx->scratch->int1);
1222 break;
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);
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;
1223 }
1224 return (SNMP_ERR_NOERROR);
1225
1226 case SNMP_OP_COMMIT:
1227 return (SNMP_ERR_NOERROR);
1228 }
1229
1230 switch (val->var.subs[sub - 1]) {
1231 case LEAF_begemotBridgeStpProtocolSpecification:
1232 val->v.integer = bif->prot_spec;
1233 break;
1234
1235 case LEAF_begemotBridgeStpPriority:
1236 val->v.integer = bif->priority;
1237 break;
1238
1239 case LEAF_begemotBridgeStpTimeSinceTopologyChange:
1240 if (bridge_get_time_since_tc(bif, &(val->v.uint32)) < 0)
1241 return (SNMP_ERR_GENERR);
1242 break;
1243
1244 case LEAF_begemotBridgeStpTopChanges:
1245 val->v.uint32 = bif->top_changes;
1246 break;
1247
1248 case LEAF_begemotBridgeStpDesignatedRoot:
1249 ret = string_get(val, bif->design_root, SNMP_BRIDGE_ID_LEN);
1250 break;
1251
1252 case LEAF_begemotBridgeStpRootCost:
1253 val->v.integer = bif->root_cost;
1254 break;
1255
1256 case LEAF_begemotBridgeStpRootPort:
1257 val->v.integer = bif->root_port;
1258 break;
1259
1260 case LEAF_begemotBridgeStpMaxAge:
1261 val->v.integer = bif->max_age;
1262 break;
1263
1264 case LEAF_begemotBridgeStpHelloTime:
1265 val->v.integer = bif->hello_time;
1266 break;
1267
1268 case LEAF_begemotBridgeStpHoldTime:
1269 val->v.integer = bif->hold_time;
1270 break;
1271
1272 case LEAF_begemotBridgeStpForwardDelay:
1273 val->v.integer = bif->fwd_delay;
1274 break;
1275
1276 case LEAF_begemotBridgeStpBridgeMaxAge:
1277 val->v.integer = bif->bridge_max_age;
1278 break;
1279
1280 case LEAF_begemotBridgeStpBridgeHelloTime:
1281 val->v.integer = bif->bridge_hello_time;
1282 break;
1283
1284 case LEAF_begemotBridgeStpBridgeForwardDelay:
1285 val->v.integer = bif->bridge_fwd_delay;
1286 break;
1264 }
1265 return (SNMP_ERR_NOERROR);
1266
1267 case SNMP_OP_COMMIT:
1268 return (SNMP_ERR_NOERROR);
1269 }
1270
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;
1287 }
1288
1289 return (ret);
1290}
1291
1292int
1293op_begemot_tp(struct snmp_context *ctx, struct snmp_value *val,
1294 uint sub, uint iidx __unused, enum snmp_op op)
1295{
1296 struct bridge_if *bif = NULL;
1297
1298 if (time(NULL) - bridge_list_age > bridge_get_data_maxage())
1299 bridge_update_all_ifs();
1300
1301 switch (op) {
1302 case SNMP_OP_GET:
1303 if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1304 return (SNMP_ERR_NOSUCHNAME);
1305 break;
1306
1307 case SNMP_OP_GETNEXT:
1308 if ((bif = bridge_if_index_getnext(&val->var, sub)) == NULL)
1309 return (SNMP_ERR_NOSUCHNAME);
1310 bridge_if_index_append(&val->var, sub, bif);
1311 break;
1312
1313 case SNMP_OP_SET:
1314 if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1315 return (SNMP_ERR_NOSUCHNAME);
1316
1317 switch (val->var.subs[sub - 1]) {
1318 case LEAF_begemotBridgeTpAgingTime:
1319 ctx->scratch->int1 = bif->age_time;
1320 if (bridge_set_aging_time(bif, val->v.integer) < 0)
1321 return (SNMP_ERR_GENERR);
1322 return (SNMP_ERR_NOERROR);
1323
1324 case LEAF_begemotBridgeTpMaxAddresses:
1325 ctx->scratch->int1 = bif->max_addrs;
1326 if (bridge_set_max_cache(bif, val->v.integer) < 0)
1327 return (SNMP_ERR_GENERR);
1328 return (SNMP_ERR_NOERROR);
1329
1330 case LEAF_begemotBridgeTpLearnedEntryDiscards:
1331 return (SNMP_ERR_NOT_WRITEABLE);
1332 }
1333 abort();
1334
1335 case SNMP_OP_ROLLBACK:
1336 if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1337 return (SNMP_ERR_GENERR);
1338
1339 switch (val->var.subs[sub - 1]) {
1340 case LEAF_begemotBridgeTpAgingTime:
1341 bridge_set_aging_time(bif, ctx->scratch->int1);
1342 break;
1343
1344 case LEAF_begemotBridgeTpMaxAddresses:
1345 bridge_set_max_cache(bif, ctx->scratch->int1);
1346 break;
1347 }
1348 return (SNMP_ERR_NOERROR);
1349
1350 case SNMP_OP_COMMIT:
1351 return (SNMP_ERR_NOERROR);
1352 }
1353
1354 switch (val->var.subs[sub - 1]) {
1355 case LEAF_begemotBridgeTpLearnedEntryDiscards:
1356 val->v.uint32 = bif->lrnt_drops;
1357 break;
1358
1359 case LEAF_begemotBridgeTpAgingTime:
1360 val->v.integer = bif->age_time;
1361 break;
1362
1363 case LEAF_begemotBridgeTpMaxAddresses:
1364 val->v.integer = bif->max_addrs;
1365 break;
1366 }
1367
1368 return (SNMP_ERR_NOERROR);
1369}
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{
1345 struct bridge_if *bif = NULL;
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);
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}