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(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, 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 102 static void 103 do_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 121 static void 122 bridge_addresses(int s, const char *prefix) 123 { 124 struct ifbaconf ifbac; 125 struct ifbareq *ifba; 126 char *inbuf = NULL, *ninbuf; 127 size_t 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 (unsigned long 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 156 static void 157 bridge_status(if_ctx *ctx __unused) 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 227 static void 228 setbridge_add(if_ctx *ctx, const char *val, int dummy __unused) 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(ctx->io_s, BRDGADD, &req, sizeof(req), 1) < 0) 235 err(1, "BRDGADD %s", val); 236 } 237 238 static void 239 setbridge_delete(if_ctx *ctx, const char *val, int dummy __unused) 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(ctx->io_s, BRDGDEL, &req, sizeof(req), 1) < 0) 246 err(1, "BRDGDEL %s", val); 247 } 248 249 static void 250 setbridge_discover(if_ctx *ctx, const char *val, int dummy __unused) 251 { 252 253 do_bridgeflag(ctx->io_s, val, IFBIF_DISCOVER, 1); 254 } 255 256 static void 257 unsetbridge_discover(if_ctx *ctx, const char *val, int dummy __unused) 258 { 259 260 do_bridgeflag(ctx->io_s, val, IFBIF_DISCOVER, 0); 261 } 262 263 static void 264 setbridge_learn(if_ctx *ctx, const char *val, int dummy __unused) 265 { 266 267 do_bridgeflag(ctx->io_s, val, IFBIF_LEARNING, 1); 268 } 269 270 static void 271 unsetbridge_learn(if_ctx *ctx, const char *val, int dummy __unused) 272 { 273 274 do_bridgeflag(ctx->io_s, val, IFBIF_LEARNING, 0); 275 } 276 277 static void 278 setbridge_sticky(if_ctx *ctx, const char *val, int dummy __unused) 279 { 280 281 do_bridgeflag(ctx->io_s, val, IFBIF_STICKY, 1); 282 } 283 284 static void 285 unsetbridge_sticky(if_ctx *ctx, const char *val, int dummy __unused) 286 { 287 288 do_bridgeflag(ctx->io_s, val, IFBIF_STICKY, 0); 289 } 290 291 static void 292 setbridge_span(if_ctx *ctx, const char *val, int dummy __unused) 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(ctx->io_s, BRDGADDS, &req, sizeof(req), 1) < 0) 299 err(1, "BRDGADDS %s", val); 300 } 301 302 static void 303 unsetbridge_span(if_ctx *ctx, const char *val, int dummy __unused) 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(ctx->io_s, BRDGDELS, &req, sizeof(req), 1) < 0) 310 err(1, "BRDGDELS %s", val); 311 } 312 313 static void 314 setbridge_stp(if_ctx *ctx, const char *val, int dummy __unused) 315 { 316 317 do_bridgeflag(ctx->io_s, val, IFBIF_STP, 1); 318 } 319 320 static void 321 unsetbridge_stp(if_ctx *ctx, const char *val, int dummy __unused) 322 { 323 324 do_bridgeflag(ctx->io_s, val, IFBIF_STP, 0); 325 } 326 327 static void 328 setbridge_edge(if_ctx *ctx, const char *val, int dummy __unused) 329 { 330 do_bridgeflag(ctx->io_s, val, IFBIF_BSTP_EDGE, 1); 331 } 332 333 static void 334 unsetbridge_edge(if_ctx *ctx, const char *val, int dummy __unused) 335 { 336 do_bridgeflag(ctx->io_s, val, IFBIF_BSTP_EDGE, 0); 337 } 338 339 static void 340 setbridge_autoedge(if_ctx *ctx, const char *val, int dummy __unused) 341 { 342 do_bridgeflag(ctx->io_s, val, IFBIF_BSTP_AUTOEDGE, 1); 343 } 344 345 static void 346 unsetbridge_autoedge(if_ctx *ctx, const char *val, int dummy __unused) 347 { 348 do_bridgeflag(ctx->io_s, val, IFBIF_BSTP_AUTOEDGE, 0); 349 } 350 351 static void 352 setbridge_ptp(if_ctx *ctx, const char *val, int dummy __unused) 353 { 354 do_bridgeflag(ctx->io_s, val, IFBIF_BSTP_PTP, 1); 355 } 356 357 static void 358 unsetbridge_ptp(if_ctx *ctx, const char *val, int dummy __unused) 359 { 360 do_bridgeflag(ctx->io_s, val, IFBIF_BSTP_PTP, 0); 361 } 362 363 static void 364 setbridge_autoptp(if_ctx *ctx, const char *val, int dummy __unused) 365 { 366 do_bridgeflag(ctx->io_s, val, IFBIF_BSTP_AUTOPTP, 1); 367 } 368 369 static void 370 unsetbridge_autoptp(if_ctx *ctx, const char *val, int dummy __unused) 371 { 372 do_bridgeflag(ctx->io_s, val, IFBIF_BSTP_AUTOPTP, 0); 373 } 374 375 static void 376 setbridge_flush(if_ctx *ctx, const char *val __unused, int dummy __unused) 377 { 378 struct ifbreq req; 379 380 memset(&req, 0, sizeof(req)); 381 req.ifbr_ifsflags = IFBF_FLUSHDYN; 382 if (do_cmd(ctx->io_s, BRDGFLUSH, &req, sizeof(req), 1) < 0) 383 err(1, "BRDGFLUSH"); 384 } 385 386 static void 387 setbridge_flushall(if_ctx *ctx, const char *val __unused, int dummy __unused) 388 { 389 struct ifbreq req; 390 391 memset(&req, 0, sizeof(req)); 392 req.ifbr_ifsflags = IFBF_FLUSHALL; 393 if (do_cmd(ctx->io_s, BRDGFLUSH, &req, sizeof(req), 1) < 0) 394 err(1, "BRDGFLUSH"); 395 } 396 397 static void 398 setbridge_static(if_ctx *ctx, const char *val, const char *mac) 399 { 400 struct ifbareq req; 401 struct ether_addr *ea; 402 403 memset(&req, 0, sizeof(req)); 404 strlcpy(req.ifba_ifsname, val, sizeof(req.ifba_ifsname)); 405 406 ea = ether_aton(mac); 407 if (ea == NULL) 408 errx(1, "%s: invalid address: %s", val, mac); 409 410 memcpy(req.ifba_dst, ea->octet, sizeof(req.ifba_dst)); 411 req.ifba_flags = IFBAF_STATIC; 412 req.ifba_vlan = 1; /* XXX allow user to specify */ 413 414 if (do_cmd(ctx->io_s, BRDGSADDR, &req, sizeof(req), 1) < 0) 415 err(1, "BRDGSADDR %s", val); 416 } 417 418 static void 419 setbridge_deladdr(if_ctx *ctx, const char *val, int dummy __unused) 420 { 421 struct ifbareq req; 422 struct ether_addr *ea; 423 424 memset(&req, 0, sizeof(req)); 425 426 ea = ether_aton(val); 427 if (ea == NULL) 428 errx(1, "invalid address: %s", val); 429 430 memcpy(req.ifba_dst, ea->octet, sizeof(req.ifba_dst)); 431 432 if (do_cmd(ctx->io_s, BRDGDADDR, &req, sizeof(req), 1) < 0) 433 err(1, "BRDGDADDR %s", val); 434 } 435 436 static void 437 setbridge_addr(if_ctx *ctx, const char *val __unused, int dummy __unused) 438 { 439 440 bridge_addresses(ctx->io_s, ""); 441 } 442 443 static void 444 setbridge_maxaddr(if_ctx *ctx, const char *arg, int dummy __unused) 445 { 446 struct ifbrparam param; 447 u_long val; 448 449 if (get_val(arg, &val) < 0 || (val & ~0xffffffff) != 0) 450 errx(1, "invalid value: %s", arg); 451 452 param.ifbrp_csize = val & 0xffffffff; 453 454 if (do_cmd(ctx->io_s, BRDGSCACHE, ¶m, sizeof(param), 1) < 0) 455 err(1, "BRDGSCACHE %s", arg); 456 } 457 458 static void 459 setbridge_hellotime(if_ctx *ctx, const char *arg, int dummy __unused) 460 { 461 struct ifbrparam param; 462 u_long val; 463 464 if (get_val(arg, &val) < 0 || (val & ~0xff) != 0) 465 errx(1, "invalid value: %s", arg); 466 467 param.ifbrp_hellotime = val & 0xff; 468 469 if (do_cmd(ctx->io_s, BRDGSHT, ¶m, sizeof(param), 1) < 0) 470 err(1, "BRDGSHT %s", arg); 471 } 472 473 static void 474 setbridge_fwddelay(if_ctx *ctx, const char *arg, int dummy __unused) 475 { 476 struct ifbrparam param; 477 u_long val; 478 479 if (get_val(arg, &val) < 0 || (val & ~0xff) != 0) 480 errx(1, "invalid value: %s", arg); 481 482 param.ifbrp_fwddelay = val & 0xff; 483 484 if (do_cmd(ctx->io_s, BRDGSFD, ¶m, sizeof(param), 1) < 0) 485 err(1, "BRDGSFD %s", arg); 486 } 487 488 static void 489 setbridge_maxage(if_ctx *ctx, const char *arg, int dummy __unused) 490 { 491 struct ifbrparam param; 492 u_long val; 493 494 if (get_val(arg, &val) < 0 || (val & ~0xff) != 0) 495 errx(1, "invalid value: %s", arg); 496 497 param.ifbrp_maxage = val & 0xff; 498 499 if (do_cmd(ctx->io_s, BRDGSMA, ¶m, sizeof(param), 1) < 0) 500 err(1, "BRDGSMA %s", arg); 501 } 502 503 static void 504 setbridge_priority(if_ctx *ctx, const char *arg, int dummy __unused) 505 { 506 struct ifbrparam param; 507 u_long val; 508 509 if (get_val(arg, &val) < 0 || (val & ~0xffff) != 0) 510 errx(1, "invalid value: %s", arg); 511 512 param.ifbrp_prio = val & 0xffff; 513 514 if (do_cmd(ctx->io_s, BRDGSPRI, ¶m, sizeof(param), 1) < 0) 515 err(1, "BRDGSPRI %s", arg); 516 } 517 518 static void 519 setbridge_protocol(if_ctx *ctx, const char *arg, int dummy __unused) 520 { 521 struct ifbrparam param; 522 523 if (strcasecmp(arg, "stp") == 0) { 524 param.ifbrp_proto = 0; 525 } else if (strcasecmp(arg, "rstp") == 0) { 526 param.ifbrp_proto = 2; 527 } else { 528 errx(1, "unknown stp protocol"); 529 } 530 531 if (do_cmd(ctx->io_s, BRDGSPROTO, ¶m, sizeof(param), 1) < 0) 532 err(1, "BRDGSPROTO %s", arg); 533 } 534 535 static void 536 setbridge_holdcount(if_ctx *ctx, const char *arg, int dummy __unused) 537 { 538 struct ifbrparam param; 539 u_long val; 540 541 if (get_val(arg, &val) < 0 || (val & ~0xff) != 0) 542 errx(1, "invalid value: %s", arg); 543 544 param.ifbrp_txhc = val & 0xff; 545 546 if (do_cmd(ctx->io_s, BRDGSTXHC, ¶m, sizeof(param), 1) < 0) 547 err(1, "BRDGSTXHC %s", arg); 548 } 549 550 static void 551 setbridge_ifpriority(if_ctx *ctx, const char *ifn, const char *pri) 552 { 553 struct ifbreq req; 554 u_long val; 555 556 memset(&req, 0, sizeof(req)); 557 558 if (get_val(pri, &val) < 0 || (val & ~0xff) != 0) 559 errx(1, "invalid value: %s", pri); 560 561 strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname)); 562 req.ifbr_priority = val & 0xff; 563 564 if (do_cmd(ctx->io_s, BRDGSIFPRIO, &req, sizeof(req), 1) < 0) 565 err(1, "BRDGSIFPRIO %s", pri); 566 } 567 568 static void 569 setbridge_ifpathcost(if_ctx *ctx, const char *ifn, const char *cost) 570 { 571 struct ifbreq req; 572 u_long val; 573 574 memset(&req, 0, sizeof(req)); 575 576 if (get_val(cost, &val) < 0) 577 errx(1, "invalid value: %s", cost); 578 579 strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname)); 580 req.ifbr_path_cost = val; 581 582 if (do_cmd(ctx->io_s, BRDGSIFCOST, &req, sizeof(req), 1) < 0) 583 err(1, "BRDGSIFCOST %s", cost); 584 } 585 586 static void 587 setbridge_ifmaxaddr(if_ctx *ctx, const char *ifn, const char *arg) 588 { 589 struct ifbreq req; 590 u_long val; 591 592 memset(&req, 0, sizeof(req)); 593 594 if (get_val(arg, &val) < 0 || (val & ~0xffffffff) != 0) 595 errx(1, "invalid value: %s", arg); 596 597 strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname)); 598 req.ifbr_addrmax = val & 0xffffffff; 599 600 if (do_cmd(ctx->io_s, BRDGSIFAMAX, &req, sizeof(req), 1) < 0) 601 err(1, "BRDGSIFAMAX %s", arg); 602 } 603 604 static void 605 setbridge_timeout(if_ctx *ctx, const char *arg, int dummy __unused) 606 { 607 struct ifbrparam param; 608 u_long val; 609 610 if (get_val(arg, &val) < 0 || (val & ~0xffffffff) != 0) 611 errx(1, "invalid value: %s", arg); 612 613 param.ifbrp_ctime = val & 0xffffffff; 614 615 if (do_cmd(ctx->io_s, BRDGSTO, ¶m, sizeof(param), 1) < 0) 616 err(1, "BRDGSTO %s", arg); 617 } 618 619 static void 620 setbridge_private(if_ctx *ctx, const char *val, int dummy __unused) 621 { 622 623 do_bridgeflag(ctx->io_s, val, IFBIF_PRIVATE, 1); 624 } 625 626 static void 627 unsetbridge_private(if_ctx *ctx, const char *val, int dummy __unused) 628 { 629 630 do_bridgeflag(ctx->io_s, val, IFBIF_PRIVATE, 0); 631 } 632 633 static struct cmd bridge_cmds[] = { 634 DEF_CMD_ARG("addm", setbridge_add), 635 DEF_CMD_ARG("deletem", setbridge_delete), 636 DEF_CMD_ARG("discover", setbridge_discover), 637 DEF_CMD_ARG("-discover", unsetbridge_discover), 638 DEF_CMD_ARG("learn", setbridge_learn), 639 DEF_CMD_ARG("-learn", unsetbridge_learn), 640 DEF_CMD_ARG("sticky", setbridge_sticky), 641 DEF_CMD_ARG("-sticky", unsetbridge_sticky), 642 DEF_CMD_ARG("span", setbridge_span), 643 DEF_CMD_ARG("-span", unsetbridge_span), 644 DEF_CMD_ARG("stp", setbridge_stp), 645 DEF_CMD_ARG("-stp", unsetbridge_stp), 646 DEF_CMD_ARG("edge", setbridge_edge), 647 DEF_CMD_ARG("-edge", unsetbridge_edge), 648 DEF_CMD_ARG("autoedge", setbridge_autoedge), 649 DEF_CMD_ARG("-autoedge", unsetbridge_autoedge), 650 DEF_CMD_ARG("ptp", setbridge_ptp), 651 DEF_CMD_ARG("-ptp", unsetbridge_ptp), 652 DEF_CMD_ARG("autoptp", setbridge_autoptp), 653 DEF_CMD_ARG("-autoptp", unsetbridge_autoptp), 654 DEF_CMD("flush", 0, setbridge_flush), 655 DEF_CMD("flushall", 0, setbridge_flushall), 656 DEF_CMD_ARG2("static", setbridge_static), 657 DEF_CMD_ARG("deladdr", setbridge_deladdr), 658 DEF_CMD("addr", 1, setbridge_addr), 659 DEF_CMD_ARG("maxaddr", setbridge_maxaddr), 660 DEF_CMD_ARG("hellotime", setbridge_hellotime), 661 DEF_CMD_ARG("fwddelay", setbridge_fwddelay), 662 DEF_CMD_ARG("maxage", setbridge_maxage), 663 DEF_CMD_ARG("priority", setbridge_priority), 664 DEF_CMD_ARG("proto", setbridge_protocol), 665 DEF_CMD_ARG("holdcnt", setbridge_holdcount), 666 DEF_CMD_ARG2("ifpriority", setbridge_ifpriority), 667 DEF_CMD_ARG2("ifpathcost", setbridge_ifpathcost), 668 DEF_CMD_ARG2("ifmaxaddr", setbridge_ifmaxaddr), 669 DEF_CMD_ARG("timeout", setbridge_timeout), 670 DEF_CMD_ARG("private", setbridge_private), 671 DEF_CMD_ARG("-private", unsetbridge_private), 672 }; 673 static struct afswtch af_bridge = { 674 .af_name = "af_bridge", 675 .af_af = AF_UNSPEC, 676 .af_other_status = bridge_status, 677 }; 678 679 static __constructor void 680 bridge_ctor(void) 681 { 682 for (size_t i = 0; i < nitems(bridge_cmds); i++) 683 cmd_register(&bridge_cmds[i]); 684 af_register(&af_bridge); 685 } 686