]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/bsnmpd/modules/snmp_bridge/bridge_sys.c
MFV r356163,r356197:
[FreeBSD/FreeBSD.git] / usr.sbin / bsnmpd / modules / snmp_bridge / bridge_sys.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
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  * $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
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
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
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
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
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
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
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
319 snmp_timeout2_sec(int32_t secs)
320 {
321         return (secs / 100);
322 }
323
324 int
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
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
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
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
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
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
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
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
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
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 *
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                  * on sparc64.
591                  */
592                 bcopy(ifa->ifa_addr, &sdl, sizeof(struct sockaddr_dl));
593
594                 if (sdl.sdl_alen > mlen)
595                         continue;
596
597                 if ((len = sdl.sdl_nlen) >= IFNAMSIZ)
598                         len = IFNAMSIZ - 1;
599
600                 bcopy(sdl.sdl_data, if_name, len);
601                 if_name[len] = '\0';
602
603                 if (strcmp(bif_name, if_name) == 0) {
604                         bcopy(sdl.sdl_data + sdl.sdl_nlen, mac, sdl.sdl_alen);
605                         freeifaddrs(ifap);
606                         return (mac);
607                 }
608         }
609
610         freeifaddrs(ifap);
611         return (NULL);
612 }
613
614 /************************************************************************
615  * Bridge ports.
616  */
617
618 /*
619  * Convert the kernel STP port state into
620  * the corresopnding enumerated type from SNMP Bridge MIB.
621  */
622 static int
623 state2snmp_st(uint8_t ifbr_state)
624 {
625         switch (ifbr_state) {
626                 case BSTP_IFSTATE_DISABLED:
627                         return (StpPortState_disabled);
628                 case BSTP_IFSTATE_LISTENING:
629                         return (StpPortState_listening);
630                 case BSTP_IFSTATE_LEARNING:
631                         return (StpPortState_learning);
632                 case BSTP_IFSTATE_FORWARDING:
633                         return (StpPortState_forwarding);
634                 case BSTP_IFSTATE_BLOCKING:
635                 case BSTP_IFSTATE_DISCARDING:
636                         return (StpPortState_blocking);
637         }
638
639         return (StpPortState_broken);
640 }
641
642 /*
643  * Fill in a bridge member information according to data polled from kernel.
644  */
645 static void
646 bridge_port_getinfo_conf(struct ifbreq *k_info, struct bridge_port *bp)
647 {
648         bp->state = state2snmp_st(k_info->ifbr_state);
649         bp->priority = k_info->ifbr_priority;
650
651         /*
652          * RFC 4188:
653          * "New implementations should support dot1dStpPortPathCost32.
654          * If the port path costs exceeds the maximum value of this
655          * object then this object should report the maximum value,
656          * namely 65535.  Applications should try to read the
657          * dot1dStpPortPathCost32 object if this object reports
658          * the maximum value."
659          */
660
661         if (k_info->ifbr_ifsflags & IFBIF_BSTP_ADMCOST)
662                 bp->admin_path_cost = k_info->ifbr_path_cost;
663         else
664                 bp->admin_path_cost = 0;
665
666         bp->path_cost = k_info->ifbr_path_cost;
667
668         if (k_info->ifbr_ifsflags & IFBIF_STP)
669                 bp->enable = dot1dStpPortEnable_enabled;
670         else
671                 bp->enable = dot1dStpPortEnable_disabled;
672
673         /* Begemot Bridge MIB only. */
674         if (k_info->ifbr_ifsflags & IFBIF_SPAN)
675                 bp->span_enable = begemotBridgeBaseSpanEnabled_enabled;
676         else
677                 bp->span_enable = begemotBridgeBaseSpanEnabled_disabled;
678
679         if (k_info->ifbr_ifsflags & IFBIF_PRIVATE)
680                 bp->priv_set = TruthValue_true;
681         else
682                 bp->priv_set = TruthValue_false;
683
684         if (k_info->ifbr_ifsflags & IFBIF_BSTP_ADMEDGE)
685                 bp->admin_edge = TruthValue_true;
686         else
687                 bp->admin_edge = TruthValue_false;
688
689         if (k_info->ifbr_ifsflags & IFBIF_BSTP_EDGE)
690                 bp->oper_edge = TruthValue_true;
691         else
692                 bp->oper_edge = TruthValue_false;
693
694         if (k_info->ifbr_ifsflags & IFBIF_BSTP_AUTOPTP) {
695                 bp->admin_ptp = StpPortAdminPointToPointType_auto;
696                 if (k_info->ifbr_ifsflags & IFBIF_BSTP_PTP)
697                         bp->oper_ptp = TruthValue_true;
698                 else
699                         bp->oper_ptp = TruthValue_false;
700         } else if (k_info->ifbr_ifsflags & IFBIF_BSTP_PTP) {
701                 bp->admin_ptp = StpPortAdminPointToPointType_forceTrue;
702                 bp->oper_ptp = TruthValue_true;
703         } else {
704                 bp->admin_ptp = StpPortAdminPointToPointType_forceFalse;
705                 bp->oper_ptp = TruthValue_false;
706         }
707 }
708
709 /*
710  * Fill in a bridge interface STP information according to
711  * data polled from kernel.
712  */
713 static void
714 bridge_port_getinfo_opstp(struct ifbpstpreq *bp_stp, struct bridge_port *bp)
715 {
716         bp->enable = dot1dStpPortEnable_enabled;
717         bp->fwd_trans = bp_stp->ifbp_fwd_trans;
718         bp->design_cost = bp_stp->ifbp_design_cost;
719         snmp_uint64_to_bridgeid(bp_stp->ifbp_design_root, bp->design_root);
720         snmp_uint64_to_bridgeid(bp_stp->ifbp_design_bridge, bp->design_bridge);
721         bcopy(&(bp_stp->ifbp_design_port), &(bp->design_port),
722             sizeof(uint16_t));
723 }
724
725 /*
726  * Clear a bridge interface STP information.
727  */
728 static void
729 bridge_port_clearinfo_opstp(struct bridge_port *bp)
730 {
731         if (bp->enable == dot1dStpPortEnable_enabled) {
732                 bp->design_cost = 0;
733                 bzero(&(bp->design_root), sizeof(bridge_id));
734                 bzero(&(bp->design_bridge), sizeof(bridge_id));
735                 bzero(&(bp->design_port), sizeof(port_id));
736                 bp->fwd_trans = 0;
737         }
738
739         bp->enable = dot1dStpPortEnable_disabled;
740 }
741
742 /*
743  * Set a bridge member priority.
744  */
745 int
746 bridge_port_set_priority(const char *bif_name, struct bridge_port *bp,
747         int32_t priority)
748 {
749         struct ifdrv ifd;
750         struct ifbreq b_req;
751
752         strlcpy(ifd.ifd_name, bif_name, sizeof(ifd.ifd_name));
753         ifd.ifd_len = sizeof(b_req);
754         ifd.ifd_data = &b_req;
755         strlcpy(b_req.ifbr_ifsname, bp->p_name, sizeof(b_req.ifbr_ifsname));
756
757         b_req.ifbr_priority = (uint8_t) priority;
758         ifd.ifd_cmd = BRDGSIFPRIO;
759
760         if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
761                 syslog(LOG_ERR, "set member %s param: ioctl(BRDGSIFPRIO) "
762                     "failed: %s", bp->p_name, strerror(errno));
763                 return (-1);
764         }
765
766         bp->priority = priority;
767         return (0);
768 }
769
770 /*
771  * Set a bridge member STP-enabled flag.
772  */
773 int
774 bridge_port_set_stp_enable(const char *bif_name, struct bridge_port *bp,
775         uint32_t enable)
776 {
777         struct ifdrv ifd;
778         struct ifbreq b_req;
779
780         if (bp->enable == enable)
781                 return (0);
782
783         bzero(&b_req, sizeof(b_req));
784         strlcpy(ifd.ifd_name, bif_name, sizeof(ifd.ifd_name));
785         ifd.ifd_len = sizeof(b_req);
786         ifd.ifd_data = &b_req;
787         strlcpy(b_req.ifbr_ifsname, bp->p_name, sizeof(b_req.ifbr_ifsname));
788         ifd.ifd_cmd = BRDGGIFFLGS;
789
790         if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
791                 syslog(LOG_ERR, "get member %s param: ioctl(BRDGGIFFLGS) "
792                     "failed: %s", bp->p_name, strerror(errno));
793                 return (-1);
794         }
795
796         if (enable == dot1dStpPortEnable_enabled)
797                 b_req.ifbr_ifsflags |= IFBIF_STP;
798         else
799                 b_req.ifbr_ifsflags &= ~IFBIF_STP;
800
801         ifd.ifd_cmd = BRDGSIFFLGS;
802         if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
803                 syslog(LOG_ERR, "set member %s param: ioctl(BRDGSIFFLGS) "
804                     "failed: %s", bp->p_name, strerror(errno));
805                 return (-1);
806         }
807
808         bp->enable = enable;
809         return (0);
810 }
811
812 /*
813  * Set a bridge member STP path cost.
814  */
815 int
816 bridge_port_set_path_cost(const char *bif_name, struct bridge_port *bp,
817         int32_t path_cost)
818 {
819         struct ifdrv ifd;
820         struct ifbreq b_req;
821
822         if (path_cost < SNMP_PORT_MIN_PATHCOST ||
823             path_cost > SNMP_PORT_PATHCOST_OBSOLETE)
824                 return (-2);
825
826         strlcpy(ifd.ifd_name, bif_name, sizeof(ifd.ifd_name));
827         ifd.ifd_len = sizeof(b_req);
828         ifd.ifd_data = &b_req;
829         strlcpy(b_req.ifbr_ifsname, bp->p_name, sizeof(b_req.ifbr_ifsname));
830
831         b_req.ifbr_path_cost = path_cost;
832         ifd.ifd_cmd = BRDGSIFCOST;
833
834         if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
835                 syslog(LOG_ERR, "set member %s param: ioctl(BRDGSIFCOST) "
836                     "failed: %s", bp->p_name, strerror(errno));
837                 return (-1);
838         }
839
840         bp->admin_path_cost = path_cost;
841
842         return (0);
843 }
844
845 /*
846  * Set the PonitToPoint status of the link administratively.
847  */
848 int
849 bridge_port_set_admin_ptp(const char *bif_name, struct bridge_port *bp,
850     uint32_t admin_ptp)
851 {
852         struct ifdrv ifd;
853         struct ifbreq b_req;
854
855         if (bp->admin_ptp == admin_ptp)
856                 return (0);
857
858         bzero(&b_req, sizeof(b_req));
859         strlcpy(ifd.ifd_name, bif_name, sizeof(ifd.ifd_name));
860         ifd.ifd_len = sizeof(b_req);
861         ifd.ifd_data = &b_req;
862         strlcpy(b_req.ifbr_ifsname, bp->p_name, sizeof(b_req.ifbr_ifsname));
863         ifd.ifd_cmd = BRDGGIFFLGS;
864
865         if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
866                 syslog(LOG_ERR, "get member %s param: ioctl(BRDGGIFFLGS) "
867                     "failed: %s", bp->p_name, strerror(errno));
868                 return (-1);
869         }
870
871         switch (admin_ptp) {
872                 case StpPortAdminPointToPointType_forceTrue:
873                         b_req.ifbr_ifsflags &= ~IFBIF_BSTP_AUTOPTP;
874                         b_req.ifbr_ifsflags |= IFBIF_BSTP_PTP;
875                         break;
876                 case StpPortAdminPointToPointType_forceFalse:
877                         b_req.ifbr_ifsflags &= ~IFBIF_BSTP_AUTOPTP;
878                         b_req.ifbr_ifsflags &= ~IFBIF_BSTP_PTP;
879                         break;
880                 case StpPortAdminPointToPointType_auto:
881                         b_req.ifbr_ifsflags |= IFBIF_BSTP_AUTOPTP;
882                         break;
883         }
884
885         ifd.ifd_cmd = BRDGSIFFLGS;
886         if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
887                 syslog(LOG_ERR, "set member %s param: ioctl(BRDGSIFFLGS) "
888                     "failed: %s", bp->p_name, strerror(errno));
889                 return (-1);
890         }
891
892         bp->admin_ptp = admin_ptp;
893         return (0);
894 }
895
896 /*
897  * Set admin edge.
898  */
899 int
900 bridge_port_set_admin_edge(const char *bif_name, struct bridge_port *bp,
901     uint32_t enable)
902 {
903         struct ifdrv ifd;
904         struct ifbreq b_req;
905
906         if (bp->admin_edge == enable)
907                 return (0);
908
909         bzero(&b_req, sizeof(b_req));
910         strlcpy(ifd.ifd_name, bif_name, sizeof(ifd.ifd_name));
911         ifd.ifd_len = sizeof(b_req);
912         ifd.ifd_data = &b_req;
913         strlcpy(b_req.ifbr_ifsname, bp->p_name, sizeof(b_req.ifbr_ifsname));
914         ifd.ifd_cmd = BRDGGIFFLGS;
915
916         if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
917                 syslog(LOG_ERR, "get member %s param: ioctl(BRDGGIFFLGS) "
918                     "failed: %s", bp->p_name, strerror(errno));
919                 return (-1);
920         }
921
922         if (enable == TruthValue_true) {
923                 b_req.ifbr_ifsflags &= ~IFBIF_BSTP_AUTOEDGE;
924                 b_req.ifbr_ifsflags |= IFBIF_BSTP_EDGE;
925         } else
926                 b_req.ifbr_ifsflags &= ~IFBIF_BSTP_EDGE;
927
928         ifd.ifd_cmd = BRDGSIFFLGS;
929         if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
930                 syslog(LOG_ERR, "set member %s param: ioctl(BRDGSIFFLGS) "
931                     "failed: %s", bp->p_name, strerror(errno));
932                 return (-1);
933         }
934
935         bp->admin_edge = enable;
936
937         return (0);
938 }
939
940 /*
941  * Set 'private' flag.
942  */
943 int
944 bridge_port_set_private(const char *bif_name, struct bridge_port *bp,
945     uint32_t priv_set)
946 {
947         struct ifdrv ifd;
948         struct ifbreq b_req;
949
950         if (bp->priv_set == priv_set)
951                 return (0);
952
953         bzero(&b_req, sizeof(b_req));
954         strlcpy(ifd.ifd_name, bif_name, sizeof(ifd.ifd_name));
955         ifd.ifd_len = sizeof(b_req);
956         ifd.ifd_data = &b_req;
957         strlcpy(b_req.ifbr_ifsname, bp->p_name, sizeof(b_req.ifbr_ifsname));
958         ifd.ifd_cmd = BRDGGIFFLGS;
959
960         if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
961                 syslog(LOG_ERR, "get member %s param: ioctl(BRDGGIFFLGS) "
962                     "failed: %s", bp->p_name, strerror(errno));
963                 return (-1);
964         }
965
966         if (priv_set == TruthValue_true)
967                 b_req.ifbr_ifsflags |= IFBIF_PRIVATE;
968         else if (priv_set == TruthValue_false)
969                 b_req.ifbr_ifsflags &= ~IFBIF_PRIVATE;
970         else
971                 return (SNMP_ERR_WRONG_VALUE);
972
973         ifd.ifd_cmd = BRDGSIFFLGS;
974         if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
975                 syslog(LOG_ERR, "set member %s param: ioctl(BRDGSIFFLGS) "
976                     "failed: %s", bp->p_name, strerror(errno));
977                 return (-1);
978         }
979
980         bp->priv_set = priv_set;
981
982         return (0);
983 }
984
985
986 /*
987  * Add a bridge member port.
988  */
989 int
990 bridge_port_addm(struct bridge_port *bp, const char *b_name)
991 {
992         struct ifdrv ifd;
993         struct ifbreq b_req;
994
995         bzero(&ifd, sizeof(ifd));
996         bzero(&b_req, sizeof(b_req));
997
998         strlcpy(ifd.ifd_name, b_name, sizeof(ifd.ifd_name));
999         ifd.ifd_len = sizeof(b_req);
1000         ifd.ifd_data = &b_req;
1001         strlcpy(b_req.ifbr_ifsname, bp->p_name, sizeof(b_req.ifbr_ifsname));
1002
1003         if (bp->span_enable == begemotBridgeBaseSpanEnabled_enabled)
1004                 ifd.ifd_cmd = BRDGADDS;
1005         else
1006                 ifd.ifd_cmd = BRDGADD;
1007
1008         if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
1009                 syslog(LOG_ERR, "%s - add member : ioctl(%s) failed: %s",
1010                     bp->p_name,
1011                     (ifd.ifd_cmd == BRDGADDS ? "BRDGADDS" : "BRDGADD"),
1012                     strerror(errno));
1013                 return (-1);
1014         }
1015
1016         return (0);
1017 }
1018
1019 /*
1020  * Delete a bridge member port.
1021  */
1022 int
1023 bridge_port_delm(struct bridge_port *bp, const char *b_name)
1024 {
1025         struct ifdrv ifd;
1026         struct ifbreq b_req;
1027
1028         bzero(&ifd, sizeof(ifd));
1029         bzero(&b_req, sizeof(b_req));
1030
1031         strlcpy(ifd.ifd_name, b_name, sizeof(ifd.ifd_name));
1032         ifd.ifd_len = sizeof(b_req);
1033         ifd.ifd_data = &b_req;
1034         strlcpy(b_req.ifbr_ifsname, bp->p_name, sizeof(b_req.ifbr_ifsname));
1035
1036         if (bp->span_enable == begemotBridgeBaseSpanEnabled_enabled)
1037                 ifd.ifd_cmd = BRDGDELS;
1038         else
1039                 ifd.ifd_cmd = BRDGDEL;
1040
1041         if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
1042                 syslog(LOG_ERR, "%s - add member : ioctl(%s) failed: %s",
1043                     bp->p_name,
1044                     (ifd.ifd_cmd == BRDGDELS ? "BRDGDELS" : "BRDGDEL"),
1045                     strerror(errno));
1046                 return (-1);
1047         }
1048
1049         return (0);
1050 }
1051
1052 /*
1053  * Fetch the bridge member list from kernel.
1054  * Return -1 on error, or buffer len if successful.
1055  */
1056 static int32_t
1057 bridge_port_get_iflist(struct bridge_if *bif, struct ifbreq **buf)
1058 {
1059         int n = 128;
1060         uint32_t len;
1061         struct ifbreq *ninbuf;
1062         struct ifbifconf ifbc;
1063         struct ifdrv ifd;
1064
1065         *buf = NULL;
1066         strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
1067         ifd.ifd_cmd = BRDGGIFS;
1068         ifd.ifd_len = sizeof(ifbc);
1069         ifd.ifd_data = &ifbc;
1070
1071         for ( ; ; ) {
1072                 len = n * sizeof(struct ifbreq);
1073                 if ((ninbuf = (struct ifbreq *)realloc(*buf, len)) == NULL) {
1074                         syslog(LOG_ERR, "get bridge member list: "
1075                             "realloc failed: %s", strerror(errno));
1076                         free(*buf);
1077                         *buf = NULL;
1078                         return (-1);
1079                 }
1080
1081                 ifbc.ifbic_len = len;
1082                 ifbc.ifbic_req = *buf = ninbuf;
1083
1084                 if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
1085                         syslog(LOG_ERR, "get bridge member list: ioctl "
1086                             "(BRDGGIFS) failed: %s", strerror(errno));
1087                         free(*buf);
1088                         buf = NULL;
1089                         return (-1);
1090                 }
1091
1092                 if ((ifbc.ifbic_len + sizeof(struct ifbreq)) < len)
1093                         break;
1094
1095                 n += 64;
1096         }
1097
1098         return (ifbc.ifbic_len);
1099 }
1100
1101 /*
1102  * Fetch the bridge STP member list from kernel.
1103  * Return -1 on error, or buffer len if successful.
1104  */
1105 static int32_t
1106 bridge_port_get_ifstplist(struct bridge_if *bif, struct ifbpstpreq **buf)
1107 {
1108         int n = 128;
1109         uint32_t len;
1110         struct ifbpstpreq *ninbuf;
1111         struct ifbpstpconf ifbstp;
1112         struct ifdrv ifd;
1113
1114         *buf = NULL;
1115         strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
1116         ifd.ifd_cmd = BRDGGIFSSTP;
1117         ifd.ifd_len = sizeof(ifbstp);
1118         ifd.ifd_data = &ifbstp;
1119
1120         for ( ; ; ) {
1121                 len = n * sizeof(struct ifbpstpreq);
1122                 if ((ninbuf = (struct ifbpstpreq *)
1123                     realloc(*buf, len)) == NULL) {
1124                         syslog(LOG_ERR, "get bridge STP ports list: "
1125                             "realloc failed: %s", strerror(errno));
1126                         free(*buf);
1127                         *buf = NULL;
1128                         return (-1);
1129                 }
1130
1131                 ifbstp.ifbpstp_len = len;
1132                 ifbstp.ifbpstp_req = *buf = ninbuf;
1133
1134                 if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
1135                         syslog(LOG_ERR, "get bridge STP ports list: ioctl "
1136                             "(BRDGGIFSSTP) failed: %s", strerror(errno));
1137                         free(*buf);
1138                         buf = NULL;
1139                         return (-1);
1140                 }
1141
1142                 if ((ifbstp.ifbpstp_len + sizeof(struct ifbpstpreq)) < len)
1143                         break;
1144
1145                 n += 64;
1146         }
1147
1148         return (ifbstp.ifbpstp_len);
1149 }
1150
1151 /*
1152  * Locate a bridge if STP params structure in a buffer.
1153  */
1154 static struct ifbpstpreq *
1155 bridge_port_find_ifstplist(uint8_t port_no, struct ifbpstpreq *buf,
1156     uint32_t buf_len)
1157 {
1158         uint32_t i;
1159         struct ifbpstpreq *bstp;
1160
1161         for (i = 0; i < buf_len / sizeof(struct ifbpstpreq); i++) {
1162                 bstp = buf + i;
1163                 if (bstp->ifbp_portno == port_no)
1164                         return (bstp);
1165         }
1166
1167         return (NULL);
1168 }
1169
1170 /*
1171  * Read the initial info for all members of a bridge interface.
1172  * Returns the number of ports, 0 - if none, otherwise
1173  * -1 if some other error occurred.
1174  */
1175 int
1176 bridge_getinfo_bif_ports(struct bridge_if *bif)
1177 {
1178         uint32_t i;
1179         int32_t buf_len;
1180         struct ifbreq *b_req_buf, *b_req;
1181         struct ifbpstpreq *bs_req_buf, *bs_req;
1182         struct bridge_port *bp;
1183         struct mibif *m_if;
1184
1185         if ((buf_len = bridge_port_get_iflist(bif, &b_req_buf)) < 0)
1186                 return (-1);
1187
1188         for (i = 0; i < buf_len / sizeof(struct ifbreq); i++) {
1189                 b_req = b_req_buf + i;
1190
1191                 if ((m_if = mib_find_if_sys(b_req->ifbr_portno)) != NULL) {
1192                         /* Hopefully we will not fail here. */
1193                         if ((bp = bridge_new_port(m_if, bif)) != NULL) {
1194                                 bp->status = RowStatus_active;
1195                                 bridge_port_getinfo_conf(b_req, bp);
1196                                 bridge_port_getinfo_mibif(m_if, bp);
1197                         }
1198                 } else {
1199                         syslog(LOG_ERR, "bridge member %s not present "
1200                             "in mibII ifTable", b_req->ifbr_ifsname);
1201                 }
1202         }
1203         free(b_req_buf);
1204
1205         if ((buf_len = bridge_port_get_ifstplist(bif, &bs_req_buf)) < 0)
1206                 return (-1);
1207
1208         for (bp = bridge_port_bif_first(bif); bp != NULL;
1209             bp = bridge_port_bif_next(bp)) {
1210                 if ((bs_req = bridge_port_find_ifstplist(bp->port_no,
1211                     bs_req_buf, buf_len)) == NULL)
1212                         bridge_port_clearinfo_opstp(bp);
1213                 else
1214                         bridge_port_getinfo_opstp(bs_req, bp);
1215         }
1216         free(bs_req_buf);
1217
1218         return (i);
1219 }
1220
1221 /*
1222  * Update the information for the bridge interface members.
1223  */
1224 int
1225 bridge_update_memif(struct bridge_if *bif)
1226 {
1227         int added, updated;
1228         uint32_t i;
1229         int32_t buf_len;
1230         struct ifbreq *b_req_buf, *b_req;
1231         struct ifbpstpreq *bs_req_buf, *bs_req;
1232         struct bridge_port *bp, *bp_next;
1233         struct mibif *m_if;
1234
1235         if ((buf_len = bridge_port_get_iflist(bif, &b_req_buf)) < 0)
1236                 return (-1);
1237
1238         added = updated = 0;
1239
1240 #define BP_FOUND        0x01
1241         for (i = 0; i < buf_len / sizeof(struct ifbreq); i++) {
1242                 b_req = b_req_buf + i;
1243
1244                 if ((m_if = mib_find_if_sys(b_req->ifbr_portno)) == NULL) {
1245                         syslog(LOG_ERR, "bridge member %s not present "
1246                             "in mibII ifTable", b_req->ifbr_ifsname);
1247                         continue;
1248                 }
1249
1250                 if ((bp = bridge_port_find(m_if->index, bif)) == NULL &&
1251                     (bp = bridge_new_port(m_if, bif)) != NULL) {
1252                         bp->status = RowStatus_active;
1253                         added++;
1254                 }
1255
1256                 if (bp != NULL) {
1257                         updated++;
1258                         bridge_port_getinfo_conf(b_req, bp);
1259                         bridge_port_getinfo_mibif(m_if, bp);
1260                         bp->flags |= BP_FOUND;
1261                 }
1262         }
1263         free(b_req_buf);
1264
1265         /* Clean up list. */
1266         for (bp = bridge_port_bif_first(bif); bp != NULL; bp = bp_next) {
1267                 bp_next  = bridge_port_bif_next(bp);
1268
1269                 if ((bp->flags & BP_FOUND) == 0 &&
1270                     bp->status == RowStatus_active)
1271                         bridge_port_remove(bp, bif);
1272                 else
1273                         bp->flags |= ~BP_FOUND;
1274         }
1275 #undef  BP_FOUND
1276
1277         if ((buf_len = bridge_port_get_ifstplist(bif, &bs_req_buf)) < 0)
1278                 return (-1);
1279
1280         for (bp = bridge_port_bif_first(bif); bp != NULL;
1281             bp = bridge_port_bif_next(bp)) {
1282                 if ((bs_req = bridge_port_find_ifstplist(bp->port_no,
1283                     bs_req_buf, buf_len)) == NULL)
1284                         bridge_port_clearinfo_opstp(bp);
1285                 else
1286                         bridge_port_getinfo_opstp(bs_req, bp);
1287         }
1288         free(bs_req_buf);
1289         bif->ports_age = time(NULL);
1290
1291         return (updated);
1292 }
1293
1294 /************************************************************************
1295  * Bridge addresses.
1296  */
1297
1298 /*
1299  * Update the bridge address info according to the polled data.
1300  */
1301 static void
1302 bridge_addrs_info_ifaddrlist(struct ifbareq *ifba, struct tp_entry *tpe)
1303 {
1304         tpe->port_no = if_nametoindex(ifba->ifba_ifsname);
1305
1306         if ((ifba->ifba_flags & IFBAF_TYPEMASK) == IFBAF_STATIC)
1307                 tpe->status = TpFdbStatus_mgmt;
1308         else
1309                 tpe->status = TpFdbStatus_learned;
1310 }
1311
1312 /*
1313  * Read the bridge addresses from kernel.
1314  * Return -1 on error, or buffer len if successful.
1315  */
1316 static int32_t
1317 bridge_addrs_getinfo_ifalist(struct bridge_if *bif, struct ifbareq **buf)
1318 {
1319         int n = 128;
1320         uint32_t len;
1321         struct ifbareq *ninbuf;
1322         struct ifbaconf bac;
1323         struct ifdrv ifd;
1324
1325         *buf = NULL;
1326         strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
1327         ifd.ifd_cmd = BRDGRTS;
1328         ifd.ifd_len = sizeof(bac);
1329         ifd.ifd_data = &bac;
1330
1331         for ( ; ; ) {
1332                 len = n * sizeof(struct ifbareq);
1333                 if ((ninbuf = (struct ifbareq *)realloc(*buf, len)) == NULL) {
1334                         syslog(LOG_ERR, "get bridge address list: "
1335                             " realloc failed: %s", strerror(errno));
1336                         free(*buf);
1337                         *buf = NULL;
1338                         return (-1);
1339                 }
1340
1341                 bac.ifbac_len = len;
1342                 bac.ifbac_req = *buf = ninbuf;
1343
1344                 if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
1345                         syslog(LOG_ERR, "get bridge address list: "
1346                             "ioctl(BRDGRTS) failed: %s", strerror(errno));
1347                         free(*buf);
1348                         buf = NULL;
1349                         return (-1);
1350                 }
1351
1352                 if ((bac.ifbac_len + sizeof(struct ifbareq)) < len)
1353                         break;
1354
1355                 n += 64;
1356         }
1357
1358         return (bac.ifbac_len);
1359 }
1360
1361 /*
1362  * Read the initial info for all addresses on a bridge interface.
1363  * Returns the number of addresses, 0 - if none, otherwise
1364  * -1 if some other error occurred.
1365  */
1366 int
1367 bridge_getinfo_bif_addrs(struct bridge_if *bif)
1368 {
1369         uint32_t i;
1370         int32_t buf_len;
1371         struct ifbareq *addr_req_buf, *addr_req;
1372         struct tp_entry *te;
1373
1374         if ((buf_len = bridge_addrs_getinfo_ifalist(bif, &addr_req_buf)) < 0)
1375                 return (-1);
1376
1377         for (i = 0; i < buf_len / sizeof(struct ifbareq); i++) {
1378                 addr_req = addr_req_buf + i;
1379
1380                 if ((te = bridge_new_addrs(addr_req->ifba_dst, bif)) != NULL)
1381                         bridge_addrs_info_ifaddrlist(addr_req, te);
1382         }
1383
1384         free(addr_req_buf);
1385         return (i);
1386 }
1387
1388 /*
1389  * Update the addresses for the bridge interface.
1390  */
1391 int
1392 bridge_update_addrs(struct bridge_if *bif)
1393 {
1394         int added, updated;
1395         uint32_t i;
1396         int32_t buf_len;
1397         struct tp_entry *te, *te_next;
1398         struct ifbareq *addr_req_buf, *addr_req;
1399
1400         if ((buf_len = bridge_addrs_getinfo_ifalist(bif, &addr_req_buf)) < 0)
1401                 return (-1);
1402
1403         added = updated = 0;
1404
1405 #define BA_FOUND        0x01
1406         for (i = 0; i < buf_len / sizeof(struct ifbareq); i++) {
1407                 addr_req = addr_req_buf + i;
1408
1409                 if ((te = bridge_addrs_find(addr_req->ifba_dst, bif)) == NULL) {
1410                         added++;
1411
1412                         if ((te = bridge_new_addrs(addr_req->ifba_dst, bif))
1413                             == NULL)
1414                                 continue;
1415                 } else
1416                         updated++;
1417
1418                 bridge_addrs_info_ifaddrlist(addr_req, te);
1419                 te-> flags |= BA_FOUND;
1420         }
1421         free(addr_req_buf);
1422
1423         for (te = bridge_addrs_bif_first(bif); te != NULL; te = te_next) {
1424                 te_next = bridge_addrs_bif_next(te);
1425
1426                 if ((te-> flags & BA_FOUND) == 0)
1427                         bridge_addrs_remove(te, bif);
1428                 else
1429                         te-> flags &= ~BA_FOUND;
1430         }
1431 #undef  BA_FOUND
1432
1433         bif->addrs_age = time(NULL);
1434         return (updated + added);
1435 }
1436
1437 /************************************************************************
1438  * Bridge packet filtering.
1439  */
1440 const char bridge_sysctl[] = "net.link.bridge.";
1441
1442 static struct {
1443         int32_t val;
1444         const char *name;
1445 } bridge_pf_sysctl[] = {
1446         { 1, "pfil_bridge" },
1447         { 1, "pfil_member" },
1448         { 1, "pfil_onlyip" },
1449         { 0, "ipfw" },
1450 };
1451
1452 int32_t
1453 bridge_get_pfval(uint8_t which)
1454 {
1455
1456         if (which > nitems(bridge_pf_sysctl) || which < 1)
1457                 return (-1);
1458
1459         return (bridge_pf_sysctl[which - 1].val);
1460 }
1461
1462 int32_t
1463 bridge_do_pfctl(int32_t bridge_ctl, enum snmp_op op, int32_t *val)
1464 {
1465         char *mib_oid;
1466         size_t len, s_len;
1467         int32_t i, s_i;
1468
1469         if (bridge_ctl >= LEAF_begemotBridgeLayer2PfStatus)
1470                 return (-2);
1471
1472         if (op == SNMP_OP_SET) {
1473                 s_i = *val;
1474                 s_len = sizeof(s_i);
1475         } else
1476                 s_len = 0;
1477
1478         len = sizeof(i);
1479
1480         asprintf(&mib_oid, "%s%s", bridge_sysctl,
1481             bridge_pf_sysctl[bridge_ctl].name);
1482         if (mib_oid == NULL)
1483                 return (-1);
1484
1485         if (sysctlbyname(mib_oid, &i, &len, (op == SNMP_OP_SET ? &s_i : NULL),
1486             s_len) == -1) {
1487                 syslog(LOG_ERR, "sysctl(%s) failed - %s", mib_oid,
1488                     strerror(errno));
1489                 free(mib_oid);
1490                 return (-1);
1491         }
1492
1493         bridge_pf_sysctl[bridge_ctl].val = i;
1494         *val = i;
1495
1496         free(mib_oid);
1497
1498         return (i);
1499 }
1500
1501 void
1502 bridge_pf_dump(void)
1503 {
1504         uint8_t i;
1505
1506         for (i = 0; i < nitems(bridge_pf_sysctl); i++) {
1507                 syslog(LOG_ERR, "%s%s = %d", bridge_sysctl,
1508                     bridge_pf_sysctl[i].name, bridge_pf_sysctl[i].val);
1509         }
1510 }