1/*- 2 * SPDX-License-Identifier: BSD-4-Clause 3 * 4 * Copyright 2001 Wasabi Systems, Inc. 5 * All rights reserved. 6 * 7 * Written by Jason R. Thorpe for Wasabi Systems, Inc. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed for the NetBSD Project by 20 * Wasabi Systems, Inc. 21 * 4. The name of Wasabi Systems, Inc. may not be used to endorse 22 * or promote products derived from this software without specific prior 23 * written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 * POSSIBILITY OF SUCH DAMAGE. 36 */ 37 38#ifndef lint 39static const char rcsid[] = 40 "$FreeBSD$"; 41#endif /* not lint */ 42 43#include <sys/param.h> 44#include <sys/ioctl.h> 45#include <sys/socket.h> 46#include <sys/sockio.h> 47 48#include <stdlib.h> 49#include <unistd.h> 50 51#include <net/ethernet.h> 52#include <net/if.h> 53#include <net/if_bridgevar.h> 54#include <net/route.h> 55 56#include <ctype.h> 57#include <stdio.h> 58#include <string.h> 59#include <stdlib.h> 60#include <unistd.h> 61#include <err.h> 62#include <errno.h> 63 64#include <libifconfig.h> 65 66#include "ifconfig.h" 67 68static const char *stpstates[] = { STP_STATES }; 69static const char *stpproto[] = { STP_PROTOS }; 70static const char *stproles[] = { STP_ROLES }; 71 72static int 73get_val(const char *cp, u_long *valp) 74{ 75 char *endptr; 76 u_long val; 77 78 errno = 0; 79 val = strtoul(cp, &endptr, 0); 80 if (cp[0] == '\0' || endptr[0] != '\0' || errno == ERANGE) 81 return (-1); 82 83 *valp = val; 84 return (0); 85} 86 87static int 88do_cmd(int sock, u_long op, void *arg, size_t argsize, int set) 89{ 90 struct ifdrv ifd; 91 92 memset(&ifd, 0, sizeof(ifd)); 93 94 strlcpy(ifd.ifd_name, ifr.ifr_name, sizeof(ifd.ifd_name)); 95 ifd.ifd_cmd = op; 96 ifd.ifd_len = argsize; 97 ifd.ifd_data = arg; 98 99 return (ioctl(sock, set ? SIOCSDRVSPEC : SIOCGDRVSPEC, &ifd)); 100} 101 102static void 103do_bridgeflag(int sock, const char *ifs, int flag, int set) 104{ 105 struct ifbreq req; 106 107 strlcpy(req.ifbr_ifsname, ifs, sizeof(req.ifbr_ifsname)); 108 109 if (do_cmd(sock, BRDGGIFFLGS, &req, sizeof(req), 0) < 0) 110 err(1, "unable to get bridge flags"); 111 112 if (set) 113 req.ifbr_ifsflags |= flag; 114 else 115 req.ifbr_ifsflags &= ~flag; 116 117 if (do_cmd(sock, BRDGSIFFLGS, &req, sizeof(req), 1) < 0) 118 err(1, "unable to set bridge flags"); 119} 120 121static void 122bridge_addresses(int s, const char *prefix) 123{ 124 struct ifbaconf ifbac; 125 struct ifbareq *ifba; 126 char *inbuf = NULL, *ninbuf; 127 int i, len = 8192; 128 struct ether_addr ea; 129 130 for (;;) { 131 ninbuf = realloc(inbuf, len); 132 if (ninbuf == NULL) 133 err(1, "unable to allocate address buffer"); 134 ifbac.ifbac_len = len; 135 ifbac.ifbac_buf = inbuf = ninbuf; 136 if (do_cmd(s, BRDGRTS, &ifbac, sizeof(ifbac), 0) < 0) 137 err(1, "unable to get address cache"); 138 if ((ifbac.ifbac_len + sizeof(*ifba)) < len) 139 break; 140 len *= 2; 141 } 142 143 for (i = 0; i < ifbac.ifbac_len / sizeof(*ifba); i++) { 144 ifba = ifbac.ifbac_req + i; 145 memcpy(ea.octet, ifba->ifba_dst, 146 sizeof(ea.octet)); 147 printf("%s%s Vlan%d %s %lu ", prefix, ether_ntoa(&ea), 148 ifba->ifba_vlan, ifba->ifba_ifsname, ifba->ifba_expire); 149 printb("flags", ifba->ifba_flags, IFBAFBITS); 150 printf("\n"); 151 } 152 153 free(inbuf); 154} 155 156static void 157bridge_status(int s) 158{ 159 struct ifconfig_bridge_status *bridge; 160 struct ifbropreq *params; 161 const char *pad, *prefix; 162 uint8_t lladdr[ETHER_ADDR_LEN]; 163 uint16_t bprio; 164 165 if (ifconfig_bridge_get_bridge_status(lifh, name, &bridge) == -1) 166 return; 167 168 params = bridge->params; 169 170 PV2ID(params->ifbop_bridgeid, bprio, lladdr); 171 printf("\tid %s priority %u hellotime %u fwddelay %u\n", 172 ether_ntoa((struct ether_addr *)lladdr), 173 params->ifbop_priority, 174 params->ifbop_hellotime, 175 params->ifbop_fwddelay); 176 printf("\tmaxage %u holdcnt %u proto %s maxaddr %u timeout %u\n", 177 params->ifbop_maxage, 178 params->ifbop_holdcount, 179 stpproto[params->ifbop_protocol], 180 bridge->cache_size, 181 bridge->cache_lifetime); 182 PV2ID(params->ifbop_designated_root, bprio, lladdr); 183 printf("\troot id %s priority %d ifcost %u port %u\n", 184 ether_ntoa((struct ether_addr *)lladdr), 185 bprio, 186 params->ifbop_root_path_cost, 187 params->ifbop_root_port & 0xfff); 188 189 prefix = "\tmember: "; 190 pad = "\t "; 191 for (size_t i = 0; i < bridge->members_count; ++i) { 192 struct ifbreq *member = &bridge->members[i]; 193 194 printf("%s%s ", prefix, member->ifbr_ifsname); 195 printb("flags", member->ifbr_ifsflags, IFBIFBITS); 196 printf("\n%s", pad); 197 printf("ifmaxaddr %u port %u priority %u path cost %u", 198 member->ifbr_addrmax, 199 member->ifbr_portno, 200 member->ifbr_priority, 201 member->ifbr_path_cost); 202 if (member->ifbr_ifsflags & IFBIF_STP) { 203 uint8_t proto = member->ifbr_proto; 204 uint8_t role = member->ifbr_role; 205 uint8_t state = member->ifbr_state; 206 207 if (proto < nitems(stpproto)) 208 printf(" proto %s", stpproto[proto]); 209 else 210 printf(" <unknown proto %d>", proto); 211 printf("\n%s", pad); 212 if (role < nitems(stproles)) 213 printf("role %s", stproles[role]); 214 else 215 printf("<unknown role %d>", role); 216 if (state < nitems(stpstates)) 217 printf(" state %s", stpstates[state]); 218 else 219 printf(" <unknown state %d>", state); 220 } 221 printf("\n"); 222 } 223 224 ifconfig_bridge_free_bridge_status(bridge); 225} 226 227static void 228setbridge_add(const char *val, int d, int s, const struct afswtch *afp) 229{ 230 struct ifbreq req; 231 232 memset(&req, 0, sizeof(req)); 233 strlcpy(req.ifbr_ifsname, val, sizeof(req.ifbr_ifsname)); 234 if (do_cmd(s, BRDGADD, &req, sizeof(req), 1) < 0) 235 err(1, "BRDGADD %s", val); 236} 237 238static void 239setbridge_delete(const char *val, int d, int s, const struct afswtch *afp) 240{ 241 struct ifbreq req; 242 243 memset(&req, 0, sizeof(req)); 244 strlcpy(req.ifbr_ifsname, val, sizeof(req.ifbr_ifsname)); 245 if (do_cmd(s, BRDGDEL, &req, sizeof(req), 1) < 0) 246 err(1, "BRDGDEL %s", val); 247} 248 249static void 250setbridge_discover(const char *val, int d, int s, const struct afswtch *afp) 251{ 252 253 do_bridgeflag(s, val, IFBIF_DISCOVER, 1); 254} 255 256static void 257unsetbridge_discover(const char *val, int d, int s, const struct afswtch *afp) 258{ 259 260 do_bridgeflag(s, val, IFBIF_DISCOVER, 0); 261} 262 263static void 264setbridge_learn(const char *val, int d, int s, const struct afswtch *afp) 265{ 266 267 do_bridgeflag(s, val, IFBIF_LEARNING, 1); 268} 269 270static void 271unsetbridge_learn(const char *val, int d, int s, const struct afswtch *afp) 272{ 273 274 do_bridgeflag(s, val, IFBIF_LEARNING, 0); 275} 276 277static void 278setbridge_sticky(const char *val, int d, int s, const struct afswtch *afp) 279{ 280 281 do_bridgeflag(s, val, IFBIF_STICKY, 1); 282} 283 284static void 285unsetbridge_sticky(const char *val, int d, int s, const struct afswtch *afp) 286{ 287 288 do_bridgeflag(s, val, IFBIF_STICKY, 0); 289} 290 291static void 292setbridge_span(const char *val, int d, int s, const struct afswtch *afp) 293{ 294 struct ifbreq req; 295 296 memset(&req, 0, sizeof(req)); 297 strlcpy(req.ifbr_ifsname, val, sizeof(req.ifbr_ifsname)); 298 if (do_cmd(s, BRDGADDS, &req, sizeof(req), 1) < 0) 299 err(1, "BRDGADDS %s", val); 300} 301 302static void 303unsetbridge_span(const char *val, int d, int s, const struct afswtch *afp) 304{ 305 struct ifbreq req; 306 307 memset(&req, 0, sizeof(req)); 308 strlcpy(req.ifbr_ifsname, val, sizeof(req.ifbr_ifsname)); 309 if (do_cmd(s, BRDGDELS, &req, sizeof(req), 1) < 0) 310 err(1, "BRDGDELS %s", val); 311} 312 313static void 314setbridge_stp(const char *val, int d, int s, const struct afswtch *afp) 315{ 316 317 do_bridgeflag(s, val, IFBIF_STP, 1); 318} 319 320static void 321unsetbridge_stp(const char *val, int d, int s, const struct afswtch *afp) 322{ 323 324 do_bridgeflag(s, val, IFBIF_STP, 0); 325} 326 327static void 328setbridge_edge(const char *val, int d, int s, const struct afswtch *afp) 329{ 330 do_bridgeflag(s, val, IFBIF_BSTP_EDGE, 1); 331} 332 333static void 334unsetbridge_edge(const char *val, int d, int s, const struct afswtch *afp) 335{ 336 do_bridgeflag(s, val, IFBIF_BSTP_EDGE, 0); 337} 338 339static void 340setbridge_autoedge(const char *val, int d, int s, const struct afswtch *afp) 341{ 342 do_bridgeflag(s, val, IFBIF_BSTP_AUTOEDGE, 1); 343} 344 345static void 346unsetbridge_autoedge(const char *val, int d, int s, const struct afswtch *afp) 347{ 348 do_bridgeflag(s, val, IFBIF_BSTP_AUTOEDGE, 0); 349} 350 351static void 352setbridge_ptp(const char *val, int d, int s, const struct afswtch *afp) 353{ 354 do_bridgeflag(s, val, IFBIF_BSTP_PTP, 1); 355} 356 357static void 358unsetbridge_ptp(const char *val, int d, int s, const struct afswtch *afp) 359{ 360 do_bridgeflag(s, val, IFBIF_BSTP_PTP, 0); 361} 362 363static void 364setbridge_autoptp(const char *val, int d, int s, const struct afswtch *afp) 365{ 366 do_bridgeflag(s, val, IFBIF_BSTP_AUTOPTP, 1); 367} 368 369static void 370unsetbridge_autoptp(const char *val, int d, int s, const struct afswtch *afp) 371{ 372 do_bridgeflag(s, val, IFBIF_BSTP_AUTOPTP, 0); 373} 374 375static void 376setbridge_flush(const char *val, int d, int s, const struct afswtch *afp) 377{ 378 struct ifbreq req; 379 380 memset(&req, 0, sizeof(req)); 381 req.ifbr_ifsflags = IFBF_FLUSHDYN; 382 if (do_cmd(s, BRDGFLUSH, &req, sizeof(req), 1) < 0) 383 err(1, "BRDGFLUSH"); 384} 385 386static void 387setbridge_flushall(const char *val, int d, int s, const struct afswtch *afp) 388{ 389 struct ifbreq req; 390 391 memset(&req, 0, sizeof(req)); 392 req.ifbr_ifsflags = IFBF_FLUSHALL; 393 if (do_cmd(s, BRDGFLUSH, &req, sizeof(req), 1) < 0) 394 err(1, "BRDGFLUSH"); 395} 396 397static void 398setbridge_static(const char *val, const char *mac, int s, 399 const struct afswtch *afp) 400{ 401 struct ifbareq req; 402 struct ether_addr *ea; 403 404 memset(&req, 0, sizeof(req)); 405 strlcpy(req.ifba_ifsname, val, sizeof(req.ifba_ifsname)); 406 407 ea = ether_aton(mac); 408 if (ea == NULL) 409 errx(1, "%s: invalid address: %s", val, mac); 410 411 memcpy(req.ifba_dst, ea->octet, sizeof(req.ifba_dst)); 412 req.ifba_flags = IFBAF_STATIC; 413 req.ifba_vlan = 1; /* XXX allow user to specify */ 414 415 if (do_cmd(s, BRDGSADDR, &req, sizeof(req), 1) < 0) 416 err(1, "BRDGSADDR %s", val); 417} 418 419static void 420setbridge_deladdr(const char *val, int d, int s, const struct afswtch *afp) 421{ 422 struct ifbareq req; 423 struct ether_addr *ea; 424 425 memset(&req, 0, sizeof(req)); 426 427 ea = ether_aton(val); 428 if (ea == NULL) 429 errx(1, "invalid address: %s", val); 430 431 memcpy(req.ifba_dst, ea->octet, sizeof(req.ifba_dst)); 432 433 if (do_cmd(s, BRDGDADDR, &req, sizeof(req), 1) < 0) 434 err(1, "BRDGDADDR %s", val); 435} 436 437static void 438setbridge_addr(const char *val, int d, int s, const struct afswtch *afp) 439{ 440 441 bridge_addresses(s, ""); 442} 443 444static void 445setbridge_maxaddr(const char *arg, int d, int s, const struct afswtch *afp) 446{ 447 struct ifbrparam param; 448 u_long val; 449 450 if (get_val(arg, &val) < 0 || (val & ~0xffffffff) != 0) 451 errx(1, "invalid value: %s", arg); 452 453 param.ifbrp_csize = val & 0xffffffff; 454 455 if (do_cmd(s, BRDGSCACHE, ¶m, sizeof(param), 1) < 0) 456 err(1, "BRDGSCACHE %s", arg); 457} 458 459static void 460setbridge_hellotime(const char *arg, int d, int s, const struct afswtch *afp) 461{ 462 struct ifbrparam param; 463 u_long val; 464 465 if (get_val(arg, &val) < 0 || (val & ~0xff) != 0) 466 errx(1, "invalid value: %s", arg); 467 468 param.ifbrp_hellotime = val & 0xff; 469 470 if (do_cmd(s, BRDGSHT, ¶m, sizeof(param), 1) < 0) 471 err(1, "BRDGSHT %s", arg); 472} 473 474static void 475setbridge_fwddelay(const char *arg, int d, int s, const struct afswtch *afp) 476{ 477 struct ifbrparam param; 478 u_long val; 479 480 if (get_val(arg, &val) < 0 || (val & ~0xff) != 0) 481 errx(1, "invalid value: %s", arg); 482 483 param.ifbrp_fwddelay = val & 0xff; 484 485 if (do_cmd(s, BRDGSFD, ¶m, sizeof(param), 1) < 0) 486 err(1, "BRDGSFD %s", arg); 487} 488 489static void 490setbridge_maxage(const char *arg, int d, int s, const struct afswtch *afp) 491{ 492 struct ifbrparam param; 493 u_long val; 494 495 if (get_val(arg, &val) < 0 || (val & ~0xff) != 0) 496 errx(1, "invalid value: %s", arg); 497 498 param.ifbrp_maxage = val & 0xff; 499 500 if (do_cmd(s, BRDGSMA, ¶m, sizeof(param), 1) < 0) 501 err(1, "BRDGSMA %s", arg); 502} 503 504static void 505setbridge_priority(const char *arg, int d, int s, const struct afswtch *afp) 506{ 507 struct ifbrparam param; 508 u_long val; 509 510 if (get_val(arg, &val) < 0 || (val & ~0xffff) != 0) 511 errx(1, "invalid value: %s", arg); 512 513 param.ifbrp_prio = val & 0xffff; 514 515 if (do_cmd(s, BRDGSPRI, ¶m, sizeof(param), 1) < 0) 516 err(1, "BRDGSPRI %s", arg); 517} 518 519static void 520setbridge_protocol(const char *arg, int d, int s, const struct afswtch *afp) 521{ 522 struct ifbrparam param; 523 524 if (strcasecmp(arg, "stp") == 0) { 525 param.ifbrp_proto = 0; 526 } else if (strcasecmp(arg, "rstp") == 0) { 527 param.ifbrp_proto = 2; 528 } else { 529 errx(1, "unknown stp protocol"); 530 } 531 532 if (do_cmd(s, BRDGSPROTO, ¶m, sizeof(param), 1) < 0) 533 err(1, "BRDGSPROTO %s", arg); 534} 535 536static void 537setbridge_holdcount(const char *arg, int d, int s, const struct afswtch *afp) 538{ 539 struct ifbrparam param; 540 u_long val; 541 542 if (get_val(arg, &val) < 0 || (val & ~0xff) != 0) 543 errx(1, "invalid value: %s", arg); 544 545 param.ifbrp_txhc = val & 0xff; 546 547 if (do_cmd(s, BRDGSTXHC, ¶m, sizeof(param), 1) < 0) 548 err(1, "BRDGSTXHC %s", arg); 549} 550 551static void 552setbridge_ifpriority(const char *ifn, const char *pri, int s, 553 const struct afswtch *afp) 554{ 555 struct ifbreq req; 556 u_long val; 557 558 memset(&req, 0, sizeof(req)); 559 560 if (get_val(pri, &val) < 0 || (val & ~0xff) != 0) 561 errx(1, "invalid value: %s", pri); 562 563 strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname)); 564 req.ifbr_priority = val & 0xff; 565 566 if (do_cmd(s, BRDGSIFPRIO, &req, sizeof(req), 1) < 0) 567 err(1, "BRDGSIFPRIO %s", pri); 568} 569 570static void 571setbridge_ifpathcost(const char *ifn, const char *cost, int s, 572 const struct afswtch *afp) 573{ 574 struct ifbreq req; 575 u_long val; 576 577 memset(&req, 0, sizeof(req)); 578 579 if (get_val(cost, &val) < 0) 580 errx(1, "invalid value: %s", cost); 581 582 strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname)); 583 req.ifbr_path_cost = val; 584 585 if (do_cmd(s, BRDGSIFCOST, &req, sizeof(req), 1) < 0) 586 err(1, "BRDGSIFCOST %s", cost); 587} 588 589static void 590setbridge_ifmaxaddr(const char *ifn, const char *arg, int s, 591 const struct afswtch *afp) 592{ 593 struct ifbreq req; 594 u_long val; 595 596 memset(&req, 0, sizeof(req)); 597 598 if (get_val(arg, &val) < 0 || (val & ~0xffffffff) != 0) 599 errx(1, "invalid value: %s", arg); 600 601 strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname)); 602 req.ifbr_addrmax = val & 0xffffffff; 603 604 if (do_cmd(s, BRDGSIFAMAX, &req, sizeof(req), 1) < 0) 605 err(1, "BRDGSIFAMAX %s", arg); 606} 607 608static void 609setbridge_timeout(const char *arg, int d, int s, const struct afswtch *afp) 610{ 611 struct ifbrparam param; 612 u_long val; 613 614 if (get_val(arg, &val) < 0 || (val & ~0xffffffff) != 0) 615 errx(1, "invalid value: %s", arg); 616 617 param.ifbrp_ctime = val & 0xffffffff; 618 619 if (do_cmd(s, BRDGSTO, ¶m, sizeof(param), 1) < 0) 620 err(1, "BRDGSTO %s", arg); 621} 622 623static void 624setbridge_private(const char *val, int d, int s, const struct afswtch *afp) 625{ 626 627 do_bridgeflag(s, val, IFBIF_PRIVATE, 1); 628} 629 630static void 631unsetbridge_private(const char *val, int d, int s, const struct afswtch *afp) 632{ 633 634 do_bridgeflag(s, val, IFBIF_PRIVATE, 0); 635} 636 637static struct cmd bridge_cmds[] = { 638 DEF_CMD_ARG("addm", setbridge_add), 639 DEF_CMD_ARG("deletem", setbridge_delete), 640 DEF_CMD_ARG("discover", setbridge_discover), 641 DEF_CMD_ARG("-discover", unsetbridge_discover), 642 DEF_CMD_ARG("learn", setbridge_learn), 643 DEF_CMD_ARG("-learn", unsetbridge_learn), 644 DEF_CMD_ARG("sticky", setbridge_sticky), 645 DEF_CMD_ARG("-sticky", unsetbridge_sticky), 646 DEF_CMD_ARG("span", setbridge_span), 647 DEF_CMD_ARG("-span", unsetbridge_span), 648 DEF_CMD_ARG("stp", setbridge_stp), 649 DEF_CMD_ARG("-stp", unsetbridge_stp), 650 DEF_CMD_ARG("edge", setbridge_edge), 651 DEF_CMD_ARG("-edge", unsetbridge_edge), 652 DEF_CMD_ARG("autoedge", setbridge_autoedge), 653 DEF_CMD_ARG("-autoedge", unsetbridge_autoedge), 654 DEF_CMD_ARG("ptp", setbridge_ptp), 655 DEF_CMD_ARG("-ptp", unsetbridge_ptp), 656 DEF_CMD_ARG("autoptp", setbridge_autoptp), 657 DEF_CMD_ARG("-autoptp", unsetbridge_autoptp), 658 DEF_CMD("flush", 0, setbridge_flush), 659 DEF_CMD("flushall", 0, setbridge_flushall), 660 DEF_CMD_ARG2("static", setbridge_static), 661 DEF_CMD_ARG("deladdr", setbridge_deladdr), 662 DEF_CMD("addr", 1, setbridge_addr), 663 DEF_CMD_ARG("maxaddr", setbridge_maxaddr), 664 DEF_CMD_ARG("hellotime", setbridge_hellotime), 665 DEF_CMD_ARG("fwddelay", setbridge_fwddelay), 666 DEF_CMD_ARG("maxage", setbridge_maxage), 667 DEF_CMD_ARG("priority", setbridge_priority), 668 DEF_CMD_ARG("proto", setbridge_protocol), 669 DEF_CMD_ARG("holdcnt", setbridge_holdcount), 670 DEF_CMD_ARG2("ifpriority", setbridge_ifpriority), 671 DEF_CMD_ARG2("ifpathcost", setbridge_ifpathcost), 672 DEF_CMD_ARG2("ifmaxaddr", setbridge_ifmaxaddr), 673 DEF_CMD_ARG("timeout", setbridge_timeout), 674 DEF_CMD_ARG("private", setbridge_private), 675 DEF_CMD_ARG("-private", unsetbridge_private), 676}; 677static struct afswtch af_bridge = { 678 .af_name = "af_bridge", 679 .af_af = AF_UNSPEC, 680 .af_other_status = bridge_status, 681}; 682 683static __constructor void 684bridge_ctor(void) 685{ 686 int i; 687 688 for (i = 0; i < nitems(bridge_cmds); i++) 689 cmd_register(&bridge_cmds[i]); 690 af_register(&af_bridge); 691} 692