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