117623Smpp/*- 217623Smpp * SPDX-License-Identifier: BSD-4-Clause 317623Smpp * 417623Smpp * Copyright 2001 Wasabi Systems, Inc. 517623Smpp * All rights reserved. 617623Smpp * 717623Smpp * Written by Jason R. Thorpe for Wasabi Systems, Inc. 817623Smpp * 917623Smpp * Redistribution and use in source and binary forms, with or without 1017623Smpp * modification, are permitted provided that the following conditions 1117623Smpp * are met: 1217623Smpp * 1. Redistributions of source code must retain the above copyright 1317623Smpp * notice, this list of conditions and the following disclaimer. 1417623Smpp * 2. Redistributions in binary form must reproduce the above copyright 1517623Smpp * notice, this list of conditions and the following disclaimer in the 1617623Smpp * documentation and/or other materials provided with the distribution. 1717623Smpp * 3. All advertising materials mentioning features or use of this software 1817623Smpp * must display the following acknowledgement: 1917623Smpp * This product includes software developed for the NetBSD Project by 2017623Smpp * Wasabi Systems, Inc. 2117623Smpp * 4. The name of Wasabi Systems, Inc. may not be used to endorse 2217623Smpp * or promote products derived from this software without specific prior 2317623Smpp * written permission. 2417623Smpp * 2517623Smpp * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 2617623Smpp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 2717623Smpp * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 2817623Smpp * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 2917623Smpp * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 3017623Smpp * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 3117623Smpp * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 3250476Speter * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 3323466Sjmg * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 3417623Smpp * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 3517623Smpp * POSSIBILITY OF SUCH DAMAGE. 3617623Smpp */ 3717623Smpp 3817623Smpp#include <sys/param.h> 3917623Smpp#include <sys/ioctl.h> 4017623Smpp#include <sys/socket.h> 4117623Smpp#include <sys/sockio.h> 4217623Smpp 4317623Smpp#include <stdlib.h> 44131530Sru#include <unistd.h> 45131530Sru 4617623Smpp#include <net/ethernet.h> 4717623Smpp#include <net/if.h> 4817623Smpp#include <net/if_bridgevar.h> 49131530Sru#include <net/route.h> 50131530Sru 5117623Smpp#include <ctype.h> 52131530Sru#include <stdio.h> 53131530Sru#include <string.h> 5417623Smpp#include <stdlib.h> 5517623Smpp#include <unistd.h> 5617623Smpp#include <err.h> 5717623Smpp#include <errno.h> 5817623Smpp 5979727Sschweikh#include <libifconfig.h> 6017623Smpp 6117623Smpp#include "ifconfig.h" 6217623Smpp 6317623Smppstatic const char *stpstates[] = { STP_STATES }; 6417623Smppstatic const char *stpproto[] = { STP_PROTOS }; 6517623Smppstatic const char *stproles[] = { STP_ROLES }; 6617623Smpp 6779727Sschweikhstatic int 6871895Sruget_val(const char *cp, u_long *valp) 6917623Smpp{ 7017623Smpp char *endptr; 7117623Smpp u_long val; 7217623Smpp 7344096Sjkoshy errno = 0; 7444096Sjkoshy val = strtoul(cp, &endptr, 0); 7544096Sjkoshy if (cp[0] == '\0' || endptr[0] != '\0' || errno == ERANGE) 7644096Sjkoshy return (-1); 7744096Sjkoshy 7879727Sschweikh *valp = val; 7944096Sjkoshy return (0); 8044096Sjkoshy} 8144096Sjkoshy 8244096Sjkoshystatic int 8344096Sjkoshydo_cmd(if_ctx *ctx, u_long op, void *arg, size_t argsize, int set) 8444096Sjkoshy{ 8544096Sjkoshy struct ifdrv ifd = {}; 8679727Sschweikh 8744096Sjkoshy strlcpy(ifd.ifd_name, ctx->ifname, sizeof(ifd.ifd_name)); 8844096Sjkoshy ifd.ifd_cmd = op; 8917623Smpp ifd.ifd_len = argsize; 9017623Smpp ifd.ifd_data = arg; 9117623Smpp 9217623Smpp return (ioctl_ctx(ctx, set ? SIOCSDRVSPEC : SIOCGDRVSPEC, &ifd)); 9317623Smpp} 9417623Smpp 9544096Sjkoshystatic void 9617623Smppdo_bridgeflag(if_ctx *ctx, const char *ifs, int flag, int set) 9717623Smpp{ 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 114static void 115bridge_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 149static void 150bridge_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 220static void 221setbridge_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 231static void 232setbridge_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 242static void 243setbridge_discover(if_ctx *ctx, const char *val, int dummy __unused) 244{ 245 246 do_bridgeflag(ctx, val, IFBIF_DISCOVER, 1); 247} 248 249static void 250unsetbridge_discover(if_ctx *ctx, const char *val, int dummy __unused) 251{ 252 253 do_bridgeflag(ctx, val, IFBIF_DISCOVER, 0); 254} 255 256static void 257setbridge_learn(if_ctx *ctx, const char *val, int dummy __unused) 258{ 259 260 do_bridgeflag(ctx, val, IFBIF_LEARNING, 1); 261} 262 263static void 264unsetbridge_learn(if_ctx *ctx, const char *val, int dummy __unused) 265{ 266 267 do_bridgeflag(ctx, val, IFBIF_LEARNING, 0); 268} 269 270static void 271setbridge_sticky(if_ctx *ctx, const char *val, int dummy __unused) 272{ 273 274 do_bridgeflag(ctx, val, IFBIF_STICKY, 1); 275} 276 277static void 278unsetbridge_sticky(if_ctx *ctx, const char *val, int dummy __unused) 279{ 280 281 do_bridgeflag(ctx, val, IFBIF_STICKY, 0); 282} 283 284static void 285setbridge_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 295static void 296unsetbridge_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 306static void 307setbridge_stp(if_ctx *ctx, const char *val, int dummy __unused) 308{ 309 310 do_bridgeflag(ctx, val, IFBIF_STP, 1); 311} 312 313static void 314unsetbridge_stp(if_ctx *ctx, const char *val, int dummy __unused) 315{ 316 317 do_bridgeflag(ctx, val, IFBIF_STP, 0); 318} 319 320static void 321setbridge_edge(if_ctx *ctx, const char *val, int dummy __unused) 322{ 323 do_bridgeflag(ctx, val, IFBIF_BSTP_EDGE, 1); 324} 325 326static void 327unsetbridge_edge(if_ctx *ctx, const char *val, int dummy __unused) 328{ 329 do_bridgeflag(ctx, val, IFBIF_BSTP_EDGE, 0); 330} 331 332static void 333setbridge_autoedge(if_ctx *ctx, const char *val, int dummy __unused) 334{ 335 do_bridgeflag(ctx, val, IFBIF_BSTP_AUTOEDGE, 1); 336} 337 338static void 339unsetbridge_autoedge(if_ctx *ctx, const char *val, int dummy __unused) 340{ 341 do_bridgeflag(ctx, val, IFBIF_BSTP_AUTOEDGE, 0); 342} 343 344static void 345setbridge_ptp(if_ctx *ctx, const char *val, int dummy __unused) 346{ 347 do_bridgeflag(ctx, val, IFBIF_BSTP_PTP, 1); 348} 349 350static void 351unsetbridge_ptp(if_ctx *ctx, const char *val, int dummy __unused) 352{ 353 do_bridgeflag(ctx, val, IFBIF_BSTP_PTP, 0); 354} 355 356static void 357setbridge_autoptp(if_ctx *ctx, const char *val, int dummy __unused) 358{ 359 do_bridgeflag(ctx, val, IFBIF_BSTP_AUTOPTP, 1); 360} 361 362static void 363unsetbridge_autoptp(if_ctx *ctx, const char *val, int dummy __unused) 364{ 365 do_bridgeflag(ctx, val, IFBIF_BSTP_AUTOPTP, 0); 366} 367 368static void 369setbridge_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 379static void 380setbridge_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 390static void 391setbridge_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 411static void 412setbridge_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 429static void 430setbridge_addr(if_ctx *ctx, const char *val __unused, int dummy __unused) 431{ 432 433 bridge_addresses(ctx, ""); 434} 435 436static void 437setbridge_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 451static void 452setbridge_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 466static void 467setbridge_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 481static void 482setbridge_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 496static void 497setbridge_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 511static void 512setbridge_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 528static void 529setbridge_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 543static void 544setbridge_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 561static void 562setbridge_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 579static void 580setbridge_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 597static void 598setbridge_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 612static void 613setbridge_private(if_ctx *ctx, const char *val, int dummy __unused) 614{ 615 616 do_bridgeflag(ctx, val, IFBIF_PRIVATE, 1); 617} 618 619static void 620unsetbridge_private(if_ctx *ctx, const char *val, int dummy __unused) 621{ 622 623 do_bridgeflag(ctx, val, IFBIF_PRIVATE, 0); 624} 625 626static 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}; 666static struct afswtch af_bridge = { 667 .af_name = "af_bridge", 668 .af_af = AF_UNSPEC, 669 .af_other_status = bridge_status, 670}; 671 672static __constructor void 673bridge_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