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