1 /*- 2 * Copyright 2001 Wasabi Systems, Inc. 3 * All rights reserved. 4 * 5 * Written by Jason R. Thorpe for Wasabi Systems, Inc. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed for the NetBSD Project by 18 * Wasabi Systems, Inc. 19 * 4. The name of Wasabi Systems, Inc. may not be used to endorse 20 * or promote products derived from this software without specific prior 21 * written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 25 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 26 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 27 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 28 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 29 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 30 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 31 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33 * POSSIBILITY OF SUCH DAMAGE. 34 * 35 * $FreeBSD: src/sbin/ifconfig/ifbridge.c,v 1.1.2.2 2005/12/28 04:12:58 thompsa Exp $ 36 */ 37 38 #include <sys/param.h> 39 #include <sys/ioctl.h> 40 #include <sys/socket.h> 41 #include <sys/sockio.h> 42 #include <net/if.h> 43 #include <net/route.h> 44 #include <net/ethernet.h> 45 #include <net/bridge/if_bridgevar.h> 46 47 #include <ctype.h> 48 #include <stdio.h> 49 #include <stdlib.h> 50 #include <string.h> 51 #include <unistd.h> 52 #include <err.h> 53 #include <errno.h> 54 55 #include "ifconfig.h" 56 57 static int 58 get_val(const char *cp, u_long *valp) 59 { 60 char *endptr; 61 u_long val; 62 63 errno = 0; 64 val = strtoul(cp, &endptr, 0); 65 if (cp[0] == '\0' || endptr[0] != '\0' || errno == ERANGE) 66 return (-1); 67 68 *valp = val; 69 return (0); 70 } 71 72 static int 73 do_cmd(int sock, u_long op, void *arg, size_t argsize, int set) 74 { 75 struct ifdrv ifd; 76 77 memset(&ifd, 0, sizeof(ifd)); 78 79 strlcpy(ifd.ifd_name, ifr.ifr_name, sizeof(ifd.ifd_name)); 80 ifd.ifd_cmd = op; 81 ifd.ifd_len = argsize; 82 ifd.ifd_data = arg; 83 84 return (ioctl(sock, set ? SIOCSDRVSPEC : SIOCGDRVSPEC, &ifd)); 85 } 86 87 static void 88 do_bridgeflag(int sock, const char *ifs, int flag, int set) 89 { 90 struct ifbreq req; 91 92 strlcpy(req.ifbr_ifsname, ifs, sizeof(req.ifbr_ifsname)); 93 94 if (do_cmd(sock, BRDGGIFFLGS, &req, sizeof(req), 0) < 0) 95 err(1, "unable to get bridge flags"); 96 97 if (set) 98 req.ifbr_ifsflags |= flag; 99 else 100 req.ifbr_ifsflags &= ~flag; 101 102 if (do_cmd(sock, BRDGSIFFLGS, &req, sizeof(req), 1) < 0) 103 err(1, "unable to set bridge flags"); 104 } 105 106 static void 107 bridge_interfaces(int s, const char *prefix) 108 { 109 static const char *stpstates[] = { 110 "disabled", 111 "listening", 112 "learning", 113 "forwarding", 114 "blocking", 115 "bonded", 116 "blocking (link1)" 117 }; 118 struct ifbifconf bifc; 119 struct ifbreq *req; 120 char *inbuf = NULL, *ninbuf; 121 char *p, *pad; 122 size_t i, len = 8192; 123 124 pad = strdup(prefix); 125 if (pad == NULL) 126 err(1, "strdup"); 127 /* replace the prefix with whitespace */ 128 for (p = pad; *p != '\0'; p++) { 129 if(isprint(*p)) 130 *p = ' '; 131 } 132 133 for (;;) { 134 ninbuf = realloc(inbuf, len); 135 if (ninbuf == NULL) 136 err(1, "unable to allocate interface buffer"); 137 bifc.ifbic_len = len; 138 bifc.ifbic_buf = inbuf = ninbuf; 139 if (do_cmd(s, BRDGGIFS, &bifc, sizeof(bifc), 0) < 0) 140 err(1, "unable to get interface list"); 141 if ((bifc.ifbic_len + sizeof(*req)) < len) 142 break; 143 len *= 2; 144 } 145 146 for (i = 0; i < bifc.ifbic_len / sizeof(*req); i++) { 147 req = bifc.ifbic_req + i; 148 printf("%s%s ", prefix, req->ifbr_ifsname); 149 printb("flags", req->ifbr_ifsflags, IFBIFBITS); 150 printf("\n"); 151 152 if (req->ifbr_ifsflags & IFBIF_STP) { 153 printf("%s", pad); 154 printf("port %u priority %u", 155 req->ifbr_portno, req->ifbr_priority); 156 printf(" pathcost %u", req->ifbr_path_cost); 157 if (req->ifbr_state < nitems(stpstates)) 158 printf(" %s", stpstates[req->ifbr_state]); 159 else 160 printf(" <unknown state %d>", 161 req->ifbr_state); 162 printf("\n"); 163 printf("%sbondweight %u\n", 164 pad, req->ifbr_bond_weight); 165 printf("%sdesignated root: %016jx\n", 166 pad, (intmax_t)req->ifbr_designated_root); 167 printf("%sdesignated bridge: %016jx\n", 168 pad, (intmax_t)req->ifbr_designated_bridge); 169 printf("%sdesignated cost: %u\n", 170 pad, req->ifbr_designated_cost); 171 printf("%sdesignated port: %u\n", 172 pad, req->ifbr_designated_port); 173 if (verbose) { 174 printf("%speer root: %016jx\n", 175 pad, (intmax_t)req->ifbr_peer_root); 176 printf("%speer bridge: %016jx\n", 177 pad, (intmax_t)req->ifbr_peer_bridge); 178 printf("%speer cost: %u\n", 179 pad, req->ifbr_peer_cost); 180 printf("%speer port: %u\n", 181 pad, req->ifbr_peer_port); 182 } 183 } 184 } 185 186 free(inbuf); 187 } 188 189 static void 190 bridge_addresses(int s, const char *prefix) 191 { 192 struct ifbaconf ifbac; 193 struct ifbareq *ifba; 194 struct ether_addr ea; 195 char *inbuf = NULL, *ninbuf; 196 size_t i, len = 8192; 197 198 for (;;) { 199 ninbuf = realloc(inbuf, len); 200 if (ninbuf == NULL) 201 err(1, "unable to allocate address buffer"); 202 ifbac.ifbac_len = len; 203 ifbac.ifbac_buf = inbuf = ninbuf; 204 if (do_cmd(s, BRDGRTS, &ifbac, sizeof(ifbac), 0) < 0) 205 err(1, "unable to get address cache"); 206 if ((ifbac.ifbac_len + sizeof(*ifba)) < len) 207 break; 208 len *= 2; 209 } 210 211 for (i = 0; i < ifbac.ifbac_len / sizeof(*ifba); i++) { 212 ifba = ifbac.ifbac_req + i; 213 memcpy(ea.octet, ifba->ifba_dst, 214 sizeof(ea.octet)); 215 printf("%s%s %s %lu ", prefix, ether_ntoa(&ea), 216 ifba->ifba_ifsname, ifba->ifba_expire); 217 printb("flags", ifba->ifba_flags, IFBAFBITS); 218 printf("\n"); 219 } 220 221 free(inbuf); 222 } 223 224 static void 225 bridge_status(int s) 226 { 227 struct ifbrparam param; 228 u_int16_t pri; 229 u_int8_t ht, fd, ma; 230 231 if (do_cmd(s, BRDGGPRI, ¶m, sizeof(param), 0) < 0) 232 return; 233 pri = param.ifbrp_prio; 234 235 if (do_cmd(s, BRDGGHT, ¶m, sizeof(param), 0) < 0) 236 return; 237 ht = param.ifbrp_hellotime; 238 239 if (do_cmd(s, BRDGGFD, ¶m, sizeof(param), 0) < 0) 240 return; 241 fd = param.ifbrp_fwddelay; 242 243 if (do_cmd(s, BRDGGMA, ¶m, sizeof(param), 0) < 0) 244 return; 245 ma = param.ifbrp_maxage; 246 247 printf("\tpriority %u hellotime %u fwddelay %u maxage %u\n", 248 pri, ht, fd, ma); 249 250 bridge_interfaces(s, "\tmember: "); 251 252 return; 253 254 } 255 256 static void 257 setbridge_add(const char *val, int d, int s, const struct afswtch *afp) 258 { 259 struct ifbreq req; 260 261 memset(&req, 0, sizeof(req)); 262 strlcpy(req.ifbr_ifsname, val, sizeof(req.ifbr_ifsname)); 263 if (do_cmd(s, BRDGADD, &req, sizeof(req), 1) < 0) 264 err(1, "BRDGADD %s", val); 265 } 266 267 static void 268 setbridge_delete(const char *val, int d, int s, const struct afswtch *afp) 269 { 270 struct ifbreq req; 271 272 memset(&req, 0, sizeof(req)); 273 strlcpy(req.ifbr_ifsname, val, sizeof(req.ifbr_ifsname)); 274 if (do_cmd(s, BRDGDEL, &req, sizeof(req), 1) < 0) 275 err(1, "BRDGDEL %s", val); 276 } 277 278 static void 279 setbridge_discover(const char *val, int d, int s, const struct afswtch *afp) 280 { 281 282 do_bridgeflag(s, val, IFBIF_DISCOVER, 1); 283 } 284 285 static void 286 unsetbridge_discover(const char *val, int d, int s, const struct afswtch *afp) 287 { 288 289 do_bridgeflag(s, val, IFBIF_DISCOVER, 0); 290 } 291 292 static void 293 setbridge_learn(const char *val, int d, int s, const struct afswtch *afp) 294 { 295 296 do_bridgeflag(s, val, IFBIF_LEARNING, 1); 297 } 298 299 static void 300 unsetbridge_learn(const char *val, int d, int s, const struct afswtch *afp) 301 { 302 303 do_bridgeflag(s, val, IFBIF_LEARNING, 0); 304 } 305 306 static void 307 setbridge_span(const char *val, int d, int s, const struct afswtch *afp) 308 { 309 struct ifbreq req; 310 311 memset(&req, 0, sizeof(req)); 312 strlcpy(req.ifbr_ifsname, val, sizeof(req.ifbr_ifsname)); 313 if (do_cmd(s, BRDGADDS, &req, sizeof(req), 1) < 0) 314 err(1, "BRDGADDS %s", val); 315 } 316 317 static void 318 unsetbridge_span(const char *val, int d, int s, const struct afswtch *afp) 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(s, BRDGDELS, &req, sizeof(req), 1) < 0) 325 err(1, "BRDGDELS %s", val); 326 } 327 328 static void 329 setbridge_stp(const char *val, int d, int s, const struct afswtch *afp) 330 { 331 332 do_bridgeflag(s, val, IFBIF_STP, 1); 333 } 334 335 static void 336 unsetbridge_stp(const char *val, int d, int s, const struct afswtch *afp) 337 { 338 339 do_bridgeflag(s, val, IFBIF_STP, 0); 340 } 341 342 static void 343 setbridge_flush(const char *val, int d, int s, const struct afswtch *afp) 344 { 345 struct ifbreq req; 346 347 memset(&req, 0, sizeof(req)); 348 req.ifbr_ifsflags = IFBF_FLUSHDYN; 349 if (do_cmd(s, BRDGFLUSH, &req, sizeof(req), 1) < 0) 350 err(1, "BRDGFLUSH"); 351 } 352 353 static void 354 setbridge_flushall(const char *val, int d, int s, const struct afswtch *afp) 355 { 356 struct ifbreq req; 357 358 memset(&req, 0, sizeof(req)); 359 req.ifbr_ifsflags = IFBF_FLUSHALL; 360 if (do_cmd(s, BRDGFLUSH, &req, sizeof(req), 1) < 0) 361 err(1, "BRDGFLUSH"); 362 } 363 364 static void 365 setbridge_static(const char *val, const char *mac, int s, 366 const struct afswtch *afp) 367 { 368 struct ifbareq req; 369 struct ether_addr *ea; 370 371 memset(&req, 0, sizeof(req)); 372 strlcpy(req.ifba_ifsname, val, sizeof(req.ifba_ifsname)); 373 374 ea = ether_aton(mac); 375 if (ea == NULL) 376 errx(1, "%s: invalid address: %s", val, mac); 377 378 memcpy(req.ifba_dst, ea->octet, sizeof(req.ifba_dst)); 379 req.ifba_flags = IFBAF_STATIC; 380 381 if (do_cmd(s, BRDGSADDR, &req, sizeof(req), 1) < 0) 382 err(1, "BRDGSADDR %s", val); 383 } 384 385 static void 386 setbridge_deladdr(const char *val, int d, int s, const struct afswtch *afp) 387 { 388 struct ifbareq req; 389 struct ether_addr *ea; 390 391 memset(&req, 0, sizeof(req)); 392 393 ea = ether_aton(val); 394 if (ea == NULL) 395 errx(1, "invalid address: %s", val); 396 397 memcpy(req.ifba_dst, ea->octet, sizeof(req.ifba_dst)); 398 399 if (do_cmd(s, BRDGDADDR, &req, sizeof(req), 1) < 0) 400 err(1, "BRDGDADDR %s", val); 401 } 402 403 static void 404 getbridge_addr(const char *val, int d, int s, const struct afswtch *afp) 405 { 406 bridge_addresses(s, ""); 407 } 408 409 static void 410 setbridge_maxaddr(const char *arg, int d, int s, const struct afswtch *afp) 411 { 412 struct ifbrparam param; 413 u_long val; 414 415 if (get_val(arg, &val) < 0 || (val & ~0xffffffff) != 0) 416 errx(1, "invalid value: %s", arg); 417 418 param.ifbrp_csize = val & 0xffffffff; 419 420 if (do_cmd(s, BRDGSCACHE, ¶m, sizeof(param), 1) < 0) 421 err(1, "BRDGSCACHE %s", arg); 422 } 423 424 static void 425 setbridge_hellotime(const char *arg, int d, int s, const struct afswtch *afp) 426 { 427 struct ifbrparam param; 428 u_long val; 429 430 if (get_val(arg, &val) < 0 || (val & ~0xff) != 0) 431 errx(1, "invalid value: %s", arg); 432 433 param.ifbrp_hellotime = val & 0xff; 434 435 if (do_cmd(s, BRDGSHT, ¶m, sizeof(param), 1) < 0) 436 err(1, "BRDGSHT %s", arg); 437 } 438 439 static void 440 setbridge_fwddelay(const char *arg, int d, int s, const struct afswtch *afp) 441 { 442 struct ifbrparam param; 443 u_long val; 444 445 if (get_val(arg, &val) < 0 || (val & ~0xff) != 0) 446 errx(1, "invalid value: %s", arg); 447 448 param.ifbrp_fwddelay = val & 0xff; 449 450 if (do_cmd(s, BRDGSFD, ¶m, sizeof(param), 1) < 0) 451 err(1, "BRDGSFD %s", arg); 452 } 453 454 static void 455 setbridge_maxage(const char *arg, int d, int s, const struct afswtch *afp) 456 { 457 struct ifbrparam param; 458 u_long val; 459 460 if (get_val(arg, &val) < 0 || (val & ~0xff) != 0) 461 errx(1, "invalid value: %s", arg); 462 463 param.ifbrp_maxage = val & 0xff; 464 465 if (do_cmd(s, BRDGSMA, ¶m, sizeof(param), 1) < 0) 466 err(1, "BRDGSMA %s", arg); 467 } 468 469 static void 470 setbridge_priority(const char *arg, int d, int s, const struct afswtch *afp) 471 { 472 struct ifbrparam param; 473 u_long val; 474 475 if (get_val(arg, &val) < 0 || (val & ~0xffff) != 0) 476 errx(1, "invalid value: %s", arg); 477 478 param.ifbrp_prio = val & 0xffff; 479 480 if (do_cmd(s, BRDGSPRI, ¶m, sizeof(param), 1) < 0) 481 err(1, "BRDGSPRI %s", arg); 482 } 483 484 static void 485 setbridge_ifpriority(const char *ifn, const char *pri, int s, 486 const struct afswtch *afp) 487 { 488 struct ifbreq req; 489 u_long val; 490 491 memset(&req, 0, sizeof(req)); 492 493 if (get_val(pri, &val) < 0 || (val & ~0xff) != 0) 494 errx(1, "invalid value: %s", pri); 495 496 strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname)); 497 req.ifbr_priority = val & 0xff; 498 499 if (do_cmd(s, BRDGSIFPRIO, &req, sizeof(req), 1) < 0) 500 err(1, "BRDGSIFPRIO %s", pri); 501 } 502 503 static void 504 setbridge_ifpathcost(const char *ifn, const char *cost, int s, 505 const struct afswtch *afp) 506 { 507 struct ifbreq req; 508 u_long val; 509 510 memset(&req, 0, sizeof(req)); 511 512 if (get_val(cost, &val) < 0 || (val & ~0xff) != 0) 513 errx(1, "invalid value: %s", cost); 514 515 strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname)); 516 req.ifbr_path_cost = val & 0xffff; 517 518 if (do_cmd(s, BRDGSIFCOST, &req, sizeof(req), 1) < 0) 519 err(1, "BRDGSIFCOST %s", cost); 520 } 521 522 static void 523 setbridge_ifbondweight(const char *ifn, const char *cost, int s, 524 const struct afswtch *afp) 525 { 526 struct ifbreq req; 527 u_long val; 528 529 memset(&req, 0, sizeof(req)); 530 531 if (get_val(cost, &val) < 0 || (val & ~0xff) != 0) 532 errx(1, "invalid value: %s", cost); 533 534 strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname)); 535 if (val > 65535) 536 val = 65535; 537 req.ifbr_bond_weight = (uint16_t)val; 538 539 if (do_cmd(s, BRDGSBONDWGHT, &req, sizeof(req), 1) < 0) 540 err(1, "BRDGSBONDWGHT %s", cost); 541 } 542 543 static void 544 setbridge_timeout(const char *arg, int d, int s, const struct afswtch *afp) 545 { 546 struct ifbrparam param; 547 u_long val; 548 549 if (get_val(arg, &val) < 0 || (val & ~0xffffffff) != 0) 550 errx(1, "invalid value: %s", arg); 551 552 param.ifbrp_ctime = val & 0xffffffff; 553 554 if (do_cmd(s, BRDGSTO, ¶m, sizeof(param), 1) < 0) 555 err(1, "BRDGSTO %s", arg); 556 } 557 558 static struct cmd bridge_cmds[] = { 559 DEF_CMD_ARG("addm", setbridge_add), 560 DEF_CMD_ARG("deletem", setbridge_delete), 561 DEF_CMD_ARG("discover", setbridge_discover), 562 DEF_CMD_ARG("-discover", unsetbridge_discover), 563 DEF_CMD_ARG("learn", setbridge_learn), 564 DEF_CMD_ARG("-learn", unsetbridge_learn), 565 DEF_CMD_ARG("span", setbridge_span), 566 DEF_CMD_ARG("-span", unsetbridge_span), 567 DEF_CMD_ARG("stp", setbridge_stp), 568 DEF_CMD_ARG("-stp", unsetbridge_stp), 569 DEF_CMD("flush", 0, setbridge_flush), 570 DEF_CMD("flushall", 0, setbridge_flushall), 571 DEF_CMD_ARG2("static", setbridge_static), 572 DEF_CMD_ARG("deladdr", setbridge_deladdr), 573 DEF_CMD("addr", 1, getbridge_addr), 574 DEF_CMD_ARG("maxaddr", setbridge_maxaddr), 575 DEF_CMD_ARG("hellotime", setbridge_hellotime), 576 DEF_CMD_ARG("fwddelay", setbridge_fwddelay), 577 DEF_CMD_ARG("maxage", setbridge_maxage), 578 DEF_CMD_ARG("priority", setbridge_priority), 579 DEF_CMD_ARG2("ifpriority", setbridge_ifpriority), 580 DEF_CMD_ARG2("ifpathcost", setbridge_ifpathcost), 581 DEF_CMD_ARG2("ifbondweight", setbridge_ifbondweight), 582 DEF_CMD_ARG("timeout", setbridge_timeout), 583 }; 584 static struct afswtch af_bridge = { 585 .af_name = "af_bridge", 586 .af_af = AF_UNSPEC, 587 .af_other_status = bridge_status, 588 }; 589 590 static __constructor(101) void 591 bridge_ctor(void) 592 { 593 size_t i; 594 595 for (i = 0; i < nitems(bridge_cmds); i++) 596 cmd_register(&bridge_cmds[i]); 597 af_register(&af_bridge); 598 } 599