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 int parse_vlans(ifbvlan_set_t *set, const char *str); 64 static int get_val(const char *cp, u_long *valp); 65 static int get_vlan_id(const char *cp, ether_vlanid_t *valp); 66 67 static const char *stpstates[] = { STP_STATES }; 68 static const char *stpproto[] = { STP_PROTOS }; 69 static const char *stproles[] = { STP_ROLES }; 70 71 static int 72 get_val(const char *cp, u_long *valp) 73 { 74 char *endptr; 75 u_long val; 76 77 errno = 0; 78 val = strtoul(cp, &endptr, 0); 79 if (cp[0] == '\0' || endptr[0] != '\0' || errno == ERANGE) 80 return (-1); 81 82 *valp = val; 83 return (0); 84 } 85 86 static int 87 get_vlan_id(const char *cp, ether_vlanid_t *valp) 88 { 89 u_long val; 90 91 if (get_val(cp, &val) == -1) 92 return (-1); 93 if (val < DOT1Q_VID_MIN || val > DOT1Q_VID_MAX) 94 return (-1); 95 96 *valp = (ether_vlanid_t)val; 97 return (0); 98 } 99 100 static int 101 do_cmd(if_ctx *ctx, u_long op, void *arg, size_t argsize, int set) 102 { 103 struct ifdrv ifd = {}; 104 105 strlcpy(ifd.ifd_name, ctx->ifname, sizeof(ifd.ifd_name)); 106 ifd.ifd_cmd = op; 107 ifd.ifd_len = argsize; 108 ifd.ifd_data = arg; 109 110 return (ioctl_ctx(ctx, set ? SIOCSDRVSPEC : SIOCGDRVSPEC, &ifd)); 111 } 112 113 static void 114 do_bridgeflag(if_ctx *ctx, const char *ifs, int flag, int set) 115 { 116 struct ifbreq req; 117 118 strlcpy(req.ifbr_ifsname, ifs, sizeof(req.ifbr_ifsname)); 119 120 if (do_cmd(ctx, BRDGGIFFLGS, &req, sizeof(req), 0) < 0) 121 err(1, "unable to get bridge flags"); 122 123 if (set) 124 req.ifbr_ifsflags |= flag; 125 else 126 req.ifbr_ifsflags &= ~flag; 127 128 if (do_cmd(ctx, BRDGSIFFLGS, &req, sizeof(req), 1) < 0) 129 err(1, "unable to set bridge flags"); 130 } 131 132 static void 133 bridge_addresses(if_ctx *ctx, const char *prefix) 134 { 135 struct ifbaconf ifbac; 136 struct ifbareq *ifba; 137 char *inbuf = NULL, *ninbuf; 138 size_t len = 8192; 139 struct ether_addr ea; 140 141 for (;;) { 142 ninbuf = realloc(inbuf, len); 143 if (ninbuf == NULL) 144 err(1, "unable to allocate address buffer"); 145 ifbac.ifbac_len = len; 146 ifbac.ifbac_buf = inbuf = ninbuf; 147 if (do_cmd(ctx, BRDGRTS, &ifbac, sizeof(ifbac), 0) < 0) 148 err(1, "unable to get address cache"); 149 if ((ifbac.ifbac_len + sizeof(*ifba)) < len) 150 break; 151 len *= 2; 152 } 153 154 for (unsigned long i = 0; i < ifbac.ifbac_len / sizeof(*ifba); i++) { 155 ifba = ifbac.ifbac_req + i; 156 memcpy(ea.octet, ifba->ifba_dst, 157 sizeof(ea.octet)); 158 printf("%s%s Vlan%d %s %lu ", prefix, ether_ntoa(&ea), 159 ifba->ifba_vlan, ifba->ifba_ifsname, ifba->ifba_expire); 160 printb("flags", ifba->ifba_flags, IFBAFBITS); 161 printf("\n"); 162 } 163 164 free(inbuf); 165 } 166 167 static void 168 print_vlans(ifbvlan_set_t *vlans) 169 { 170 unsigned printed = 0; 171 172 for (unsigned vlan = DOT1Q_VID_MIN; vlan <= DOT1Q_VID_MAX;) { 173 unsigned last; 174 175 if (!BRVLAN_TEST(vlans, vlan)) { 176 ++vlan; 177 continue; 178 } 179 180 last = vlan; 181 while (last < DOT1Q_VID_MAX && BRVLAN_TEST(vlans, last + 1)) 182 ++last; 183 184 if (printed == 0) 185 printf(" tagged "); 186 else 187 printf(","); 188 189 printf("%u", vlan); 190 if (last != vlan) 191 printf("-%u", last); 192 ++printed; 193 vlan = last + 1; 194 } 195 } 196 197 static char const * 198 vlan_proto_name(uint16_t proto) 199 { 200 switch (proto) { 201 case 0: 202 return "none"; 203 case ETHERTYPE_VLAN: 204 return "802.1q"; 205 case ETHERTYPE_QINQ: 206 return "802.1ad"; 207 default: 208 return "unknown"; 209 } 210 } 211 212 static void 213 bridge_status(if_ctx *ctx) 214 { 215 struct ifconfig_bridge_status *bridge; 216 struct ifbropreq *params; 217 const char *pad, *prefix; 218 uint8_t lladdr[ETHER_ADDR_LEN]; 219 uint16_t bprio; 220 221 if (ifconfig_bridge_get_bridge_status(lifh, ctx->ifname, &bridge) == -1) 222 return; 223 224 params = bridge->params; 225 226 PV2ID(params->ifbop_bridgeid, bprio, lladdr); 227 printf("\tid %s priority %u hellotime %u fwddelay %u\n", 228 ether_ntoa((struct ether_addr *)lladdr), 229 params->ifbop_priority, 230 params->ifbop_hellotime, 231 params->ifbop_fwddelay); 232 printf("\tmaxage %u holdcnt %u proto %s maxaddr %u timeout %u\n", 233 params->ifbop_maxage, 234 params->ifbop_holdcount, 235 stpproto[params->ifbop_protocol], 236 bridge->cache_size, 237 bridge->cache_lifetime); 238 PV2ID(params->ifbop_designated_root, bprio, lladdr); 239 printf("\troot id %s priority %d ifcost %u port %u\n", 240 ether_ntoa((struct ether_addr *)lladdr), 241 bprio, 242 params->ifbop_root_path_cost, 243 params->ifbop_root_port & 0xfff); 244 245 printb("\tbridge flags", bridge->flags, IFBRFBITS); 246 if (bridge->defpvid) 247 printf(" defuntagged=%u", (unsigned) bridge->defpvid); 248 printf("\n"); 249 250 prefix = "\tmember: "; 251 pad = "\t "; 252 for (size_t i = 0; i < bridge->members_count; ++i) { 253 struct ifbreq *member = &bridge->members[i]; 254 255 printf("%s%s ", prefix, member->ifbr_ifsname); 256 printb("flags", member->ifbr_ifsflags, IFBIFBITS); 257 printf("\n%s", pad); 258 if (member->ifbr_addrmax != 0) 259 printf("ifmaxaddr %u ", member->ifbr_addrmax); 260 printf("port %u priority %u path cost %u", 261 member->ifbr_portno, 262 member->ifbr_priority, 263 member->ifbr_path_cost); 264 if (member->ifbr_ifsflags & IFBIF_STP) { 265 uint8_t proto = member->ifbr_proto; 266 uint8_t role = member->ifbr_role; 267 uint8_t state = member->ifbr_state; 268 269 if (proto < nitems(stpproto)) 270 printf(" proto %s", stpproto[proto]); 271 else 272 printf(" <unknown proto %d>", proto); 273 printf("\n%s", pad); 274 if (role < nitems(stproles)) 275 printf("role %s", stproles[role]); 276 else 277 printf("<unknown role %d>", role); 278 if (state < nitems(stpstates)) 279 printf(" state %s", stpstates[state]); 280 else 281 printf(" <unknown state %d>", state); 282 } 283 if (member->ifbr_vlanproto != 0) 284 printf(" vlan protocol %s", 285 vlan_proto_name(member->ifbr_vlanproto)); 286 if (member->ifbr_pvid != 0) 287 printf(" untagged %u", (unsigned)member->ifbr_pvid); 288 print_vlans(&bridge->member_vlans[i]); 289 printf("\n"); 290 } 291 292 ifconfig_bridge_free_bridge_status(bridge); 293 } 294 295 static int 296 setbridge_add(if_ctx *ctx, int argc, const char *const *argv) 297 { 298 struct ifbreq req; 299 struct ifbif_vlan_req vlreq; 300 int oargc = argc; 301 302 memset(&req, 0, sizeof(req)); 303 memset(&vlreq, 0, sizeof(vlreq)); 304 305 if (argc < 1) 306 errx(1, "usage: addm <interface> [opts ...]"); 307 308 strlcpy(req.ifbr_ifsname, argv[0], sizeof(req.ifbr_ifsname)); 309 --argc; ++argv; 310 311 while (argc) { 312 if (strcmp(argv[0], "untagged") == 0) { 313 if (argc < 2) 314 errx(1, "usage: untagged <vlan id>"); 315 316 if (get_vlan_id(argv[1], &req.ifbr_pvid) < 0) 317 errx(1, "invalid VLAN identifier: %s", argv[1]); 318 319 argc -= 2; 320 argv += 2; 321 } else if (strcmp(argv[0], "tagged") == 0) { 322 if (argc < 2) 323 errx(1, "usage: tagged <vlan set>"); 324 325 vlreq.bv_op = BRDG_VLAN_OP_SET; 326 strlcpy(vlreq.bv_ifname, req.ifbr_ifsname, 327 sizeof(vlreq.bv_ifname)); 328 if (parse_vlans(&vlreq.bv_set, argv[1]) != 0) 329 errx(1, "invalid vlan set: %s", argv[1]); 330 331 argc -= 2; 332 argv += 2; 333 } else { 334 break; 335 } 336 } 337 338 if (do_cmd(ctx, BRDGADD, &req, sizeof(req), 1) < 0) 339 err(1, "BRDGADD %s", req.ifbr_ifsname); 340 341 if (req.ifbr_pvid != 0 && 342 do_cmd(ctx, BRDGSIFPVID, &req, sizeof(req), 1) < 0) 343 err(1, "BRDGSIFPVID %s %u", req.ifbr_ifsname, 344 (unsigned)req.ifbr_pvid); 345 346 if (vlreq.bv_op != 0 && 347 do_cmd(ctx, BRDGSIFVLANSET, &vlreq, sizeof(vlreq), 1) < 0) 348 err(1, "BRDGSIFVLANSET %s", req.ifbr_ifsname); 349 350 return (oargc - argc); 351 } 352 353 static void 354 setbridge_delete(if_ctx *ctx, const char *val, int dummy __unused) 355 { 356 struct ifbreq req; 357 358 memset(&req, 0, sizeof(req)); 359 strlcpy(req.ifbr_ifsname, val, sizeof(req.ifbr_ifsname)); 360 if (do_cmd(ctx, BRDGDEL, &req, sizeof(req), 1) < 0) 361 err(1, "BRDGDEL %s", val); 362 } 363 364 static void 365 setbridge_discover(if_ctx *ctx, const char *val, int dummy __unused) 366 { 367 368 do_bridgeflag(ctx, val, IFBIF_DISCOVER, 1); 369 } 370 371 static void 372 unsetbridge_discover(if_ctx *ctx, const char *val, int dummy __unused) 373 { 374 375 do_bridgeflag(ctx, val, IFBIF_DISCOVER, 0); 376 } 377 378 static void 379 setbridge_learn(if_ctx *ctx, const char *val, int dummy __unused) 380 { 381 382 do_bridgeflag(ctx, val, IFBIF_LEARNING, 1); 383 } 384 385 static void 386 unsetbridge_learn(if_ctx *ctx, const char *val, int dummy __unused) 387 { 388 389 do_bridgeflag(ctx, val, IFBIF_LEARNING, 0); 390 } 391 392 static void 393 setbridge_sticky(if_ctx *ctx, const char *val, int dummy __unused) 394 { 395 396 do_bridgeflag(ctx, val, IFBIF_STICKY, 1); 397 } 398 399 static void 400 unsetbridge_sticky(if_ctx *ctx, const char *val, int dummy __unused) 401 { 402 403 do_bridgeflag(ctx, val, IFBIF_STICKY, 0); 404 } 405 406 static void 407 setbridge_span(if_ctx *ctx, const char *val, int dummy __unused) 408 { 409 struct ifbreq req; 410 411 memset(&req, 0, sizeof(req)); 412 strlcpy(req.ifbr_ifsname, val, sizeof(req.ifbr_ifsname)); 413 if (do_cmd(ctx, BRDGADDS, &req, sizeof(req), 1) < 0) 414 err(1, "BRDGADDS %s", val); 415 } 416 417 static void 418 unsetbridge_span(if_ctx *ctx, const char *val, int dummy __unused) 419 { 420 struct ifbreq req; 421 422 memset(&req, 0, sizeof(req)); 423 strlcpy(req.ifbr_ifsname, val, sizeof(req.ifbr_ifsname)); 424 if (do_cmd(ctx, BRDGDELS, &req, sizeof(req), 1) < 0) 425 err(1, "BRDGDELS %s", val); 426 } 427 428 static void 429 setbridge_stp(if_ctx *ctx, const char *val, int dummy __unused) 430 { 431 432 do_bridgeflag(ctx, val, IFBIF_STP, 1); 433 } 434 435 static void 436 unsetbridge_stp(if_ctx *ctx, const char *val, int dummy __unused) 437 { 438 439 do_bridgeflag(ctx, val, IFBIF_STP, 0); 440 } 441 442 static void 443 setbridge_edge(if_ctx *ctx, const char *val, int dummy __unused) 444 { 445 do_bridgeflag(ctx, val, IFBIF_BSTP_EDGE, 1); 446 } 447 448 static void 449 unsetbridge_edge(if_ctx *ctx, const char *val, int dummy __unused) 450 { 451 do_bridgeflag(ctx, val, IFBIF_BSTP_EDGE, 0); 452 } 453 454 static void 455 setbridge_autoedge(if_ctx *ctx, const char *val, int dummy __unused) 456 { 457 do_bridgeflag(ctx, val, IFBIF_BSTP_AUTOEDGE, 1); 458 } 459 460 static void 461 unsetbridge_autoedge(if_ctx *ctx, const char *val, int dummy __unused) 462 { 463 do_bridgeflag(ctx, val, IFBIF_BSTP_AUTOEDGE, 0); 464 } 465 466 static void 467 setbridge_ptp(if_ctx *ctx, const char *val, int dummy __unused) 468 { 469 do_bridgeflag(ctx, val, IFBIF_BSTP_PTP, 1); 470 } 471 472 static void 473 unsetbridge_ptp(if_ctx *ctx, const char *val, int dummy __unused) 474 { 475 do_bridgeflag(ctx, val, IFBIF_BSTP_PTP, 0); 476 } 477 478 static void 479 setbridge_autoptp(if_ctx *ctx, const char *val, int dummy __unused) 480 { 481 do_bridgeflag(ctx, val, IFBIF_BSTP_AUTOPTP, 1); 482 } 483 484 static void 485 unsetbridge_autoptp(if_ctx *ctx, const char *val, int dummy __unused) 486 { 487 do_bridgeflag(ctx, val, IFBIF_BSTP_AUTOPTP, 0); 488 } 489 490 static void 491 setbridge_flush(if_ctx *ctx, const char *val __unused, int dummy __unused) 492 { 493 struct ifbreq req; 494 495 memset(&req, 0, sizeof(req)); 496 req.ifbr_ifsflags = IFBF_FLUSHDYN; 497 if (do_cmd(ctx, BRDGFLUSH, &req, sizeof(req), 1) < 0) 498 err(1, "BRDGFLUSH"); 499 } 500 501 static void 502 setbridge_flushall(if_ctx *ctx, const char *val __unused, int dummy __unused) 503 { 504 struct ifbreq req; 505 506 memset(&req, 0, sizeof(req)); 507 req.ifbr_ifsflags = IFBF_FLUSHALL; 508 if (do_cmd(ctx, BRDGFLUSH, &req, sizeof(req), 1) < 0) 509 err(1, "BRDGFLUSH"); 510 } 511 512 static int 513 setbridge_static(if_ctx *ctx, int argc, const char *const *argv) 514 { 515 struct ifbareq req; 516 struct ether_addr *ea; 517 int arg; 518 519 if (argc < 2) 520 errx(1, "usage: static <interface> <address> [vlan <id>]"); 521 arg = 0; 522 523 memset(&req, 0, sizeof(req)); 524 req.ifba_flags = IFBAF_STATIC; 525 526 strlcpy(req.ifba_ifsname, argv[arg], sizeof(req.ifba_ifsname)); 527 ++arg; 528 529 ea = ether_aton(argv[arg]); 530 if (ea == NULL) 531 errx(1, "invalid address: %s", argv[arg]); 532 memcpy(req.ifba_dst, ea->octet, sizeof(req.ifba_dst)); 533 ++arg; 534 535 req.ifba_vlan = 0; 536 if (argc > 2 && strcmp(argv[arg], "vlan") == 0) { 537 if (argc < 3) 538 errx(1, "usage: static <interface> <address> " 539 "[vlan <id>]"); 540 ++arg; 541 542 if (get_vlan_id(argv[arg], &req.ifba_vlan) < 0) 543 errx(1, "invalid vlan id: %s", argv[arg]); 544 ++arg; 545 } 546 547 if (do_cmd(ctx, BRDGSADDR, &req, sizeof(req), 1) < 0) 548 err(1, "BRDGSADDR"); 549 return arg; 550 } 551 552 static int 553 setbridge_deladdr(if_ctx *ctx, int argc, const char *const *argv) 554 { 555 struct ifbareq req; 556 struct ether_addr *ea; 557 int arg; 558 559 if (argc < 1) 560 errx(1, "usage: deladdr <address> [vlan <id>]"); 561 arg = 0; 562 563 memset(&req, 0, sizeof(req)); 564 565 ea = ether_aton(argv[arg]); 566 if (ea == NULL) 567 errx(1, "invalid address: %s", argv[arg]); 568 memcpy(req.ifba_dst, ea->octet, sizeof(req.ifba_dst)); 569 ++arg; 570 571 req.ifba_vlan = 0; 572 if (argc >= 2 && strcmp(argv[arg], "vlan") == 0) { 573 if (argc < 3) 574 errx(1, "usage: deladdr <address> [vlan <id>]"); 575 ++arg; 576 577 if (get_vlan_id(argv[arg], &req.ifba_vlan) < 0) 578 errx(1, "invalid vlan id: %s", argv[arg]); 579 ++arg; 580 } 581 582 if (do_cmd(ctx, BRDGDADDR, &req, sizeof(req), 1) < 0) 583 err(1, "BRDGDADDR"); 584 585 return arg; 586 } 587 588 static void 589 setbridge_addr(if_ctx *ctx, const char *val __unused, int dummy __unused) 590 { 591 bridge_addresses(ctx, ""); 592 } 593 594 static void 595 setbridge_maxaddr(if_ctx *ctx, const char *arg, int dummy __unused) 596 { 597 struct ifbrparam param; 598 u_long val; 599 600 if (get_val(arg, &val) < 0 || (val & ~0xffffffff) != 0) 601 errx(1, "invalid value: %s", arg); 602 603 param.ifbrp_csize = val & 0xffffffff; 604 605 if (do_cmd(ctx, BRDGSCACHE, ¶m, sizeof(param), 1) < 0) 606 err(1, "BRDGSCACHE %s", arg); 607 } 608 609 static void 610 setbridge_hellotime(if_ctx *ctx, const char *arg, int dummy __unused) 611 { 612 struct ifbrparam param; 613 u_long val; 614 615 if (get_val(arg, &val) < 0 || (val & ~0xff) != 0) 616 errx(1, "invalid value: %s", arg); 617 618 param.ifbrp_hellotime = val & 0xff; 619 620 if (do_cmd(ctx, BRDGSHT, ¶m, sizeof(param), 1) < 0) 621 err(1, "BRDGSHT %s", arg); 622 } 623 624 static void 625 setbridge_fwddelay(if_ctx *ctx, const char *arg, int dummy __unused) 626 { 627 struct ifbrparam param; 628 u_long val; 629 630 if (get_val(arg, &val) < 0 || (val & ~0xff) != 0) 631 errx(1, "invalid value: %s", arg); 632 633 param.ifbrp_fwddelay = val & 0xff; 634 635 if (do_cmd(ctx, BRDGSFD, ¶m, sizeof(param), 1) < 0) 636 err(1, "BRDGSFD %s", arg); 637 } 638 639 static void 640 setbridge_maxage(if_ctx *ctx, const char *arg, int dummy __unused) 641 { 642 struct ifbrparam param; 643 u_long val; 644 645 if (get_val(arg, &val) < 0 || (val & ~0xff) != 0) 646 errx(1, "invalid value: %s", arg); 647 648 param.ifbrp_maxage = val & 0xff; 649 650 if (do_cmd(ctx, BRDGSMA, ¶m, sizeof(param), 1) < 0) 651 err(1, "BRDGSMA %s", arg); 652 } 653 654 static void 655 setbridge_priority(if_ctx *ctx, const char *arg, int dummy __unused) 656 { 657 struct ifbrparam param; 658 u_long val; 659 660 if (get_val(arg, &val) < 0 || (val & ~0xffff) != 0) 661 errx(1, "invalid value: %s", arg); 662 663 param.ifbrp_prio = val & 0xffff; 664 665 if (do_cmd(ctx, BRDGSPRI, ¶m, sizeof(param), 1) < 0) 666 err(1, "BRDGSPRI %s", arg); 667 } 668 669 static void 670 setbridge_protocol(if_ctx *ctx, const char *arg, int dummy __unused) 671 { 672 struct ifbrparam param; 673 674 if (strcasecmp(arg, "stp") == 0) { 675 param.ifbrp_proto = 0; 676 } else if (strcasecmp(arg, "rstp") == 0) { 677 param.ifbrp_proto = 2; 678 } else { 679 errx(1, "unknown stp protocol"); 680 } 681 682 if (do_cmd(ctx, BRDGSPROTO, ¶m, sizeof(param), 1) < 0) 683 err(1, "BRDGSPROTO %s", arg); 684 } 685 686 static void 687 setbridge_holdcount(if_ctx *ctx, const char *arg, int dummy __unused) 688 { 689 struct ifbrparam param; 690 u_long val; 691 692 if (get_val(arg, &val) < 0 || (val & ~0xff) != 0) 693 errx(1, "invalid value: %s", arg); 694 695 param.ifbrp_txhc = val & 0xff; 696 697 if (do_cmd(ctx, BRDGSTXHC, ¶m, sizeof(param), 1) < 0) 698 err(1, "BRDGSTXHC %s", arg); 699 } 700 701 static void 702 setbridge_ifpriority(if_ctx *ctx, const char *ifn, const char *pri) 703 { 704 struct ifbreq req; 705 u_long val; 706 707 memset(&req, 0, sizeof(req)); 708 709 if (get_val(pri, &val) < 0 || (val & ~0xff) != 0) 710 errx(1, "invalid value: %s", pri); 711 712 strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname)); 713 req.ifbr_priority = val & 0xff; 714 715 if (do_cmd(ctx, BRDGSIFPRIO, &req, sizeof(req), 1) < 0) 716 err(1, "BRDGSIFPRIO %s", pri); 717 } 718 719 static void 720 setbridge_ifpathcost(if_ctx *ctx, const char *ifn, const char *cost) 721 { 722 struct ifbreq req; 723 u_long val; 724 725 memset(&req, 0, sizeof(req)); 726 727 if (get_val(cost, &val) < 0) 728 errx(1, "invalid value: %s", cost); 729 730 strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname)); 731 req.ifbr_path_cost = val; 732 733 if (do_cmd(ctx, BRDGSIFCOST, &req, sizeof(req), 1) < 0) 734 err(1, "BRDGSIFCOST %s", cost); 735 } 736 737 static void 738 setbridge_ifuntagged(if_ctx *ctx, const char *ifn, const char *vlanid) 739 { 740 struct ifbreq req; 741 742 memset(&req, 0, sizeof(req)); 743 strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname)); 744 745 if (get_vlan_id(vlanid, &req.ifbr_pvid) < 0) 746 errx(1, "invalid VLAN identifier: %s", vlanid); 747 748 if (do_cmd(ctx, BRDGSIFPVID, &req, sizeof(req), 1) < 0) 749 err(1, "BRDGSIFPVID %s", vlanid); 750 } 751 752 static void 753 unsetbridge_ifuntagged(if_ctx *ctx, const char *ifn, int dummy __unused) 754 { 755 struct ifbreq req; 756 757 memset(&req, 0, sizeof(req)); 758 759 strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname)); 760 req.ifbr_pvid = 0; 761 762 if (do_cmd(ctx, BRDGSIFPVID, &req, sizeof(req), 1) < 0) 763 err(1, "BRDGSIFPVID"); 764 } 765 766 static void 767 setbridge_ifmaxaddr(if_ctx *ctx, const char *ifn, const char *arg) 768 { 769 struct ifbreq req; 770 u_long val; 771 772 memset(&req, 0, sizeof(req)); 773 774 if (get_val(arg, &val) < 0 || (val & ~0xffffffff) != 0) 775 errx(1, "invalid value: %s", arg); 776 777 strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname)); 778 req.ifbr_addrmax = val & 0xffffffff; 779 780 if (do_cmd(ctx, BRDGSIFAMAX, &req, sizeof(req), 1) < 0) 781 err(1, "BRDGSIFAMAX %s", arg); 782 } 783 784 static void 785 setbridge_timeout(if_ctx *ctx, const char *arg, int dummy __unused) 786 { 787 struct ifbrparam param; 788 u_long val; 789 790 if (get_val(arg, &val) < 0 || (val & ~0xffffffff) != 0) 791 errx(1, "invalid value: %s", arg); 792 793 param.ifbrp_ctime = val & 0xffffffff; 794 795 if (do_cmd(ctx, BRDGSTO, ¶m, sizeof(param), 1) < 0) 796 err(1, "BRDGSTO %s", arg); 797 } 798 799 static void 800 setbridge_private(if_ctx *ctx, const char *val, int dummy __unused) 801 { 802 do_bridgeflag(ctx, val, IFBIF_PRIVATE, 1); 803 } 804 805 static void 806 unsetbridge_private(if_ctx *ctx, const char *val, int dummy __unused) 807 { 808 do_bridgeflag(ctx, val, IFBIF_PRIVATE, 0); 809 } 810 811 static int 812 parse_vlans(ifbvlan_set_t *set, const char *str) 813 { 814 char *s, *token; 815 816 /* "none" means the empty vlan set */ 817 if (strcmp(str, "none") == 0) { 818 __BIT_ZERO(BRVLAN_SETSIZE, set); 819 return (0); 820 } 821 822 /* "all" means all vlans, except for 0 and 4095 which are reserved */ 823 if (strcmp(str, "all") == 0) { 824 __BIT_FILL(BRVLAN_SETSIZE, set); 825 BRVLAN_CLR(set, DOT1Q_VID_NULL); 826 BRVLAN_CLR(set, DOT1Q_VID_RSVD_IMPL); 827 return (0); 828 } 829 830 if ((s = strdup(str)) == NULL) 831 return (-1); 832 833 while ((token = strsep(&s, ",")) != NULL) { 834 unsigned long first, last; 835 char *p, *lastp; 836 837 if ((lastp = strchr(token, '-')) != NULL) 838 *lastp++ = '\0'; 839 840 first = last = strtoul(token, &p, 10); 841 if (*p != '\0') 842 goto err; 843 if (first < DOT1Q_VID_MIN || first > DOT1Q_VID_MAX) 844 goto err; 845 846 if (lastp) { 847 last = strtoul(lastp, &p, 10); 848 if (*p != '\0') 849 goto err; 850 if (last < DOT1Q_VID_MIN || last > DOT1Q_VID_MAX || 851 last < first) 852 goto err; 853 } 854 855 for (unsigned vlan = first; vlan <= last; ++vlan) 856 BRVLAN_SET(set, vlan); 857 } 858 859 free(s); 860 return (0); 861 862 err: 863 free(s); 864 return (-1); 865 } 866 867 static void 868 set_bridge_vlanset(if_ctx *ctx, const char *ifn, const char *vlans, int op) 869 { 870 struct ifbif_vlan_req req; 871 872 memset(&req, 0, sizeof(req)); 873 874 if (parse_vlans(&req.bv_set, vlans) != 0) 875 errx(1, "invalid vlan set: %s", vlans); 876 877 strlcpy(req.bv_ifname, ifn, sizeof(req.bv_ifname)); 878 req.bv_op = op; 879 880 if (do_cmd(ctx, BRDGSIFVLANSET, &req, sizeof(req), 1) < 0) 881 err(1, "BRDGSIFVLANSET %s", vlans); 882 } 883 884 static void 885 setbridge_iftagged(if_ctx *ctx, const char *ifn, const char *vlans) 886 { 887 set_bridge_vlanset(ctx, ifn, vlans, BRDG_VLAN_OP_SET); 888 } 889 890 static void 891 addbridge_iftagged(if_ctx *ctx, const char *ifn, const char *vlans) 892 { 893 set_bridge_vlanset(ctx, ifn, vlans, BRDG_VLAN_OP_ADD); 894 } 895 896 static void 897 delbridge_iftagged(if_ctx *ctx, const char *ifn, const char *vlans) 898 { 899 set_bridge_vlanset(ctx, ifn, vlans, BRDG_VLAN_OP_DEL); 900 } 901 902 static void 903 setbridge_flags(if_ctx *ctx, const char *val __unused, int newflags) 904 { 905 struct ifbrparam req; 906 907 if (do_cmd(ctx, BRDGGFLAGS, &req, sizeof(req), 0) < 0) 908 err(1, "BRDGGFLAGS"); 909 910 req.ifbrp_flags |= (uint32_t)newflags; 911 912 if (do_cmd(ctx, BRDGSFLAGS, &req, sizeof(req), 1) < 0) 913 err(1, "BRDGSFLAGS"); 914 } 915 916 static void 917 unsetbridge_flags(if_ctx *ctx, const char *val __unused, int newflags) 918 { 919 struct ifbrparam req; 920 921 if (do_cmd(ctx, BRDGGFLAGS, &req, sizeof(req), 0) < 0) 922 err(1, "BRDGGFLAGS"); 923 924 req.ifbrp_flags &= ~(uint32_t)newflags; 925 926 if (do_cmd(ctx, BRDGSFLAGS, &req, sizeof(req), 1) < 0) 927 err(1, "BRDGSFLAGS"); 928 } 929 930 static void 931 setbridge_defuntagged(if_ctx *ctx, const char *arg, int dummy __unused) 932 { 933 struct ifbrparam req; 934 935 memset(&req, 0, sizeof(req)); 936 if (get_vlan_id(arg, &req.ifbrp_defpvid) < 0) 937 errx(1, "invalid vlan id: %s", arg); 938 939 if (do_cmd(ctx, BRDGSDEFPVID, &req, sizeof(req), 1) < 0) 940 err(1, "BRDGSDEFPVID"); 941 } 942 943 static void 944 unsetbridge_defuntagged(if_ctx *ctx, const char *val __unused, int dummy __unused) 945 { 946 struct ifbrparam req; 947 948 memset(&req, 0, sizeof(req)); 949 req.ifbrp_defpvid = 0; 950 951 if (do_cmd(ctx, BRDGSDEFPVID, &req, sizeof(req), 1) < 0) 952 err(1, "BRDGSDEFPVID"); 953 } 954 955 static void 956 setbridge_qinq(if_ctx *ctx, const char *val, int dummy __unused) 957 { 958 do_bridgeflag(ctx, val, IFBIF_QINQ, 1); 959 } 960 961 static void 962 unsetbridge_qinq(if_ctx *ctx, const char *val, int dummy __unused) 963 { 964 do_bridgeflag(ctx, val, IFBIF_QINQ, 0); 965 } 966 967 static void 968 setbridge_ifvlanproto(if_ctx *ctx, const char *ifname, const char *proto) 969 { 970 struct ifbreq req; 971 972 memset(&req, 0, sizeof(req)); 973 strlcpy(req.ifbr_ifsname, ifname, sizeof(req.ifbr_ifsname)); 974 975 if (strcmp(proto, "802.1q") == 0) 976 req.ifbr_vlanproto = ETHERTYPE_VLAN; 977 else if (strcmp(proto, "802.1ad") == 0) 978 req.ifbr_vlanproto = ETHERTYPE_QINQ; 979 else 980 errx(1, "unrecognised VLAN protocol: %s", proto); 981 982 if (do_cmd(ctx, BRDGSIFVLANPROTO, &req, sizeof(req), 1) < 0) 983 err(1, "BRDGSIFVLANPROTO"); 984 } 985 986 static struct cmd bridge_cmds[] = { 987 DEF_CMD_VARG("addm", setbridge_add), 988 DEF_CMD_ARG("deletem", setbridge_delete), 989 DEF_CMD_ARG("discover", setbridge_discover), 990 DEF_CMD_ARG("-discover", unsetbridge_discover), 991 DEF_CMD_ARG("learn", setbridge_learn), 992 DEF_CMD_ARG("-learn", unsetbridge_learn), 993 DEF_CMD_ARG("sticky", setbridge_sticky), 994 DEF_CMD_ARG("-sticky", unsetbridge_sticky), 995 DEF_CMD_ARG("span", setbridge_span), 996 DEF_CMD_ARG("-span", unsetbridge_span), 997 DEF_CMD_ARG("stp", setbridge_stp), 998 DEF_CMD_ARG("-stp", unsetbridge_stp), 999 DEF_CMD_ARG("edge", setbridge_edge), 1000 DEF_CMD_ARG("-edge", unsetbridge_edge), 1001 DEF_CMD_ARG("autoedge", setbridge_autoedge), 1002 DEF_CMD_ARG("-autoedge", unsetbridge_autoedge), 1003 DEF_CMD_ARG("ptp", setbridge_ptp), 1004 DEF_CMD_ARG("-ptp", unsetbridge_ptp), 1005 DEF_CMD_ARG("autoptp", setbridge_autoptp), 1006 DEF_CMD_ARG("-autoptp", unsetbridge_autoptp), 1007 DEF_CMD("flush", 0, setbridge_flush), 1008 DEF_CMD("flushall", 0, setbridge_flushall), 1009 DEF_CMD_VARG("static", setbridge_static), 1010 DEF_CMD_VARG("deladdr", setbridge_deladdr), 1011 DEF_CMD("addr", 1, setbridge_addr), 1012 DEF_CMD_ARG("maxaddr", setbridge_maxaddr), 1013 DEF_CMD_ARG("hellotime", setbridge_hellotime), 1014 DEF_CMD_ARG("fwddelay", setbridge_fwddelay), 1015 DEF_CMD_ARG("maxage", setbridge_maxage), 1016 DEF_CMD_ARG("priority", setbridge_priority), 1017 DEF_CMD_ARG("proto", setbridge_protocol), 1018 DEF_CMD_ARG("holdcnt", setbridge_holdcount), 1019 DEF_CMD_ARG2("ifpriority", setbridge_ifpriority), 1020 DEF_CMD_ARG2("ifpathcost", setbridge_ifpathcost), 1021 DEF_CMD_ARG2("ifmaxaddr", setbridge_ifmaxaddr), 1022 DEF_CMD_ARG2("ifuntagged", setbridge_ifuntagged), 1023 DEF_CMD_ARG("-ifuntagged", unsetbridge_ifuntagged), 1024 DEF_CMD_ARG2("iftagged", setbridge_iftagged), 1025 DEF_CMD_ARG2("+iftagged", addbridge_iftagged), 1026 DEF_CMD_ARG2("-iftagged", delbridge_iftagged), 1027 DEF_CMD_ARG2("ifvlanproto", setbridge_ifvlanproto), 1028 DEF_CMD_ARG("timeout", setbridge_timeout), 1029 DEF_CMD_ARG("private", setbridge_private), 1030 DEF_CMD_ARG("-private", unsetbridge_private), 1031 DEF_CMD("vlanfilter", (int32_t)IFBRF_VLANFILTER, 1032 setbridge_flags), 1033 DEF_CMD("-vlanfilter", (int32_t)IFBRF_VLANFILTER, 1034 unsetbridge_flags), 1035 DEF_CMD_ARG("defuntagged", setbridge_defuntagged), 1036 DEF_CMD("-defuntagged", 0, unsetbridge_defuntagged), 1037 DEF_CMD("defqinq", (int32_t)IFBRF_DEFQINQ, 1038 setbridge_flags), 1039 DEF_CMD("-defqinq", (int32_t)IFBRF_DEFQINQ, 1040 unsetbridge_flags), 1041 DEF_CMD_ARG("qinq", setbridge_qinq), 1042 DEF_CMD_ARG("-qinq", unsetbridge_qinq), 1043 }; 1044 1045 static struct afswtch af_bridge = { 1046 .af_name = "af_bridge", 1047 .af_af = AF_UNSPEC, 1048 .af_other_status = bridge_status, 1049 }; 1050 1051 static __constructor void 1052 bridge_ctor(void) 1053 { 1054 for (size_t i = 0; i < nitems(bridge_cmds); i++) 1055 cmd_register(&bridge_cmds[i]); 1056 af_register(&af_bridge); 1057 } 1058