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