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 print_vlans(ifbvlan_set_t *vlans) 151 { 152 unsigned printed = 0; 153 154 for (unsigned vlan = DOT1Q_VID_MIN; vlan <= DOT1Q_VID_MAX;) { 155 unsigned last; 156 157 if (!BRVLAN_TEST(vlans, vlan)) { 158 ++vlan; 159 continue; 160 } 161 162 last = vlan; 163 while (last < DOT1Q_VID_MAX && BRVLAN_TEST(vlans, last + 1)) 164 ++last; 165 166 if (printed == 0) 167 printf(" tagged "); 168 else 169 printf(","); 170 171 printf("%u", vlan); 172 if (last != vlan) 173 printf("-%u", last); 174 ++printed; 175 vlan = last + 1; 176 } 177 } 178 179 static void 180 bridge_status(if_ctx *ctx) 181 { 182 struct ifconfig_bridge_status *bridge; 183 struct ifbropreq *params; 184 const char *pad, *prefix; 185 uint8_t lladdr[ETHER_ADDR_LEN]; 186 uint16_t bprio; 187 188 if (ifconfig_bridge_get_bridge_status(lifh, ctx->ifname, &bridge) == -1) 189 return; 190 191 params = bridge->params; 192 193 PV2ID(params->ifbop_bridgeid, bprio, lladdr); 194 printf("\tid %s priority %u hellotime %u fwddelay %u\n", 195 ether_ntoa((struct ether_addr *)lladdr), 196 params->ifbop_priority, 197 params->ifbop_hellotime, 198 params->ifbop_fwddelay); 199 printf("\tmaxage %u holdcnt %u proto %s maxaddr %u timeout %u\n", 200 params->ifbop_maxage, 201 params->ifbop_holdcount, 202 stpproto[params->ifbop_protocol], 203 bridge->cache_size, 204 bridge->cache_lifetime); 205 PV2ID(params->ifbop_designated_root, bprio, lladdr); 206 printf("\troot id %s priority %d ifcost %u port %u\n", 207 ether_ntoa((struct ether_addr *)lladdr), 208 bprio, 209 params->ifbop_root_path_cost, 210 params->ifbop_root_port & 0xfff); 211 212 prefix = "\tmember: "; 213 pad = "\t "; 214 for (size_t i = 0; i < bridge->members_count; ++i) { 215 struct ifbreq *member = &bridge->members[i]; 216 217 printf("%s%s ", prefix, member->ifbr_ifsname); 218 printb("flags", member->ifbr_ifsflags, IFBIFBITS); 219 printf("\n%s", pad); 220 printf("ifmaxaddr %u port %u priority %u path cost %u", 221 member->ifbr_addrmax, 222 member->ifbr_portno, 223 member->ifbr_priority, 224 member->ifbr_path_cost); 225 if (member->ifbr_ifsflags & IFBIF_STP) { 226 uint8_t proto = member->ifbr_proto; 227 uint8_t role = member->ifbr_role; 228 uint8_t state = member->ifbr_state; 229 230 if (proto < nitems(stpproto)) 231 printf(" proto %s", stpproto[proto]); 232 else 233 printf(" <unknown proto %d>", proto); 234 printf("\n%s", pad); 235 if (role < nitems(stproles)) 236 printf("role %s", stproles[role]); 237 else 238 printf("<unknown role %d>", role); 239 if (state < nitems(stpstates)) 240 printf(" state %s", stpstates[state]); 241 else 242 printf(" <unknown state %d>", state); 243 } 244 if (member->ifbr_untagged != 0) 245 printf(" untagged %u", (unsigned)member->ifbr_untagged); 246 print_vlans(&bridge->member_vlans[i]); 247 printf("\n"); 248 } 249 250 ifconfig_bridge_free_bridge_status(bridge); 251 } 252 253 static void 254 setbridge_add(if_ctx *ctx, const char *val, int dummy __unused) 255 { 256 struct ifbreq req; 257 258 memset(&req, 0, sizeof(req)); 259 strlcpy(req.ifbr_ifsname, val, sizeof(req.ifbr_ifsname)); 260 if (do_cmd(ctx, BRDGADD, &req, sizeof(req), 1) < 0) 261 err(1, "BRDGADD %s", val); 262 } 263 264 static void 265 setbridge_delete(if_ctx *ctx, const char *val, int dummy __unused) 266 { 267 struct ifbreq req; 268 269 memset(&req, 0, sizeof(req)); 270 strlcpy(req.ifbr_ifsname, val, sizeof(req.ifbr_ifsname)); 271 if (do_cmd(ctx, BRDGDEL, &req, sizeof(req), 1) < 0) 272 err(1, "BRDGDEL %s", val); 273 } 274 275 static void 276 setbridge_discover(if_ctx *ctx, const char *val, int dummy __unused) 277 { 278 279 do_bridgeflag(ctx, val, IFBIF_DISCOVER, 1); 280 } 281 282 static void 283 unsetbridge_discover(if_ctx *ctx, const char *val, int dummy __unused) 284 { 285 286 do_bridgeflag(ctx, val, IFBIF_DISCOVER, 0); 287 } 288 289 static void 290 setbridge_learn(if_ctx *ctx, const char *val, int dummy __unused) 291 { 292 293 do_bridgeflag(ctx, val, IFBIF_LEARNING, 1); 294 } 295 296 static void 297 unsetbridge_learn(if_ctx *ctx, const char *val, int dummy __unused) 298 { 299 300 do_bridgeflag(ctx, val, IFBIF_LEARNING, 0); 301 } 302 303 static void 304 setbridge_sticky(if_ctx *ctx, const char *val, int dummy __unused) 305 { 306 307 do_bridgeflag(ctx, val, IFBIF_STICKY, 1); 308 } 309 310 static void 311 unsetbridge_sticky(if_ctx *ctx, const char *val, int dummy __unused) 312 { 313 314 do_bridgeflag(ctx, val, IFBIF_STICKY, 0); 315 } 316 317 static void 318 setbridge_span(if_ctx *ctx, const char *val, int dummy __unused) 319 { 320 struct ifbreq req; 321 322 memset(&req, 0, sizeof(req)); 323 strlcpy(req.ifbr_ifsname, val, sizeof(req.ifbr_ifsname)); 324 if (do_cmd(ctx, BRDGADDS, &req, sizeof(req), 1) < 0) 325 err(1, "BRDGADDS %s", val); 326 } 327 328 static void 329 unsetbridge_span(if_ctx *ctx, const char *val, int dummy __unused) 330 { 331 struct ifbreq req; 332 333 memset(&req, 0, sizeof(req)); 334 strlcpy(req.ifbr_ifsname, val, sizeof(req.ifbr_ifsname)); 335 if (do_cmd(ctx, BRDGDELS, &req, sizeof(req), 1) < 0) 336 err(1, "BRDGDELS %s", val); 337 } 338 339 static void 340 setbridge_stp(if_ctx *ctx, const char *val, int dummy __unused) 341 { 342 343 do_bridgeflag(ctx, val, IFBIF_STP, 1); 344 } 345 346 static void 347 unsetbridge_stp(if_ctx *ctx, const char *val, int dummy __unused) 348 { 349 350 do_bridgeflag(ctx, val, IFBIF_STP, 0); 351 } 352 353 static void 354 setbridge_edge(if_ctx *ctx, const char *val, int dummy __unused) 355 { 356 do_bridgeflag(ctx, val, IFBIF_BSTP_EDGE, 1); 357 } 358 359 static void 360 unsetbridge_edge(if_ctx *ctx, const char *val, int dummy __unused) 361 { 362 do_bridgeflag(ctx, val, IFBIF_BSTP_EDGE, 0); 363 } 364 365 static void 366 setbridge_autoedge(if_ctx *ctx, const char *val, int dummy __unused) 367 { 368 do_bridgeflag(ctx, val, IFBIF_BSTP_AUTOEDGE, 1); 369 } 370 371 static void 372 unsetbridge_autoedge(if_ctx *ctx, const char *val, int dummy __unused) 373 { 374 do_bridgeflag(ctx, val, IFBIF_BSTP_AUTOEDGE, 0); 375 } 376 377 static void 378 setbridge_ptp(if_ctx *ctx, const char *val, int dummy __unused) 379 { 380 do_bridgeflag(ctx, val, IFBIF_BSTP_PTP, 1); 381 } 382 383 static void 384 unsetbridge_ptp(if_ctx *ctx, const char *val, int dummy __unused) 385 { 386 do_bridgeflag(ctx, val, IFBIF_BSTP_PTP, 0); 387 } 388 389 static void 390 setbridge_autoptp(if_ctx *ctx, const char *val, int dummy __unused) 391 { 392 do_bridgeflag(ctx, val, IFBIF_BSTP_AUTOPTP, 1); 393 } 394 395 static void 396 unsetbridge_autoptp(if_ctx *ctx, const char *val, int dummy __unused) 397 { 398 do_bridgeflag(ctx, val, IFBIF_BSTP_AUTOPTP, 0); 399 } 400 401 static void 402 setbridge_flush(if_ctx *ctx, const char *val __unused, int dummy __unused) 403 { 404 struct ifbreq req; 405 406 memset(&req, 0, sizeof(req)); 407 req.ifbr_ifsflags = IFBF_FLUSHDYN; 408 if (do_cmd(ctx, BRDGFLUSH, &req, sizeof(req), 1) < 0) 409 err(1, "BRDGFLUSH"); 410 } 411 412 static void 413 setbridge_flushall(if_ctx *ctx, const char *val __unused, int dummy __unused) 414 { 415 struct ifbreq req; 416 417 memset(&req, 0, sizeof(req)); 418 req.ifbr_ifsflags = IFBF_FLUSHALL; 419 if (do_cmd(ctx, BRDGFLUSH, &req, sizeof(req), 1) < 0) 420 err(1, "BRDGFLUSH"); 421 } 422 423 static void 424 setbridge_static(if_ctx *ctx, const char *val, const char *mac) 425 { 426 struct ifbareq req; 427 struct ether_addr *ea; 428 429 memset(&req, 0, sizeof(req)); 430 strlcpy(req.ifba_ifsname, val, sizeof(req.ifba_ifsname)); 431 432 ea = ether_aton(mac); 433 if (ea == NULL) 434 errx(1, "%s: invalid address: %s", val, mac); 435 436 memcpy(req.ifba_dst, ea->octet, sizeof(req.ifba_dst)); 437 req.ifba_flags = IFBAF_STATIC; 438 req.ifba_vlan = 0; /* XXX allow user to specify */ 439 440 if (do_cmd(ctx, BRDGSADDR, &req, sizeof(req), 1) < 0) 441 err(1, "BRDGSADDR %s", val); 442 } 443 444 static void 445 setbridge_deladdr(if_ctx *ctx, const char *val, int dummy __unused) 446 { 447 struct ifbareq req; 448 struct ether_addr *ea; 449 450 memset(&req, 0, sizeof(req)); 451 452 ea = ether_aton(val); 453 if (ea == NULL) 454 errx(1, "invalid address: %s", val); 455 456 memcpy(req.ifba_dst, ea->octet, sizeof(req.ifba_dst)); 457 458 if (do_cmd(ctx, BRDGDADDR, &req, sizeof(req), 1) < 0) 459 err(1, "BRDGDADDR %s", val); 460 } 461 462 static void 463 setbridge_addr(if_ctx *ctx, const char *val __unused, int dummy __unused) 464 { 465 466 bridge_addresses(ctx, ""); 467 } 468 469 static void 470 setbridge_maxaddr(if_ctx *ctx, const char *arg, int dummy __unused) 471 { 472 struct ifbrparam param; 473 u_long val; 474 475 if (get_val(arg, &val) < 0 || (val & ~0xffffffff) != 0) 476 errx(1, "invalid value: %s", arg); 477 478 param.ifbrp_csize = val & 0xffffffff; 479 480 if (do_cmd(ctx, BRDGSCACHE, ¶m, sizeof(param), 1) < 0) 481 err(1, "BRDGSCACHE %s", arg); 482 } 483 484 static void 485 setbridge_hellotime(if_ctx *ctx, const char *arg, int dummy __unused) 486 { 487 struct ifbrparam param; 488 u_long val; 489 490 if (get_val(arg, &val) < 0 || (val & ~0xff) != 0) 491 errx(1, "invalid value: %s", arg); 492 493 param.ifbrp_hellotime = val & 0xff; 494 495 if (do_cmd(ctx, BRDGSHT, ¶m, sizeof(param), 1) < 0) 496 err(1, "BRDGSHT %s", arg); 497 } 498 499 static void 500 setbridge_fwddelay(if_ctx *ctx, const char *arg, int dummy __unused) 501 { 502 struct ifbrparam param; 503 u_long val; 504 505 if (get_val(arg, &val) < 0 || (val & ~0xff) != 0) 506 errx(1, "invalid value: %s", arg); 507 508 param.ifbrp_fwddelay = val & 0xff; 509 510 if (do_cmd(ctx, BRDGSFD, ¶m, sizeof(param), 1) < 0) 511 err(1, "BRDGSFD %s", arg); 512 } 513 514 static void 515 setbridge_maxage(if_ctx *ctx, const char *arg, int dummy __unused) 516 { 517 struct ifbrparam param; 518 u_long val; 519 520 if (get_val(arg, &val) < 0 || (val & ~0xff) != 0) 521 errx(1, "invalid value: %s", arg); 522 523 param.ifbrp_maxage = val & 0xff; 524 525 if (do_cmd(ctx, BRDGSMA, ¶m, sizeof(param), 1) < 0) 526 err(1, "BRDGSMA %s", arg); 527 } 528 529 static void 530 setbridge_priority(if_ctx *ctx, const char *arg, int dummy __unused) 531 { 532 struct ifbrparam param; 533 u_long val; 534 535 if (get_val(arg, &val) < 0 || (val & ~0xffff) != 0) 536 errx(1, "invalid value: %s", arg); 537 538 param.ifbrp_prio = val & 0xffff; 539 540 if (do_cmd(ctx, BRDGSPRI, ¶m, sizeof(param), 1) < 0) 541 err(1, "BRDGSPRI %s", arg); 542 } 543 544 static void 545 setbridge_protocol(if_ctx *ctx, const char *arg, int dummy __unused) 546 { 547 struct ifbrparam param; 548 549 if (strcasecmp(arg, "stp") == 0) { 550 param.ifbrp_proto = 0; 551 } else if (strcasecmp(arg, "rstp") == 0) { 552 param.ifbrp_proto = 2; 553 } else { 554 errx(1, "unknown stp protocol"); 555 } 556 557 if (do_cmd(ctx, BRDGSPROTO, ¶m, sizeof(param), 1) < 0) 558 err(1, "BRDGSPROTO %s", arg); 559 } 560 561 static void 562 setbridge_holdcount(if_ctx *ctx, const char *arg, int dummy __unused) 563 { 564 struct ifbrparam param; 565 u_long val; 566 567 if (get_val(arg, &val) < 0 || (val & ~0xff) != 0) 568 errx(1, "invalid value: %s", arg); 569 570 param.ifbrp_txhc = val & 0xff; 571 572 if (do_cmd(ctx, BRDGSTXHC, ¶m, sizeof(param), 1) < 0) 573 err(1, "BRDGSTXHC %s", arg); 574 } 575 576 static void 577 setbridge_ifpriority(if_ctx *ctx, const char *ifn, const char *pri) 578 { 579 struct ifbreq req; 580 u_long val; 581 582 memset(&req, 0, sizeof(req)); 583 584 if (get_val(pri, &val) < 0 || (val & ~0xff) != 0) 585 errx(1, "invalid value: %s", pri); 586 587 strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname)); 588 req.ifbr_priority = val & 0xff; 589 590 if (do_cmd(ctx, BRDGSIFPRIO, &req, sizeof(req), 1) < 0) 591 err(1, "BRDGSIFPRIO %s", pri); 592 } 593 594 static void 595 setbridge_ifpathcost(if_ctx *ctx, const char *ifn, const char *cost) 596 { 597 struct ifbreq req; 598 u_long val; 599 600 memset(&req, 0, sizeof(req)); 601 602 if (get_val(cost, &val) < 0) 603 errx(1, "invalid value: %s", cost); 604 605 strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname)); 606 req.ifbr_path_cost = val; 607 608 if (do_cmd(ctx, BRDGSIFCOST, &req, sizeof(req), 1) < 0) 609 err(1, "BRDGSIFCOST %s", cost); 610 } 611 612 static void 613 setbridge_untagged(if_ctx *ctx, const char *ifn, const char *vlanid) 614 { 615 struct ifbreq req; 616 u_long val; 617 618 memset(&req, 0, sizeof(req)); 619 620 if (get_val(vlanid, &val) < 0) 621 errx(1, "invalid VLAN identifier: %s", vlanid); 622 623 /* 624 * Reject vlan 0, since it's not a valid vlan identifier and has a 625 * special meaning in the kernel interface. 626 */ 627 if (val == 0) 628 errx(1, "invalid VLAN identifier: %lu", val); 629 630 strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname)); 631 req.ifbr_untagged = val; 632 633 if (do_cmd(ctx, BRDGSIFUNTAGGED, &req, sizeof(req), 1) < 0) 634 err(1, "BRDGSIFUNTAGGED %s", vlanid); 635 } 636 637 static void 638 unsetbridge_untagged(if_ctx *ctx, const char *ifn, int dummy __unused) 639 { 640 struct ifbreq req; 641 642 memset(&req, 0, sizeof(req)); 643 644 strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname)); 645 req.ifbr_untagged = 0; 646 647 if (do_cmd(ctx, BRDGSIFUNTAGGED, &req, sizeof(req), 1) < 0) 648 err(1, "BRDGSIFUNTAGGED"); 649 } 650 651 static void 652 setbridge_ifmaxaddr(if_ctx *ctx, const char *ifn, const char *arg) 653 { 654 struct ifbreq req; 655 u_long val; 656 657 memset(&req, 0, sizeof(req)); 658 659 if (get_val(arg, &val) < 0 || (val & ~0xffffffff) != 0) 660 errx(1, "invalid value: %s", arg); 661 662 strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname)); 663 req.ifbr_addrmax = val & 0xffffffff; 664 665 if (do_cmd(ctx, BRDGSIFAMAX, &req, sizeof(req), 1) < 0) 666 err(1, "BRDGSIFAMAX %s", arg); 667 } 668 669 static void 670 setbridge_timeout(if_ctx *ctx, const char *arg, int dummy __unused) 671 { 672 struct ifbrparam param; 673 u_long val; 674 675 if (get_val(arg, &val) < 0 || (val & ~0xffffffff) != 0) 676 errx(1, "invalid value: %s", arg); 677 678 param.ifbrp_ctime = val & 0xffffffff; 679 680 if (do_cmd(ctx, BRDGSTO, ¶m, sizeof(param), 1) < 0) 681 err(1, "BRDGSTO %s", arg); 682 } 683 684 static void 685 setbridge_private(if_ctx *ctx, const char *val, int dummy __unused) 686 { 687 do_bridgeflag(ctx, val, IFBIF_PRIVATE, 1); 688 } 689 690 static void 691 unsetbridge_private(if_ctx *ctx, const char *val, int dummy __unused) 692 { 693 do_bridgeflag(ctx, val, IFBIF_PRIVATE, 0); 694 } 695 696 static void 697 setbridge_vlanfilter(if_ctx *ctx, const char *val, int dummy __unused) 698 { 699 do_bridgeflag(ctx, val, IFBIF_VLANFILTER, 1); 700 } 701 702 static void 703 unsetbridge_vlanfilter(if_ctx *ctx, const char *val, int dummy __unused) 704 { 705 do_bridgeflag(ctx, val, IFBIF_VLANFILTER, 0); 706 } 707 708 static int 709 parse_vlans(ifbvlan_set_t *set, const char *str) 710 { 711 char *s, *token; 712 713 /* "none" means the empty vlan set */ 714 if (strcmp(str, "none") == 0) { 715 __BIT_ZERO(BRVLAN_SETSIZE, set); 716 return (0); 717 } 718 719 /* "all" means all vlans, except for 0 and 4095 which are reserved */ 720 if (strcmp(str, "all") == 0) { 721 __BIT_FILL(BRVLAN_SETSIZE, set); 722 BRVLAN_CLR(set, DOT1Q_VID_NULL); 723 BRVLAN_CLR(set, DOT1Q_VID_RSVD_IMPL); 724 return (0); 725 } 726 727 if ((s = strdup(str)) == NULL) 728 return (-1); 729 730 while ((token = strsep(&s, ",")) != NULL) { 731 unsigned long first, last; 732 char *p, *lastp; 733 734 if ((lastp = strchr(token, '-')) != NULL) 735 *lastp++ = '\0'; 736 737 first = last = strtoul(token, &p, 10); 738 if (*p != '\0') 739 goto err; 740 if (first < DOT1Q_VID_MIN || first > DOT1Q_VID_MAX) 741 goto err; 742 743 if (lastp) { 744 last = strtoul(lastp, &p, 10); 745 if (*p != '\0') 746 goto err; 747 if (last < DOT1Q_VID_MIN || last > DOT1Q_VID_MAX || 748 last < first) 749 goto err; 750 } 751 752 for (unsigned vlan = first; vlan <= last; ++vlan) 753 BRVLAN_SET(set, vlan); 754 } 755 756 free(s); 757 return (0); 758 759 err: 760 free(s); 761 return (-1); 762 } 763 764 static void 765 set_bridge_vlanset(if_ctx *ctx, const char *ifn, const char *vlans, int op) 766 { 767 struct ifbif_vlan_req req; 768 769 memset(&req, 0, sizeof(req)); 770 771 if (parse_vlans(&req.bv_set, vlans) != 0) 772 errx(1, "invalid vlan set: %s", vlans); 773 774 strlcpy(req.bv_ifname, ifn, sizeof(req.bv_ifname)); 775 req.bv_op = op; 776 777 if (do_cmd(ctx, BRDGSIFVLANSET, &req, sizeof(req), 1) < 0) 778 err(1, "BRDGSIFVLANSET %s", vlans); 779 } 780 781 static void 782 setbridge_tagged(if_ctx *ctx, const char *ifn, const char *vlans) 783 { 784 set_bridge_vlanset(ctx, ifn, vlans, BRDG_VLAN_OP_SET); 785 } 786 787 static void 788 addbridge_tagged(if_ctx *ctx, const char *ifn, const char *vlans) 789 { 790 set_bridge_vlanset(ctx, ifn, vlans, BRDG_VLAN_OP_ADD); 791 } 792 793 static void 794 delbridge_tagged(if_ctx *ctx, const char *ifn, const char *vlans) 795 { 796 set_bridge_vlanset(ctx, ifn, vlans, BRDG_VLAN_OP_DEL); 797 } 798 799 static struct cmd bridge_cmds[] = { 800 DEF_CMD_ARG("addm", setbridge_add), 801 DEF_CMD_ARG("deletem", setbridge_delete), 802 DEF_CMD_ARG("discover", setbridge_discover), 803 DEF_CMD_ARG("-discover", unsetbridge_discover), 804 DEF_CMD_ARG("learn", setbridge_learn), 805 DEF_CMD_ARG("-learn", unsetbridge_learn), 806 DEF_CMD_ARG("sticky", setbridge_sticky), 807 DEF_CMD_ARG("-sticky", unsetbridge_sticky), 808 DEF_CMD_ARG("span", setbridge_span), 809 DEF_CMD_ARG("-span", unsetbridge_span), 810 DEF_CMD_ARG("stp", setbridge_stp), 811 DEF_CMD_ARG("-stp", unsetbridge_stp), 812 DEF_CMD_ARG("edge", setbridge_edge), 813 DEF_CMD_ARG("-edge", unsetbridge_edge), 814 DEF_CMD_ARG("autoedge", setbridge_autoedge), 815 DEF_CMD_ARG("-autoedge", unsetbridge_autoedge), 816 DEF_CMD_ARG("ptp", setbridge_ptp), 817 DEF_CMD_ARG("-ptp", unsetbridge_ptp), 818 DEF_CMD_ARG("autoptp", setbridge_autoptp), 819 DEF_CMD_ARG("-autoptp", unsetbridge_autoptp), 820 DEF_CMD("flush", 0, setbridge_flush), 821 DEF_CMD("flushall", 0, setbridge_flushall), 822 DEF_CMD_ARG2("static", setbridge_static), 823 DEF_CMD_ARG("deladdr", setbridge_deladdr), 824 DEF_CMD("addr", 1, setbridge_addr), 825 DEF_CMD_ARG("maxaddr", setbridge_maxaddr), 826 DEF_CMD_ARG("hellotime", setbridge_hellotime), 827 DEF_CMD_ARG("fwddelay", setbridge_fwddelay), 828 DEF_CMD_ARG("maxage", setbridge_maxage), 829 DEF_CMD_ARG("priority", setbridge_priority), 830 DEF_CMD_ARG("proto", setbridge_protocol), 831 DEF_CMD_ARG("holdcnt", setbridge_holdcount), 832 DEF_CMD_ARG2("ifpriority", setbridge_ifpriority), 833 DEF_CMD_ARG2("ifpathcost", setbridge_ifpathcost), 834 DEF_CMD_ARG2("ifmaxaddr", setbridge_ifmaxaddr), 835 DEF_CMD_ARG("vlanfilter", setbridge_vlanfilter), 836 DEF_CMD_ARG("-vlanfilter", unsetbridge_vlanfilter), 837 DEF_CMD_ARG2("untagged", setbridge_untagged), 838 DEF_CMD_ARG("-untagged", unsetbridge_untagged), 839 DEF_CMD_ARG2("tagged", setbridge_tagged), 840 DEF_CMD_ARG2("+tagged", addbridge_tagged), 841 DEF_CMD_ARG2("-tagged", delbridge_tagged), 842 DEF_CMD_ARG("timeout", setbridge_timeout), 843 DEF_CMD_ARG("private", setbridge_private), 844 DEF_CMD_ARG("-private", unsetbridge_private), 845 }; 846 static struct afswtch af_bridge = { 847 .af_name = "af_bridge", 848 .af_af = AF_UNSPEC, 849 .af_other_status = bridge_status, 850 }; 851 852 static __constructor void 853 bridge_ctor(void) 854 { 855 for (size_t i = 0; i < nitems(bridge_cmds); i++) 856 cmd_register(&bridge_cmds[i]); 857 af_register(&af_bridge); 858 } 859