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