bridge_sys.c revision 164410
1/*- 2 * Copyright (c) 2006 Shteryana Shopova <syrinx@FreeBSD.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * Bridge MIB implementation for SNMPd. 27 * Bridge OS specific ioctls. 28 * 29 * $FreeBSD: head/usr.sbin/bsnmpd/modules/snmp_bridge/bridge_sys.c 164410 2006-11-19 15:42:48Z syrinx $ 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#if __FreeBSD_version > 700018 40#include <net/bridgestp.h> 41#endif 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 242 if (b_req.ifbop_root_port == 0 && 243 bif->root_port != b_req.ifbop_root_port) 244 new_root_send = 2; 245 else 246 new_root_send = 0; 247 248 bif->root_port = b_req.ifbop_root_port; 249 bif->root_cost = b_req.ifbop_root_path_cost; 250 snmp_uint64_to_bridgeid(b_req.ifbop_designated_root, 251 bif->design_root); 252 253 if (bif->last_tc_time.tv_sec != b_req.ifbop_last_tc_time.tv_sec) { 254 bif->top_changes++; 255 bif->last_tc_time.tv_sec = b_req.ifbop_last_tc_time.tv_sec; 256 bif->last_tc_time.tv_usec = b_req.ifbop_last_tc_time.tv_usec; 257 258 /* 259 * "The trap is not sent if a (begemotBridge)NewRoot 260 * trap is sent for the same transition." 261 */ 262 if (new_root_send == 0) 263 return (1); 264 } 265 266 return (new_root_send); 267} 268 269int 270bridge_getinfo_bif(struct bridge_if *bif) 271{ 272 if (bridge_get_conf_param(bif) < 0) 273 return (-1); 274 275 return (bridge_get_op_param(bif)); 276} 277 278int 279bridge_set_priority(struct bridge_if *bif, int32_t priority) 280{ 281 struct ifdrv ifd; 282 struct ifbrparam b_param; 283 284 /* Sanity check. */ 285 if (priority > SNMP_BRIDGE_MAX_PRIORITY || priority % 4096 != 0) 286 return (-1); 287 288 strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ); 289 ifd.ifd_len = sizeof(b_param); 290 ifd.ifd_data = &b_param; 291 b_param.ifbrp_prio = (uint32_t) priority; 292 ifd.ifd_cmd = BRDGSPRI; 293 294 if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) { 295 syslog(LOG_ERR, "set bridge param: ioctl(BRDGSPRI) " 296 "failed: %s", strerror(errno)); 297 return (-1); 298 } 299 300 /* 301 * Re-fetching the data from the driver after that might be a good 302 * idea, since changing our bridge's priority should invoke 303 * recalculation of the active spanning tree topology in the network. 304 */ 305 bif->priority = priority; 306 return (0); 307} 308 309/* 310 * Convert 1/100 of seconds to 1/256 of seconds. 311 * Timeout ::= TEXTUAL-CONVENTION. 312 * To convert a Timeout value into a value in units of 313 * 1/256 seconds, the following algorithm should be used: 314 * b = floor( (n * 256) / 100) 315 */ 316static uint32_t 317snmp_hundred_secs2_256(int32_t h_secs) 318{ 319 return ((h_secs * 256) / 100); 320} 321 322int 323bridge_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 = (uint32_t) 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 344int 345bridge_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_hundred_secs2_256(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 366int 367bridge_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_hundred_secs2_256(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 388int 389bridge_set_aging_time(struct bridge_if *bif, int32_t age_time) 390{ 391 struct ifdrv ifd; 392 struct ifbrparam b_param; 393 394 /* Sanity check. */ 395 if (age_time < SNMP_BRIDGE_MIN_AGE_TIME || 396 age_time > SNMP_BRIDGE_MAX_AGE_TIME) 397 return (-1); 398 399 strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ); 400 ifd.ifd_len = sizeof(b_param); 401 ifd.ifd_data = &b_param; 402 b_param.ifbrp_ctime = (uint32_t) age_time; 403 ifd.ifd_cmd = BRDGSTO; 404 405 if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) { 406 syslog(LOG_ERR, "set bridge param: ioctl(BRDGSTO) " 407 "failed: %s", strerror(errno)); 408 return (-1); 409 } 410 411 bif->age_time = age_time; 412 return (0); 413} 414 415int 416bridge_set_max_cache(struct bridge_if *bif, int32_t max_cache) 417{ 418 struct ifdrv ifd; 419 struct ifbrparam b_param; 420 421 strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ); 422 ifd.ifd_len = sizeof(b_param); 423 ifd.ifd_data = &b_param; 424 b_param.ifbrp_csize = max_cache; 425 ifd.ifd_cmd = BRDGSCACHE; 426 427 if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) { 428 syslog(LOG_ERR, "set bridge param: ioctl(BRDGSCACHE) " 429 "failed: %s", strerror(errno)); 430 return (-1); 431 } 432 433 bif->max_addrs = b_param.ifbrp_csize; 434 return (0); 435} 436 437/* 438 * Set the bridge interface status to up/down. 439 */ 440int 441bridge_set_if_up(const char* b_name, int8_t up) 442{ 443 int flags; 444 struct ifreq ifr; 445 446 bzero(&ifr, sizeof(ifr)); 447 strcpy(ifr.ifr_name, b_name); 448 if (ioctl(sock, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) { 449 syslog(LOG_ERR, "set bridge up: ioctl(SIOCGIFFLAGS) " 450 "failed: %s", strerror(errno)); 451 return (-1); 452 } 453 454 flags = (ifr.ifr_flags & 0xffff) | (ifr.ifr_flagshigh << 16); 455 if (up == 1) 456 flags |= IFF_UP; 457 else 458 flags &= ~IFF_UP; 459 460 ifr.ifr_flags = flags & 0xffff; 461 ifr.ifr_flagshigh = flags >> 16; 462 if (ioctl(sock, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) { 463 syslog(LOG_ERR, "set bridge up: ioctl(SIOCSIFFLAGS) " 464 "failed: %s", strerror(errno)); 465 return (-1); 466 } 467 468 return (0); 469} 470 471int 472bridge_create(const char *b_name) 473{ 474 char *new_name; 475 struct ifreq ifr; 476 477 bzero(&ifr, sizeof(ifr)); 478 strcpy(ifr.ifr_name, b_name); 479 480 if (ioctl(sock, SIOCIFCREATE, &ifr) < 0) { 481 syslog(LOG_ERR, "create bridge: ioctl(SIOCIFCREATE) " 482 "failed: %s", strerror(errno)); 483 return (-1); 484 } 485 486 if (strcmp(b_name, ifr.ifr_name) == 0) 487 return (0); 488 489 if ((new_name = strdup(b_name)) == NULL) { 490 syslog(LOG_ERR, "create bridge: strdup() failed"); 491 return (-1); 492 } 493 494 ifr.ifr_data = new_name; 495 if (ioctl(sock, SIOCSIFNAME, (caddr_t) &ifr) < 0) { 496 syslog(LOG_ERR, "create bridge: ioctl(SIOCSIFNAME) " 497 "failed: %s", strerror(errno)); 498 free(new_name); 499 return (-1); 500 } 501 502 return (0); 503} 504 505int 506bridge_destroy(const char *b_name) 507{ 508 struct ifreq ifr; 509 510 bzero(&ifr, sizeof(ifr)); 511 strcpy(ifr.ifr_name, b_name); 512 513 if (ioctl(sock, SIOCIFDESTROY, &ifr) < 0) { 514 syslog(LOG_ERR, "destroy bridge: ioctl(SIOCIFDESTROY) " 515 "failed: %s", strerror(errno)); 516 return (-1); 517 } 518 519 return (0); 520} 521 522/* 523 * Fetch the bridge base MAC address. Return pointer to the 524 * buffer containing the mac address, NULL on failure. 525 */ 526u_char * 527bridge_get_basemac(const char *bif_name, u_char *mac) 528{ 529 int len; 530 char if_name[IFNAMSIZ]; 531 struct ifaddrs *ifap, *tmp; 532 struct sockaddr_dl *sdl; 533 534 if (getifaddrs(&ifap) < 0) { 535 syslog(LOG_ERR, "bridge get mac: getifaddrs() failed - %s", 536 strerror(errno)); 537 return (NULL); 538 } 539 540 for (tmp = ifap; tmp != NULL; tmp = tmp->ifa_next) { 541 sdl = (struct sockaddr_dl *) tmp->ifa_addr; 542 543 if ((len = sdl->sdl_nlen) >= IFNAMSIZ) 544 len = IFNAMSIZ - 1; 545 546 bcopy(sdl->sdl_data, if_name, len); 547 if_name[len] = '\0'; 548 549 if (sdl->sdl_family == AF_LINK && !strncmp(bif_name, 550 if_name, strlen(bif_name))) { 551 bcopy(sdl->sdl_data + sdl->sdl_nlen, mac, 552 ETHER_ADDR_LEN); 553 freeifaddrs(ifap); 554 return (mac); 555 } 556 } 557 558 freeifaddrs(ifap); 559 return (NULL); 560} 561 562/************************************************************************ 563 * Bridge ports. 564 */ 565 566/* 567 * Convert the kernel STP port state into 568 * the corresopnding enumerated type from SNMP Bridge MIB. 569 */ 570static int 571state2snmp_st(uint8_t ifbr_state) 572{ 573 switch (ifbr_state) { 574 case BSTP_IFSTATE_DISABLED: 575 return (StpPortState_disabled); 576 case BSTP_IFSTATE_LISTENING: 577 return (StpPortState_listening); 578 case BSTP_IFSTATE_LEARNING: 579 return (StpPortState_learning); 580 case BSTP_IFSTATE_FORWARDING: 581 return (StpPortState_forwarding); 582 case BSTP_IFSTATE_BLOCKING: 583 return (StpPortState_blocking); 584 } 585 586 return (StpPortState_broken); 587} 588 589/* 590 * Fill in a bridge member information according to data polled from kernel. 591 */ 592static void 593bridge_port_getinfo_conf(struct ifbreq *k_info, struct bridge_port *bp) 594{ 595 bp->state = state2snmp_st(k_info->ifbr_state); 596 bp->priority = k_info->ifbr_priority; 597 598 /* 599 * RFC 4188: 600 * "New implementations should support dot1dStpPortPathCost32. 601 * If the port path costs exceeds the maximum value of this 602 * object then this object should report the maximum value, 603 * namely 65535. Applications should try to read the 604 * dot1dStpPortPathCost32 object if this object reports 605 * the maximum value." 606 */ 607 608#if 0 609 /* 610 * Kernel variable is a 32-bit integer but the ioctl supports 611 * only getting/setting a 8-bit value. 612 */ 613 614 if (k_info->ifbr_path_cost > SNMP_PORT_PATHCOST_OBSOLETE) { 615 bp->path_cost = SNMP_PORT_PATHCOST_OBSOLETE; 616 bp->path_cost32 = k_info->ifbr_path_cost; 617 } else 618 619 bp->path_cost = bp->path_cost32 = k_info->ifbr_path_cost; 620#endif 621 622 bp->path_cost = k_info->ifbr_path_cost; 623 624 if (k_info->ifbr_ifsflags & IFBIF_STP) 625 bp->enable = dot1dStpPortEnable_enabled; 626 else 627 bp->enable = dot1dStpPortEnable_disabled; 628 629 /* Begemot Bridge MIB only. */ 630 if (k_info->ifbr_ifsflags & IFBIF_SPAN) 631 bp->span_enable = begemotBridgeBaseSpanEnabled_enabled; 632 else 633 bp->span_enable = begemotBridgeBaseSpanEnabled_disabled; 634} 635 636/* 637 * Fill in a bridge interface STP information according to 638 * data polled from kernel. 639 */ 640static void 641bridge_port_getinfo_opstp(struct ifbpstpreq *bp_stp, struct bridge_port *bp) 642{ 643 bp->enable = dot1dStpPortEnable_enabled; 644 bp->fwd_trans = bp_stp->ifbp_fwd_trans; 645 bp->design_cost = bp_stp->ifbp_design_cost; 646 snmp_uint64_to_bridgeid(bp_stp->ifbp_design_root, bp->design_root); 647 snmp_uint64_to_bridgeid(bp_stp->ifbp_design_bridge, bp->design_bridge); 648 bcopy(&(bp_stp->ifbp_design_port), &(bp->design_port), 649 sizeof(uint16_t)); 650} 651 652/* 653 * Clear a bridge interface STP information. 654 */ 655static void 656bridge_port_clearinfo_opstp(struct bridge_port *bp) 657{ 658 if (bp->enable == dot1dStpPortEnable_enabled) { 659 bp->design_cost = 0; 660 bzero(&(bp->design_root), sizeof(bridge_id)); 661 bzero(&(bp->design_bridge), sizeof(bridge_id)); 662 bzero(&(bp->design_port), sizeof(port_id)); 663 bp->fwd_trans = 0; 664 } 665 666 bp->enable = dot1dStpPortEnable_disabled; 667} 668 669/* 670 * Set a bridge member priority. 671 */ 672int 673bridge_port_set_priority(const char *bif_name, struct bridge_port *bp, 674 int32_t priority) 675{ 676 struct ifdrv ifd; 677 struct ifbreq b_req; 678 679 if (priority < 0 || priority > 255) 680 return (-2); 681 682 strlcpy(ifd.ifd_name, bif_name, sizeof(ifd.ifd_name)); 683 ifd.ifd_len = sizeof(b_req); 684 ifd.ifd_data = &b_req; 685 strlcpy(b_req.ifbr_ifsname, bp->p_name, sizeof(b_req.ifbr_ifsname)); 686 687 b_req.ifbr_priority = (uint8_t) priority; 688 ifd.ifd_cmd = BRDGSIFPRIO; 689 690 if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) { 691 syslog(LOG_ERR, "set member %s param: ioctl(BRDGSIFPRIO) " 692 "failed: %s", bp->p_name, strerror(errno)); 693 return (-1); 694 } 695 696 bp->priority = priority; 697 return (0); 698} 699 700/* 701 * Set a bridge member STP-enabled flag. 702 */ 703int 704bridge_port_set_stp_enable(const char *bif_name, struct bridge_port *bp, 705 uint32_t enable) 706{ 707 struct ifdrv ifd; 708 struct ifbreq b_req; 709 710 if (bp->enable == enable) 711 return (0); 712 713 if (enable != dot1dStpPortEnable_enabled && 714 enable != dot1dStpPortEnable_disabled) 715 return (-2); 716 717 bzero(&b_req, sizeof(b_req)); 718 strlcpy(ifd.ifd_name, bif_name, sizeof(ifd.ifd_name)); 719 ifd.ifd_len = sizeof(b_req); 720 ifd.ifd_data = &b_req; 721 strlcpy(b_req.ifbr_ifsname, bp->p_name, sizeof(b_req.ifbr_ifsname)); 722 ifd.ifd_cmd = BRDGGIFFLGS; 723 724 if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) { 725 syslog(LOG_ERR, "get member %s param: ioctl(BRDGGIFFLGS) " 726 "failed: %s", bp->p_name, strerror(errno)); 727 return (-1); 728 } 729 730 if (enable == dot1dStpPortEnable_enabled) 731 b_req.ifbr_ifsflags |= IFBIF_STP; 732 else 733 b_req.ifbr_ifsflags &= ~IFBIF_STP; 734 735 ifd.ifd_cmd = BRDGSIFFLGS; 736 if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) { 737 syslog(LOG_ERR, "set member %s param: ioctl(BRDGSIFFLGS) " 738 "failed: %s", bp->p_name, strerror(errno)); 739 return (-1); 740 } 741 742 bp->enable = enable; 743 return (0); 744} 745 746/* 747 * Set a bridge member STP path cost. 748 */ 749int 750bridge_port_set_path_cost(const char *bif_name, struct bridge_port *bp, 751 int32_t path_cost) 752{ 753 struct ifdrv ifd; 754 struct ifbreq b_req; 755 756 if (path_cost > SNMP_PORT_PATHCOST_OBSOLETE) 757 return (-2); 758 759 strlcpy(ifd.ifd_name, bif_name, sizeof(ifd.ifd_name)); 760 ifd.ifd_len = sizeof(b_req); 761 ifd.ifd_data = &b_req; 762 strlcpy(b_req.ifbr_ifsname, bp->p_name, sizeof(b_req.ifbr_ifsname)); 763 764 b_req.ifbr_path_cost = (uint16_t) path_cost; 765 ifd.ifd_cmd = BRDGSIFCOST; 766 767 if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) { 768 syslog(LOG_ERR, "set member %s param: ioctl(BRDGSIFCOST) " 769 "failed: %s", bp->p_name, strerror(errno)); 770 return (-1); 771 } 772 773 bp->path_cost = path_cost; 774 return (0); 775} 776 777/* 778 * Add a bridge member port. 779 */ 780int 781bridge_port_addm(struct bridge_port *bp, const char *b_name) 782{ 783 struct ifdrv ifd; 784 struct ifbreq b_req; 785 786 bzero(&ifd, sizeof(ifd)); 787 bzero(&b_req, sizeof(b_req)); 788 789 strlcpy(ifd.ifd_name, b_name, sizeof(ifd.ifd_name)); 790 ifd.ifd_len = sizeof(b_req); 791 ifd.ifd_data = &b_req; 792 strlcpy(b_req.ifbr_ifsname, bp->p_name, sizeof(b_req.ifbr_ifsname)); 793 794 if (bp->span_enable == begemotBridgeBaseSpanEnabled_enabled) 795 ifd.ifd_cmd = BRDGADDS; 796 else 797 ifd.ifd_cmd = BRDGADD; 798 799 if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) { 800 syslog(LOG_ERR, "%s - add member : ioctl(%s) failed: %s", 801 bp->p_name, 802 (ifd.ifd_cmd == BRDGADDS ? "BRDGADDS" : "BRDGADD"), 803 strerror(errno)); 804 return (-1); 805 } 806 807 return (0); 808} 809 810/* 811 * Delete a bridge member port. 812 */ 813int 814bridge_port_delm(struct bridge_port *bp, const char *b_name) 815{ 816 struct ifdrv ifd; 817 struct ifbreq b_req; 818 819 bzero(&ifd, sizeof(ifd)); 820 bzero(&b_req, sizeof(b_req)); 821 822 strlcpy(ifd.ifd_name, b_name, sizeof(ifd.ifd_name)); 823 ifd.ifd_len = sizeof(b_req); 824 ifd.ifd_data = &b_req; 825 strlcpy(b_req.ifbr_ifsname, bp->p_name, sizeof(b_req.ifbr_ifsname)); 826 827 if (bp->span_enable == begemotBridgeBaseSpanEnabled_enabled) 828 ifd.ifd_cmd = BRDGDELS; 829 else 830 ifd.ifd_cmd = BRDGDEL; 831 832 if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) { 833 syslog(LOG_ERR, "%s - add member : ioctl(%s) failed: %s", 834 bp->p_name, 835 (ifd.ifd_cmd == BRDGDELS ? "BRDGDELS" : "BRDGDEL"), 836 strerror(errno)); 837 return (-1); 838 } 839 840 return (0); 841} 842 843/* 844 * Fetch the bridge member list from kernel. 845 * Return -1 on error, or buffer len if successful. 846 */ 847static int32_t 848bridge_port_get_iflist(struct bridge_if *bif, char **buf) 849{ 850 uint32_t len = 8192; /* ??? */ 851 char *ninbuf; 852 struct ifbifconf ifbc; 853 struct ifdrv ifd; 854 855 *buf = NULL; 856 strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ); 857 ifd.ifd_cmd = BRDGGIFS; 858 ifd.ifd_len = sizeof(ifbc); 859 ifd.ifd_data = &ifbc; 860 861 for ( ; ; ) { 862 if ((ninbuf = realloc(*buf, len) /* ??? */) == NULL) { 863 syslog(LOG_ERR, "get bridge member list: " 864 "realloc failed: %s", strerror(errno)); 865 free(*buf); 866 *buf = NULL; 867 return (-1); 868 } 869 870 ifbc.ifbic_len = len; 871 ifbc.ifbic_buf = *buf = ninbuf; 872 873 if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) { 874 syslog(LOG_ERR, "get bridge member list: ioctl " 875 "(BRDGGIFS) failed: %s", strerror(errno)); 876 free(*buf); 877 buf = NULL; 878 return (-1); 879 } 880 881 if ((ifbc.ifbic_len + sizeof(struct ifbreq)) < len) 882 break; 883 884 len += 8192; 885 } 886 887 return (ifbc.ifbic_len); 888} 889 890/* 891 * Fetch the bridge STP member list from kernel. 892 * Return -1 on error, or buffer len if successful. 893 */ 894static int32_t 895bridge_port_get_ifstplist(struct bridge_if *bif, char **buf) 896{ 897 uint32_t len = 8192; /* ??? */ 898 char *ninbuf; 899 struct ifbpstpconf ifbstp; 900 struct ifdrv ifd; 901 902 *buf = NULL; 903 strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ); 904 ifd.ifd_cmd = BRDGGIFSSTP; 905 ifd.ifd_len = sizeof(ifbstp); 906 ifd.ifd_data = &ifbstp; 907 908 for ( ; ; ) { 909 if ((ninbuf = realloc(*buf, len) /* ??? */) == NULL) { 910 syslog(LOG_ERR, "get bridge STP ports list: " 911 "realloc failed: %s", strerror(errno)); 912 free(*buf); 913 *buf = NULL; 914 return (-1); 915 } 916 917 ifbstp.ifbpstp_len = len; 918 ifbstp.ifbpstp_buf = *buf = ninbuf; 919 920 if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) { 921 syslog(LOG_ERR, "get bridge STP ports list: ioctl " 922 "(BRDGGIFSSTP) failed: %s", strerror(errno)); 923 free(*buf); 924 buf = NULL; 925 return (-1); 926 } 927 928 if ((ifbstp.ifbpstp_len + sizeof(struct ifbpstpreq)) < len) 929 break; 930 931 len += 8192; 932 } 933 934 return (ifbstp.ifbpstp_len); 935} 936 937/* 938 * Locate a bridge if STP params structure in a buffer. 939 */ 940static struct ifbpstpreq * 941bridge_port_find_ifstplist(uint8_t port_no, char *buf, uint32_t buf_len) 942{ 943 uint32_t i; 944 struct ifbpstpreq *bstp; 945 946 for (i = 0; i < buf_len / sizeof(*bstp); i++) { 947 bstp = (struct ifbpstpreq *) buf + i; 948 if (bstp->ifbp_portno == port_no) 949 return (bstp); 950 } 951 952 return (NULL); 953} 954 955/* 956 * Read the initial info for all members of a bridge interface. 957 * Returns the number of ports, 0 - if none, otherwise 958 * -1 if some other error occured. 959 */ 960int 961bridge_getinfo_bif_ports(struct bridge_if *bif) 962{ 963 uint32_t i; 964 int32_t buf_len; 965 char *mem_buf; 966 struct ifbreq *b_req; 967 struct ifbpstpreq *bs_req; 968 struct bridge_port *bp; 969 struct mibif *m_if; 970 971 if ((buf_len = bridge_port_get_iflist(bif, &mem_buf)) < 0) 972 return (-1); 973 974 for (i = 0; i < buf_len / sizeof(struct ifbreq); i++) { 975 b_req = (struct ifbreq *) mem_buf + i; 976 977 if ((m_if = mib_find_if_sys(b_req->ifbr_portno)) != NULL) { 978 /* Hopefully we will not fail here. */ 979 if ((bp = bridge_new_port(m_if, bif)) != NULL) { 980 bp->status = RowStatus_active; 981 bridge_port_getinfo_conf(b_req, bp); 982 bridge_port_getinfo_mibif(m_if, bp); 983 } 984 } else { 985 syslog(LOG_ERR, "bridge member %s not present " 986 "in mibII ifTable", b_req->ifbr_ifsname); 987 } 988 } 989 free(mem_buf); 990 991 if ((buf_len = bridge_port_get_ifstplist(bif, &mem_buf)) < 0) 992 return (-1); 993 994 for (bp = bridge_port_bif_first(bif); bp != NULL; 995 bp = bridge_port_bif_next(bp)) { 996 if ((bs_req = bridge_port_find_ifstplist(bp->port_no, 997 mem_buf, buf_len)) == NULL) 998 bridge_port_clearinfo_opstp(bp); 999 else 1000 bridge_port_getinfo_opstp(bs_req, bp); 1001 } 1002 free(mem_buf); 1003 1004 return (i); 1005} 1006 1007/* 1008 * Update the information for the bridge interface members. 1009 */ 1010int 1011bridge_update_memif(struct bridge_if *bif) 1012{ 1013 int added, updated; 1014 uint32_t i; 1015 int32_t buf_len; 1016 char *if_buf; 1017 struct ifbreq *b_req; 1018 struct ifbpstpreq *bs_req; 1019 struct bridge_port *bp, *bp_next; 1020 struct mibif *m_if; 1021 1022 if ((buf_len = bridge_port_get_iflist(bif, &if_buf)) < 0) 1023 return (-1); 1024 1025 added = updated = 0; 1026 1027#define BP_FOUND 0x01 1028 for (i = 0; i < buf_len / sizeof(struct ifbreq); i++) { 1029 b_req = (struct ifbreq *) if_buf + i; 1030 1031 if ((m_if = mib_find_if_sys(b_req->ifbr_portno)) == NULL) { 1032 syslog(LOG_ERR, "bridge member %s not present " 1033 "in mibII ifTable", b_req->ifbr_ifsname); 1034 continue; 1035 } 1036 1037 if ((bp = bridge_port_find(m_if->index, bif)) == NULL && 1038 (bp = bridge_new_port(m_if, bif)) != NULL) { 1039 bp->status = RowStatus_active; 1040 added++; 1041 } 1042 1043 if (bp != NULL) { 1044 updated++; 1045 bridge_port_getinfo_conf(b_req, bp); 1046 bridge_port_getinfo_mibif(m_if, bp); 1047 bp->flags |= BP_FOUND; 1048 } 1049 } 1050 free(if_buf); 1051 1052 /* Clean up list. */ 1053 for (bp = bridge_port_bif_first(bif); bp != NULL; bp = bp_next) { 1054 bp_next = bridge_port_bif_next(bp); 1055 1056 if ((bp->flags & BP_FOUND) == 0 && 1057 bp->status == RowStatus_active) 1058 bridge_port_remove(bp, bif); 1059 else 1060 bp->flags |= ~BP_FOUND; 1061 } 1062#undef BP_FOUND 1063 1064 if ((buf_len = bridge_port_get_ifstplist(bif, &if_buf)) < 0) 1065 return (-1); 1066 1067 for (bp = bridge_port_bif_first(bif); bp != NULL; 1068 bp = bridge_port_bif_next(bp)) { 1069 if ((bs_req = bridge_port_find_ifstplist(bp->port_no, 1070 if_buf, buf_len)) == NULL) 1071 bridge_port_clearinfo_opstp(bp); 1072 else 1073 bridge_port_getinfo_opstp(bs_req, bp); 1074 } 1075 free(if_buf); 1076 bif->ports_age = time(NULL); 1077 1078 return (updated); 1079} 1080 1081/************************************************************************ 1082 * Bridge addresses. 1083 */ 1084 1085/* 1086 * Update the bridge address info according to the polled data. 1087 */ 1088static void 1089bridge_addrs_info_ifaddrlist(struct ifbareq *ifba, struct tp_entry *tpe) 1090{ 1091 tpe->port_no = if_nametoindex(ifba->ifba_ifsname); 1092 1093 if ((ifba->ifba_flags & IFBAF_TYPEMASK) == IFBAF_STATIC) 1094 tpe->status = TpFdbStatus_mgmt; 1095 else 1096 tpe->status = TpFdbStatus_learned; 1097} 1098 1099/* 1100 * Read the bridge addresses from kernel. 1101 * Return -1 on error, or buffer len if successful. 1102 */ 1103static int32_t 1104bridge_addrs_getinfo_ifalist(struct bridge_if *bif, char **buf) 1105{ 1106 uint32_t len = 8192; /* ??? */ 1107 char *ninbuf; 1108 struct ifbaconf bac; 1109 struct ifdrv ifd; 1110 1111 *buf = NULL; 1112 strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ); 1113 ifd.ifd_cmd = BRDGRTS; 1114 ifd.ifd_len = sizeof(bac); 1115 ifd.ifd_data = &bac; 1116 1117 for ( ; ; ) { 1118 if ((ninbuf = realloc(*buf, len) /* ??? */) == NULL) { 1119 syslog(LOG_ERR, "get bridge address list: " 1120 " realloc failed: %s", strerror(errno)); 1121 free(*buf); 1122 *buf = NULL; 1123 return (-1); 1124 } 1125 1126 bac.ifbac_len = len; 1127 bac.ifbac_buf = *buf = ninbuf; 1128 1129 if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) { 1130 syslog(LOG_ERR, "get bridge address list: " 1131 "ioctl(BRDGRTS) failed: %s", strerror(errno)); 1132 free(*buf); 1133 buf = NULL; 1134 return (-1); 1135 } 1136 1137 if ((bac.ifbac_len + sizeof(struct ifbareq)) < len) 1138 break; 1139 1140 len += 8192; 1141 } 1142 1143 return (bac.ifbac_len); 1144} 1145 1146/* 1147 * Read the initial info for all addresses on a bridge interface. 1148 * Returns the number of addresses, 0 - if none, otherwise 1149 * -1 if some other error occured. 1150 */ 1151int 1152bridge_getinfo_bif_addrs(struct bridge_if *bif) 1153{ 1154 uint32_t i; 1155 int32_t buf_len; 1156 char *addr_buf; 1157 struct ifbareq *addr_req; 1158 struct tp_entry *te; 1159 1160 if ((buf_len = bridge_addrs_getinfo_ifalist(bif, &addr_buf)) < 0) 1161 return (-1); 1162 1163 for (i = 0; i < buf_len / sizeof(struct ifbareq); i++) { 1164 addr_req = (struct ifbareq *) addr_buf + i; 1165 1166 if ((te = bridge_new_addrs(addr_req->ifba_dst, bif)) != NULL) 1167 bridge_addrs_info_ifaddrlist(addr_req, te); 1168 } 1169 1170 free(addr_buf); 1171 return (i); 1172} 1173 1174/* 1175 * Update the addresses for the bridge interface. 1176 */ 1177int 1178bridge_update_addrs(struct bridge_if *bif) 1179{ 1180 int added, updated; 1181 uint32_t i; 1182 int32_t buf_len; 1183 char *ifbad_buf; 1184 struct tp_entry *te, *te_next; 1185 struct ifbareq *a_req; 1186 1187 if ((buf_len = bridge_addrs_getinfo_ifalist(bif, &ifbad_buf)) < 0) 1188 return (-1); 1189 1190 added = updated = 0; 1191 1192#define BA_FOUND 0x01 1193 for (i = 0; i < buf_len / sizeof(struct ifbareq); i++) { 1194 a_req = (struct ifbareq *) ifbad_buf + i; 1195 1196 if ((te = bridge_addrs_find(a_req->ifba_dst, bif)) == NULL) { 1197 added++; 1198 1199 if ((te = bridge_new_addrs(a_req->ifba_dst, bif)) 1200 == NULL) 1201 continue; 1202 } else 1203 updated++; 1204 1205 bridge_addrs_info_ifaddrlist(a_req, te); 1206 te-> flags |= BA_FOUND; 1207 } 1208 free(ifbad_buf); 1209 1210 for (te = bridge_addrs_bif_first(bif); te != NULL; te = te_next) { 1211 te_next = bridge_addrs_bif_next(te); 1212 1213 if ((te-> flags & BA_FOUND) == 0) 1214 bridge_addrs_remove(te, bif); 1215 else 1216 te-> flags &= ~BA_FOUND; 1217 } 1218#undef BA_FOUND 1219 1220 bif->addrs_age = time(NULL); 1221 return (updated + added); 1222} 1223 1224/************************************************************************ 1225 * Bridge packet filtering. 1226 */ 1227const char bridge_sysctl[] = "net.link.bridge."; 1228 1229static struct { 1230 int32_t val; 1231 const char *name; 1232} bridge_pf_sysctl[] = { 1233 { 1, "pfil_bridge" }, 1234 { 1, "pfil_member" }, 1235 { 1, "pfil_onlyip" }, 1236 { 0, "ipfw" }, 1237}; 1238 1239int32_t 1240bridge_get_pfval(uint8_t which) 1241{ 1242 if (which > sizeof(bridge_pf_sysctl) / sizeof(bridge_pf_sysctl[0]) 1243 || which < 1) 1244 return (-1); 1245 1246 return (bridge_pf_sysctl[which - 1].val); 1247} 1248 1249int32_t 1250bridge_do_pfctl(int32_t bridge_ctl, enum snmp_op op, int32_t *val) 1251{ 1252 char mib_name[100]; 1253 int32_t i, s_i; 1254 size_t len, s_len; 1255 1256 if (bridge_ctl >= LEAF_begemotBridgeLayer2PfStatus) 1257 return (-2); 1258 1259 if (op == SNMP_OP_SET) { 1260 s_i = *val; 1261 s_len = sizeof(s_i); 1262 } else 1263 s_len = 0; 1264 1265 len = sizeof(i); 1266 1267 strcpy(mib_name, bridge_sysctl); 1268 1269 if (sysctlbyname(strcat(mib_name, 1270 bridge_pf_sysctl[bridge_ctl].name), &i, &len, 1271 (op == SNMP_OP_SET ? &s_i : NULL), s_len) == -1) { 1272 syslog(LOG_ERR, "sysctl(%s%s) failed - %s", bridge_sysctl, 1273 bridge_pf_sysctl[bridge_ctl].name, strerror(errno)); 1274 return (-1); 1275 } 1276 1277 bridge_pf_sysctl[bridge_ctl].val = i; 1278 *val = i; 1279 1280 return (i); 1281} 1282 1283void 1284bridge_pf_dump(void) 1285{ 1286 uint8_t i; 1287 1288 for (i = 0; i < sizeof(bridge_pf_sysctl) / sizeof(bridge_pf_sysctl[0]); 1289 i++) { 1290 syslog(LOG_ERR, "%s%s = %d", bridge_sysctl, 1291 bridge_pf_sysctl[i].name, bridge_pf_sysctl[i].val); 1292 } 1293} 1294