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