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, 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 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 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 156 static void 157 bridge_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 227 static void 228 setbridge_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 238 static void 239 setbridge_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 249 static void 250 setbridge_discover(const char *val, int d, int s, const struct afswtch *afp) 251 { 252 253 do_bridgeflag(s, val, IFBIF_DISCOVER, 1); 254 } 255 256 static void 257 unsetbridge_discover(const char *val, int d, int s, const struct afswtch *afp) 258 { 259 260 do_bridgeflag(s, val, IFBIF_DISCOVER, 0); 261 } 262 263 static void 264 setbridge_learn(const char *val, int d, int s, const struct afswtch *afp) 265 { 266 267 do_bridgeflag(s, val, IFBIF_LEARNING, 1); 268 } 269 270 static void 271 unsetbridge_learn(const char *val, int d, int s, const struct afswtch *afp) 272 { 273 274 do_bridgeflag(s, val, IFBIF_LEARNING, 0); 275 } 276 277 static void 278 setbridge_sticky(const char *val, int d, int s, const struct afswtch *afp) 279 { 280 281 do_bridgeflag(s, val, IFBIF_STICKY, 1); 282 } 283 284 static void 285 unsetbridge_sticky(const char *val, int d, int s, const struct afswtch *afp) 286 { 287 288 do_bridgeflag(s, val, IFBIF_STICKY, 0); 289 } 290 291 static void 292 setbridge_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 302 static void 303 unsetbridge_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 313 static void 314 setbridge_stp(const char *val, int d, int s, const struct afswtch *afp) 315 { 316 317 do_bridgeflag(s, val, IFBIF_STP, 1); 318 } 319 320 static void 321 unsetbridge_stp(const char *val, int d, int s, const struct afswtch *afp) 322 { 323 324 do_bridgeflag(s, val, IFBIF_STP, 0); 325 } 326 327 static void 328 setbridge_edge(const char *val, int d, int s, const struct afswtch *afp) 329 { 330 do_bridgeflag(s, val, IFBIF_BSTP_EDGE, 1); 331 } 332 333 static void 334 unsetbridge_edge(const char *val, int d, int s, const struct afswtch *afp) 335 { 336 do_bridgeflag(s, val, IFBIF_BSTP_EDGE, 0); 337 } 338 339 static void 340 setbridge_autoedge(const char *val, int d, int s, const struct afswtch *afp) 341 { 342 do_bridgeflag(s, val, IFBIF_BSTP_AUTOEDGE, 1); 343 } 344 345 static void 346 unsetbridge_autoedge(const char *val, int d, int s, const struct afswtch *afp) 347 { 348 do_bridgeflag(s, val, IFBIF_BSTP_AUTOEDGE, 0); 349 } 350 351 static void 352 setbridge_ptp(const char *val, int d, int s, const struct afswtch *afp) 353 { 354 do_bridgeflag(s, val, IFBIF_BSTP_PTP, 1); 355 } 356 357 static void 358 unsetbridge_ptp(const char *val, int d, int s, const struct afswtch *afp) 359 { 360 do_bridgeflag(s, val, IFBIF_BSTP_PTP, 0); 361 } 362 363 static void 364 setbridge_autoptp(const char *val, int d, int s, const struct afswtch *afp) 365 { 366 do_bridgeflag(s, val, IFBIF_BSTP_AUTOPTP, 1); 367 } 368 369 static void 370 unsetbridge_autoptp(const char *val, int d, int s, const struct afswtch *afp) 371 { 372 do_bridgeflag(s, val, IFBIF_BSTP_AUTOPTP, 0); 373 } 374 375 static void 376 setbridge_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 386 static void 387 setbridge_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 397 static void 398 setbridge_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 419 static void 420 setbridge_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 437 static void 438 setbridge_addr(const char *val, int d, int s, const struct afswtch *afp) 439 { 440 441 bridge_addresses(s, ""); 442 } 443 444 static void 445 setbridge_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 459 static void 460 setbridge_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 474 static void 475 setbridge_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 489 static void 490 setbridge_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 504 static void 505 setbridge_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 519 static void 520 setbridge_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 536 static void 537 setbridge_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 551 static void 552 setbridge_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 570 static void 571 setbridge_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 589 static void 590 setbridge_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 608 static void 609 setbridge_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 623 static void 624 setbridge_private(const char *val, int d, int s, const struct afswtch *afp) 625 { 626 627 do_bridgeflag(s, val, IFBIF_PRIVATE, 1); 628 } 629 630 static void 631 unsetbridge_private(const char *val, int d, int s, const struct afswtch *afp) 632 { 633 634 do_bridgeflag(s, val, IFBIF_PRIVATE, 0); 635 } 636 637 static 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 }; 677 static struct afswtch af_bridge = { 678 .af_name = "af_bridge", 679 .af_af = AF_UNSPEC, 680 .af_other_status = bridge_status, 681 }; 682 683 static __constructor void 684 bridge_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