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