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