1164410Ssyrinx/*- 2330449Seadler * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3330449Seadler * 4164410Ssyrinx * Copyright (c) 2006 Shteryana Shopova <syrinx@FreeBSD.org> 5164410Ssyrinx * All rights reserved. 6164410Ssyrinx * 7164410Ssyrinx * Redistribution and use in source and binary forms, with or without 8164410Ssyrinx * modification, are permitted provided that the following conditions 9164410Ssyrinx * are met: 10164410Ssyrinx * 1. Redistributions of source code must retain the above copyright 11164410Ssyrinx * notice, this list of conditions and the following disclaimer. 12164410Ssyrinx * 2. Redistributions in binary form must reproduce the above copyright 13164410Ssyrinx * notice, this list of conditions and the following disclaimer in the 14164410Ssyrinx * documentation and/or other materials provided with the distribution. 15164410Ssyrinx * 16164410Ssyrinx * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17164410Ssyrinx * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18164410Ssyrinx * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19164410Ssyrinx * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20164410Ssyrinx * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21164410Ssyrinx * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22164410Ssyrinx * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23164410Ssyrinx * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24164410Ssyrinx * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25164410Ssyrinx * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26164410Ssyrinx * SUCH DAMAGE. 27164410Ssyrinx * 28164410Ssyrinx * Bridge MIB implementation for SNMPd. 29164410Ssyrinx * Bridge OS specific ioctls. 30164410Ssyrinx * 31164410Ssyrinx * $FreeBSD: stable/11/usr.sbin/bsnmpd/modules/snmp_bridge/bridge_sys.c 330449 2018-03-05 07:26:05Z eadler $ 32164410Ssyrinx */ 33164410Ssyrinx 34164410Ssyrinx#include <sys/ioctl.h> 35164410Ssyrinx#include <sys/param.h> 36164410Ssyrinx#include <sys/module.h> 37164410Ssyrinx#include <sys/linker.h> 38164410Ssyrinx#include <sys/socket.h> 39164410Ssyrinx#include <sys/sysctl.h> 40164410Ssyrinx 41164410Ssyrinx#include <net/bridgestp.h> 42164410Ssyrinx#include <net/ethernet.h> 43164410Ssyrinx#include <net/if.h> 44164410Ssyrinx#include <net/if_bridgevar.h> 45164410Ssyrinx#include <net/if_dl.h> 46164410Ssyrinx#include <net/if_mib.h> 47164410Ssyrinx#include <net/if_types.h> 48164410Ssyrinx#include <netinet/in.h> 49164410Ssyrinx 50164410Ssyrinx#include <errno.h> 51164410Ssyrinx#include <ifaddrs.h> 52164410Ssyrinx#include <stdarg.h> 53164410Ssyrinx#include <stdlib.h> 54164410Ssyrinx#include <stdio.h> 55164410Ssyrinx#include <string.h> 56164410Ssyrinx#include <syslog.h> 57164410Ssyrinx 58164410Ssyrinx#include <bsnmp/snmpmod.h> 59164410Ssyrinx#include <bsnmp/snmp_mibII.h> 60164410Ssyrinx 61164410Ssyrinx#include "bridge_tree.h" 62164410Ssyrinx#include "bridge_snmp.h" 63164410Ssyrinx 64164410Ssyrinxint sock = -1; 65164410Ssyrinx 66164410Ssyrinxint 67164410Ssyrinxbridge_ioctl_init(void) 68164410Ssyrinx{ 69164410Ssyrinx if ((sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { 70164410Ssyrinx syslog(LOG_ERR, "cannot open socket : %s", strerror(errno)); 71164410Ssyrinx return (-1); 72164410Ssyrinx } 73164410Ssyrinx 74164410Ssyrinx return (0); 75164410Ssyrinx} 76164410Ssyrinx 77164410Ssyrinx/* 78164410Ssyrinx * Load the if_bridge.ko module in kernel if not already there. 79164410Ssyrinx */ 80164410Ssyrinxint 81164410Ssyrinxbridge_kmod_load(void) 82164410Ssyrinx{ 83164410Ssyrinx int fileid, modid; 84164410Ssyrinx const char mod_name[] = "if_bridge"; 85164410Ssyrinx struct module_stat mstat; 86164410Ssyrinx 87164410Ssyrinx /* Scan files in kernel. */ 88164410Ssyrinx mstat.version = sizeof(struct module_stat); 89164410Ssyrinx for (fileid = kldnext(0); fileid > 0; fileid = kldnext(fileid)) { 90164410Ssyrinx /* Scan modules in file. */ 91164410Ssyrinx for (modid = kldfirstmod(fileid); modid > 0; 92164410Ssyrinx modid = modfnext(modid)) { 93164410Ssyrinx 94164410Ssyrinx if (modstat(modid, &mstat) < 0) 95164410Ssyrinx continue; 96164410Ssyrinx 97164410Ssyrinx if (strcmp(mod_name, mstat.name) == 0) 98164410Ssyrinx return (0); 99164410Ssyrinx } 100164410Ssyrinx } 101164410Ssyrinx 102164410Ssyrinx /* Not present - load it. */ 103164410Ssyrinx if (kldload(mod_name) < 0) { 104164410Ssyrinx syslog(LOG_ERR, "failed to load %s kernel module", mod_name); 105164410Ssyrinx return (-1); 106164410Ssyrinx } 107164410Ssyrinx 108164410Ssyrinx return (1); 109164410Ssyrinx} 110164410Ssyrinx 111164410Ssyrinx/************************************************************************ 112164410Ssyrinx * Bridge interfaces. 113164410Ssyrinx */ 114164410Ssyrinx 115164410Ssyrinx/* 116164410Ssyrinx * Convert the kernel uint64_t value for a bridge id 117164410Ssyrinx */ 118164410Ssyrinxstatic void 119164410Ssyrinxsnmp_uint64_to_bridgeid(uint64_t id, bridge_id b_id) 120164410Ssyrinx{ 121164410Ssyrinx int i; 122164410Ssyrinx u_char *o; 123164410Ssyrinx 124164410Ssyrinx o = (u_char *) &id; 125164410Ssyrinx 126164410Ssyrinx for (i = 0; i < SNMP_BRIDGE_ID_LEN; i++, o++) 127164410Ssyrinx b_id[SNMP_BRIDGE_ID_LEN - i - 1] = *o; 128164410Ssyrinx} 129164410Ssyrinx 130164410Ssyrinx/* 131164410Ssyrinx * Fetch the bridge configuration parameters from the kernel excluding 132164410Ssyrinx * it's base MAC address. 133164410Ssyrinx */ 134164410Ssyrinxstatic int 135164410Ssyrinxbridge_get_conf_param(struct bridge_if *bif) 136164410Ssyrinx{ 137164410Ssyrinx struct ifdrv ifd; 138164410Ssyrinx struct ifbrparam b_param; 139164410Ssyrinx 140164410Ssyrinx strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ); 141164410Ssyrinx ifd.ifd_len = sizeof(b_param); 142164410Ssyrinx ifd.ifd_data = &b_param; 143164410Ssyrinx 144164410Ssyrinx /* Bridge priority. */ 145164410Ssyrinx ifd.ifd_cmd = BRDGGPRI; 146164410Ssyrinx if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) { 147164410Ssyrinx syslog(LOG_ERR, "update bridge: ioctl(BRDGGPRI) failed: %s", 148164410Ssyrinx strerror(errno)); 149164410Ssyrinx return (-1); 150164410Ssyrinx } 151164410Ssyrinx 152164410Ssyrinx bif->priority = b_param.ifbrp_prio; 153164410Ssyrinx 154164410Ssyrinx /* Configured max age. */ 155164410Ssyrinx ifd.ifd_cmd = BRDGGMA; 156164410Ssyrinx if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) { 157164410Ssyrinx syslog(LOG_ERR, "update bridge: ioctl(BRDGGMA) failed: %s", 158164410Ssyrinx strerror(errno)); 159164410Ssyrinx return (-1); 160164410Ssyrinx } 161164410Ssyrinx 162164410Ssyrinx /* Centi-seconds. */ 163164410Ssyrinx bif->bridge_max_age = 100 * b_param.ifbrp_maxage; 164164410Ssyrinx 165164410Ssyrinx /* Configured hello time. */ 166164410Ssyrinx ifd.ifd_cmd = BRDGGHT; 167164410Ssyrinx if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) { 168164410Ssyrinx syslog(LOG_ERR, "update bridge: ioctl(BRDGGHT) failed: %s", 169164410Ssyrinx strerror(errno)); 170164410Ssyrinx return (-1); 171164410Ssyrinx } 172164410Ssyrinx bif->bridge_hello_time = 100 * b_param.ifbrp_hellotime; 173164410Ssyrinx 174164410Ssyrinx /* Forward delay. */ 175164410Ssyrinx ifd.ifd_cmd = BRDGGFD; 176164410Ssyrinx if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) { 177164410Ssyrinx syslog(LOG_ERR, "update bridge: ioctl(BRDGGFD) failed: %s", 178164410Ssyrinx strerror(errno)); 179164410Ssyrinx return (-1); 180164410Ssyrinx } 181164410Ssyrinx bif->bridge_fwd_delay = 100 * b_param.ifbrp_fwddelay; 182164410Ssyrinx 183164410Ssyrinx /* Number of dropped addresses. */ 184164410Ssyrinx ifd.ifd_cmd = BRDGGRTE; 185164410Ssyrinx if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) { 186164410Ssyrinx syslog(LOG_ERR, "update bridge: ioctl(BRDGGRTE) failed: %s", 187164410Ssyrinx strerror(errno)); 188164410Ssyrinx return (-1); 189164410Ssyrinx } 190164410Ssyrinx bif->lrnt_drops = b_param.ifbrp_cexceeded; 191164410Ssyrinx 192164410Ssyrinx /* Address table timeout. */ 193164410Ssyrinx ifd.ifd_cmd = BRDGGTO; 194164410Ssyrinx if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) { 195164410Ssyrinx syslog(LOG_ERR, "update bridge: ioctl(BRDGGTO) failed: %s", 196164410Ssyrinx strerror(errno)); 197164410Ssyrinx return (-1); 198164410Ssyrinx } 199164410Ssyrinx bif->age_time = b_param.ifbrp_ctime; 200164410Ssyrinx 201164410Ssyrinx /* Address table size. */ 202164410Ssyrinx ifd.ifd_cmd = BRDGGCACHE; 203164410Ssyrinx if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) { 204164410Ssyrinx syslog(LOG_ERR, "update bridge: ioctl(BRDGGCACHE) " 205164410Ssyrinx "failed: %s", strerror(errno)); 206164410Ssyrinx return (-1); 207164410Ssyrinx } 208164410Ssyrinx bif->max_addrs = b_param.ifbrp_csize; 209164410Ssyrinx 210164410Ssyrinx return (0); 211164410Ssyrinx} 212164410Ssyrinx 213164410Ssyrinx/* 214164410Ssyrinx * Fetch the current bridge STP operational parameters. 215164410Ssyrinx * Returns: -1 - on error; 216164410Ssyrinx * 0 - old TC time and Root Port values are same; 217164410Ssyrinx * 1 - topologyChange notification should be sent; 218164410Ssyrinx * 2 - newRoot notification should be sent. 219164410Ssyrinx */ 220164410Ssyrinxint 221164410Ssyrinxbridge_get_op_param(struct bridge_if *bif) 222164410Ssyrinx{ 223164410Ssyrinx int new_root_send; 224164410Ssyrinx struct ifdrv ifd; 225164410Ssyrinx struct ifbropreq b_req; 226164410Ssyrinx 227164410Ssyrinx strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ); 228164410Ssyrinx ifd.ifd_len = sizeof(b_req); 229164410Ssyrinx ifd.ifd_data = &b_req; 230164410Ssyrinx ifd.ifd_cmd = BRDGPARAM; 231164410Ssyrinx 232164410Ssyrinx if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) { 233164410Ssyrinx syslog(LOG_ERR, "update bridge: ioctl(BRDGPARAM) failed: %s", 234164410Ssyrinx strerror(errno)); 235164410Ssyrinx return (-1); 236164410Ssyrinx } 237164410Ssyrinx 238164410Ssyrinx bif->max_age = 100 * b_req.ifbop_maxage; 239164410Ssyrinx bif->hello_time = 100 * b_req.ifbop_hellotime; 240164410Ssyrinx bif->fwd_delay = 100 * b_req.ifbop_fwddelay; 241164997Ssyrinx bif->stp_version = b_req.ifbop_protocol; 242164997Ssyrinx bif->tx_hold_count = b_req.ifbop_holdcount; 243164410Ssyrinx 244164410Ssyrinx if (b_req.ifbop_root_port == 0 && 245164410Ssyrinx bif->root_port != b_req.ifbop_root_port) 246164410Ssyrinx new_root_send = 2; 247164410Ssyrinx else 248164410Ssyrinx new_root_send = 0; 249164410Ssyrinx 250164410Ssyrinx bif->root_port = b_req.ifbop_root_port; 251164410Ssyrinx bif->root_cost = b_req.ifbop_root_path_cost; 252164410Ssyrinx snmp_uint64_to_bridgeid(b_req.ifbop_designated_root, 253164410Ssyrinx bif->design_root); 254164410Ssyrinx 255164410Ssyrinx if (bif->last_tc_time.tv_sec != b_req.ifbop_last_tc_time.tv_sec) { 256164410Ssyrinx bif->top_changes++; 257164410Ssyrinx bif->last_tc_time.tv_sec = b_req.ifbop_last_tc_time.tv_sec; 258164410Ssyrinx bif->last_tc_time.tv_usec = b_req.ifbop_last_tc_time.tv_usec; 259164410Ssyrinx 260164410Ssyrinx /* 261164410Ssyrinx * "The trap is not sent if a (begemotBridge)NewRoot 262164410Ssyrinx * trap is sent for the same transition." 263164410Ssyrinx */ 264164410Ssyrinx if (new_root_send == 0) 265164410Ssyrinx return (1); 266164410Ssyrinx } 267164410Ssyrinx 268164410Ssyrinx return (new_root_send); 269164410Ssyrinx} 270164410Ssyrinx 271164410Ssyrinxint 272164410Ssyrinxbridge_getinfo_bif(struct bridge_if *bif) 273164410Ssyrinx{ 274164410Ssyrinx if (bridge_get_conf_param(bif) < 0) 275164410Ssyrinx return (-1); 276164410Ssyrinx 277164410Ssyrinx return (bridge_get_op_param(bif)); 278164410Ssyrinx} 279164410Ssyrinx 280164410Ssyrinxint 281164410Ssyrinxbridge_set_priority(struct bridge_if *bif, int32_t priority) 282164410Ssyrinx{ 283164410Ssyrinx struct ifdrv ifd; 284164410Ssyrinx struct ifbrparam b_param; 285164410Ssyrinx 286164410Ssyrinx strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ); 287164410Ssyrinx ifd.ifd_len = sizeof(b_param); 288164410Ssyrinx ifd.ifd_data = &b_param; 289164410Ssyrinx b_param.ifbrp_prio = (uint32_t) priority; 290164410Ssyrinx ifd.ifd_cmd = BRDGSPRI; 291164410Ssyrinx 292164410Ssyrinx if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) { 293164410Ssyrinx syslog(LOG_ERR, "set bridge param: ioctl(BRDGSPRI) " 294164410Ssyrinx "failed: %s", strerror(errno)); 295164410Ssyrinx return (-1); 296164410Ssyrinx } 297164410Ssyrinx 298164410Ssyrinx /* 299164410Ssyrinx * Re-fetching the data from the driver after that might be a good 300310901Sngie * idea, since changing our bridge's priority should invoke 301164410Ssyrinx * recalculation of the active spanning tree topology in the network. 302164410Ssyrinx */ 303164410Ssyrinx bif->priority = priority; 304164410Ssyrinx return (0); 305164410Ssyrinx} 306164410Ssyrinx 307164410Ssyrinx/* 308164410Ssyrinx * Convert 1/100 of seconds to 1/256 of seconds. 309164410Ssyrinx * Timeout ::= TEXTUAL-CONVENTION. 310164410Ssyrinx * To convert a Timeout value into a value in units of 311164410Ssyrinx * 1/256 seconds, the following algorithm should be used: 312164410Ssyrinx * b = floor( (n * 256) / 100) 313164997Ssyrinx * The conversion to 1/256 of a second happens in the kernel - 314164997Ssyrinx * just make sure we correctly convert the seconds to Timout 315164997Ssyrinx * and vice versa. 316164410Ssyrinx */ 317164410Ssyrinxstatic uint32_t 318164997Ssyrinxsnmp_timeout2_sec(int32_t secs) 319164410Ssyrinx{ 320164997Ssyrinx return (secs / 100); 321164410Ssyrinx} 322164410Ssyrinx 323164410Ssyrinxint 324164410Ssyrinxbridge_set_maxage(struct bridge_if *bif, int32_t max_age) 325164410Ssyrinx{ 326164410Ssyrinx struct ifdrv ifd; 327164410Ssyrinx struct ifbrparam b_param; 328164410Ssyrinx 329164410Ssyrinx strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ); 330164410Ssyrinx ifd.ifd_len = sizeof(b_param); 331164410Ssyrinx ifd.ifd_data = &b_param; 332164997Ssyrinx b_param.ifbrp_maxage = snmp_timeout2_sec(max_age); 333164410Ssyrinx ifd.ifd_cmd = BRDGSMA; 334164410Ssyrinx 335164410Ssyrinx if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) { 336164410Ssyrinx syslog(LOG_ERR, "set bridge param: ioctl(BRDGSMA) " 337164410Ssyrinx "failed: %s", strerror(errno)); 338164410Ssyrinx return (-1); 339164410Ssyrinx } 340164410Ssyrinx 341164410Ssyrinx bif->bridge_max_age = max_age; 342164410Ssyrinx return (0); 343164410Ssyrinx} 344164410Ssyrinx 345164410Ssyrinxint 346164410Ssyrinxbridge_set_hello_time(struct bridge_if *bif, int32_t hello_time) 347164410Ssyrinx{ 348164410Ssyrinx struct ifdrv ifd; 349164410Ssyrinx struct ifbrparam b_param; 350164410Ssyrinx 351164410Ssyrinx strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ); 352164410Ssyrinx ifd.ifd_len = sizeof(b_param); 353164410Ssyrinx ifd.ifd_data = &b_param; 354164997Ssyrinx b_param.ifbrp_hellotime = snmp_timeout2_sec(hello_time); 355164410Ssyrinx ifd.ifd_cmd = BRDGSHT; 356164410Ssyrinx 357164410Ssyrinx if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) { 358164410Ssyrinx syslog(LOG_ERR, "set bridge param: ioctl(BRDGSHT) " 359164410Ssyrinx "failed: %s", strerror(errno)); 360164410Ssyrinx return (-1); 361164410Ssyrinx } 362164410Ssyrinx 363164410Ssyrinx bif->bridge_hello_time = b_param.ifbrp_hellotime; 364164410Ssyrinx return (0); 365164410Ssyrinx} 366164410Ssyrinx 367164410Ssyrinxint 368164410Ssyrinxbridge_set_forward_delay(struct bridge_if *bif, int32_t fwd_delay) 369164410Ssyrinx{ 370164410Ssyrinx struct ifdrv ifd; 371164410Ssyrinx struct ifbrparam b_param; 372164410Ssyrinx 373164410Ssyrinx strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ); 374164410Ssyrinx ifd.ifd_len = sizeof(b_param); 375164410Ssyrinx ifd.ifd_data = &b_param; 376164997Ssyrinx b_param.ifbrp_fwddelay = snmp_timeout2_sec(fwd_delay); 377164410Ssyrinx ifd.ifd_cmd = BRDGSFD; 378164410Ssyrinx 379164410Ssyrinx if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) { 380164410Ssyrinx syslog(LOG_ERR, "set bridge param: ioctl(BRDGSFD) " 381164410Ssyrinx "failed: %s", strerror(errno)); 382164410Ssyrinx return (-1); 383164410Ssyrinx } 384164410Ssyrinx 385164410Ssyrinx bif->bridge_fwd_delay = b_param.ifbrp_fwddelay; 386164410Ssyrinx return (0); 387164410Ssyrinx} 388164410Ssyrinx 389164410Ssyrinxint 390164410Ssyrinxbridge_set_aging_time(struct bridge_if *bif, int32_t age_time) 391164410Ssyrinx{ 392164410Ssyrinx struct ifdrv ifd; 393164410Ssyrinx struct ifbrparam b_param; 394164410Ssyrinx 395164410Ssyrinx strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ); 396164410Ssyrinx ifd.ifd_len = sizeof(b_param); 397164410Ssyrinx ifd.ifd_data = &b_param; 398164410Ssyrinx b_param.ifbrp_ctime = (uint32_t) age_time; 399164410Ssyrinx ifd.ifd_cmd = BRDGSTO; 400164410Ssyrinx 401164410Ssyrinx if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) { 402164410Ssyrinx syslog(LOG_ERR, "set bridge param: ioctl(BRDGSTO) " 403164410Ssyrinx "failed: %s", strerror(errno)); 404164410Ssyrinx return (-1); 405164410Ssyrinx } 406164410Ssyrinx 407164410Ssyrinx bif->age_time = age_time; 408164410Ssyrinx return (0); 409164410Ssyrinx} 410164410Ssyrinx 411164410Ssyrinxint 412164410Ssyrinxbridge_set_max_cache(struct bridge_if *bif, int32_t max_cache) 413164410Ssyrinx{ 414164410Ssyrinx struct ifdrv ifd; 415164410Ssyrinx struct ifbrparam b_param; 416164410Ssyrinx 417164410Ssyrinx strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ); 418164410Ssyrinx ifd.ifd_len = sizeof(b_param); 419164410Ssyrinx ifd.ifd_data = &b_param; 420164410Ssyrinx b_param.ifbrp_csize = max_cache; 421164410Ssyrinx ifd.ifd_cmd = BRDGSCACHE; 422164410Ssyrinx 423164410Ssyrinx if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) { 424164410Ssyrinx syslog(LOG_ERR, "set bridge param: ioctl(BRDGSCACHE) " 425164410Ssyrinx "failed: %s", strerror(errno)); 426164410Ssyrinx return (-1); 427164410Ssyrinx } 428164410Ssyrinx 429164410Ssyrinx bif->max_addrs = b_param.ifbrp_csize; 430164410Ssyrinx return (0); 431164410Ssyrinx} 432164410Ssyrinx 433164997Ssyrinxint 434171791Ssyrinxbridge_set_tx_hold_count(struct bridge_if *bif, int32_t tx_hc) 435164997Ssyrinx{ 436164997Ssyrinx struct ifdrv ifd; 437164997Ssyrinx struct ifbrparam b_param; 438164997Ssyrinx 439164997Ssyrinx if (tx_hc < SNMP_BRIDGE_MIN_TXHC || tx_hc > SNMP_BRIDGE_MAX_TXHC) 440164997Ssyrinx return (-1); 441164997Ssyrinx 442164997Ssyrinx strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ); 443164997Ssyrinx ifd.ifd_len = sizeof(b_param); 444164997Ssyrinx ifd.ifd_data = &b_param; 445164997Ssyrinx b_param.ifbrp_txhc = tx_hc; 446164997Ssyrinx ifd.ifd_cmd = BRDGSTXHC; 447164997Ssyrinx 448164997Ssyrinx if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) { 449164997Ssyrinx syslog(LOG_ERR, "set bridge param: ioctl(BRDGSTXHC) " 450164997Ssyrinx "failed: %s", strerror(errno)); 451164997Ssyrinx return (-1); 452164997Ssyrinx } 453164997Ssyrinx 454164997Ssyrinx bif->tx_hold_count = b_param.ifbrp_txhc; 455164997Ssyrinx return (0); 456164997Ssyrinx} 457164997Ssyrinx 458164997Ssyrinxint 459171791Ssyrinxbridge_set_stp_version(struct bridge_if *bif, int32_t stp_proto) 460164997Ssyrinx{ 461164997Ssyrinx struct ifdrv ifd; 462164997Ssyrinx struct ifbrparam b_param; 463164997Ssyrinx 464164997Ssyrinx strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ); 465164997Ssyrinx ifd.ifd_len = sizeof(b_param); 466164997Ssyrinx ifd.ifd_data = &b_param; 467164997Ssyrinx b_param.ifbrp_proto = stp_proto; 468164997Ssyrinx ifd.ifd_cmd = BRDGSPROTO; 469164997Ssyrinx 470164997Ssyrinx if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) { 471164997Ssyrinx syslog(LOG_ERR, "set bridge param: ioctl(BRDGSPROTO) " 472164997Ssyrinx "failed: %s", strerror(errno)); 473164997Ssyrinx return (-1); 474164997Ssyrinx } 475164997Ssyrinx 476164997Ssyrinx bif->stp_version = b_param.ifbrp_proto; 477164997Ssyrinx return (0); 478164997Ssyrinx} 479164997Ssyrinx 480164410Ssyrinx/* 481164410Ssyrinx * Set the bridge interface status to up/down. 482164410Ssyrinx */ 483164410Ssyrinxint 484164410Ssyrinxbridge_set_if_up(const char* b_name, int8_t up) 485164410Ssyrinx{ 486164410Ssyrinx int flags; 487164410Ssyrinx struct ifreq ifr; 488164410Ssyrinx 489164410Ssyrinx bzero(&ifr, sizeof(ifr)); 490312043Sngie strlcpy(ifr.ifr_name, b_name, sizeof(ifr.ifr_name)); 491164410Ssyrinx if (ioctl(sock, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) { 492164410Ssyrinx syslog(LOG_ERR, "set bridge up: ioctl(SIOCGIFFLAGS) " 493164410Ssyrinx "failed: %s", strerror(errno)); 494164410Ssyrinx return (-1); 495164410Ssyrinx } 496164410Ssyrinx 497164410Ssyrinx flags = (ifr.ifr_flags & 0xffff) | (ifr.ifr_flagshigh << 16); 498164410Ssyrinx if (up == 1) 499164410Ssyrinx flags |= IFF_UP; 500164410Ssyrinx else 501164410Ssyrinx flags &= ~IFF_UP; 502164410Ssyrinx 503164410Ssyrinx ifr.ifr_flags = flags & 0xffff; 504164410Ssyrinx ifr.ifr_flagshigh = flags >> 16; 505164410Ssyrinx if (ioctl(sock, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) { 506164410Ssyrinx syslog(LOG_ERR, "set bridge up: ioctl(SIOCSIFFLAGS) " 507164410Ssyrinx "failed: %s", strerror(errno)); 508164410Ssyrinx return (-1); 509164410Ssyrinx } 510164410Ssyrinx 511164410Ssyrinx return (0); 512164410Ssyrinx} 513164410Ssyrinx 514164410Ssyrinxint 515164410Ssyrinxbridge_create(const char *b_name) 516164410Ssyrinx{ 517164410Ssyrinx char *new_name; 518164410Ssyrinx struct ifreq ifr; 519164410Ssyrinx 520164410Ssyrinx bzero(&ifr, sizeof(ifr)); 521312043Sngie strlcpy(ifr.ifr_name, b_name, sizeof(ifr.ifr_name)); 522164410Ssyrinx 523164410Ssyrinx if (ioctl(sock, SIOCIFCREATE, &ifr) < 0) { 524164410Ssyrinx syslog(LOG_ERR, "create bridge: ioctl(SIOCIFCREATE) " 525164410Ssyrinx "failed: %s", strerror(errno)); 526164410Ssyrinx return (-1); 527164410Ssyrinx } 528164410Ssyrinx 529164410Ssyrinx if (strcmp(b_name, ifr.ifr_name) == 0) 530164410Ssyrinx return (0); 531164410Ssyrinx 532164410Ssyrinx if ((new_name = strdup(b_name)) == NULL) { 533164410Ssyrinx syslog(LOG_ERR, "create bridge: strdup() failed"); 534164410Ssyrinx return (-1); 535164410Ssyrinx } 536164410Ssyrinx 537164410Ssyrinx ifr.ifr_data = new_name; 538164410Ssyrinx if (ioctl(sock, SIOCSIFNAME, (caddr_t) &ifr) < 0) { 539164410Ssyrinx syslog(LOG_ERR, "create bridge: ioctl(SIOCSIFNAME) " 540164410Ssyrinx "failed: %s", strerror(errno)); 541164410Ssyrinx free(new_name); 542164410Ssyrinx return (-1); 543164410Ssyrinx } 544164410Ssyrinx 545164410Ssyrinx return (0); 546164410Ssyrinx} 547164410Ssyrinx 548164410Ssyrinxint 549164410Ssyrinxbridge_destroy(const char *b_name) 550164410Ssyrinx{ 551164410Ssyrinx struct ifreq ifr; 552164410Ssyrinx 553164410Ssyrinx bzero(&ifr, sizeof(ifr)); 554312043Sngie strlcpy(ifr.ifr_name, b_name, sizeof(ifr.ifr_name)); 555164410Ssyrinx 556164410Ssyrinx if (ioctl(sock, SIOCIFDESTROY, &ifr) < 0) { 557164410Ssyrinx syslog(LOG_ERR, "destroy bridge: ioctl(SIOCIFDESTROY) " 558164410Ssyrinx "failed: %s", strerror(errno)); 559164410Ssyrinx return (-1); 560164410Ssyrinx } 561164410Ssyrinx 562164410Ssyrinx return (0); 563164410Ssyrinx} 564164410Ssyrinx 565164410Ssyrinx/* 566164410Ssyrinx * Fetch the bridge base MAC address. Return pointer to the 567165642Sbz * buffer containing the MAC address, NULL on failure. 568164410Ssyrinx */ 569164410Ssyrinxu_char * 570165642Sbzbridge_get_basemac(const char *bif_name, u_char *mac, size_t mlen) 571164410Ssyrinx{ 572164410Ssyrinx int len; 573164410Ssyrinx char if_name[IFNAMSIZ]; 574165642Sbz struct ifaddrs *ifap, *ifa; 575165642Sbz struct sockaddr_dl sdl; 576164410Ssyrinx 577165642Sbz if (getifaddrs(&ifap) != 0) { 578164410Ssyrinx syslog(LOG_ERR, "bridge get mac: getifaddrs() failed - %s", 579164410Ssyrinx strerror(errno)); 580164410Ssyrinx return (NULL); 581164410Ssyrinx } 582164410Ssyrinx 583165642Sbz for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) { 584165642Sbz if (ifa->ifa_addr->sa_family != AF_LINK) 585165642Sbz continue; 586164410Ssyrinx 587165642Sbz /* 588165642Sbz * Not just casting because of alignment constraints 589268351Smarcel * on sparc64. 590165642Sbz */ 591165642Sbz bcopy(ifa->ifa_addr, &sdl, sizeof(struct sockaddr_dl)); 592165642Sbz 593165642Sbz if (sdl.sdl_alen > mlen) 594165642Sbz continue; 595165642Sbz 596165642Sbz if ((len = sdl.sdl_nlen) >= IFNAMSIZ) 597164410Ssyrinx len = IFNAMSIZ - 1; 598164410Ssyrinx 599165642Sbz bcopy(sdl.sdl_data, if_name, len); 600164410Ssyrinx if_name[len] = '\0'; 601164410Ssyrinx 602165642Sbz if (strcmp(bif_name, if_name) == 0) { 603165642Sbz bcopy(sdl.sdl_data + sdl.sdl_nlen, mac, sdl.sdl_alen); 604164410Ssyrinx freeifaddrs(ifap); 605164410Ssyrinx return (mac); 606164410Ssyrinx } 607164410Ssyrinx } 608164410Ssyrinx 609164410Ssyrinx freeifaddrs(ifap); 610164410Ssyrinx return (NULL); 611164410Ssyrinx} 612164410Ssyrinx 613164410Ssyrinx/************************************************************************ 614164410Ssyrinx * Bridge ports. 615164410Ssyrinx */ 616164410Ssyrinx 617164410Ssyrinx/* 618164410Ssyrinx * Convert the kernel STP port state into 619164410Ssyrinx * the corresopnding enumerated type from SNMP Bridge MIB. 620164410Ssyrinx */ 621164410Ssyrinxstatic int 622164410Ssyrinxstate2snmp_st(uint8_t ifbr_state) 623164410Ssyrinx{ 624164410Ssyrinx switch (ifbr_state) { 625164410Ssyrinx case BSTP_IFSTATE_DISABLED: 626164410Ssyrinx return (StpPortState_disabled); 627164410Ssyrinx case BSTP_IFSTATE_LISTENING: 628164410Ssyrinx return (StpPortState_listening); 629164410Ssyrinx case BSTP_IFSTATE_LEARNING: 630164410Ssyrinx return (StpPortState_learning); 631164410Ssyrinx case BSTP_IFSTATE_FORWARDING: 632164410Ssyrinx return (StpPortState_forwarding); 633164410Ssyrinx case BSTP_IFSTATE_BLOCKING: 634164997Ssyrinx case BSTP_IFSTATE_DISCARDING: 635164410Ssyrinx return (StpPortState_blocking); 636164410Ssyrinx } 637164410Ssyrinx 638164410Ssyrinx return (StpPortState_broken); 639164410Ssyrinx} 640164410Ssyrinx 641164410Ssyrinx/* 642164410Ssyrinx * Fill in a bridge member information according to data polled from kernel. 643164410Ssyrinx */ 644164410Ssyrinxstatic void 645164410Ssyrinxbridge_port_getinfo_conf(struct ifbreq *k_info, struct bridge_port *bp) 646164410Ssyrinx{ 647164410Ssyrinx bp->state = state2snmp_st(k_info->ifbr_state); 648164410Ssyrinx bp->priority = k_info->ifbr_priority; 649164410Ssyrinx 650164410Ssyrinx /* 651164410Ssyrinx * RFC 4188: 652164410Ssyrinx * "New implementations should support dot1dStpPortPathCost32. 653164410Ssyrinx * If the port path costs exceeds the maximum value of this 654164410Ssyrinx * object then this object should report the maximum value, 655164410Ssyrinx * namely 65535. Applications should try to read the 656164410Ssyrinx * dot1dStpPortPathCost32 object if this object reports 657164410Ssyrinx * the maximum value." 658164410Ssyrinx */ 659164410Ssyrinx 660164997Ssyrinx if (k_info->ifbr_ifsflags & IFBIF_BSTP_ADMCOST) 661164997Ssyrinx bp->admin_path_cost = k_info->ifbr_path_cost; 662164997Ssyrinx else 663164997Ssyrinx bp->admin_path_cost = 0; 664166493Ssyrinx 665164410Ssyrinx bp->path_cost = k_info->ifbr_path_cost; 666164410Ssyrinx 667164410Ssyrinx if (k_info->ifbr_ifsflags & IFBIF_STP) 668164410Ssyrinx bp->enable = dot1dStpPortEnable_enabled; 669164410Ssyrinx else 670164410Ssyrinx bp->enable = dot1dStpPortEnable_disabled; 671164410Ssyrinx 672164410Ssyrinx /* Begemot Bridge MIB only. */ 673164410Ssyrinx if (k_info->ifbr_ifsflags & IFBIF_SPAN) 674164410Ssyrinx bp->span_enable = begemotBridgeBaseSpanEnabled_enabled; 675164410Ssyrinx else 676164410Ssyrinx bp->span_enable = begemotBridgeBaseSpanEnabled_disabled; 677164997Ssyrinx 678171791Ssyrinx if (k_info->ifbr_ifsflags & IFBIF_PRIVATE) 679171791Ssyrinx bp->priv_set = TruthValue_true; 680171791Ssyrinx else 681171791Ssyrinx bp->priv_set = TruthValue_false; 682171791Ssyrinx 683164997Ssyrinx if (k_info->ifbr_ifsflags & IFBIF_BSTP_ADMEDGE) 684164997Ssyrinx bp->admin_edge = TruthValue_true; 685164997Ssyrinx else 686164997Ssyrinx bp->admin_edge = TruthValue_false; 687164997Ssyrinx 688164997Ssyrinx if (k_info->ifbr_ifsflags & IFBIF_BSTP_EDGE) 689164997Ssyrinx bp->oper_edge = TruthValue_true; 690164997Ssyrinx else 691164997Ssyrinx bp->oper_edge = TruthValue_false; 692164997Ssyrinx 693165416Ssyrinx if (k_info->ifbr_ifsflags & IFBIF_BSTP_AUTOPTP) { 694165416Ssyrinx bp->admin_ptp = StpPortAdminPointToPointType_auto; 695165416Ssyrinx if (k_info->ifbr_ifsflags & IFBIF_BSTP_PTP) 696165416Ssyrinx bp->oper_ptp = TruthValue_true; 697164997Ssyrinx else 698165416Ssyrinx bp->oper_ptp = TruthValue_false; 699165416Ssyrinx } else if (k_info->ifbr_ifsflags & IFBIF_BSTP_PTP) { 700165416Ssyrinx bp->admin_ptp = StpPortAdminPointToPointType_forceTrue; 701165416Ssyrinx bp->oper_ptp = TruthValue_true; 702164997Ssyrinx } else { 703165416Ssyrinx bp->admin_ptp = StpPortAdminPointToPointType_forceFalse; 704165416Ssyrinx bp->oper_ptp = TruthValue_false; 705164997Ssyrinx } 706164410Ssyrinx} 707164410Ssyrinx 708164410Ssyrinx/* 709164410Ssyrinx * Fill in a bridge interface STP information according to 710164410Ssyrinx * data polled from kernel. 711164410Ssyrinx */ 712164410Ssyrinxstatic void 713164410Ssyrinxbridge_port_getinfo_opstp(struct ifbpstpreq *bp_stp, struct bridge_port *bp) 714164410Ssyrinx{ 715164410Ssyrinx bp->enable = dot1dStpPortEnable_enabled; 716164410Ssyrinx bp->fwd_trans = bp_stp->ifbp_fwd_trans; 717164410Ssyrinx bp->design_cost = bp_stp->ifbp_design_cost; 718164410Ssyrinx snmp_uint64_to_bridgeid(bp_stp->ifbp_design_root, bp->design_root); 719164410Ssyrinx snmp_uint64_to_bridgeid(bp_stp->ifbp_design_bridge, bp->design_bridge); 720164410Ssyrinx bcopy(&(bp_stp->ifbp_design_port), &(bp->design_port), 721164410Ssyrinx sizeof(uint16_t)); 722164410Ssyrinx} 723164410Ssyrinx 724164410Ssyrinx/* 725164410Ssyrinx * Clear a bridge interface STP information. 726164410Ssyrinx */ 727164410Ssyrinxstatic void 728164410Ssyrinxbridge_port_clearinfo_opstp(struct bridge_port *bp) 729164410Ssyrinx{ 730164410Ssyrinx if (bp->enable == dot1dStpPortEnable_enabled) { 731164410Ssyrinx bp->design_cost = 0; 732164410Ssyrinx bzero(&(bp->design_root), sizeof(bridge_id)); 733164410Ssyrinx bzero(&(bp->design_bridge), sizeof(bridge_id)); 734164410Ssyrinx bzero(&(bp->design_port), sizeof(port_id)); 735164410Ssyrinx bp->fwd_trans = 0; 736164410Ssyrinx } 737164410Ssyrinx 738164410Ssyrinx bp->enable = dot1dStpPortEnable_disabled; 739164410Ssyrinx} 740164410Ssyrinx 741164410Ssyrinx/* 742164410Ssyrinx * Set a bridge member priority. 743164410Ssyrinx */ 744164410Ssyrinxint 745164410Ssyrinxbridge_port_set_priority(const char *bif_name, struct bridge_port *bp, 746164410Ssyrinx int32_t priority) 747164410Ssyrinx{ 748164410Ssyrinx struct ifdrv ifd; 749164410Ssyrinx struct ifbreq b_req; 750164410Ssyrinx 751164410Ssyrinx strlcpy(ifd.ifd_name, bif_name, sizeof(ifd.ifd_name)); 752164410Ssyrinx ifd.ifd_len = sizeof(b_req); 753164410Ssyrinx ifd.ifd_data = &b_req; 754164410Ssyrinx strlcpy(b_req.ifbr_ifsname, bp->p_name, sizeof(b_req.ifbr_ifsname)); 755164410Ssyrinx 756164410Ssyrinx b_req.ifbr_priority = (uint8_t) priority; 757164410Ssyrinx ifd.ifd_cmd = BRDGSIFPRIO; 758164410Ssyrinx 759164410Ssyrinx if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) { 760164410Ssyrinx syslog(LOG_ERR, "set member %s param: ioctl(BRDGSIFPRIO) " 761164410Ssyrinx "failed: %s", bp->p_name, strerror(errno)); 762164410Ssyrinx return (-1); 763164410Ssyrinx } 764164410Ssyrinx 765164410Ssyrinx bp->priority = priority; 766164410Ssyrinx return (0); 767164410Ssyrinx} 768164410Ssyrinx 769164410Ssyrinx/* 770164410Ssyrinx * Set a bridge member STP-enabled flag. 771164410Ssyrinx */ 772164410Ssyrinxint 773164410Ssyrinxbridge_port_set_stp_enable(const char *bif_name, struct bridge_port *bp, 774164410Ssyrinx uint32_t enable) 775164410Ssyrinx{ 776164410Ssyrinx struct ifdrv ifd; 777164410Ssyrinx struct ifbreq b_req; 778164410Ssyrinx 779164410Ssyrinx if (bp->enable == enable) 780164410Ssyrinx return (0); 781164410Ssyrinx 782164410Ssyrinx bzero(&b_req, sizeof(b_req)); 783164410Ssyrinx strlcpy(ifd.ifd_name, bif_name, sizeof(ifd.ifd_name)); 784164410Ssyrinx ifd.ifd_len = sizeof(b_req); 785164410Ssyrinx ifd.ifd_data = &b_req; 786164410Ssyrinx strlcpy(b_req.ifbr_ifsname, bp->p_name, sizeof(b_req.ifbr_ifsname)); 787164410Ssyrinx ifd.ifd_cmd = BRDGGIFFLGS; 788164410Ssyrinx 789164410Ssyrinx if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) { 790164410Ssyrinx syslog(LOG_ERR, "get member %s param: ioctl(BRDGGIFFLGS) " 791164410Ssyrinx "failed: %s", bp->p_name, strerror(errno)); 792164410Ssyrinx return (-1); 793164410Ssyrinx } 794164410Ssyrinx 795164410Ssyrinx if (enable == dot1dStpPortEnable_enabled) 796164410Ssyrinx b_req.ifbr_ifsflags |= IFBIF_STP; 797164410Ssyrinx else 798164410Ssyrinx b_req.ifbr_ifsflags &= ~IFBIF_STP; 799164410Ssyrinx 800164410Ssyrinx ifd.ifd_cmd = BRDGSIFFLGS; 801164410Ssyrinx if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) { 802164410Ssyrinx syslog(LOG_ERR, "set member %s param: ioctl(BRDGSIFFLGS) " 803164410Ssyrinx "failed: %s", bp->p_name, strerror(errno)); 804164410Ssyrinx return (-1); 805164410Ssyrinx } 806164410Ssyrinx 807164410Ssyrinx bp->enable = enable; 808164410Ssyrinx return (0); 809164410Ssyrinx} 810164410Ssyrinx 811164410Ssyrinx/* 812164410Ssyrinx * Set a bridge member STP path cost. 813164410Ssyrinx */ 814164410Ssyrinxint 815164410Ssyrinxbridge_port_set_path_cost(const char *bif_name, struct bridge_port *bp, 816164410Ssyrinx int32_t path_cost) 817164410Ssyrinx{ 818164410Ssyrinx struct ifdrv ifd; 819164410Ssyrinx struct ifbreq b_req; 820164410Ssyrinx 821164997Ssyrinx if (path_cost < SNMP_PORT_MIN_PATHCOST || 822164997Ssyrinx path_cost > SNMP_PORT_PATHCOST_OBSOLETE) 823164997Ssyrinx return (-2); 824164410Ssyrinx 825164410Ssyrinx strlcpy(ifd.ifd_name, bif_name, sizeof(ifd.ifd_name)); 826164410Ssyrinx ifd.ifd_len = sizeof(b_req); 827164410Ssyrinx ifd.ifd_data = &b_req; 828164410Ssyrinx strlcpy(b_req.ifbr_ifsname, bp->p_name, sizeof(b_req.ifbr_ifsname)); 829164410Ssyrinx 830164997Ssyrinx b_req.ifbr_path_cost = path_cost; 831164410Ssyrinx ifd.ifd_cmd = BRDGSIFCOST; 832164410Ssyrinx 833164410Ssyrinx if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) { 834164410Ssyrinx syslog(LOG_ERR, "set member %s param: ioctl(BRDGSIFCOST) " 835164410Ssyrinx "failed: %s", bp->p_name, strerror(errno)); 836164410Ssyrinx return (-1); 837164410Ssyrinx } 838164410Ssyrinx 839164997Ssyrinx bp->admin_path_cost = path_cost; 840164997Ssyrinx 841164410Ssyrinx return (0); 842164410Ssyrinx} 843164410Ssyrinx 844164410Ssyrinx/* 845164997Ssyrinx * Set the PonitToPoint status of the link administratively. 846164997Ssyrinx */ 847164997Ssyrinxint 848171791Ssyrinxbridge_port_set_admin_ptp(const char *bif_name, struct bridge_port *bp, 849171791Ssyrinx uint32_t admin_ptp) 850164997Ssyrinx{ 851164997Ssyrinx struct ifdrv ifd; 852164997Ssyrinx struct ifbreq b_req; 853164997Ssyrinx 854165416Ssyrinx if (bp->admin_ptp == admin_ptp) 855164997Ssyrinx return (0); 856164997Ssyrinx 857164997Ssyrinx bzero(&b_req, sizeof(b_req)); 858164997Ssyrinx strlcpy(ifd.ifd_name, bif_name, sizeof(ifd.ifd_name)); 859164997Ssyrinx ifd.ifd_len = sizeof(b_req); 860164997Ssyrinx ifd.ifd_data = &b_req; 861164997Ssyrinx strlcpy(b_req.ifbr_ifsname, bp->p_name, sizeof(b_req.ifbr_ifsname)); 862164997Ssyrinx ifd.ifd_cmd = BRDGGIFFLGS; 863164997Ssyrinx 864164997Ssyrinx if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) { 865164997Ssyrinx syslog(LOG_ERR, "get member %s param: ioctl(BRDGGIFFLGS) " 866164997Ssyrinx "failed: %s", bp->p_name, strerror(errno)); 867164997Ssyrinx return (-1); 868164997Ssyrinx } 869164997Ssyrinx 870165416Ssyrinx switch (admin_ptp) { 871164997Ssyrinx case StpPortAdminPointToPointType_forceTrue: 872165416Ssyrinx b_req.ifbr_ifsflags &= ~IFBIF_BSTP_AUTOPTP; 873165416Ssyrinx b_req.ifbr_ifsflags |= IFBIF_BSTP_PTP; 874164997Ssyrinx break; 875164997Ssyrinx case StpPortAdminPointToPointType_forceFalse: 876165416Ssyrinx b_req.ifbr_ifsflags &= ~IFBIF_BSTP_AUTOPTP; 877165416Ssyrinx b_req.ifbr_ifsflags &= ~IFBIF_BSTP_PTP; 878164997Ssyrinx break; 879164997Ssyrinx case StpPortAdminPointToPointType_auto: 880165416Ssyrinx b_req.ifbr_ifsflags |= IFBIF_BSTP_AUTOPTP; 881164997Ssyrinx break; 882164997Ssyrinx } 883164997Ssyrinx 884164997Ssyrinx ifd.ifd_cmd = BRDGSIFFLGS; 885164997Ssyrinx if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) { 886164997Ssyrinx syslog(LOG_ERR, "set member %s param: ioctl(BRDGSIFFLGS) " 887164997Ssyrinx "failed: %s", bp->p_name, strerror(errno)); 888164997Ssyrinx return (-1); 889164997Ssyrinx } 890164997Ssyrinx 891165416Ssyrinx bp->admin_ptp = admin_ptp; 892164997Ssyrinx return (0); 893164997Ssyrinx} 894164997Ssyrinx 895164997Ssyrinx/* 896164997Ssyrinx * Set admin edge. 897164997Ssyrinx */ 898164997Ssyrinxint 899171791Ssyrinxbridge_port_set_admin_edge(const char *bif_name, struct bridge_port *bp, 900171791Ssyrinx uint32_t enable) 901164997Ssyrinx{ 902164997Ssyrinx struct ifdrv ifd; 903164997Ssyrinx struct ifbreq b_req; 904164997Ssyrinx 905164997Ssyrinx if (bp->admin_edge == enable) 906164997Ssyrinx return (0); 907164997Ssyrinx 908164997Ssyrinx bzero(&b_req, sizeof(b_req)); 909164997Ssyrinx strlcpy(ifd.ifd_name, bif_name, sizeof(ifd.ifd_name)); 910164997Ssyrinx ifd.ifd_len = sizeof(b_req); 911164997Ssyrinx ifd.ifd_data = &b_req; 912164997Ssyrinx strlcpy(b_req.ifbr_ifsname, bp->p_name, sizeof(b_req.ifbr_ifsname)); 913164997Ssyrinx ifd.ifd_cmd = BRDGGIFFLGS; 914164997Ssyrinx 915164997Ssyrinx if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) { 916164997Ssyrinx syslog(LOG_ERR, "get member %s param: ioctl(BRDGGIFFLGS) " 917164997Ssyrinx "failed: %s", bp->p_name, strerror(errno)); 918164997Ssyrinx return (-1); 919164997Ssyrinx } 920164997Ssyrinx 921164997Ssyrinx if (enable == TruthValue_true) { 922164997Ssyrinx b_req.ifbr_ifsflags &= ~IFBIF_BSTP_AUTOEDGE; 923164997Ssyrinx b_req.ifbr_ifsflags |= IFBIF_BSTP_EDGE; 924164997Ssyrinx } else 925164997Ssyrinx b_req.ifbr_ifsflags &= ~IFBIF_BSTP_EDGE; 926164997Ssyrinx 927164997Ssyrinx ifd.ifd_cmd = BRDGSIFFLGS; 928164997Ssyrinx if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) { 929164997Ssyrinx syslog(LOG_ERR, "set member %s param: ioctl(BRDGSIFFLGS) " 930164997Ssyrinx "failed: %s", bp->p_name, strerror(errno)); 931164997Ssyrinx return (-1); 932164997Ssyrinx } 933164997Ssyrinx 934164997Ssyrinx bp->admin_edge = enable; 935166493Ssyrinx 936164997Ssyrinx return (0); 937164997Ssyrinx} 938164997Ssyrinx 939164997Ssyrinx/* 940171791Ssyrinx * Set 'private' flag. 941171791Ssyrinx */ 942171791Ssyrinxint 943171791Ssyrinxbridge_port_set_private(const char *bif_name, struct bridge_port *bp, 944171791Ssyrinx uint32_t priv_set) 945171791Ssyrinx{ 946171791Ssyrinx struct ifdrv ifd; 947171791Ssyrinx struct ifbreq b_req; 948171791Ssyrinx 949171791Ssyrinx if (bp->priv_set == priv_set) 950171791Ssyrinx return (0); 951171791Ssyrinx 952171791Ssyrinx bzero(&b_req, sizeof(b_req)); 953171791Ssyrinx strlcpy(ifd.ifd_name, bif_name, sizeof(ifd.ifd_name)); 954171791Ssyrinx ifd.ifd_len = sizeof(b_req); 955171791Ssyrinx ifd.ifd_data = &b_req; 956171791Ssyrinx strlcpy(b_req.ifbr_ifsname, bp->p_name, sizeof(b_req.ifbr_ifsname)); 957171791Ssyrinx ifd.ifd_cmd = BRDGGIFFLGS; 958171791Ssyrinx 959171791Ssyrinx if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) { 960171791Ssyrinx syslog(LOG_ERR, "get member %s param: ioctl(BRDGGIFFLGS) " 961171791Ssyrinx "failed: %s", bp->p_name, strerror(errno)); 962171791Ssyrinx return (-1); 963171791Ssyrinx } 964171791Ssyrinx 965171791Ssyrinx if (priv_set == TruthValue_true) 966171791Ssyrinx b_req.ifbr_ifsflags |= IFBIF_PRIVATE; 967171791Ssyrinx else if (priv_set == TruthValue_false) 968171791Ssyrinx b_req.ifbr_ifsflags &= ~IFBIF_PRIVATE; 969171791Ssyrinx else 970171791Ssyrinx return (SNMP_ERR_WRONG_VALUE); 971171791Ssyrinx 972171791Ssyrinx ifd.ifd_cmd = BRDGSIFFLGS; 973171791Ssyrinx if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) { 974171791Ssyrinx syslog(LOG_ERR, "set member %s param: ioctl(BRDGSIFFLGS) " 975171791Ssyrinx "failed: %s", bp->p_name, strerror(errno)); 976171791Ssyrinx return (-1); 977171791Ssyrinx } 978171791Ssyrinx 979171791Ssyrinx bp->priv_set = priv_set; 980171791Ssyrinx 981171791Ssyrinx return (0); 982171791Ssyrinx} 983171791Ssyrinx 984171791Ssyrinx 985171791Ssyrinx/* 986164410Ssyrinx * Add a bridge member port. 987164410Ssyrinx */ 988164410Ssyrinxint 989164410Ssyrinxbridge_port_addm(struct bridge_port *bp, const char *b_name) 990164410Ssyrinx{ 991164410Ssyrinx struct ifdrv ifd; 992164410Ssyrinx struct ifbreq b_req; 993164410Ssyrinx 994164410Ssyrinx bzero(&ifd, sizeof(ifd)); 995164410Ssyrinx bzero(&b_req, sizeof(b_req)); 996164410Ssyrinx 997164410Ssyrinx strlcpy(ifd.ifd_name, b_name, sizeof(ifd.ifd_name)); 998164410Ssyrinx ifd.ifd_len = sizeof(b_req); 999164410Ssyrinx ifd.ifd_data = &b_req; 1000164410Ssyrinx strlcpy(b_req.ifbr_ifsname, bp->p_name, sizeof(b_req.ifbr_ifsname)); 1001164410Ssyrinx 1002164410Ssyrinx if (bp->span_enable == begemotBridgeBaseSpanEnabled_enabled) 1003164410Ssyrinx ifd.ifd_cmd = BRDGADDS; 1004164410Ssyrinx else 1005164410Ssyrinx ifd.ifd_cmd = BRDGADD; 1006164410Ssyrinx 1007164410Ssyrinx if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) { 1008164410Ssyrinx syslog(LOG_ERR, "%s - add member : ioctl(%s) failed: %s", 1009164410Ssyrinx bp->p_name, 1010164410Ssyrinx (ifd.ifd_cmd == BRDGADDS ? "BRDGADDS" : "BRDGADD"), 1011164410Ssyrinx strerror(errno)); 1012164410Ssyrinx return (-1); 1013164410Ssyrinx } 1014164410Ssyrinx 1015164410Ssyrinx return (0); 1016164410Ssyrinx} 1017164410Ssyrinx 1018164410Ssyrinx/* 1019164410Ssyrinx * Delete a bridge member port. 1020164410Ssyrinx */ 1021164410Ssyrinxint 1022164410Ssyrinxbridge_port_delm(struct bridge_port *bp, const char *b_name) 1023164410Ssyrinx{ 1024164410Ssyrinx struct ifdrv ifd; 1025164410Ssyrinx struct ifbreq b_req; 1026164410Ssyrinx 1027164410Ssyrinx bzero(&ifd, sizeof(ifd)); 1028164410Ssyrinx bzero(&b_req, sizeof(b_req)); 1029164410Ssyrinx 1030164410Ssyrinx strlcpy(ifd.ifd_name, b_name, sizeof(ifd.ifd_name)); 1031164410Ssyrinx ifd.ifd_len = sizeof(b_req); 1032164410Ssyrinx ifd.ifd_data = &b_req; 1033164410Ssyrinx strlcpy(b_req.ifbr_ifsname, bp->p_name, sizeof(b_req.ifbr_ifsname)); 1034164410Ssyrinx 1035164410Ssyrinx if (bp->span_enable == begemotBridgeBaseSpanEnabled_enabled) 1036164410Ssyrinx ifd.ifd_cmd = BRDGDELS; 1037164410Ssyrinx else 1038164410Ssyrinx ifd.ifd_cmd = BRDGDEL; 1039164410Ssyrinx 1040164410Ssyrinx if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) { 1041164410Ssyrinx syslog(LOG_ERR, "%s - add member : ioctl(%s) failed: %s", 1042164410Ssyrinx bp->p_name, 1043164410Ssyrinx (ifd.ifd_cmd == BRDGDELS ? "BRDGDELS" : "BRDGDEL"), 1044164410Ssyrinx strerror(errno)); 1045164410Ssyrinx return (-1); 1046164410Ssyrinx } 1047164410Ssyrinx 1048164410Ssyrinx return (0); 1049164410Ssyrinx} 1050164410Ssyrinx 1051164410Ssyrinx/* 1052164410Ssyrinx * Fetch the bridge member list from kernel. 1053164410Ssyrinx * Return -1 on error, or buffer len if successful. 1054164410Ssyrinx */ 1055164410Ssyrinxstatic int32_t 1056165642Sbzbridge_port_get_iflist(struct bridge_if *bif, struct ifbreq **buf) 1057164410Ssyrinx{ 1058165642Sbz int n = 128; 1059165642Sbz uint32_t len; 1060165642Sbz struct ifbreq *ninbuf; 1061164410Ssyrinx struct ifbifconf ifbc; 1062164410Ssyrinx struct ifdrv ifd; 1063164410Ssyrinx 1064164410Ssyrinx *buf = NULL; 1065164410Ssyrinx strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ); 1066164410Ssyrinx ifd.ifd_cmd = BRDGGIFS; 1067164410Ssyrinx ifd.ifd_len = sizeof(ifbc); 1068164410Ssyrinx ifd.ifd_data = &ifbc; 1069164410Ssyrinx 1070164410Ssyrinx for ( ; ; ) { 1071165642Sbz len = n * sizeof(struct ifbreq); 1072165642Sbz if ((ninbuf = (struct ifbreq *)realloc(*buf, len)) == NULL) { 1073164410Ssyrinx syslog(LOG_ERR, "get bridge member list: " 1074164410Ssyrinx "realloc failed: %s", strerror(errno)); 1075164410Ssyrinx free(*buf); 1076164410Ssyrinx *buf = NULL; 1077164410Ssyrinx return (-1); 1078164410Ssyrinx } 1079164410Ssyrinx 1080164410Ssyrinx ifbc.ifbic_len = len; 1081165642Sbz ifbc.ifbic_req = *buf = ninbuf; 1082164410Ssyrinx 1083164410Ssyrinx if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) { 1084164410Ssyrinx syslog(LOG_ERR, "get bridge member list: ioctl " 1085164410Ssyrinx "(BRDGGIFS) failed: %s", strerror(errno)); 1086164410Ssyrinx free(*buf); 1087164410Ssyrinx buf = NULL; 1088164410Ssyrinx return (-1); 1089164410Ssyrinx } 1090164410Ssyrinx 1091164410Ssyrinx if ((ifbc.ifbic_len + sizeof(struct ifbreq)) < len) 1092164410Ssyrinx break; 1093164410Ssyrinx 1094165642Sbz n += 64; 1095164410Ssyrinx } 1096164410Ssyrinx 1097164410Ssyrinx return (ifbc.ifbic_len); 1098164410Ssyrinx} 1099164410Ssyrinx 1100164410Ssyrinx/* 1101164410Ssyrinx * Fetch the bridge STP member list from kernel. 1102164410Ssyrinx * Return -1 on error, or buffer len if successful. 1103164410Ssyrinx */ 1104164410Ssyrinxstatic int32_t 1105165642Sbzbridge_port_get_ifstplist(struct bridge_if *bif, struct ifbpstpreq **buf) 1106164410Ssyrinx{ 1107165642Sbz int n = 128; 1108165642Sbz uint32_t len; 1109165642Sbz struct ifbpstpreq *ninbuf; 1110164410Ssyrinx struct ifbpstpconf ifbstp; 1111164410Ssyrinx struct ifdrv ifd; 1112164410Ssyrinx 1113164997Ssyrinx *buf = NULL; 1114164410Ssyrinx strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ); 1115164410Ssyrinx ifd.ifd_cmd = BRDGGIFSSTP; 1116164410Ssyrinx ifd.ifd_len = sizeof(ifbstp); 1117164410Ssyrinx ifd.ifd_data = &ifbstp; 1118164410Ssyrinx 1119164410Ssyrinx for ( ; ; ) { 1120165642Sbz len = n * sizeof(struct ifbpstpreq); 1121165642Sbz if ((ninbuf = (struct ifbpstpreq *) 1122165642Sbz realloc(*buf, len)) == NULL) { 1123164410Ssyrinx syslog(LOG_ERR, "get bridge STP ports list: " 1124164410Ssyrinx "realloc failed: %s", strerror(errno)); 1125164410Ssyrinx free(*buf); 1126164410Ssyrinx *buf = NULL; 1127164410Ssyrinx return (-1); 1128164410Ssyrinx } 1129164410Ssyrinx 1130164410Ssyrinx ifbstp.ifbpstp_len = len; 1131165642Sbz ifbstp.ifbpstp_req = *buf = ninbuf; 1132164410Ssyrinx 1133164410Ssyrinx if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) { 1134164410Ssyrinx syslog(LOG_ERR, "get bridge STP ports list: ioctl " 1135164410Ssyrinx "(BRDGGIFSSTP) failed: %s", strerror(errno)); 1136164410Ssyrinx free(*buf); 1137164410Ssyrinx buf = NULL; 1138164410Ssyrinx return (-1); 1139164410Ssyrinx } 1140164410Ssyrinx 1141164410Ssyrinx if ((ifbstp.ifbpstp_len + sizeof(struct ifbpstpreq)) < len) 1142164410Ssyrinx break; 1143164410Ssyrinx 1144165642Sbz n += 64; 1145164410Ssyrinx } 1146164410Ssyrinx 1147164410Ssyrinx return (ifbstp.ifbpstp_len); 1148164410Ssyrinx} 1149164410Ssyrinx 1150164410Ssyrinx/* 1151164410Ssyrinx * Locate a bridge if STP params structure in a buffer. 1152164410Ssyrinx */ 1153164410Ssyrinxstatic struct ifbpstpreq * 1154165642Sbzbridge_port_find_ifstplist(uint8_t port_no, struct ifbpstpreq *buf, 1155165642Sbz uint32_t buf_len) 1156164410Ssyrinx{ 1157164410Ssyrinx uint32_t i; 1158164410Ssyrinx struct ifbpstpreq *bstp; 1159164410Ssyrinx 1160165642Sbz for (i = 0; i < buf_len / sizeof(struct ifbpstpreq); i++) { 1161165642Sbz bstp = buf + i; 1162164410Ssyrinx if (bstp->ifbp_portno == port_no) 1163164410Ssyrinx return (bstp); 1164164410Ssyrinx } 1165164410Ssyrinx 1166164410Ssyrinx return (NULL); 1167164410Ssyrinx} 1168164410Ssyrinx 1169164410Ssyrinx/* 1170164410Ssyrinx * Read the initial info for all members of a bridge interface. 1171164410Ssyrinx * Returns the number of ports, 0 - if none, otherwise 1172228990Suqs * -1 if some other error occurred. 1173164410Ssyrinx */ 1174164410Ssyrinxint 1175164410Ssyrinxbridge_getinfo_bif_ports(struct bridge_if *bif) 1176164410Ssyrinx{ 1177164410Ssyrinx uint32_t i; 1178164410Ssyrinx int32_t buf_len; 1179165642Sbz struct ifbreq *b_req_buf, *b_req; 1180165642Sbz struct ifbpstpreq *bs_req_buf, *bs_req; 1181164410Ssyrinx struct bridge_port *bp; 1182164410Ssyrinx struct mibif *m_if; 1183164410Ssyrinx 1184165642Sbz if ((buf_len = bridge_port_get_iflist(bif, &b_req_buf)) < 0) 1185164410Ssyrinx return (-1); 1186164410Ssyrinx 1187164410Ssyrinx for (i = 0; i < buf_len / sizeof(struct ifbreq); i++) { 1188165642Sbz b_req = b_req_buf + i; 1189164410Ssyrinx 1190164410Ssyrinx if ((m_if = mib_find_if_sys(b_req->ifbr_portno)) != NULL) { 1191164410Ssyrinx /* Hopefully we will not fail here. */ 1192164410Ssyrinx if ((bp = bridge_new_port(m_if, bif)) != NULL) { 1193164410Ssyrinx bp->status = RowStatus_active; 1194164410Ssyrinx bridge_port_getinfo_conf(b_req, bp); 1195164410Ssyrinx bridge_port_getinfo_mibif(m_if, bp); 1196164410Ssyrinx } 1197164410Ssyrinx } else { 1198164410Ssyrinx syslog(LOG_ERR, "bridge member %s not present " 1199164410Ssyrinx "in mibII ifTable", b_req->ifbr_ifsname); 1200164410Ssyrinx } 1201164410Ssyrinx } 1202165642Sbz free(b_req_buf); 1203164410Ssyrinx 1204165642Sbz if ((buf_len = bridge_port_get_ifstplist(bif, &bs_req_buf)) < 0) 1205164410Ssyrinx return (-1); 1206164410Ssyrinx 1207164410Ssyrinx for (bp = bridge_port_bif_first(bif); bp != NULL; 1208164410Ssyrinx bp = bridge_port_bif_next(bp)) { 1209164410Ssyrinx if ((bs_req = bridge_port_find_ifstplist(bp->port_no, 1210165642Sbz bs_req_buf, buf_len)) == NULL) 1211164410Ssyrinx bridge_port_clearinfo_opstp(bp); 1212164410Ssyrinx else 1213164410Ssyrinx bridge_port_getinfo_opstp(bs_req, bp); 1214164410Ssyrinx } 1215165642Sbz free(bs_req_buf); 1216164410Ssyrinx 1217164410Ssyrinx return (i); 1218164410Ssyrinx} 1219164410Ssyrinx 1220164410Ssyrinx/* 1221164410Ssyrinx * Update the information for the bridge interface members. 1222164410Ssyrinx */ 1223164410Ssyrinxint 1224164410Ssyrinxbridge_update_memif(struct bridge_if *bif) 1225164410Ssyrinx{ 1226164410Ssyrinx int added, updated; 1227164410Ssyrinx uint32_t i; 1228164410Ssyrinx int32_t buf_len; 1229165642Sbz struct ifbreq *b_req_buf, *b_req; 1230165642Sbz struct ifbpstpreq *bs_req_buf, *bs_req; 1231164410Ssyrinx struct bridge_port *bp, *bp_next; 1232164410Ssyrinx struct mibif *m_if; 1233164410Ssyrinx 1234165642Sbz if ((buf_len = bridge_port_get_iflist(bif, &b_req_buf)) < 0) 1235164410Ssyrinx return (-1); 1236164410Ssyrinx 1237164410Ssyrinx added = updated = 0; 1238164410Ssyrinx 1239164410Ssyrinx#define BP_FOUND 0x01 1240164410Ssyrinx for (i = 0; i < buf_len / sizeof(struct ifbreq); i++) { 1241165642Sbz b_req = b_req_buf + i; 1242164410Ssyrinx 1243164410Ssyrinx if ((m_if = mib_find_if_sys(b_req->ifbr_portno)) == NULL) { 1244164410Ssyrinx syslog(LOG_ERR, "bridge member %s not present " 1245164410Ssyrinx "in mibII ifTable", b_req->ifbr_ifsname); 1246164410Ssyrinx continue; 1247164410Ssyrinx } 1248164410Ssyrinx 1249164410Ssyrinx if ((bp = bridge_port_find(m_if->index, bif)) == NULL && 1250164410Ssyrinx (bp = bridge_new_port(m_if, bif)) != NULL) { 1251164410Ssyrinx bp->status = RowStatus_active; 1252164410Ssyrinx added++; 1253164410Ssyrinx } 1254164410Ssyrinx 1255164410Ssyrinx if (bp != NULL) { 1256164410Ssyrinx updated++; 1257164410Ssyrinx bridge_port_getinfo_conf(b_req, bp); 1258164410Ssyrinx bridge_port_getinfo_mibif(m_if, bp); 1259164410Ssyrinx bp->flags |= BP_FOUND; 1260164410Ssyrinx } 1261164410Ssyrinx } 1262165642Sbz free(b_req_buf); 1263164410Ssyrinx 1264164410Ssyrinx /* Clean up list. */ 1265164410Ssyrinx for (bp = bridge_port_bif_first(bif); bp != NULL; bp = bp_next) { 1266164410Ssyrinx bp_next = bridge_port_bif_next(bp); 1267164410Ssyrinx 1268164410Ssyrinx if ((bp->flags & BP_FOUND) == 0 && 1269164410Ssyrinx bp->status == RowStatus_active) 1270164410Ssyrinx bridge_port_remove(bp, bif); 1271164410Ssyrinx else 1272164410Ssyrinx bp->flags |= ~BP_FOUND; 1273164410Ssyrinx } 1274164410Ssyrinx#undef BP_FOUND 1275164410Ssyrinx 1276165642Sbz if ((buf_len = bridge_port_get_ifstplist(bif, &bs_req_buf)) < 0) 1277164410Ssyrinx return (-1); 1278164410Ssyrinx 1279164410Ssyrinx for (bp = bridge_port_bif_first(bif); bp != NULL; 1280164410Ssyrinx bp = bridge_port_bif_next(bp)) { 1281164410Ssyrinx if ((bs_req = bridge_port_find_ifstplist(bp->port_no, 1282165642Sbz bs_req_buf, buf_len)) == NULL) 1283164410Ssyrinx bridge_port_clearinfo_opstp(bp); 1284164410Ssyrinx else 1285164410Ssyrinx bridge_port_getinfo_opstp(bs_req, bp); 1286164410Ssyrinx } 1287165642Sbz free(bs_req_buf); 1288164410Ssyrinx bif->ports_age = time(NULL); 1289164410Ssyrinx 1290164410Ssyrinx return (updated); 1291164410Ssyrinx} 1292164410Ssyrinx 1293164410Ssyrinx/************************************************************************ 1294164410Ssyrinx * Bridge addresses. 1295164410Ssyrinx */ 1296164410Ssyrinx 1297164410Ssyrinx/* 1298164410Ssyrinx * Update the bridge address info according to the polled data. 1299164410Ssyrinx */ 1300164410Ssyrinxstatic void 1301164410Ssyrinxbridge_addrs_info_ifaddrlist(struct ifbareq *ifba, struct tp_entry *tpe) 1302164410Ssyrinx{ 1303164410Ssyrinx tpe->port_no = if_nametoindex(ifba->ifba_ifsname); 1304164410Ssyrinx 1305164410Ssyrinx if ((ifba->ifba_flags & IFBAF_TYPEMASK) == IFBAF_STATIC) 1306164410Ssyrinx tpe->status = TpFdbStatus_mgmt; 1307164410Ssyrinx else 1308164410Ssyrinx tpe->status = TpFdbStatus_learned; 1309164410Ssyrinx} 1310164410Ssyrinx 1311164410Ssyrinx/* 1312164410Ssyrinx * Read the bridge addresses from kernel. 1313164410Ssyrinx * Return -1 on error, or buffer len if successful. 1314164410Ssyrinx */ 1315164410Ssyrinxstatic int32_t 1316165642Sbzbridge_addrs_getinfo_ifalist(struct bridge_if *bif, struct ifbareq **buf) 1317164410Ssyrinx{ 1318165642Sbz int n = 128; 1319165642Sbz uint32_t len; 1320165642Sbz struct ifbareq *ninbuf; 1321164410Ssyrinx struct ifbaconf bac; 1322164410Ssyrinx struct ifdrv ifd; 1323164410Ssyrinx 1324310901Sngie *buf = NULL; 1325164410Ssyrinx strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ); 1326164410Ssyrinx ifd.ifd_cmd = BRDGRTS; 1327164410Ssyrinx ifd.ifd_len = sizeof(bac); 1328164410Ssyrinx ifd.ifd_data = &bac; 1329164410Ssyrinx 1330164410Ssyrinx for ( ; ; ) { 1331165642Sbz len = n * sizeof(struct ifbareq); 1332165642Sbz if ((ninbuf = (struct ifbareq *)realloc(*buf, len)) == NULL) { 1333164410Ssyrinx syslog(LOG_ERR, "get bridge address list: " 1334164410Ssyrinx " realloc failed: %s", strerror(errno)); 1335164410Ssyrinx free(*buf); 1336164410Ssyrinx *buf = NULL; 1337164410Ssyrinx return (-1); 1338164410Ssyrinx } 1339164410Ssyrinx 1340164410Ssyrinx bac.ifbac_len = len; 1341165642Sbz bac.ifbac_req = *buf = ninbuf; 1342164410Ssyrinx 1343164410Ssyrinx if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) { 1344164410Ssyrinx syslog(LOG_ERR, "get bridge address list: " 1345164410Ssyrinx "ioctl(BRDGRTS) failed: %s", strerror(errno)); 1346164410Ssyrinx free(*buf); 1347164410Ssyrinx buf = NULL; 1348164410Ssyrinx return (-1); 1349164410Ssyrinx } 1350164410Ssyrinx 1351164410Ssyrinx if ((bac.ifbac_len + sizeof(struct ifbareq)) < len) 1352164410Ssyrinx break; 1353164410Ssyrinx 1354165642Sbz n += 64; 1355164410Ssyrinx } 1356164410Ssyrinx 1357164410Ssyrinx return (bac.ifbac_len); 1358164410Ssyrinx} 1359164410Ssyrinx 1360164410Ssyrinx/* 1361164410Ssyrinx * Read the initial info for all addresses on a bridge interface. 1362164410Ssyrinx * Returns the number of addresses, 0 - if none, otherwise 1363228990Suqs * -1 if some other error occurred. 1364164410Ssyrinx */ 1365164410Ssyrinxint 1366164410Ssyrinxbridge_getinfo_bif_addrs(struct bridge_if *bif) 1367164410Ssyrinx{ 1368164410Ssyrinx uint32_t i; 1369164410Ssyrinx int32_t buf_len; 1370165642Sbz struct ifbareq *addr_req_buf, *addr_req; 1371164410Ssyrinx struct tp_entry *te; 1372164410Ssyrinx 1373165642Sbz if ((buf_len = bridge_addrs_getinfo_ifalist(bif, &addr_req_buf)) < 0) 1374164410Ssyrinx return (-1); 1375164410Ssyrinx 1376164410Ssyrinx for (i = 0; i < buf_len / sizeof(struct ifbareq); i++) { 1377165642Sbz addr_req = addr_req_buf + i; 1378164410Ssyrinx 1379164410Ssyrinx if ((te = bridge_new_addrs(addr_req->ifba_dst, bif)) != NULL) 1380164410Ssyrinx bridge_addrs_info_ifaddrlist(addr_req, te); 1381164410Ssyrinx } 1382164410Ssyrinx 1383165642Sbz free(addr_req_buf); 1384164410Ssyrinx return (i); 1385164410Ssyrinx} 1386164410Ssyrinx 1387164410Ssyrinx/* 1388164410Ssyrinx * Update the addresses for the bridge interface. 1389164410Ssyrinx */ 1390164410Ssyrinxint 1391164410Ssyrinxbridge_update_addrs(struct bridge_if *bif) 1392164410Ssyrinx{ 1393164410Ssyrinx int added, updated; 1394164410Ssyrinx uint32_t i; 1395164410Ssyrinx int32_t buf_len; 1396164410Ssyrinx struct tp_entry *te, *te_next; 1397165642Sbz struct ifbareq *addr_req_buf, *addr_req; 1398164410Ssyrinx 1399165642Sbz if ((buf_len = bridge_addrs_getinfo_ifalist(bif, &addr_req_buf)) < 0) 1400164410Ssyrinx return (-1); 1401164410Ssyrinx 1402164410Ssyrinx added = updated = 0; 1403164410Ssyrinx 1404164410Ssyrinx#define BA_FOUND 0x01 1405164410Ssyrinx for (i = 0; i < buf_len / sizeof(struct ifbareq); i++) { 1406165642Sbz addr_req = addr_req_buf + i; 1407164410Ssyrinx 1408165642Sbz if ((te = bridge_addrs_find(addr_req->ifba_dst, bif)) == NULL) { 1409164410Ssyrinx added++; 1410164410Ssyrinx 1411165642Sbz if ((te = bridge_new_addrs(addr_req->ifba_dst, bif)) 1412164410Ssyrinx == NULL) 1413164410Ssyrinx continue; 1414164410Ssyrinx } else 1415164410Ssyrinx updated++; 1416164410Ssyrinx 1417165642Sbz bridge_addrs_info_ifaddrlist(addr_req, te); 1418164410Ssyrinx te-> flags |= BA_FOUND; 1419164410Ssyrinx } 1420165642Sbz free(addr_req_buf); 1421164410Ssyrinx 1422164410Ssyrinx for (te = bridge_addrs_bif_first(bif); te != NULL; te = te_next) { 1423164410Ssyrinx te_next = bridge_addrs_bif_next(te); 1424164410Ssyrinx 1425164410Ssyrinx if ((te-> flags & BA_FOUND) == 0) 1426164410Ssyrinx bridge_addrs_remove(te, bif); 1427164410Ssyrinx else 1428164410Ssyrinx te-> flags &= ~BA_FOUND; 1429164410Ssyrinx } 1430164410Ssyrinx#undef BA_FOUND 1431164410Ssyrinx 1432164410Ssyrinx bif->addrs_age = time(NULL); 1433164410Ssyrinx return (updated + added); 1434164410Ssyrinx} 1435164410Ssyrinx 1436164410Ssyrinx/************************************************************************ 1437164410Ssyrinx * Bridge packet filtering. 1438164410Ssyrinx */ 1439164410Ssyrinxconst char bridge_sysctl[] = "net.link.bridge."; 1440164410Ssyrinx 1441164410Ssyrinxstatic struct { 1442164410Ssyrinx int32_t val; 1443164410Ssyrinx const char *name; 1444164410Ssyrinx} bridge_pf_sysctl[] = { 1445164410Ssyrinx { 1, "pfil_bridge" }, 1446164410Ssyrinx { 1, "pfil_member" }, 1447164410Ssyrinx { 1, "pfil_onlyip" }, 1448164410Ssyrinx { 0, "ipfw" }, 1449164410Ssyrinx}; 1450164410Ssyrinx 1451164410Ssyrinxint32_t 1452164410Ssyrinxbridge_get_pfval(uint8_t which) 1453164410Ssyrinx{ 1454311600Sngie 1455311600Sngie if (which > nitems(bridge_pf_sysctl) || which < 1) 1456164410Ssyrinx return (-1); 1457164410Ssyrinx 1458164410Ssyrinx return (bridge_pf_sysctl[which - 1].val); 1459164410Ssyrinx} 1460164410Ssyrinx 1461164410Ssyrinxint32_t 1462164410Ssyrinxbridge_do_pfctl(int32_t bridge_ctl, enum snmp_op op, int32_t *val) 1463164410Ssyrinx{ 1464312043Sngie char *mib_oid; 1465312043Sngie size_t len, s_len; 1466164410Ssyrinx int32_t i, s_i; 1467164410Ssyrinx 1468164410Ssyrinx if (bridge_ctl >= LEAF_begemotBridgeLayer2PfStatus) 1469164410Ssyrinx return (-2); 1470164410Ssyrinx 1471164410Ssyrinx if (op == SNMP_OP_SET) { 1472164410Ssyrinx s_i = *val; 1473164410Ssyrinx s_len = sizeof(s_i); 1474164410Ssyrinx } else 1475164410Ssyrinx s_len = 0; 1476164410Ssyrinx 1477310905Sngie len = sizeof(i); 1478164410Ssyrinx 1479312043Sngie asprintf(&mib_oid, "%s%s", bridge_sysctl, 1480312043Sngie bridge_pf_sysctl[bridge_ctl].name); 1481312043Sngie if (mib_oid == NULL) 1482312043Sngie return (-1); 1483164410Ssyrinx 1484312043Sngie if (sysctlbyname(mib_oid, &i, &len, (op == SNMP_OP_SET ? &s_i : NULL), 1485312043Sngie s_len) == -1) { 1486312043Sngie syslog(LOG_ERR, "sysctl(%s) failed - %s", mib_oid, 1487312043Sngie strerror(errno)); 1488312043Sngie free(mib_oid); 1489164410Ssyrinx return (-1); 1490164410Ssyrinx } 1491164410Ssyrinx 1492164410Ssyrinx bridge_pf_sysctl[bridge_ctl].val = i; 1493164410Ssyrinx *val = i; 1494164410Ssyrinx 1495312043Sngie free(mib_oid); 1496312043Sngie 1497164410Ssyrinx return (i); 1498164410Ssyrinx} 1499164410Ssyrinx 1500164410Ssyrinxvoid 1501164410Ssyrinxbridge_pf_dump(void) 1502164410Ssyrinx{ 1503164410Ssyrinx uint8_t i; 1504164410Ssyrinx 1505312043Sngie for (i = 0; i < nitems(bridge_pf_sysctl); i++) { 1506164410Ssyrinx syslog(LOG_ERR, "%s%s = %d", bridge_sysctl, 1507164410Ssyrinx bridge_pf_sysctl[i].name, bridge_pf_sysctl[i].val); 1508164410Ssyrinx } 1509164410Ssyrinx} 1510