1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2006 Shteryana Shopova <syrinx@FreeBSD.org>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 *
28 * Bridge MIB implementation for SNMPd.
29 * Bridge OS specific ioctls.
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 #define SNMPTREE_TYPES
60 #include "bridge_tree.h"
61 #include "bridge_snmp.h"
62
63 int sock = -1;
64
65 int
bridge_ioctl_init(void)66 bridge_ioctl_init(void)
67 {
68 if ((sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
69 syslog(LOG_ERR, "cannot open socket : %s", strerror(errno));
70 return (-1);
71 }
72
73 return (0);
74 }
75
76 /*
77 * Load the if_bridge.ko module in kernel if not already there.
78 */
79 int
bridge_kmod_load(void)80 bridge_kmod_load(void)
81 {
82 int fileid, modid;
83 const char mod_name[] = "if_bridge";
84 struct module_stat mstat;
85
86 /* Scan files in kernel. */
87 mstat.version = sizeof(struct module_stat);
88 for (fileid = kldnext(0); fileid > 0; fileid = kldnext(fileid)) {
89 /* Scan modules in file. */
90 for (modid = kldfirstmod(fileid); modid > 0;
91 modid = modfnext(modid)) {
92
93 if (modstat(modid, &mstat) < 0)
94 continue;
95
96 if (strcmp(mod_name, mstat.name) == 0)
97 return (0);
98 }
99 }
100
101 /* Not present - load it. */
102 if (kldload(mod_name) < 0) {
103 syslog(LOG_ERR, "failed to load %s kernel module", mod_name);
104 return (-1);
105 }
106
107 return (1);
108 }
109
110 /************************************************************************
111 * Bridge interfaces.
112 */
113
114 /*
115 * Convert the kernel uint64_t value for a bridge id
116 */
117 static void
snmp_uint64_to_bridgeid(uint64_t id,bridge_id b_id)118 snmp_uint64_to_bridgeid(uint64_t id, bridge_id b_id)
119 {
120 int i;
121 u_char *o;
122
123 o = (u_char *) &id;
124
125 for (i = 0; i < SNMP_BRIDGE_ID_LEN; i++, o++)
126 b_id[SNMP_BRIDGE_ID_LEN - i - 1] = *o;
127 }
128
129 /*
130 * Fetch the bridge configuration parameters from the kernel excluding
131 * it's base MAC address.
132 */
133 static int
bridge_get_conf_param(struct bridge_if * bif)134 bridge_get_conf_param(struct bridge_if *bif)
135 {
136 struct ifdrv ifd;
137 struct ifbrparam b_param;
138
139 strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
140 ifd.ifd_len = sizeof(b_param);
141 ifd.ifd_data = &b_param;
142
143 /* Bridge priority. */
144 ifd.ifd_cmd = BRDGGPRI;
145 if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
146 syslog(LOG_ERR, "update bridge: ioctl(BRDGGPRI) failed: %s",
147 strerror(errno));
148 return (-1);
149 }
150
151 bif->priority = b_param.ifbrp_prio;
152
153 /* Configured max age. */
154 ifd.ifd_cmd = BRDGGMA;
155 if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
156 syslog(LOG_ERR, "update bridge: ioctl(BRDGGMA) failed: %s",
157 strerror(errno));
158 return (-1);
159 }
160
161 /* Centi-seconds. */
162 bif->bridge_max_age = 100 * b_param.ifbrp_maxage;
163
164 /* Configured hello time. */
165 ifd.ifd_cmd = BRDGGHT;
166 if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
167 syslog(LOG_ERR, "update bridge: ioctl(BRDGGHT) failed: %s",
168 strerror(errno));
169 return (-1);
170 }
171 bif->bridge_hello_time = 100 * b_param.ifbrp_hellotime;
172
173 /* Forward delay. */
174 ifd.ifd_cmd = BRDGGFD;
175 if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
176 syslog(LOG_ERR, "update bridge: ioctl(BRDGGFD) failed: %s",
177 strerror(errno));
178 return (-1);
179 }
180 bif->bridge_fwd_delay = 100 * b_param.ifbrp_fwddelay;
181
182 /* Number of dropped addresses. */
183 ifd.ifd_cmd = BRDGGRTE;
184 if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
185 syslog(LOG_ERR, "update bridge: ioctl(BRDGGRTE) failed: %s",
186 strerror(errno));
187 return (-1);
188 }
189 bif->lrnt_drops = b_param.ifbrp_cexceeded;
190
191 /* Address table timeout. */
192 ifd.ifd_cmd = BRDGGTO;
193 if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
194 syslog(LOG_ERR, "update bridge: ioctl(BRDGGTO) failed: %s",
195 strerror(errno));
196 return (-1);
197 }
198 bif->age_time = b_param.ifbrp_ctime;
199
200 /* Address table size. */
201 ifd.ifd_cmd = BRDGGCACHE;
202 if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
203 syslog(LOG_ERR, "update bridge: ioctl(BRDGGCACHE) "
204 "failed: %s", strerror(errno));
205 return (-1);
206 }
207 bif->max_addrs = b_param.ifbrp_csize;
208
209 return (0);
210 }
211
212 /*
213 * Fetch the current bridge STP operational parameters.
214 * Returns: -1 - on error;
215 * 0 - old TC time and Root Port values are same;
216 * 1 - topologyChange notification should be sent;
217 * 2 - newRoot notification should be sent.
218 */
219 int
bridge_get_op_param(struct bridge_if * bif)220 bridge_get_op_param(struct bridge_if *bif)
221 {
222 int new_root_send;
223 struct ifdrv ifd;
224 struct ifbropreq b_req;
225
226 strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
227 ifd.ifd_len = sizeof(b_req);
228 ifd.ifd_data = &b_req;
229 ifd.ifd_cmd = BRDGPARAM;
230
231 if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
232 syslog(LOG_ERR, "update bridge: ioctl(BRDGPARAM) failed: %s",
233 strerror(errno));
234 return (-1);
235 }
236
237 bif->max_age = 100 * b_req.ifbop_maxage;
238 bif->hello_time = 100 * b_req.ifbop_hellotime;
239 bif->fwd_delay = 100 * b_req.ifbop_fwddelay;
240 bif->stp_version = b_req.ifbop_protocol;
241 bif->tx_hold_count = b_req.ifbop_holdcount;
242
243 if (b_req.ifbop_root_port == 0 &&
244 bif->root_port != b_req.ifbop_root_port)
245 new_root_send = 2;
246 else
247 new_root_send = 0;
248
249 bif->root_port = b_req.ifbop_root_port;
250 bif->root_cost = b_req.ifbop_root_path_cost;
251 snmp_uint64_to_bridgeid(b_req.ifbop_designated_root,
252 bif->design_root);
253
254 if (bif->last_tc_time.tv_sec != b_req.ifbop_last_tc_time.tv_sec) {
255 bif->top_changes++;
256 bif->last_tc_time.tv_sec = b_req.ifbop_last_tc_time.tv_sec;
257 bif->last_tc_time.tv_usec = b_req.ifbop_last_tc_time.tv_usec;
258
259 /*
260 * "The trap is not sent if a (begemotBridge)NewRoot
261 * trap is sent for the same transition."
262 */
263 if (new_root_send == 0)
264 return (1);
265 }
266
267 return (new_root_send);
268 }
269
270 int
bridge_getinfo_bif(struct bridge_if * bif)271 bridge_getinfo_bif(struct bridge_if *bif)
272 {
273 if (bridge_get_conf_param(bif) < 0)
274 return (-1);
275
276 return (bridge_get_op_param(bif));
277 }
278
279 int
bridge_set_priority(struct bridge_if * bif,int32_t priority)280 bridge_set_priority(struct bridge_if *bif, int32_t priority)
281 {
282 struct ifdrv ifd;
283 struct ifbrparam b_param;
284
285 strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
286 ifd.ifd_len = sizeof(b_param);
287 ifd.ifd_data = &b_param;
288 b_param.ifbrp_prio = (uint32_t) priority;
289 ifd.ifd_cmd = BRDGSPRI;
290
291 if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
292 syslog(LOG_ERR, "set bridge param: ioctl(BRDGSPRI) "
293 "failed: %s", strerror(errno));
294 return (-1);
295 }
296
297 /*
298 * Re-fetching the data from the driver after that might be a good
299 * idea, since changing our bridge's priority should invoke
300 * recalculation of the active spanning tree topology in the network.
301 */
302 bif->priority = priority;
303 return (0);
304 }
305
306 /*
307 * Convert 1/100 of seconds to 1/256 of seconds.
308 * Timeout ::= TEXTUAL-CONVENTION.
309 * To convert a Timeout value into a value in units of
310 * 1/256 seconds, the following algorithm should be used:
311 * b = floor( (n * 256) / 100)
312 * The conversion to 1/256 of a second happens in the kernel -
313 * just make sure we correctly convert the seconds to Timeout
314 * and vice versa.
315 */
316 static uint32_t
snmp_timeout2_sec(int32_t secs)317 snmp_timeout2_sec(int32_t secs)
318 {
319 return (secs / 100);
320 }
321
322 int
bridge_set_maxage(struct bridge_if * bif,int32_t max_age)323 bridge_set_maxage(struct bridge_if *bif, int32_t max_age)
324 {
325 struct ifdrv ifd;
326 struct ifbrparam b_param;
327
328 strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
329 ifd.ifd_len = sizeof(b_param);
330 ifd.ifd_data = &b_param;
331 b_param.ifbrp_maxage = snmp_timeout2_sec(max_age);
332 ifd.ifd_cmd = BRDGSMA;
333
334 if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
335 syslog(LOG_ERR, "set bridge param: ioctl(BRDGSMA) "
336 "failed: %s", strerror(errno));
337 return (-1);
338 }
339
340 bif->bridge_max_age = max_age;
341 return (0);
342 }
343
344 int
bridge_set_hello_time(struct bridge_if * bif,int32_t hello_time)345 bridge_set_hello_time(struct bridge_if *bif, int32_t hello_time)
346 {
347 struct ifdrv ifd;
348 struct ifbrparam b_param;
349
350 strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
351 ifd.ifd_len = sizeof(b_param);
352 ifd.ifd_data = &b_param;
353 b_param.ifbrp_hellotime = snmp_timeout2_sec(hello_time);
354 ifd.ifd_cmd = BRDGSHT;
355
356 if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
357 syslog(LOG_ERR, "set bridge param: ioctl(BRDGSHT) "
358 "failed: %s", strerror(errno));
359 return (-1);
360 }
361
362 bif->bridge_hello_time = b_param.ifbrp_hellotime;
363 return (0);
364 }
365
366 int
bridge_set_forward_delay(struct bridge_if * bif,int32_t fwd_delay)367 bridge_set_forward_delay(struct bridge_if *bif, int32_t fwd_delay)
368 {
369 struct ifdrv ifd;
370 struct ifbrparam b_param;
371
372 strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
373 ifd.ifd_len = sizeof(b_param);
374 ifd.ifd_data = &b_param;
375 b_param.ifbrp_fwddelay = snmp_timeout2_sec(fwd_delay);
376 ifd.ifd_cmd = BRDGSFD;
377
378 if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
379 syslog(LOG_ERR, "set bridge param: ioctl(BRDGSFD) "
380 "failed: %s", strerror(errno));
381 return (-1);
382 }
383
384 bif->bridge_fwd_delay = b_param.ifbrp_fwddelay;
385 return (0);
386 }
387
388 int
bridge_set_aging_time(struct bridge_if * bif,int32_t age_time)389 bridge_set_aging_time(struct bridge_if *bif, int32_t age_time)
390 {
391 struct ifdrv ifd;
392 struct ifbrparam b_param;
393
394 strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
395 ifd.ifd_len = sizeof(b_param);
396 ifd.ifd_data = &b_param;
397 b_param.ifbrp_ctime = (uint32_t) age_time;
398 ifd.ifd_cmd = BRDGSTO;
399
400 if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
401 syslog(LOG_ERR, "set bridge param: ioctl(BRDGSTO) "
402 "failed: %s", strerror(errno));
403 return (-1);
404 }
405
406 bif->age_time = age_time;
407 return (0);
408 }
409
410 int
bridge_set_max_cache(struct bridge_if * bif,int32_t max_cache)411 bridge_set_max_cache(struct bridge_if *bif, int32_t max_cache)
412 {
413 struct ifdrv ifd;
414 struct ifbrparam b_param;
415
416 strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
417 ifd.ifd_len = sizeof(b_param);
418 ifd.ifd_data = &b_param;
419 b_param.ifbrp_csize = max_cache;
420 ifd.ifd_cmd = BRDGSCACHE;
421
422 if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
423 syslog(LOG_ERR, "set bridge param: ioctl(BRDGSCACHE) "
424 "failed: %s", strerror(errno));
425 return (-1);
426 }
427
428 bif->max_addrs = b_param.ifbrp_csize;
429 return (0);
430 }
431
432 int
bridge_set_tx_hold_count(struct bridge_if * bif,int32_t tx_hc)433 bridge_set_tx_hold_count(struct bridge_if *bif, int32_t tx_hc)
434 {
435 struct ifdrv ifd;
436 struct ifbrparam b_param;
437
438 if (tx_hc < SNMP_BRIDGE_MIN_TXHC || tx_hc > SNMP_BRIDGE_MAX_TXHC)
439 return (-1);
440
441 strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
442 ifd.ifd_len = sizeof(b_param);
443 ifd.ifd_data = &b_param;
444 b_param.ifbrp_txhc = tx_hc;
445 ifd.ifd_cmd = BRDGSTXHC;
446
447 if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
448 syslog(LOG_ERR, "set bridge param: ioctl(BRDGSTXHC) "
449 "failed: %s", strerror(errno));
450 return (-1);
451 }
452
453 bif->tx_hold_count = b_param.ifbrp_txhc;
454 return (0);
455 }
456
457 int
bridge_set_stp_version(struct bridge_if * bif,int32_t stp_proto)458 bridge_set_stp_version(struct bridge_if *bif, int32_t stp_proto)
459 {
460 struct ifdrv ifd;
461 struct ifbrparam b_param;
462
463 strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
464 ifd.ifd_len = sizeof(b_param);
465 ifd.ifd_data = &b_param;
466 b_param.ifbrp_proto = stp_proto;
467 ifd.ifd_cmd = BRDGSPROTO;
468
469 if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
470 syslog(LOG_ERR, "set bridge param: ioctl(BRDGSPROTO) "
471 "failed: %s", strerror(errno));
472 return (-1);
473 }
474
475 bif->stp_version = b_param.ifbrp_proto;
476 return (0);
477 }
478
479 /*
480 * Set the bridge interface status to up/down.
481 */
482 int
bridge_set_if_up(const char * b_name,int8_t up)483 bridge_set_if_up(const char* b_name, int8_t up)
484 {
485 int flags;
486 struct ifreq ifr;
487
488 bzero(&ifr, sizeof(ifr));
489 strlcpy(ifr.ifr_name, b_name, sizeof(ifr.ifr_name));
490 if (ioctl(sock, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
491 syslog(LOG_ERR, "set bridge up: ioctl(SIOCGIFFLAGS) "
492 "failed: %s", strerror(errno));
493 return (-1);
494 }
495
496 flags = (ifr.ifr_flags & 0xffff) | (ifr.ifr_flagshigh << 16);
497 if (up == 1)
498 flags |= IFF_UP;
499 else
500 flags &= ~IFF_UP;
501
502 ifr.ifr_flags = flags & 0xffff;
503 ifr.ifr_flagshigh = flags >> 16;
504 if (ioctl(sock, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
505 syslog(LOG_ERR, "set bridge up: ioctl(SIOCSIFFLAGS) "
506 "failed: %s", strerror(errno));
507 return (-1);
508 }
509
510 return (0);
511 }
512
513 int
bridge_create(const char * b_name)514 bridge_create(const char *b_name)
515 {
516 char *new_name;
517 struct ifreq ifr;
518
519 bzero(&ifr, sizeof(ifr));
520 strlcpy(ifr.ifr_name, b_name, sizeof(ifr.ifr_name));
521
522 if (ioctl(sock, SIOCIFCREATE, &ifr) < 0) {
523 syslog(LOG_ERR, "create bridge: ioctl(SIOCIFCREATE) "
524 "failed: %s", strerror(errno));
525 return (-1);
526 }
527
528 if (strcmp(b_name, ifr.ifr_name) == 0)
529 return (0);
530
531 if ((new_name = strdup(b_name)) == NULL) {
532 syslog(LOG_ERR, "create bridge: strdup() failed");
533 return (-1);
534 }
535
536 ifr.ifr_data = new_name;
537 if (ioctl(sock, SIOCSIFNAME, (caddr_t) &ifr) < 0) {
538 syslog(LOG_ERR, "create bridge: ioctl(SIOCSIFNAME) "
539 "failed: %s", strerror(errno));
540 free(new_name);
541 return (-1);
542 }
543
544 return (0);
545 }
546
547 int
bridge_destroy(const char * b_name)548 bridge_destroy(const char *b_name)
549 {
550 struct ifreq ifr;
551
552 bzero(&ifr, sizeof(ifr));
553 strlcpy(ifr.ifr_name, b_name, sizeof(ifr.ifr_name));
554
555 if (ioctl(sock, SIOCIFDESTROY, &ifr) < 0) {
556 syslog(LOG_ERR, "destroy bridge: ioctl(SIOCIFDESTROY) "
557 "failed: %s", strerror(errno));
558 return (-1);
559 }
560
561 return (0);
562 }
563
564 /*
565 * Fetch the bridge base MAC address. Return pointer to the
566 * buffer containing the MAC address, NULL on failure.
567 */
568 u_char *
bridge_get_basemac(const char * bif_name,u_char * mac,size_t mlen)569 bridge_get_basemac(const char *bif_name, u_char *mac, size_t mlen)
570 {
571 int len;
572 char if_name[IFNAMSIZ];
573 struct ifaddrs *ifap, *ifa;
574 struct sockaddr_dl sdl;
575
576 if (getifaddrs(&ifap) != 0) {
577 syslog(LOG_ERR, "bridge get mac: getifaddrs() failed - %s",
578 strerror(errno));
579 return (NULL);
580 }
581
582 for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
583 if (ifa->ifa_addr->sa_family != AF_LINK)
584 continue;
585
586 /*
587 * Not just casting because of alignment constraints.
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 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 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 }
1251
1252 if (bp != NULL) {
1253 updated++;
1254 bridge_port_getinfo_conf(b_req, bp);
1255 bridge_port_getinfo_mibif(m_if, bp);
1256 bp->flags |= BP_FOUND;
1257 }
1258 }
1259 free(b_req_buf);
1260
1261 /* Clean up list. */
1262 for (bp = bridge_port_bif_first(bif); bp != NULL; bp = bp_next) {
1263 bp_next = bridge_port_bif_next(bp);
1264
1265 if ((bp->flags & BP_FOUND) == 0 &&
1266 bp->status == RowStatus_active)
1267 bridge_port_remove(bp, bif);
1268 else
1269 bp->flags |= ~BP_FOUND;
1270 }
1271 #undef BP_FOUND
1272
1273 if ((buf_len = bridge_port_get_ifstplist(bif, &bs_req_buf)) < 0)
1274 return (-1);
1275
1276 for (bp = bridge_port_bif_first(bif); bp != NULL;
1277 bp = bridge_port_bif_next(bp)) {
1278 if ((bs_req = bridge_port_find_ifstplist(bp->port_no,
1279 bs_req_buf, buf_len)) == NULL)
1280 bridge_port_clearinfo_opstp(bp);
1281 else
1282 bridge_port_getinfo_opstp(bs_req, bp);
1283 }
1284 free(bs_req_buf);
1285 bif->ports_age = time(NULL);
1286
1287 return (updated);
1288 }
1289
1290 /************************************************************************
1291 * Bridge addresses.
1292 */
1293
1294 /*
1295 * Update the bridge address info according to the polled data.
1296 */
1297 static void
bridge_addrs_info_ifaddrlist(struct ifbareq * ifba,struct tp_entry * tpe)1298 bridge_addrs_info_ifaddrlist(struct ifbareq *ifba, struct tp_entry *tpe)
1299 {
1300 tpe->port_no = if_nametoindex(ifba->ifba_ifsname);
1301
1302 if ((ifba->ifba_flags & IFBAF_TYPEMASK) == IFBAF_STATIC)
1303 tpe->status = TpFdbStatus_mgmt;
1304 else
1305 tpe->status = TpFdbStatus_learned;
1306 }
1307
1308 /*
1309 * Read the bridge addresses from kernel.
1310 * Return -1 on error, or buffer len if successful.
1311 */
1312 static int32_t
bridge_addrs_getinfo_ifalist(struct bridge_if * bif,struct ifbareq ** buf)1313 bridge_addrs_getinfo_ifalist(struct bridge_if *bif, struct ifbareq **buf)
1314 {
1315 int n = 128;
1316 uint32_t len;
1317 struct ifbareq *ninbuf;
1318 struct ifbaconf bac;
1319 struct ifdrv ifd;
1320
1321 *buf = NULL;
1322 strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
1323 ifd.ifd_cmd = BRDGRTS;
1324 ifd.ifd_len = sizeof(bac);
1325 ifd.ifd_data = &bac;
1326
1327 for ( ; ; ) {
1328 len = n * sizeof(struct ifbareq);
1329 if ((ninbuf = (struct ifbareq *)realloc(*buf, len)) == NULL) {
1330 syslog(LOG_ERR, "get bridge address list: "
1331 " realloc failed: %s", strerror(errno));
1332 free(*buf);
1333 *buf = NULL;
1334 return (-1);
1335 }
1336
1337 bac.ifbac_len = len;
1338 bac.ifbac_req = *buf = ninbuf;
1339
1340 if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
1341 syslog(LOG_ERR, "get bridge address list: "
1342 "ioctl(BRDGRTS) failed: %s", strerror(errno));
1343 free(*buf);
1344 buf = NULL;
1345 return (-1);
1346 }
1347
1348 if ((bac.ifbac_len + sizeof(struct ifbareq)) < len)
1349 break;
1350
1351 n += 64;
1352 }
1353
1354 return (bac.ifbac_len);
1355 }
1356
1357 /*
1358 * Read the initial info for all addresses on a bridge interface.
1359 * Returns the number of addresses, 0 - if none, otherwise
1360 * -1 if some other error occurred.
1361 */
1362 int
bridge_getinfo_bif_addrs(struct bridge_if * bif)1363 bridge_getinfo_bif_addrs(struct bridge_if *bif)
1364 {
1365 uint32_t i;
1366 int32_t buf_len;
1367 struct ifbareq *addr_req_buf, *addr_req;
1368 struct tp_entry *te;
1369
1370 if ((buf_len = bridge_addrs_getinfo_ifalist(bif, &addr_req_buf)) < 0)
1371 return (-1);
1372
1373 for (i = 0; i < buf_len / sizeof(struct ifbareq); i++) {
1374 addr_req = addr_req_buf + i;
1375
1376 if ((te = bridge_new_addrs(addr_req->ifba_dst, bif)) != NULL)
1377 bridge_addrs_info_ifaddrlist(addr_req, te);
1378 }
1379
1380 free(addr_req_buf);
1381 return (i);
1382 }
1383
1384 /*
1385 * Update the addresses for the bridge interface.
1386 */
1387 int
bridge_update_addrs(struct bridge_if * bif)1388 bridge_update_addrs(struct bridge_if *bif)
1389 {
1390 int added, updated;
1391 uint32_t i;
1392 int32_t buf_len;
1393 struct tp_entry *te, *te_next;
1394 struct ifbareq *addr_req_buf, *addr_req;
1395
1396 if ((buf_len = bridge_addrs_getinfo_ifalist(bif, &addr_req_buf)) < 0)
1397 return (-1);
1398
1399 added = updated = 0;
1400
1401 #define BA_FOUND 0x01
1402 for (i = 0; i < buf_len / sizeof(struct ifbareq); i++) {
1403 addr_req = addr_req_buf + i;
1404
1405 if ((te = bridge_addrs_find(addr_req->ifba_dst, bif)) == NULL) {
1406 added++;
1407
1408 if ((te = bridge_new_addrs(addr_req->ifba_dst, bif))
1409 == NULL)
1410 continue;
1411 } else
1412 updated++;
1413
1414 bridge_addrs_info_ifaddrlist(addr_req, te);
1415 te-> flags |= BA_FOUND;
1416 }
1417 free(addr_req_buf);
1418
1419 for (te = bridge_addrs_bif_first(bif); te != NULL; te = te_next) {
1420 te_next = bridge_addrs_bif_next(te);
1421
1422 if ((te-> flags & BA_FOUND) == 0)
1423 bridge_addrs_remove(te, bif);
1424 else
1425 te-> flags &= ~BA_FOUND;
1426 }
1427 #undef BA_FOUND
1428
1429 bif->addrs_age = time(NULL);
1430 return (updated + added);
1431 }
1432
1433 /************************************************************************
1434 * Bridge packet filtering.
1435 */
1436 const char bridge_sysctl[] = "net.link.bridge.";
1437
1438 static struct {
1439 int32_t val;
1440 const char *name;
1441 } bridge_pf_sysctl[] = {
1442 { 1, "pfil_bridge" },
1443 { 1, "pfil_member" },
1444 { 1, "pfil_onlyip" },
1445 { 0, "ipfw" },
1446 };
1447
1448 int32_t
bridge_get_pfval(uint8_t which)1449 bridge_get_pfval(uint8_t which)
1450 {
1451
1452 if (which > nitems(bridge_pf_sysctl) || which < 1)
1453 return (-1);
1454
1455 return (bridge_pf_sysctl[which - 1].val);
1456 }
1457
1458 int32_t
bridge_do_pfctl(int32_t bridge_ctl,enum snmp_op op,int32_t * val)1459 bridge_do_pfctl(int32_t bridge_ctl, enum snmp_op op, int32_t *val)
1460 {
1461 char *mib_oid;
1462 size_t len, s_len;
1463 int32_t i, s_i;
1464
1465 if (bridge_ctl >= LEAF_begemotBridgeLayer2PfStatus)
1466 return (-2);
1467
1468 if (op == SNMP_OP_SET) {
1469 s_i = *val;
1470 s_len = sizeof(s_i);
1471 } else
1472 s_len = 0;
1473
1474 len = sizeof(i);
1475
1476 asprintf(&mib_oid, "%s%s", bridge_sysctl,
1477 bridge_pf_sysctl[bridge_ctl].name);
1478 if (mib_oid == NULL)
1479 return (-1);
1480
1481 if (sysctlbyname(mib_oid, &i, &len, (op == SNMP_OP_SET ? &s_i : NULL),
1482 s_len) == -1) {
1483 syslog(LOG_ERR, "sysctl(%s) failed - %s", mib_oid,
1484 strerror(errno));
1485 free(mib_oid);
1486 return (-1);
1487 }
1488
1489 bridge_pf_sysctl[bridge_ctl].val = i;
1490 *val = i;
1491
1492 free(mib_oid);
1493
1494 return (i);
1495 }
1496
1497 void
bridge_pf_dump(void)1498 bridge_pf_dump(void)
1499 {
1500 uint8_t i;
1501
1502 for (i = 0; i < nitems(bridge_pf_sysctl); i++) {
1503 syslog(LOG_ERR, "%s%s = %d", bridge_sysctl,
1504 bridge_pf_sysctl[i].name, bridge_pf_sysctl[i].val);
1505 }
1506 }
1507