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: stable/11/usr.sbin/bsnmpd/modules/snmp_bridge/bridge_sys.c 330449 2018-03-05 07:26:05Z eadler $ 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#include "bridge_tree.h" 62#include "bridge_snmp.h" 63 64int sock = -1; 65 66int 67bridge_ioctl_init(void) 68{ 69 if ((sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { 70 syslog(LOG_ERR, "cannot open socket : %s", strerror(errno)); 71 return (-1); 72 } 73 74 return (0); 75} 76 77/* 78 * Load the if_bridge.ko module in kernel if not already there. 79 */ 80int 81bridge_kmod_load(void) 82{ 83 int fileid, modid; 84 const char mod_name[] = "if_bridge"; 85 struct module_stat mstat; 86 87 /* Scan files in kernel. */ 88 mstat.version = sizeof(struct module_stat); 89 for (fileid = kldnext(0); fileid > 0; fileid = kldnext(fileid)) { 90 /* Scan modules in file. */ 91 for (modid = kldfirstmod(fileid); modid > 0; 92 modid = modfnext(modid)) { 93 94 if (modstat(modid, &mstat) < 0) 95 continue; 96 97 if (strcmp(mod_name, mstat.name) == 0) 98 return (0); 99 } 100 } 101 102 /* Not present - load it. */ 103 if (kldload(mod_name) < 0) { 104 syslog(LOG_ERR, "failed to load %s kernel module", mod_name); 105 return (-1); 106 } 107 108 return (1); 109} 110 111/************************************************************************ 112 * Bridge interfaces. 113 */ 114 115/* 116 * Convert the kernel uint64_t value for a bridge id 117 */ 118static void 119snmp_uint64_to_bridgeid(uint64_t id, bridge_id b_id) 120{ 121 int i; 122 u_char *o; 123 124 o = (u_char *) &id; 125 126 for (i = 0; i < SNMP_BRIDGE_ID_LEN; i++, o++) 127 b_id[SNMP_BRIDGE_ID_LEN - i - 1] = *o; 128} 129 130/* 131 * Fetch the bridge configuration parameters from the kernel excluding 132 * it's base MAC address. 133 */ 134static int 135bridge_get_conf_param(struct bridge_if *bif) 136{ 137 struct ifdrv ifd; 138 struct ifbrparam b_param; 139 140 strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ); 141 ifd.ifd_len = sizeof(b_param); 142 ifd.ifd_data = &b_param; 143 144 /* Bridge priority. */ 145 ifd.ifd_cmd = BRDGGPRI; 146 if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) { 147 syslog(LOG_ERR, "update bridge: ioctl(BRDGGPRI) failed: %s", 148 strerror(errno)); 149 return (-1); 150 } 151 152 bif->priority = b_param.ifbrp_prio; 153 154 /* Configured max age. */ 155 ifd.ifd_cmd = BRDGGMA; 156 if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) { 157 syslog(LOG_ERR, "update bridge: ioctl(BRDGGMA) failed: %s", 158 strerror(errno)); 159 return (-1); 160 } 161 162 /* Centi-seconds. */ 163 bif->bridge_max_age = 100 * b_param.ifbrp_maxage; 164 165 /* Configured hello time. */ 166 ifd.ifd_cmd = BRDGGHT; 167 if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) { 168 syslog(LOG_ERR, "update bridge: ioctl(BRDGGHT) failed: %s", 169 strerror(errno)); 170 return (-1); 171 } 172 bif->bridge_hello_time = 100 * b_param.ifbrp_hellotime; 173 174 /* Forward delay. */ 175 ifd.ifd_cmd = BRDGGFD; 176 if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) { 177 syslog(LOG_ERR, "update bridge: ioctl(BRDGGFD) failed: %s", 178 strerror(errno)); 179 return (-1); 180 } 181 bif->bridge_fwd_delay = 100 * b_param.ifbrp_fwddelay; 182 183 /* Number of dropped addresses. */ 184 ifd.ifd_cmd = BRDGGRTE; 185 if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) { 186 syslog(LOG_ERR, "update bridge: ioctl(BRDGGRTE) failed: %s", 187 strerror(errno)); 188 return (-1); 189 } 190 bif->lrnt_drops = b_param.ifbrp_cexceeded; 191 192 /* Address table timeout. */ 193 ifd.ifd_cmd = BRDGGTO; 194 if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) { 195 syslog(LOG_ERR, "update bridge: ioctl(BRDGGTO) failed: %s", 196 strerror(errno)); 197 return (-1); 198 } 199 bif->age_time = b_param.ifbrp_ctime; 200 201 /* Address table size. */ 202 ifd.ifd_cmd = BRDGGCACHE; 203 if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) { 204 syslog(LOG_ERR, "update bridge: ioctl(BRDGGCACHE) " 205 "failed: %s", strerror(errno)); 206 return (-1); 207 } 208 bif->max_addrs = b_param.ifbrp_csize; 209 210 return (0); 211} 212 213/* 214 * Fetch the current bridge STP operational parameters. 215 * Returns: -1 - on error; 216 * 0 - old TC time and Root Port values are same; 217 * 1 - topologyChange notification should be sent; 218 * 2 - newRoot notification should be sent. 219 */ 220int 221bridge_get_op_param(struct bridge_if *bif) 222{ 223 int new_root_send; 224 struct ifdrv ifd; 225 struct ifbropreq b_req; 226 227 strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ); 228 ifd.ifd_len = sizeof(b_req); 229 ifd.ifd_data = &b_req; 230 ifd.ifd_cmd = BRDGPARAM; 231 232 if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) { 233 syslog(LOG_ERR, "update bridge: ioctl(BRDGPARAM) failed: %s", 234 strerror(errno)); 235 return (-1); 236 } 237 238 bif->max_age = 100 * b_req.ifbop_maxage; 239 bif->hello_time = 100 * b_req.ifbop_hellotime; 240 bif->fwd_delay = 100 * b_req.ifbop_fwddelay; 241 bif->stp_version = b_req.ifbop_protocol; 242 bif->tx_hold_count = b_req.ifbop_holdcount; 243 244 if (b_req.ifbop_root_port == 0 && 245 bif->root_port != b_req.ifbop_root_port) 246 new_root_send = 2; 247 else 248 new_root_send = 0; 249 250 bif->root_port = b_req.ifbop_root_port; 251 bif->root_cost = b_req.ifbop_root_path_cost; 252 snmp_uint64_to_bridgeid(b_req.ifbop_designated_root, 253 bif->design_root); 254 255 if (bif->last_tc_time.tv_sec != b_req.ifbop_last_tc_time.tv_sec) { 256 bif->top_changes++; 257 bif->last_tc_time.tv_sec = b_req.ifbop_last_tc_time.tv_sec; 258 bif->last_tc_time.tv_usec = b_req.ifbop_last_tc_time.tv_usec; 259 260 /* 261 * "The trap is not sent if a (begemotBridge)NewRoot 262 * trap is sent for the same transition." 263 */ 264 if (new_root_send == 0) 265 return (1); 266 } 267 268 return (new_root_send); 269} 270 271int 272bridge_getinfo_bif(struct bridge_if *bif) 273{ 274 if (bridge_get_conf_param(bif) < 0) 275 return (-1); 276 277 return (bridge_get_op_param(bif)); 278} 279 280int 281bridge_set_priority(struct bridge_if *bif, int32_t priority) 282{ 283 struct ifdrv ifd; 284 struct ifbrparam b_param; 285 286 strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ); 287 ifd.ifd_len = sizeof(b_param); 288 ifd.ifd_data = &b_param; 289 b_param.ifbrp_prio = (uint32_t) priority; 290 ifd.ifd_cmd = BRDGSPRI; 291 292 if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) { 293 syslog(LOG_ERR, "set bridge param: ioctl(BRDGSPRI) " 294 "failed: %s", strerror(errno)); 295 return (-1); 296 } 297 298 /* 299 * Re-fetching the data from the driver after that might be a good 300 * idea, since changing our bridge's priority should invoke 301 * recalculation of the active spanning tree topology in the network. 302 */ 303 bif->priority = priority; 304 return (0); 305} 306 307/* 308 * Convert 1/100 of seconds to 1/256 of seconds. 309 * Timeout ::= TEXTUAL-CONVENTION. 310 * To convert a Timeout value into a value in units of 311 * 1/256 seconds, the following algorithm should be used: 312 * b = floor( (n * 256) / 100) 313 * The conversion to 1/256 of a second happens in the kernel - 314 * just make sure we correctly convert the seconds to Timout 315 * and vice versa. 316 */ 317static uint32_t 318snmp_timeout2_sec(int32_t secs) 319{ 320 return (secs / 100); 321} 322 323int 324bridge_set_maxage(struct bridge_if *bif, int32_t max_age) 325{ 326 struct ifdrv ifd; 327 struct ifbrparam b_param; 328 329 strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ); 330 ifd.ifd_len = sizeof(b_param); 331 ifd.ifd_data = &b_param; 332 b_param.ifbrp_maxage = snmp_timeout2_sec(max_age); 333 ifd.ifd_cmd = BRDGSMA; 334 335 if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) { 336 syslog(LOG_ERR, "set bridge param: ioctl(BRDGSMA) " 337 "failed: %s", strerror(errno)); 338 return (-1); 339 } 340 341 bif->bridge_max_age = max_age; 342 return (0); 343} 344 345int 346bridge_set_hello_time(struct bridge_if *bif, int32_t hello_time) 347{ 348 struct ifdrv ifd; 349 struct ifbrparam b_param; 350 351 strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ); 352 ifd.ifd_len = sizeof(b_param); 353 ifd.ifd_data = &b_param; 354 b_param.ifbrp_hellotime = snmp_timeout2_sec(hello_time); 355 ifd.ifd_cmd = BRDGSHT; 356 357 if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) { 358 syslog(LOG_ERR, "set bridge param: ioctl(BRDGSHT) " 359 "failed: %s", strerror(errno)); 360 return (-1); 361 } 362 363 bif->bridge_hello_time = b_param.ifbrp_hellotime; 364 return (0); 365} 366 367int 368bridge_set_forward_delay(struct bridge_if *bif, int32_t fwd_delay) 369{ 370 struct ifdrv ifd; 371 struct ifbrparam b_param; 372 373 strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ); 374 ifd.ifd_len = sizeof(b_param); 375 ifd.ifd_data = &b_param; 376 b_param.ifbrp_fwddelay = snmp_timeout2_sec(fwd_delay); 377 ifd.ifd_cmd = BRDGSFD; 378 379 if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) { 380 syslog(LOG_ERR, "set bridge param: ioctl(BRDGSFD) " 381 "failed: %s", strerror(errno)); 382 return (-1); 383 } 384 385 bif->bridge_fwd_delay = b_param.ifbrp_fwddelay; 386 return (0); 387} 388 389int 390bridge_set_aging_time(struct bridge_if *bif, int32_t age_time) 391{ 392 struct ifdrv ifd; 393 struct ifbrparam b_param; 394 395 strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ); 396 ifd.ifd_len = sizeof(b_param); 397 ifd.ifd_data = &b_param; 398 b_param.ifbrp_ctime = (uint32_t) age_time; 399 ifd.ifd_cmd = BRDGSTO; 400 401 if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) { 402 syslog(LOG_ERR, "set bridge param: ioctl(BRDGSTO) " 403 "failed: %s", strerror(errno)); 404 return (-1); 405 } 406 407 bif->age_time = age_time; 408 return (0); 409} 410 411int 412bridge_set_max_cache(struct bridge_if *bif, int32_t max_cache) 413{ 414 struct ifdrv ifd; 415 struct ifbrparam b_param; 416 417 strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ); 418 ifd.ifd_len = sizeof(b_param); 419 ifd.ifd_data = &b_param; 420 b_param.ifbrp_csize = max_cache; 421 ifd.ifd_cmd = BRDGSCACHE; 422 423 if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) { 424 syslog(LOG_ERR, "set bridge param: ioctl(BRDGSCACHE) " 425 "failed: %s", strerror(errno)); 426 return (-1); 427 } 428 429 bif->max_addrs = b_param.ifbrp_csize; 430 return (0); 431} 432 433int 434bridge_set_tx_hold_count(struct bridge_if *bif, int32_t tx_hc) 435{ 436 struct ifdrv ifd; 437 struct ifbrparam b_param; 438 439 if (tx_hc < SNMP_BRIDGE_MIN_TXHC || tx_hc > SNMP_BRIDGE_MAX_TXHC) 440 return (-1); 441 442 strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ); 443 ifd.ifd_len = sizeof(b_param); 444 ifd.ifd_data = &b_param; 445 b_param.ifbrp_txhc = tx_hc; 446 ifd.ifd_cmd = BRDGSTXHC; 447 448 if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) { 449 syslog(LOG_ERR, "set bridge param: ioctl(BRDGSTXHC) " 450 "failed: %s", strerror(errno)); 451 return (-1); 452 } 453 454 bif->tx_hold_count = b_param.ifbrp_txhc; 455 return (0); 456} 457 458int 459bridge_set_stp_version(struct bridge_if *bif, int32_t stp_proto) 460{ 461 struct ifdrv ifd; 462 struct ifbrparam b_param; 463 464 strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ); 465 ifd.ifd_len = sizeof(b_param); 466 ifd.ifd_data = &b_param; 467 b_param.ifbrp_proto = stp_proto; 468 ifd.ifd_cmd = BRDGSPROTO; 469 470 if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) { 471 syslog(LOG_ERR, "set bridge param: ioctl(BRDGSPROTO) " 472 "failed: %s", strerror(errno)); 473 return (-1); 474 } 475 476 bif->stp_version = b_param.ifbrp_proto; 477 return (0); 478} 479 480/* 481 * Set the bridge interface status to up/down. 482 */ 483int 484bridge_set_if_up(const char* b_name, int8_t up) 485{ 486 int flags; 487 struct ifreq ifr; 488 489 bzero(&ifr, sizeof(ifr)); 490 strlcpy(ifr.ifr_name, b_name, sizeof(ifr.ifr_name)); 491 if (ioctl(sock, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) { 492 syslog(LOG_ERR, "set bridge up: ioctl(SIOCGIFFLAGS) " 493 "failed: %s", strerror(errno)); 494 return (-1); 495 } 496 497 flags = (ifr.ifr_flags & 0xffff) | (ifr.ifr_flagshigh << 16); 498 if (up == 1) 499 flags |= IFF_UP; 500 else 501 flags &= ~IFF_UP; 502 503 ifr.ifr_flags = flags & 0xffff; 504 ifr.ifr_flagshigh = flags >> 16; 505 if (ioctl(sock, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) { 506 syslog(LOG_ERR, "set bridge up: ioctl(SIOCSIFFLAGS) " 507 "failed: %s", strerror(errno)); 508 return (-1); 509 } 510 511 return (0); 512} 513 514int 515bridge_create(const char *b_name) 516{ 517 char *new_name; 518 struct ifreq ifr; 519 520 bzero(&ifr, sizeof(ifr)); 521 strlcpy(ifr.ifr_name, b_name, sizeof(ifr.ifr_name)); 522 523 if (ioctl(sock, SIOCIFCREATE, &ifr) < 0) { 524 syslog(LOG_ERR, "create bridge: ioctl(SIOCIFCREATE) " 525 "failed: %s", strerror(errno)); 526 return (-1); 527 } 528 529 if (strcmp(b_name, ifr.ifr_name) == 0) 530 return (0); 531 532 if ((new_name = strdup(b_name)) == NULL) { 533 syslog(LOG_ERR, "create bridge: strdup() failed"); 534 return (-1); 535 } 536 537 ifr.ifr_data = new_name; 538 if (ioctl(sock, SIOCSIFNAME, (caddr_t) &ifr) < 0) { 539 syslog(LOG_ERR, "create bridge: ioctl(SIOCSIFNAME) " 540 "failed: %s", strerror(errno)); 541 free(new_name); 542 return (-1); 543 } 544 545 return (0); 546} 547 548int 549bridge_destroy(const char *b_name) 550{ 551 struct ifreq ifr; 552 553 bzero(&ifr, sizeof(ifr)); 554 strlcpy(ifr.ifr_name, b_name, sizeof(ifr.ifr_name)); 555 556 if (ioctl(sock, SIOCIFDESTROY, &ifr) < 0) { 557 syslog(LOG_ERR, "destroy bridge: ioctl(SIOCIFDESTROY) " 558 "failed: %s", strerror(errno)); 559 return (-1); 560 } 561 562 return (0); 563} 564 565/* 566 * Fetch the bridge base MAC address. Return pointer to the 567 * buffer containing the MAC address, NULL on failure. 568 */ 569u_char * 570bridge_get_basemac(const char *bif_name, u_char *mac, size_t mlen) 571{ 572 int len; 573 char if_name[IFNAMSIZ]; 574 struct ifaddrs *ifap, *ifa; 575 struct sockaddr_dl sdl; 576 577 if (getifaddrs(&ifap) != 0) { 578 syslog(LOG_ERR, "bridge get mac: getifaddrs() failed - %s", 579 strerror(errno)); 580 return (NULL); 581 } 582 583 for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) { 584 if (ifa->ifa_addr->sa_family != AF_LINK) 585 continue; 586 587 /* 588 * Not just casting because of alignment constraints 589 * on sparc64. 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 */ 621static int 622state2snmp_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 */ 644static void 645bridge_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 */ 712static void 713bridge_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 */ 727static void 728bridge_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 */ 744int 745bridge_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 */ 772int 773bridge_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 */ 814int 815bridge_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 */ 847int 848bridge_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 */ 898int 899bridge_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 */ 942int 943bridge_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 */ 988int 989bridge_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 */ 1021int 1022bridge_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 */ 1055static int32_t 1056bridge_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 */ 1104static int32_t 1105bridge_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 */ 1153static struct ifbpstpreq * 1154bridge_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 */ 1174int 1175bridge_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 */ 1223int 1224bridge_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 */ 1300static void 1301bridge_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 */ 1315static int32_t 1316bridge_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 */ 1365int 1366bridge_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 */ 1390int 1391bridge_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 */ 1439const char bridge_sysctl[] = "net.link.bridge."; 1440 1441static 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 1451int32_t 1452bridge_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 1461int32_t 1462bridge_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 1500void 1501bridge_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} 1510