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