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 OS specific ioctls.
28 *
29 * $FreeBSD: stable/10/usr.sbin/bsnmpd/modules/snmp_bridge/bridge_sys.c 312044 2017-01-13 08:51:46Z ngie $
30 */
31
32 #include <sys/ioctl.h>
33 #include <sys/param.h>
34 #include <sys/module.h>
35 #include <sys/linker.h>
36 #include <sys/socket.h>
37 #include <sys/sysctl.h>
38
39 #include <net/bridgestp.h>
40 #include <net/ethernet.h>
41 #include <net/if.h>
42 #include <net/if_bridgevar.h>
43 #include <net/if_dl.h>
44 #include <net/if_mib.h>
45 #include <net/if_types.h>
46 #include <netinet/in.h>
47
48 #include <errno.h>
49 #include <ifaddrs.h>
50 #include <stdarg.h>
51 #include <stdlib.h>
52 #include <stdio.h>
53 #include <string.h>
54 #include <syslog.h>
55
56 #include <bsnmp/snmpmod.h>
57 #include <bsnmp/snmp_mibII.h>
58
59 #include "bridge_tree.h"
60 #include "bridge_snmp.h"
61
62 int sock = -1;
63
64 int
bridge_ioctl_init(void)65 bridge_ioctl_init(void)
66 {
67 if ((sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
68 syslog(LOG_ERR, "cannot open socket : %s", strerror(errno));
69 return (-1);
70 }
71
72 return (0);
73 }
74
75 /*
76 * Load the if_bridge.ko module in kernel if not already there.
77 */
78 int
bridge_kmod_load(void)79 bridge_kmod_load(void)
80 {
81 int fileid, modid;
82 const char mod_name[] = "if_bridge";
83 struct module_stat mstat;
84
85 /* Scan files in kernel. */
86 mstat.version = sizeof(struct module_stat);
87 for (fileid = kldnext(0); fileid > 0; fileid = kldnext(fileid)) {
88 /* Scan modules in file. */
89 for (modid = kldfirstmod(fileid); modid > 0;
90 modid = modfnext(modid)) {
91
92 if (modstat(modid, &mstat) < 0)
93 continue;
94
95 if (strcmp(mod_name, mstat.name) == 0)
96 return (0);
97 }
98 }
99
100 /* Not present - load it. */
101 if (kldload(mod_name) < 0) {
102 syslog(LOG_ERR, "failed to load %s kernel module", mod_name);
103 return (-1);
104 }
105
106 return (1);
107 }
108
109 /************************************************************************
110 * Bridge interfaces.
111 */
112
113 /*
114 * Convert the kernel uint64_t value for a bridge id
115 */
116 static void
snmp_uint64_to_bridgeid(uint64_t id,bridge_id b_id)117 snmp_uint64_to_bridgeid(uint64_t id, bridge_id b_id)
118 {
119 int i;
120 u_char *o;
121
122 o = (u_char *) &id;
123
124 for (i = 0; i < SNMP_BRIDGE_ID_LEN; i++, o++)
125 b_id[SNMP_BRIDGE_ID_LEN - i - 1] = *o;
126 }
127
128 /*
129 * Fetch the bridge configuration parameters from the kernel excluding
130 * it's base MAC address.
131 */
132 static int
bridge_get_conf_param(struct bridge_if * bif)133 bridge_get_conf_param(struct bridge_if *bif)
134 {
135 struct ifdrv ifd;
136 struct ifbrparam b_param;
137
138 strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
139 ifd.ifd_len = sizeof(b_param);
140 ifd.ifd_data = &b_param;
141
142 /* Bridge priority. */
143 ifd.ifd_cmd = BRDGGPRI;
144 if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
145 syslog(LOG_ERR, "update bridge: ioctl(BRDGGPRI) failed: %s",
146 strerror(errno));
147 return (-1);
148 }
149
150 bif->priority = b_param.ifbrp_prio;
151
152 /* Configured max age. */
153 ifd.ifd_cmd = BRDGGMA;
154 if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
155 syslog(LOG_ERR, "update bridge: ioctl(BRDGGMA) failed: %s",
156 strerror(errno));
157 return (-1);
158 }
159
160 /* Centi-seconds. */
161 bif->bridge_max_age = 100 * b_param.ifbrp_maxage;
162
163 /* Configured hello time. */
164 ifd.ifd_cmd = BRDGGHT;
165 if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
166 syslog(LOG_ERR, "update bridge: ioctl(BRDGGHT) failed: %s",
167 strerror(errno));
168 return (-1);
169 }
170 bif->bridge_hello_time = 100 * b_param.ifbrp_hellotime;
171
172 /* Forward delay. */
173 ifd.ifd_cmd = BRDGGFD;
174 if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
175 syslog(LOG_ERR, "update bridge: ioctl(BRDGGFD) failed: %s",
176 strerror(errno));
177 return (-1);
178 }
179 bif->bridge_fwd_delay = 100 * b_param.ifbrp_fwddelay;
180
181 /* Number of dropped addresses. */
182 ifd.ifd_cmd = BRDGGRTE;
183 if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
184 syslog(LOG_ERR, "update bridge: ioctl(BRDGGRTE) failed: %s",
185 strerror(errno));
186 return (-1);
187 }
188 bif->lrnt_drops = b_param.ifbrp_cexceeded;
189
190 /* Address table timeout. */
191 ifd.ifd_cmd = BRDGGTO;
192 if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
193 syslog(LOG_ERR, "update bridge: ioctl(BRDGGTO) failed: %s",
194 strerror(errno));
195 return (-1);
196 }
197 bif->age_time = b_param.ifbrp_ctime;
198
199 /* Address table size. */
200 ifd.ifd_cmd = BRDGGCACHE;
201 if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
202 syslog(LOG_ERR, "update bridge: ioctl(BRDGGCACHE) "
203 "failed: %s", strerror(errno));
204 return (-1);
205 }
206 bif->max_addrs = b_param.ifbrp_csize;
207
208 return (0);
209 }
210
211 /*
212 * Fetch the current bridge STP operational parameters.
213 * Returns: -1 - on error;
214 * 0 - old TC time and Root Port values are same;
215 * 1 - topologyChange notification should be sent;
216 * 2 - newRoot notification should be sent.
217 */
218 int
bridge_get_op_param(struct bridge_if * bif)219 bridge_get_op_param(struct bridge_if *bif)
220 {
221 int new_root_send;
222 struct ifdrv ifd;
223 struct ifbropreq b_req;
224
225 strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
226 ifd.ifd_len = sizeof(b_req);
227 ifd.ifd_data = &b_req;
228 ifd.ifd_cmd = BRDGPARAM;
229
230 if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
231 syslog(LOG_ERR, "update bridge: ioctl(BRDGPARAM) failed: %s",
232 strerror(errno));
233 return (-1);
234 }
235
236 bif->max_age = 100 * b_req.ifbop_maxage;
237 bif->hello_time = 100 * b_req.ifbop_hellotime;
238 bif->fwd_delay = 100 * b_req.ifbop_fwddelay;
239 bif->stp_version = b_req.ifbop_protocol;
240 bif->tx_hold_count = b_req.ifbop_holdcount;
241
242 if (b_req.ifbop_root_port == 0 &&
243 bif->root_port != b_req.ifbop_root_port)
244 new_root_send = 2;
245 else
246 new_root_send = 0;
247
248 bif->root_port = b_req.ifbop_root_port;
249 bif->root_cost = b_req.ifbop_root_path_cost;
250 snmp_uint64_to_bridgeid(b_req.ifbop_designated_root,
251 bif->design_root);
252
253 if (bif->last_tc_time.tv_sec != b_req.ifbop_last_tc_time.tv_sec) {
254 bif->top_changes++;
255 bif->last_tc_time.tv_sec = b_req.ifbop_last_tc_time.tv_sec;
256 bif->last_tc_time.tv_usec = b_req.ifbop_last_tc_time.tv_usec;
257
258 /*
259 * "The trap is not sent if a (begemotBridge)NewRoot
260 * trap is sent for the same transition."
261 */
262 if (new_root_send == 0)
263 return (1);
264 }
265
266 return (new_root_send);
267 }
268
269 int
bridge_getinfo_bif(struct bridge_if * bif)270 bridge_getinfo_bif(struct bridge_if *bif)
271 {
272 if (bridge_get_conf_param(bif) < 0)
273 return (-1);
274
275 return (bridge_get_op_param(bif));
276 }
277
278 int
bridge_set_priority(struct bridge_if * bif,int32_t priority)279 bridge_set_priority(struct bridge_if *bif, int32_t priority)
280 {
281 struct ifdrv ifd;
282 struct ifbrparam b_param;
283
284 strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
285 ifd.ifd_len = sizeof(b_param);
286 ifd.ifd_data = &b_param;
287 b_param.ifbrp_prio = (uint32_t) priority;
288 ifd.ifd_cmd = BRDGSPRI;
289
290 if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
291 syslog(LOG_ERR, "set bridge param: ioctl(BRDGSPRI) "
292 "failed: %s", strerror(errno));
293 return (-1);
294 }
295
296 /*
297 * Re-fetching the data from the driver after that might be a good
298 * idea, since changing our bridge's priority should invoke
299 * recalculation of the active spanning tree topology in the network.
300 */
301 bif->priority = priority;
302 return (0);
303 }
304
305 /*
306 * Convert 1/100 of seconds to 1/256 of seconds.
307 * Timeout ::= TEXTUAL-CONVENTION.
308 * To convert a Timeout value into a value in units of
309 * 1/256 seconds, the following algorithm should be used:
310 * b = floor( (n * 256) / 100)
311 * The conversion to 1/256 of a second happens in the kernel -
312 * just make sure we correctly convert the seconds to Timout
313 * and vice versa.
314 */
315 static uint32_t
snmp_timeout2_sec(int32_t secs)316 snmp_timeout2_sec(int32_t secs)
317 {
318 return (secs / 100);
319 }
320
321 int
bridge_set_maxage(struct bridge_if * bif,int32_t max_age)322 bridge_set_maxage(struct bridge_if *bif, int32_t max_age)
323 {
324 struct ifdrv ifd;
325 struct ifbrparam b_param;
326
327 strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
328 ifd.ifd_len = sizeof(b_param);
329 ifd.ifd_data = &b_param;
330 b_param.ifbrp_maxage = snmp_timeout2_sec(max_age);
331 ifd.ifd_cmd = BRDGSMA;
332
333 if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
334 syslog(LOG_ERR, "set bridge param: ioctl(BRDGSMA) "
335 "failed: %s", strerror(errno));
336 return (-1);
337 }
338
339 bif->bridge_max_age = max_age;
340 return (0);
341 }
342
343 int
bridge_set_hello_time(struct bridge_if * bif,int32_t hello_time)344 bridge_set_hello_time(struct bridge_if *bif, int32_t hello_time)
345 {
346 struct ifdrv ifd;
347 struct ifbrparam b_param;
348
349 strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
350 ifd.ifd_len = sizeof(b_param);
351 ifd.ifd_data = &b_param;
352 b_param.ifbrp_hellotime = snmp_timeout2_sec(hello_time);
353 ifd.ifd_cmd = BRDGSHT;
354
355 if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
356 syslog(LOG_ERR, "set bridge param: ioctl(BRDGSHT) "
357 "failed: %s", strerror(errno));
358 return (-1);
359 }
360
361 bif->bridge_hello_time = b_param.ifbrp_hellotime;
362 return (0);
363 }
364
365 int
bridge_set_forward_delay(struct bridge_if * bif,int32_t fwd_delay)366 bridge_set_forward_delay(struct bridge_if *bif, int32_t fwd_delay)
367 {
368 struct ifdrv ifd;
369 struct ifbrparam b_param;
370
371 strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
372 ifd.ifd_len = sizeof(b_param);
373 ifd.ifd_data = &b_param;
374 b_param.ifbrp_fwddelay = snmp_timeout2_sec(fwd_delay);
375 ifd.ifd_cmd = BRDGSFD;
376
377 if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
378 syslog(LOG_ERR, "set bridge param: ioctl(BRDGSFD) "
379 "failed: %s", strerror(errno));
380 return (-1);
381 }
382
383 bif->bridge_fwd_delay = b_param.ifbrp_fwddelay;
384 return (0);
385 }
386
387 int
bridge_set_aging_time(struct bridge_if * bif,int32_t age_time)388 bridge_set_aging_time(struct bridge_if *bif, int32_t age_time)
389 {
390 struct ifdrv ifd;
391 struct ifbrparam b_param;
392
393 strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
394 ifd.ifd_len = sizeof(b_param);
395 ifd.ifd_data = &b_param;
396 b_param.ifbrp_ctime = (uint32_t) age_time;
397 ifd.ifd_cmd = BRDGSTO;
398
399 if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
400 syslog(LOG_ERR, "set bridge param: ioctl(BRDGSTO) "
401 "failed: %s", strerror(errno));
402 return (-1);
403 }
404
405 bif->age_time = age_time;
406 return (0);
407 }
408
409 int
bridge_set_max_cache(struct bridge_if * bif,int32_t max_cache)410 bridge_set_max_cache(struct bridge_if *bif, int32_t max_cache)
411 {
412 struct ifdrv ifd;
413 struct ifbrparam b_param;
414
415 strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
416 ifd.ifd_len = sizeof(b_param);
417 ifd.ifd_data = &b_param;
418 b_param.ifbrp_csize = max_cache;
419 ifd.ifd_cmd = BRDGSCACHE;
420
421 if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
422 syslog(LOG_ERR, "set bridge param: ioctl(BRDGSCACHE) "
423 "failed: %s", strerror(errno));
424 return (-1);
425 }
426
427 bif->max_addrs = b_param.ifbrp_csize;
428 return (0);
429 }
430
431 int
bridge_set_tx_hold_count(struct bridge_if * bif,int32_t tx_hc)432 bridge_set_tx_hold_count(struct bridge_if *bif, int32_t tx_hc)
433 {
434 struct ifdrv ifd;
435 struct ifbrparam b_param;
436
437 if (tx_hc < SNMP_BRIDGE_MIN_TXHC || tx_hc > SNMP_BRIDGE_MAX_TXHC)
438 return (-1);
439
440 strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
441 ifd.ifd_len = sizeof(b_param);
442 ifd.ifd_data = &b_param;
443 b_param.ifbrp_txhc = tx_hc;
444 ifd.ifd_cmd = BRDGSTXHC;
445
446 if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
447 syslog(LOG_ERR, "set bridge param: ioctl(BRDGSTXHC) "
448 "failed: %s", strerror(errno));
449 return (-1);
450 }
451
452 bif->tx_hold_count = b_param.ifbrp_txhc;
453 return (0);
454 }
455
456 int
bridge_set_stp_version(struct bridge_if * bif,int32_t stp_proto)457 bridge_set_stp_version(struct bridge_if *bif, int32_t stp_proto)
458 {
459 struct ifdrv ifd;
460 struct ifbrparam b_param;
461
462 strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
463 ifd.ifd_len = sizeof(b_param);
464 ifd.ifd_data = &b_param;
465 b_param.ifbrp_proto = stp_proto;
466 ifd.ifd_cmd = BRDGSPROTO;
467
468 if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
469 syslog(LOG_ERR, "set bridge param: ioctl(BRDGSPROTO) "
470 "failed: %s", strerror(errno));
471 return (-1);
472 }
473
474 bif->stp_version = b_param.ifbrp_proto;
475 return (0);
476 }
477
478 /*
479 * Set the bridge interface status to up/down.
480 */
481 int
bridge_set_if_up(const char * b_name,int8_t up)482 bridge_set_if_up(const char* b_name, int8_t up)
483 {
484 int flags;
485 struct ifreq ifr;
486
487 bzero(&ifr, sizeof(ifr));
488 strlcpy(ifr.ifr_name, b_name, sizeof(ifr.ifr_name));
489 if (ioctl(sock, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
490 syslog(LOG_ERR, "set bridge up: ioctl(SIOCGIFFLAGS) "
491 "failed: %s", strerror(errno));
492 return (-1);
493 }
494
495 flags = (ifr.ifr_flags & 0xffff) | (ifr.ifr_flagshigh << 16);
496 if (up == 1)
497 flags |= IFF_UP;
498 else
499 flags &= ~IFF_UP;
500
501 ifr.ifr_flags = flags & 0xffff;
502 ifr.ifr_flagshigh = flags >> 16;
503 if (ioctl(sock, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
504 syslog(LOG_ERR, "set bridge up: ioctl(SIOCSIFFLAGS) "
505 "failed: %s", strerror(errno));
506 return (-1);
507 }
508
509 return (0);
510 }
511
512 int
bridge_create(const char * b_name)513 bridge_create(const char *b_name)
514 {
515 char *new_name;
516 struct ifreq ifr;
517
518 bzero(&ifr, sizeof(ifr));
519 strlcpy(ifr.ifr_name, b_name, sizeof(ifr.ifr_name));
520
521 if (ioctl(sock, SIOCIFCREATE, &ifr) < 0) {
522 syslog(LOG_ERR, "create bridge: ioctl(SIOCIFCREATE) "
523 "failed: %s", strerror(errno));
524 return (-1);
525 }
526
527 if (strcmp(b_name, ifr.ifr_name) == 0)
528 return (0);
529
530 if ((new_name = strdup(b_name)) == NULL) {
531 syslog(LOG_ERR, "create bridge: strdup() failed");
532 return (-1);
533 }
534
535 ifr.ifr_data = new_name;
536 if (ioctl(sock, SIOCSIFNAME, (caddr_t) &ifr) < 0) {
537 syslog(LOG_ERR, "create bridge: ioctl(SIOCSIFNAME) "
538 "failed: %s", strerror(errno));
539 free(new_name);
540 return (-1);
541 }
542
543 return (0);
544 }
545
546 int
bridge_destroy(const char * b_name)547 bridge_destroy(const char *b_name)
548 {
549 struct ifreq ifr;
550
551 bzero(&ifr, sizeof(ifr));
552 strlcpy(ifr.ifr_name, b_name, sizeof(ifr.ifr_name));
553
554 if (ioctl(sock, SIOCIFDESTROY, &ifr) < 0) {
555 syslog(LOG_ERR, "destroy bridge: ioctl(SIOCIFDESTROY) "
556 "failed: %s", strerror(errno));
557 return (-1);
558 }
559
560 return (0);
561 }
562
563 /*
564 * Fetch the bridge base MAC address. Return pointer to the
565 * buffer containing the MAC address, NULL on failure.
566 */
567 u_char *
bridge_get_basemac(const char * bif_name,u_char * mac,size_t mlen)568 bridge_get_basemac(const char *bif_name, u_char *mac, size_t mlen)
569 {
570 int len;
571 char if_name[IFNAMSIZ];
572 struct ifaddrs *ifap, *ifa;
573 struct sockaddr_dl sdl;
574
575 if (getifaddrs(&ifap) != 0) {
576 syslog(LOG_ERR, "bridge get mac: getifaddrs() failed - %s",
577 strerror(errno));
578 return (NULL);
579 }
580
581 for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
582 if (ifa->ifa_addr->sa_family != AF_LINK)
583 continue;
584
585 /*
586 * Not just casting because of alignment constraints
587 * on sparc64 and ia64.
588 */
589 bcopy(ifa->ifa_addr, &sdl, sizeof(struct sockaddr_dl));
590
591 if (sdl.sdl_alen > mlen)
592 continue;
593
594 if ((len = sdl.sdl_nlen) >= IFNAMSIZ)
595 len = IFNAMSIZ - 1;
596
597 bcopy(sdl.sdl_data, if_name, len);
598 if_name[len] = '\0';
599
600 if (strcmp(bif_name, if_name) == 0) {
601 bcopy(sdl.sdl_data + sdl.sdl_nlen, mac, sdl.sdl_alen);
602 freeifaddrs(ifap);
603 return (mac);
604 }
605 }
606
607 freeifaddrs(ifap);
608 return (NULL);
609 }
610
611 /************************************************************************
612 * Bridge ports.
613 */
614
615 /*
616 * Convert the kernel STP port state into
617 * the corresopnding enumerated type from SNMP Bridge MIB.
618 */
619 static int
state2snmp_st(uint8_t ifbr_state)620 state2snmp_st(uint8_t ifbr_state)
621 {
622 switch (ifbr_state) {
623 case BSTP_IFSTATE_DISABLED:
624 return (StpPortState_disabled);
625 case BSTP_IFSTATE_LISTENING:
626 return (StpPortState_listening);
627 case BSTP_IFSTATE_LEARNING:
628 return (StpPortState_learning);
629 case BSTP_IFSTATE_FORWARDING:
630 return (StpPortState_forwarding);
631 case BSTP_IFSTATE_BLOCKING:
632 case BSTP_IFSTATE_DISCARDING:
633 return (StpPortState_blocking);
634 }
635
636 return (StpPortState_broken);
637 }
638
639 /*
640 * Fill in a bridge member information according to data polled from kernel.
641 */
642 static void
bridge_port_getinfo_conf(struct ifbreq * k_info,struct bridge_port * bp)643 bridge_port_getinfo_conf(struct ifbreq *k_info, struct bridge_port *bp)
644 {
645 bp->state = state2snmp_st(k_info->ifbr_state);
646 bp->priority = k_info->ifbr_priority;
647
648 /*
649 * RFC 4188:
650 * "New implementations should support dot1dStpPortPathCost32.
651 * If the port path costs exceeds the maximum value of this
652 * object then this object should report the maximum value,
653 * namely 65535. Applications should try to read the
654 * dot1dStpPortPathCost32 object if this object reports
655 * the maximum value."
656 */
657
658 if (k_info->ifbr_ifsflags & IFBIF_BSTP_ADMCOST)
659 bp->admin_path_cost = k_info->ifbr_path_cost;
660 else
661 bp->admin_path_cost = 0;
662
663 bp->path_cost = k_info->ifbr_path_cost;
664
665 if (k_info->ifbr_ifsflags & IFBIF_STP)
666 bp->enable = dot1dStpPortEnable_enabled;
667 else
668 bp->enable = dot1dStpPortEnable_disabled;
669
670 /* Begemot Bridge MIB only. */
671 if (k_info->ifbr_ifsflags & IFBIF_SPAN)
672 bp->span_enable = begemotBridgeBaseSpanEnabled_enabled;
673 else
674 bp->span_enable = begemotBridgeBaseSpanEnabled_disabled;
675
676 if (k_info->ifbr_ifsflags & IFBIF_PRIVATE)
677 bp->priv_set = TruthValue_true;
678 else
679 bp->priv_set = TruthValue_false;
680
681 if (k_info->ifbr_ifsflags & IFBIF_BSTP_ADMEDGE)
682 bp->admin_edge = TruthValue_true;
683 else
684 bp->admin_edge = TruthValue_false;
685
686 if (k_info->ifbr_ifsflags & IFBIF_BSTP_EDGE)
687 bp->oper_edge = TruthValue_true;
688 else
689 bp->oper_edge = TruthValue_false;
690
691 if (k_info->ifbr_ifsflags & IFBIF_BSTP_AUTOPTP) {
692 bp->admin_ptp = StpPortAdminPointToPointType_auto;
693 if (k_info->ifbr_ifsflags & IFBIF_BSTP_PTP)
694 bp->oper_ptp = TruthValue_true;
695 else
696 bp->oper_ptp = TruthValue_false;
697 } else if (k_info->ifbr_ifsflags & IFBIF_BSTP_PTP) {
698 bp->admin_ptp = StpPortAdminPointToPointType_forceTrue;
699 bp->oper_ptp = TruthValue_true;
700 } else {
701 bp->admin_ptp = StpPortAdminPointToPointType_forceFalse;
702 bp->oper_ptp = TruthValue_false;
703 }
704 }
705
706 /*
707 * Fill in a bridge interface STP information according to
708 * data polled from kernel.
709 */
710 static void
bridge_port_getinfo_opstp(struct ifbpstpreq * bp_stp,struct bridge_port * bp)711 bridge_port_getinfo_opstp(struct ifbpstpreq *bp_stp, struct bridge_port *bp)
712 {
713 bp->enable = dot1dStpPortEnable_enabled;
714 bp->fwd_trans = bp_stp->ifbp_fwd_trans;
715 bp->design_cost = bp_stp->ifbp_design_cost;
716 snmp_uint64_to_bridgeid(bp_stp->ifbp_design_root, bp->design_root);
717 snmp_uint64_to_bridgeid(bp_stp->ifbp_design_bridge, bp->design_bridge);
718 bcopy(&(bp_stp->ifbp_design_port), &(bp->design_port),
719 sizeof(uint16_t));
720 }
721
722 /*
723 * Clear a bridge interface STP information.
724 */
725 static void
bridge_port_clearinfo_opstp(struct bridge_port * bp)726 bridge_port_clearinfo_opstp(struct bridge_port *bp)
727 {
728 if (bp->enable == dot1dStpPortEnable_enabled) {
729 bp->design_cost = 0;
730 bzero(&(bp->design_root), sizeof(bridge_id));
731 bzero(&(bp->design_bridge), sizeof(bridge_id));
732 bzero(&(bp->design_port), sizeof(port_id));
733 bp->fwd_trans = 0;
734 }
735
736 bp->enable = dot1dStpPortEnable_disabled;
737 }
738
739 /*
740 * Set a bridge member priority.
741 */
742 int
bridge_port_set_priority(const char * bif_name,struct bridge_port * bp,int32_t priority)743 bridge_port_set_priority(const char *bif_name, struct bridge_port *bp,
744 int32_t priority)
745 {
746 struct ifdrv ifd;
747 struct ifbreq b_req;
748
749 strlcpy(ifd.ifd_name, bif_name, sizeof(ifd.ifd_name));
750 ifd.ifd_len = sizeof(b_req);
751 ifd.ifd_data = &b_req;
752 strlcpy(b_req.ifbr_ifsname, bp->p_name, sizeof(b_req.ifbr_ifsname));
753
754 b_req.ifbr_priority = (uint8_t) priority;
755 ifd.ifd_cmd = BRDGSIFPRIO;
756
757 if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
758 syslog(LOG_ERR, "set member %s param: ioctl(BRDGSIFPRIO) "
759 "failed: %s", bp->p_name, strerror(errno));
760 return (-1);
761 }
762
763 bp->priority = priority;
764 return (0);
765 }
766
767 /*
768 * Set a bridge member STP-enabled flag.
769 */
770 int
bridge_port_set_stp_enable(const char * bif_name,struct bridge_port * bp,uint32_t enable)771 bridge_port_set_stp_enable(const char *bif_name, struct bridge_port *bp,
772 uint32_t enable)
773 {
774 struct ifdrv ifd;
775 struct ifbreq b_req;
776
777 if (bp->enable == enable)
778 return (0);
779
780 bzero(&b_req, sizeof(b_req));
781 strlcpy(ifd.ifd_name, bif_name, sizeof(ifd.ifd_name));
782 ifd.ifd_len = sizeof(b_req);
783 ifd.ifd_data = &b_req;
784 strlcpy(b_req.ifbr_ifsname, bp->p_name, sizeof(b_req.ifbr_ifsname));
785 ifd.ifd_cmd = BRDGGIFFLGS;
786
787 if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
788 syslog(LOG_ERR, "get member %s param: ioctl(BRDGGIFFLGS) "
789 "failed: %s", bp->p_name, strerror(errno));
790 return (-1);
791 }
792
793 if (enable == dot1dStpPortEnable_enabled)
794 b_req.ifbr_ifsflags |= IFBIF_STP;
795 else
796 b_req.ifbr_ifsflags &= ~IFBIF_STP;
797
798 ifd.ifd_cmd = BRDGSIFFLGS;
799 if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
800 syslog(LOG_ERR, "set member %s param: ioctl(BRDGSIFFLGS) "
801 "failed: %s", bp->p_name, strerror(errno));
802 return (-1);
803 }
804
805 bp->enable = enable;
806 return (0);
807 }
808
809 /*
810 * Set a bridge member STP path cost.
811 */
812 int
bridge_port_set_path_cost(const char * bif_name,struct bridge_port * bp,int32_t path_cost)813 bridge_port_set_path_cost(const char *bif_name, struct bridge_port *bp,
814 int32_t path_cost)
815 {
816 struct ifdrv ifd;
817 struct ifbreq b_req;
818
819 if (path_cost < SNMP_PORT_MIN_PATHCOST ||
820 path_cost > SNMP_PORT_PATHCOST_OBSOLETE)
821 return (-2);
822
823 strlcpy(ifd.ifd_name, bif_name, sizeof(ifd.ifd_name));
824 ifd.ifd_len = sizeof(b_req);
825 ifd.ifd_data = &b_req;
826 strlcpy(b_req.ifbr_ifsname, bp->p_name, sizeof(b_req.ifbr_ifsname));
827
828 b_req.ifbr_path_cost = path_cost;
829 ifd.ifd_cmd = BRDGSIFCOST;
830
831 if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
832 syslog(LOG_ERR, "set member %s param: ioctl(BRDGSIFCOST) "
833 "failed: %s", bp->p_name, strerror(errno));
834 return (-1);
835 }
836
837 bp->admin_path_cost = path_cost;
838
839 return (0);
840 }
841
842 /*
843 * Set the PonitToPoint status of the link administratively.
844 */
845 int
bridge_port_set_admin_ptp(const char * bif_name,struct bridge_port * bp,uint32_t admin_ptp)846 bridge_port_set_admin_ptp(const char *bif_name, struct bridge_port *bp,
847 uint32_t admin_ptp)
848 {
849 struct ifdrv ifd;
850 struct ifbreq b_req;
851
852 if (bp->admin_ptp == admin_ptp)
853 return (0);
854
855 bzero(&b_req, sizeof(b_req));
856 strlcpy(ifd.ifd_name, bif_name, sizeof(ifd.ifd_name));
857 ifd.ifd_len = sizeof(b_req);
858 ifd.ifd_data = &b_req;
859 strlcpy(b_req.ifbr_ifsname, bp->p_name, sizeof(b_req.ifbr_ifsname));
860 ifd.ifd_cmd = BRDGGIFFLGS;
861
862 if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
863 syslog(LOG_ERR, "get member %s param: ioctl(BRDGGIFFLGS) "
864 "failed: %s", bp->p_name, strerror(errno));
865 return (-1);
866 }
867
868 switch (admin_ptp) {
869 case StpPortAdminPointToPointType_forceTrue:
870 b_req.ifbr_ifsflags &= ~IFBIF_BSTP_AUTOPTP;
871 b_req.ifbr_ifsflags |= IFBIF_BSTP_PTP;
872 break;
873 case StpPortAdminPointToPointType_forceFalse:
874 b_req.ifbr_ifsflags &= ~IFBIF_BSTP_AUTOPTP;
875 b_req.ifbr_ifsflags &= ~IFBIF_BSTP_PTP;
876 break;
877 case StpPortAdminPointToPointType_auto:
878 b_req.ifbr_ifsflags |= IFBIF_BSTP_AUTOPTP;
879 break;
880 }
881
882 ifd.ifd_cmd = BRDGSIFFLGS;
883 if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
884 syslog(LOG_ERR, "set member %s param: ioctl(BRDGSIFFLGS) "
885 "failed: %s", bp->p_name, strerror(errno));
886 return (-1);
887 }
888
889 bp->admin_ptp = admin_ptp;
890 return (0);
891 }
892
893 /*
894 * Set admin edge.
895 */
896 int
bridge_port_set_admin_edge(const char * bif_name,struct bridge_port * bp,uint32_t enable)897 bridge_port_set_admin_edge(const char *bif_name, struct bridge_port *bp,
898 uint32_t enable)
899 {
900 struct ifdrv ifd;
901 struct ifbreq b_req;
902
903 if (bp->admin_edge == enable)
904 return (0);
905
906 bzero(&b_req, sizeof(b_req));
907 strlcpy(ifd.ifd_name, bif_name, sizeof(ifd.ifd_name));
908 ifd.ifd_len = sizeof(b_req);
909 ifd.ifd_data = &b_req;
910 strlcpy(b_req.ifbr_ifsname, bp->p_name, sizeof(b_req.ifbr_ifsname));
911 ifd.ifd_cmd = BRDGGIFFLGS;
912
913 if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
914 syslog(LOG_ERR, "get member %s param: ioctl(BRDGGIFFLGS) "
915 "failed: %s", bp->p_name, strerror(errno));
916 return (-1);
917 }
918
919 if (enable == TruthValue_true) {
920 b_req.ifbr_ifsflags &= ~IFBIF_BSTP_AUTOEDGE;
921 b_req.ifbr_ifsflags |= IFBIF_BSTP_EDGE;
922 } else
923 b_req.ifbr_ifsflags &= ~IFBIF_BSTP_EDGE;
924
925 ifd.ifd_cmd = BRDGSIFFLGS;
926 if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
927 syslog(LOG_ERR, "set member %s param: ioctl(BRDGSIFFLGS) "
928 "failed: %s", bp->p_name, strerror(errno));
929 return (-1);
930 }
931
932 bp->admin_edge = enable;
933
934 return (0);
935 }
936
937 /*
938 * Set 'private' flag.
939 */
940 int
bridge_port_set_private(const char * bif_name,struct bridge_port * bp,uint32_t priv_set)941 bridge_port_set_private(const char *bif_name, struct bridge_port *bp,
942 uint32_t priv_set)
943 {
944 struct ifdrv ifd;
945 struct ifbreq b_req;
946
947 if (bp->priv_set == priv_set)
948 return (0);
949
950 bzero(&b_req, sizeof(b_req));
951 strlcpy(ifd.ifd_name, bif_name, sizeof(ifd.ifd_name));
952 ifd.ifd_len = sizeof(b_req);
953 ifd.ifd_data = &b_req;
954 strlcpy(b_req.ifbr_ifsname, bp->p_name, sizeof(b_req.ifbr_ifsname));
955 ifd.ifd_cmd = BRDGGIFFLGS;
956
957 if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
958 syslog(LOG_ERR, "get member %s param: ioctl(BRDGGIFFLGS) "
959 "failed: %s", bp->p_name, strerror(errno));
960 return (-1);
961 }
962
963 if (priv_set == TruthValue_true)
964 b_req.ifbr_ifsflags |= IFBIF_PRIVATE;
965 else if (priv_set == TruthValue_false)
966 b_req.ifbr_ifsflags &= ~IFBIF_PRIVATE;
967 else
968 return (SNMP_ERR_WRONG_VALUE);
969
970 ifd.ifd_cmd = BRDGSIFFLGS;
971 if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
972 syslog(LOG_ERR, "set member %s param: ioctl(BRDGSIFFLGS) "
973 "failed: %s", bp->p_name, strerror(errno));
974 return (-1);
975 }
976
977 bp->priv_set = priv_set;
978
979 return (0);
980 }
981
982
983 /*
984 * Add a bridge member port.
985 */
986 int
bridge_port_addm(struct bridge_port * bp,const char * b_name)987 bridge_port_addm(struct bridge_port *bp, const char *b_name)
988 {
989 struct ifdrv ifd;
990 struct ifbreq b_req;
991
992 bzero(&ifd, sizeof(ifd));
993 bzero(&b_req, sizeof(b_req));
994
995 strlcpy(ifd.ifd_name, b_name, sizeof(ifd.ifd_name));
996 ifd.ifd_len = sizeof(b_req);
997 ifd.ifd_data = &b_req;
998 strlcpy(b_req.ifbr_ifsname, bp->p_name, sizeof(b_req.ifbr_ifsname));
999
1000 if (bp->span_enable == begemotBridgeBaseSpanEnabled_enabled)
1001 ifd.ifd_cmd = BRDGADDS;
1002 else
1003 ifd.ifd_cmd = BRDGADD;
1004
1005 if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
1006 syslog(LOG_ERR, "%s - add member : ioctl(%s) failed: %s",
1007 bp->p_name,
1008 (ifd.ifd_cmd == BRDGADDS ? "BRDGADDS" : "BRDGADD"),
1009 strerror(errno));
1010 return (-1);
1011 }
1012
1013 return (0);
1014 }
1015
1016 /*
1017 * Delete a bridge member port.
1018 */
1019 int
bridge_port_delm(struct bridge_port * bp,const char * b_name)1020 bridge_port_delm(struct bridge_port *bp, const char *b_name)
1021 {
1022 struct ifdrv ifd;
1023 struct ifbreq b_req;
1024
1025 bzero(&ifd, sizeof(ifd));
1026 bzero(&b_req, sizeof(b_req));
1027
1028 strlcpy(ifd.ifd_name, b_name, sizeof(ifd.ifd_name));
1029 ifd.ifd_len = sizeof(b_req);
1030 ifd.ifd_data = &b_req;
1031 strlcpy(b_req.ifbr_ifsname, bp->p_name, sizeof(b_req.ifbr_ifsname));
1032
1033 if (bp->span_enable == begemotBridgeBaseSpanEnabled_enabled)
1034 ifd.ifd_cmd = BRDGDELS;
1035 else
1036 ifd.ifd_cmd = BRDGDEL;
1037
1038 if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
1039 syslog(LOG_ERR, "%s - add member : ioctl(%s) failed: %s",
1040 bp->p_name,
1041 (ifd.ifd_cmd == BRDGDELS ? "BRDGDELS" : "BRDGDEL"),
1042 strerror(errno));
1043 return (-1);
1044 }
1045
1046 return (0);
1047 }
1048
1049 /*
1050 * Fetch the bridge member list from kernel.
1051 * Return -1 on error, or buffer len if successful.
1052 */
1053 static int32_t
bridge_port_get_iflist(struct bridge_if * bif,struct ifbreq ** buf)1054 bridge_port_get_iflist(struct bridge_if *bif, struct ifbreq **buf)
1055 {
1056 int n = 128;
1057 uint32_t len;
1058 struct ifbreq *ninbuf;
1059 struct ifbifconf ifbc;
1060 struct ifdrv ifd;
1061
1062 *buf = NULL;
1063 strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
1064 ifd.ifd_cmd = BRDGGIFS;
1065 ifd.ifd_len = sizeof(ifbc);
1066 ifd.ifd_data = &ifbc;
1067
1068 for ( ; ; ) {
1069 len = n * sizeof(struct ifbreq);
1070 if ((ninbuf = (struct ifbreq *)realloc(*buf, len)) == NULL) {
1071 syslog(LOG_ERR, "get bridge member list: "
1072 "realloc failed: %s", strerror(errno));
1073 free(*buf);
1074 *buf = NULL;
1075 return (-1);
1076 }
1077
1078 ifbc.ifbic_len = len;
1079 ifbc.ifbic_req = *buf = ninbuf;
1080
1081 if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
1082 syslog(LOG_ERR, "get bridge member list: ioctl "
1083 "(BRDGGIFS) failed: %s", strerror(errno));
1084 free(*buf);
1085 buf = NULL;
1086 return (-1);
1087 }
1088
1089 if ((ifbc.ifbic_len + sizeof(struct ifbreq)) < len)
1090 break;
1091
1092 n += 64;
1093 }
1094
1095 return (ifbc.ifbic_len);
1096 }
1097
1098 /*
1099 * Fetch the bridge STP member list from kernel.
1100 * Return -1 on error, or buffer len if successful.
1101 */
1102 static int32_t
bridge_port_get_ifstplist(struct bridge_if * bif,struct ifbpstpreq ** buf)1103 bridge_port_get_ifstplist(struct bridge_if *bif, struct ifbpstpreq **buf)
1104 {
1105 int n = 128;
1106 uint32_t len;
1107 struct ifbpstpreq *ninbuf;
1108 struct ifbpstpconf ifbstp;
1109 struct ifdrv ifd;
1110
1111 *buf = NULL;
1112 strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
1113 ifd.ifd_cmd = BRDGGIFSSTP;
1114 ifd.ifd_len = sizeof(ifbstp);
1115 ifd.ifd_data = &ifbstp;
1116
1117 for ( ; ; ) {
1118 len = n * sizeof(struct ifbpstpreq);
1119 if ((ninbuf = (struct ifbpstpreq *)
1120 realloc(*buf, len)) == NULL) {
1121 syslog(LOG_ERR, "get bridge STP ports list: "
1122 "realloc failed: %s", strerror(errno));
1123 free(*buf);
1124 *buf = NULL;
1125 return (-1);
1126 }
1127
1128 ifbstp.ifbpstp_len = len;
1129 ifbstp.ifbpstp_req = *buf = ninbuf;
1130
1131 if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
1132 syslog(LOG_ERR, "get bridge STP ports list: ioctl "
1133 "(BRDGGIFSSTP) failed: %s", strerror(errno));
1134 free(*buf);
1135 buf = NULL;
1136 return (-1);
1137 }
1138
1139 if ((ifbstp.ifbpstp_len + sizeof(struct ifbpstpreq)) < len)
1140 break;
1141
1142 n += 64;
1143 }
1144
1145 return (ifbstp.ifbpstp_len);
1146 }
1147
1148 /*
1149 * Locate a bridge if STP params structure in a buffer.
1150 */
1151 static struct ifbpstpreq *
bridge_port_find_ifstplist(uint8_t port_no,struct ifbpstpreq * buf,uint32_t buf_len)1152 bridge_port_find_ifstplist(uint8_t port_no, struct ifbpstpreq *buf,
1153 uint32_t buf_len)
1154 {
1155 uint32_t i;
1156 struct ifbpstpreq *bstp;
1157
1158 for (i = 0; i < buf_len / sizeof(struct ifbpstpreq); i++) {
1159 bstp = buf + i;
1160 if (bstp->ifbp_portno == port_no)
1161 return (bstp);
1162 }
1163
1164 return (NULL);
1165 }
1166
1167 /*
1168 * Read the initial info for all members of a bridge interface.
1169 * Returns the number of ports, 0 - if none, otherwise
1170 * -1 if some other error occurred.
1171 */
1172 int
bridge_getinfo_bif_ports(struct bridge_if * bif)1173 bridge_getinfo_bif_ports(struct bridge_if *bif)
1174 {
1175 uint32_t i;
1176 int32_t buf_len;
1177 struct ifbreq *b_req_buf, *b_req;
1178 struct ifbpstpreq *bs_req_buf, *bs_req;
1179 struct bridge_port *bp;
1180 struct mibif *m_if;
1181
1182 if ((buf_len = bridge_port_get_iflist(bif, &b_req_buf)) < 0)
1183 return (-1);
1184
1185 for (i = 0; i < buf_len / sizeof(struct ifbreq); i++) {
1186 b_req = b_req_buf + i;
1187
1188 if ((m_if = mib_find_if_sys(b_req->ifbr_portno)) != NULL) {
1189 /* Hopefully we will not fail here. */
1190 if ((bp = bridge_new_port(m_if, bif)) != NULL) {
1191 bp->status = RowStatus_active;
1192 bridge_port_getinfo_conf(b_req, bp);
1193 bridge_port_getinfo_mibif(m_if, bp);
1194 }
1195 } else {
1196 syslog(LOG_ERR, "bridge member %s not present "
1197 "in mibII ifTable", b_req->ifbr_ifsname);
1198 }
1199 }
1200 free(b_req_buf);
1201
1202 if ((buf_len = bridge_port_get_ifstplist(bif, &bs_req_buf)) < 0)
1203 return (-1);
1204
1205 for (bp = bridge_port_bif_first(bif); bp != NULL;
1206 bp = bridge_port_bif_next(bp)) {
1207 if ((bs_req = bridge_port_find_ifstplist(bp->port_no,
1208 bs_req_buf, buf_len)) == NULL)
1209 bridge_port_clearinfo_opstp(bp);
1210 else
1211 bridge_port_getinfo_opstp(bs_req, bp);
1212 }
1213 free(bs_req_buf);
1214
1215 return (i);
1216 }
1217
1218 /*
1219 * Update the information for the bridge interface members.
1220 */
1221 int
bridge_update_memif(struct bridge_if * bif)1222 bridge_update_memif(struct bridge_if *bif)
1223 {
1224 int added, updated;
1225 uint32_t i;
1226 int32_t buf_len;
1227 struct ifbreq *b_req_buf, *b_req;
1228 struct ifbpstpreq *bs_req_buf, *bs_req;
1229 struct bridge_port *bp, *bp_next;
1230 struct mibif *m_if;
1231
1232 if ((buf_len = bridge_port_get_iflist(bif, &b_req_buf)) < 0)
1233 return (-1);
1234
1235 added = updated = 0;
1236
1237 #define BP_FOUND 0x01
1238 for (i = 0; i < buf_len / sizeof(struct ifbreq); i++) {
1239 b_req = b_req_buf + i;
1240
1241 if ((m_if = mib_find_if_sys(b_req->ifbr_portno)) == NULL) {
1242 syslog(LOG_ERR, "bridge member %s not present "
1243 "in mibII ifTable", b_req->ifbr_ifsname);
1244 continue;
1245 }
1246
1247 if ((bp = bridge_port_find(m_if->index, bif)) == NULL &&
1248 (bp = bridge_new_port(m_if, bif)) != NULL) {
1249 bp->status = RowStatus_active;
1250 added++;
1251 }
1252
1253 if (bp != NULL) {
1254 updated++;
1255 bridge_port_getinfo_conf(b_req, bp);
1256 bridge_port_getinfo_mibif(m_if, bp);
1257 bp->flags |= BP_FOUND;
1258 }
1259 }
1260 free(b_req_buf);
1261
1262 /* Clean up list. */
1263 for (bp = bridge_port_bif_first(bif); bp != NULL; bp = bp_next) {
1264 bp_next = bridge_port_bif_next(bp);
1265
1266 if ((bp->flags & BP_FOUND) == 0 &&
1267 bp->status == RowStatus_active)
1268 bridge_port_remove(bp, bif);
1269 else
1270 bp->flags |= ~BP_FOUND;
1271 }
1272 #undef BP_FOUND
1273
1274 if ((buf_len = bridge_port_get_ifstplist(bif, &bs_req_buf)) < 0)
1275 return (-1);
1276
1277 for (bp = bridge_port_bif_first(bif); bp != NULL;
1278 bp = bridge_port_bif_next(bp)) {
1279 if ((bs_req = bridge_port_find_ifstplist(bp->port_no,
1280 bs_req_buf, buf_len)) == NULL)
1281 bridge_port_clearinfo_opstp(bp);
1282 else
1283 bridge_port_getinfo_opstp(bs_req, bp);
1284 }
1285 free(bs_req_buf);
1286 bif->ports_age = time(NULL);
1287
1288 return (updated);
1289 }
1290
1291 /************************************************************************
1292 * Bridge addresses.
1293 */
1294
1295 /*
1296 * Update the bridge address info according to the polled data.
1297 */
1298 static void
bridge_addrs_info_ifaddrlist(struct ifbareq * ifba,struct tp_entry * tpe)1299 bridge_addrs_info_ifaddrlist(struct ifbareq *ifba, struct tp_entry *tpe)
1300 {
1301 tpe->port_no = if_nametoindex(ifba->ifba_ifsname);
1302
1303 if ((ifba->ifba_flags & IFBAF_TYPEMASK) == IFBAF_STATIC)
1304 tpe->status = TpFdbStatus_mgmt;
1305 else
1306 tpe->status = TpFdbStatus_learned;
1307 }
1308
1309 /*
1310 * Read the bridge addresses from kernel.
1311 * Return -1 on error, or buffer len if successful.
1312 */
1313 static int32_t
bridge_addrs_getinfo_ifalist(struct bridge_if * bif,struct ifbareq ** buf)1314 bridge_addrs_getinfo_ifalist(struct bridge_if *bif, struct ifbareq **buf)
1315 {
1316 int n = 128;
1317 uint32_t len;
1318 struct ifbareq *ninbuf;
1319 struct ifbaconf bac;
1320 struct ifdrv ifd;
1321
1322 *buf = NULL;
1323 strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
1324 ifd.ifd_cmd = BRDGRTS;
1325 ifd.ifd_len = sizeof(bac);
1326 ifd.ifd_data = &bac;
1327
1328 for ( ; ; ) {
1329 len = n * sizeof(struct ifbareq);
1330 if ((ninbuf = (struct ifbareq *)realloc(*buf, len)) == NULL) {
1331 syslog(LOG_ERR, "get bridge address list: "
1332 " realloc failed: %s", strerror(errno));
1333 free(*buf);
1334 *buf = NULL;
1335 return (-1);
1336 }
1337
1338 bac.ifbac_len = len;
1339 bac.ifbac_req = *buf = ninbuf;
1340
1341 if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
1342 syslog(LOG_ERR, "get bridge address list: "
1343 "ioctl(BRDGRTS) failed: %s", strerror(errno));
1344 free(*buf);
1345 buf = NULL;
1346 return (-1);
1347 }
1348
1349 if ((bac.ifbac_len + sizeof(struct ifbareq)) < len)
1350 break;
1351
1352 n += 64;
1353 }
1354
1355 return (bac.ifbac_len);
1356 }
1357
1358 /*
1359 * Read the initial info for all addresses on a bridge interface.
1360 * Returns the number of addresses, 0 - if none, otherwise
1361 * -1 if some other error occurred.
1362 */
1363 int
bridge_getinfo_bif_addrs(struct bridge_if * bif)1364 bridge_getinfo_bif_addrs(struct bridge_if *bif)
1365 {
1366 uint32_t i;
1367 int32_t buf_len;
1368 struct ifbareq *addr_req_buf, *addr_req;
1369 struct tp_entry *te;
1370
1371 if ((buf_len = bridge_addrs_getinfo_ifalist(bif, &addr_req_buf)) < 0)
1372 return (-1);
1373
1374 for (i = 0; i < buf_len / sizeof(struct ifbareq); i++) {
1375 addr_req = addr_req_buf + i;
1376
1377 if ((te = bridge_new_addrs(addr_req->ifba_dst, bif)) != NULL)
1378 bridge_addrs_info_ifaddrlist(addr_req, te);
1379 }
1380
1381 free(addr_req_buf);
1382 return (i);
1383 }
1384
1385 /*
1386 * Update the addresses for the bridge interface.
1387 */
1388 int
bridge_update_addrs(struct bridge_if * bif)1389 bridge_update_addrs(struct bridge_if *bif)
1390 {
1391 int added, updated;
1392 uint32_t i;
1393 int32_t buf_len;
1394 struct tp_entry *te, *te_next;
1395 struct ifbareq *addr_req_buf, *addr_req;
1396
1397 if ((buf_len = bridge_addrs_getinfo_ifalist(bif, &addr_req_buf)) < 0)
1398 return (-1);
1399
1400 added = updated = 0;
1401
1402 #define BA_FOUND 0x01
1403 for (i = 0; i < buf_len / sizeof(struct ifbareq); i++) {
1404 addr_req = addr_req_buf + i;
1405
1406 if ((te = bridge_addrs_find(addr_req->ifba_dst, bif)) == NULL) {
1407 added++;
1408
1409 if ((te = bridge_new_addrs(addr_req->ifba_dst, bif))
1410 == NULL)
1411 continue;
1412 } else
1413 updated++;
1414
1415 bridge_addrs_info_ifaddrlist(addr_req, te);
1416 te-> flags |= BA_FOUND;
1417 }
1418 free(addr_req_buf);
1419
1420 for (te = bridge_addrs_bif_first(bif); te != NULL; te = te_next) {
1421 te_next = bridge_addrs_bif_next(te);
1422
1423 if ((te-> flags & BA_FOUND) == 0)
1424 bridge_addrs_remove(te, bif);
1425 else
1426 te-> flags &= ~BA_FOUND;
1427 }
1428 #undef BA_FOUND
1429
1430 bif->addrs_age = time(NULL);
1431 return (updated + added);
1432 }
1433
1434 /************************************************************************
1435 * Bridge packet filtering.
1436 */
1437 const char bridge_sysctl[] = "net.link.bridge.";
1438
1439 static struct {
1440 int32_t val;
1441 const char *name;
1442 } bridge_pf_sysctl[] = {
1443 { 1, "pfil_bridge" },
1444 { 1, "pfil_member" },
1445 { 1, "pfil_onlyip" },
1446 { 0, "ipfw" },
1447 };
1448
1449 int32_t
bridge_get_pfval(uint8_t which)1450 bridge_get_pfval(uint8_t which)
1451 {
1452
1453 if (which > nitems(bridge_pf_sysctl) || which < 1)
1454 return (-1);
1455
1456 return (bridge_pf_sysctl[which - 1].val);
1457 }
1458
1459 int32_t
bridge_do_pfctl(int32_t bridge_ctl,enum snmp_op op,int32_t * val)1460 bridge_do_pfctl(int32_t bridge_ctl, enum snmp_op op, int32_t *val)
1461 {
1462 char *mib_oid;
1463 size_t len, s_len;
1464 int32_t i, s_i;
1465
1466 if (bridge_ctl >= LEAF_begemotBridgeLayer2PfStatus)
1467 return (-2);
1468
1469 if (op == SNMP_OP_SET) {
1470 s_i = *val;
1471 s_len = sizeof(s_i);
1472 } else
1473 s_len = 0;
1474
1475 len = sizeof(i);
1476
1477 asprintf(&mib_oid, "%s%s", bridge_sysctl,
1478 bridge_pf_sysctl[bridge_ctl].name);
1479 if (mib_oid == NULL)
1480 return (-1);
1481
1482 if (sysctlbyname(mib_oid, &i, &len, (op == SNMP_OP_SET ? &s_i : NULL),
1483 s_len) == -1) {
1484 syslog(LOG_ERR, "sysctl(%s) failed - %s", mib_oid,
1485 strerror(errno));
1486 free(mib_oid);
1487 return (-1);
1488 }
1489
1490 bridge_pf_sysctl[bridge_ctl].val = i;
1491 *val = i;
1492
1493 free(mib_oid);
1494
1495 return (i);
1496 }
1497
1498 void
bridge_pf_dump(void)1499 bridge_pf_dump(void)
1500 {
1501 uint8_t i;
1502
1503 for (i = 0; i < nitems(bridge_pf_sysctl); i++) {
1504 syslog(LOG_ERR, "%s%s = %d", bridge_sysctl,
1505 bridge_pf_sysctl[i].name, bridge_pf_sysctl[i].val);
1506 }
1507 }
1508