1 1.18 ozaki /* $NetBSD: brconfig.c,v 1.18 2024/09/03 08:00:30 ozaki-r Exp $ */ 2 1.1 thorpej 3 1.1 thorpej /* 4 1.1 thorpej * Copyright 2001 Wasabi Systems, Inc. 5 1.1 thorpej * All rights reserved. 6 1.1 thorpej * 7 1.1 thorpej * Written by Jason R. Thorpe for Wasabi Systems, Inc. 8 1.1 thorpej * 9 1.1 thorpej * Redistribution and use in source and binary forms, with or without 10 1.1 thorpej * modification, are permitted provided that the following conditions 11 1.1 thorpej * are met: 12 1.1 thorpej * 1. Redistributions of source code must retain the above copyright 13 1.1 thorpej * notice, this list of conditions and the following disclaimer. 14 1.1 thorpej * 2. Redistributions in binary form must reproduce the above copyright 15 1.1 thorpej * notice, this list of conditions and the following disclaimer in the 16 1.1 thorpej * documentation and/or other materials provided with the distribution. 17 1.1 thorpej * 3. All advertising materials mentioning features or use of this software 18 1.1 thorpej * must display the following acknowledgement: 19 1.1 thorpej * This product includes software developed for the NetBSD Project by 20 1.1 thorpej * Wasabi Systems, Inc. 21 1.1 thorpej * 4. The name of Wasabi Systems, Inc. may not be used to endorse 22 1.1 thorpej * or promote products derived from this software without specific prior 23 1.1 thorpej * written permission. 24 1.1 thorpej * 25 1.1 thorpej * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 26 1.1 thorpej * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27 1.1 thorpej * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28 1.1 thorpej * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 29 1.1 thorpej * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 1.1 thorpej * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 1.1 thorpej * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 1.1 thorpej * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 1.1 thorpej * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 1.1 thorpej * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 1.1 thorpej * POSSIBILITY OF SUCH DAMAGE. 36 1.1 thorpej */ 37 1.1 thorpej 38 1.1 thorpej /* 39 1.1 thorpej * brconfig(8) -- 40 1.1 thorpej * 41 1.1 thorpej * Configuration utility for the bridge(4) driver. 42 1.1 thorpej */ 43 1.6 agc #include <sys/cdefs.h> 44 1.6 agc 45 1.6 agc #ifndef lint 46 1.18 ozaki __RCSID("$NetBSD: brconfig.c,v 1.18 2024/09/03 08:00:30 ozaki-r Exp $"); 47 1.6 agc #endif 48 1.6 agc 49 1.1 thorpej 50 1.1 thorpej #include <sys/param.h> 51 1.1 thorpej #include <sys/socket.h> 52 1.1 thorpej #include <sys/ioctl.h> 53 1.1 thorpej 54 1.1 thorpej #include <net/if.h> 55 1.1 thorpej #include <net/if_ether.h> 56 1.1 thorpej #include <net/if_bridgevar.h> 57 1.1 thorpej 58 1.1 thorpej #include <ctype.h> 59 1.1 thorpej #include <err.h> 60 1.1 thorpej #include <errno.h> 61 1.1 thorpej #include <stdio.h> 62 1.1 thorpej #include <stdlib.h> 63 1.1 thorpej #include <string.h> 64 1.1 thorpej #include <unistd.h> 65 1.1 thorpej #include <ifaddrs.h> 66 1.1 thorpej 67 1.1 thorpej struct command { 68 1.1 thorpej const char *cmd_keyword; 69 1.1 thorpej int cmd_argcnt; 70 1.1 thorpej int cmd_flags; 71 1.1 thorpej void (*cmd_func)(const struct command *, int, const char *, 72 1.1 thorpej char **); 73 1.1 thorpej }; 74 1.1 thorpej 75 1.1 thorpej #define CMD_INVERT 0x01 /* "invert" the sense of the command */ 76 1.1 thorpej 77 1.13 joerg static void cmd_add(const struct command *, int, const char *, char **); 78 1.13 joerg static void cmd_delete(const struct command *, int, const char *, char **); 79 1.13 joerg static void cmd_up(const struct command *, int, const char *, char **); 80 1.13 joerg static void cmd_down(const struct command *, int, const char *, char **); 81 1.13 joerg static void cmd_discover(const struct command *, int, const char *, char **); 82 1.13 joerg static void cmd_learn(const struct command *, int, const char *, char **); 83 1.13 joerg static void cmd_flush(const struct command *, int, const char *, char **); 84 1.13 joerg static void cmd_flushall(const struct command *, int, const char *, char **); 85 1.13 joerg static void cmd_static(const struct command *, int, const char *, char **); 86 1.13 joerg static void cmd_deladdr(const struct command *, int, const char *, char **); 87 1.13 joerg static void cmd_addr(const struct command *, int, const char *, char **); 88 1.13 joerg static void cmd_maxaddr(const struct command *, int, const char *, char **); 89 1.13 joerg static void cmd_hellotime(const struct command *, int, const char *, char **); 90 1.13 joerg static void cmd_fwddelay(const struct command *, int, const char *, char **); 91 1.13 joerg static void cmd_maxage(const struct command *, int, const char *, char **); 92 1.13 joerg static void cmd_priority(const struct command *, int, const char *, char **); 93 1.13 joerg static void cmd_ifpriority(const struct command *, int, const char *, char **); 94 1.13 joerg static void cmd_ifpathcost(const struct command *, int, const char *, char **); 95 1.13 joerg static void cmd_timeout(const struct command *, int, const char *, char **); 96 1.13 joerg static void cmd_stp(const struct command *, int, const char *, char **); 97 1.13 joerg static void cmd_ipf(const struct command *, int, const char *, char **); 98 1.18 ozaki static void cmd_protect(const struct command *, int, const char *, char **); 99 1.1 thorpej 100 1.13 joerg static const struct command command_table[] = { 101 1.1 thorpej { "add", 1, 0, cmd_add }, 102 1.1 thorpej { "delete", 1, 0, cmd_delete }, 103 1.1 thorpej 104 1.1 thorpej { "up", 0, 0, cmd_up }, 105 1.1 thorpej { "down", 0, 0, cmd_down }, 106 1.1 thorpej 107 1.1 thorpej { "discover", 1, 0, cmd_discover }, 108 1.1 thorpej { "-discover", 1, CMD_INVERT, cmd_discover }, 109 1.1 thorpej 110 1.1 thorpej { "learn", 1, 0, cmd_learn }, 111 1.1 thorpej { "-learn", 1, CMD_INVERT, cmd_learn }, 112 1.1 thorpej 113 1.1 thorpej { "flush", 0, 0, cmd_flush }, 114 1.1 thorpej { "flushall", 0, 0, cmd_flushall }, 115 1.1 thorpej 116 1.1 thorpej { "static", 2, 0, cmd_static }, 117 1.1 thorpej { "deladdr", 1, 0, cmd_deladdr }, 118 1.1 thorpej 119 1.1 thorpej { "addr", 0, 0, cmd_addr }, 120 1.1 thorpej { "maxaddr", 1, 0, cmd_maxaddr }, 121 1.1 thorpej 122 1.1 thorpej { "hellotime", 1, 0, cmd_hellotime }, 123 1.1 thorpej { "fwddelay", 1, 0, cmd_fwddelay }, 124 1.1 thorpej { "maxage", 1, 0, cmd_maxage }, 125 1.1 thorpej { "priority", 1, 0, cmd_priority }, 126 1.1 thorpej { "ifpriority", 2, 0, cmd_ifpriority }, 127 1.5 bouyer { "ifpathcost", 2, 0, cmd_ifpathcost }, 128 1.1 thorpej { "timeout", 1, 0, cmd_timeout }, 129 1.1 thorpej { "stp", 1, 0, cmd_stp }, 130 1.1 thorpej { "-stp", 1, CMD_INVERT, cmd_stp }, 131 1.1 thorpej 132 1.3 perseant { "ipf", 0, 0, cmd_ipf }, 133 1.3 perseant { "-ipf", 0, CMD_INVERT, cmd_ipf }, 134 1.3 perseant 135 1.18 ozaki { "protect", 1, 0, cmd_protect }, 136 1.18 ozaki { "-protect", 1, CMD_INVERT, cmd_protect }, 137 1.18 ozaki 138 1.1 thorpej { NULL, 0, 0, NULL }, 139 1.1 thorpej }; 140 1.1 thorpej 141 1.13 joerg static void printall(int); 142 1.13 joerg static void status(int, const char *); 143 1.13 joerg static int is_bridge(const char *); 144 1.13 joerg static void show_config(int, const char *, const char *); 145 1.13 joerg static void show_interfaces(int, const char *, const char *); 146 1.13 joerg static void show_addresses(int, const char *, const char *); 147 1.13 joerg static int get_val(const char *, u_long *); 148 1.17 matt #define do_cmd(a,b,c,d,e,f) do_cmd2((a),(b),(c),(d),(e),NULL,(f)) 149 1.17 matt static int do_cmd2(int, const char *, u_long, void *, size_t, size_t *, int); 150 1.13 joerg static void do_ifflag(int, const char *, int, int); 151 1.13 joerg static void do_bridgeflag(int, const char *, const char *, int, int); 152 1.1 thorpej 153 1.13 joerg static void printb(const char *, u_int, const char *); 154 1.1 thorpej 155 1.13 joerg __dead static void usage(void); 156 1.1 thorpej 157 1.13 joerg static int aflag; 158 1.1 thorpej 159 1.13 joerg static struct ifreq g_ifr; 160 1.13 joerg static int g_ifr_updated; 161 1.1 thorpej 162 1.1 thorpej int 163 1.1 thorpej main(int argc, char *argv[]) 164 1.1 thorpej { 165 1.1 thorpej const struct command *cmd; 166 1.1 thorpej char *bridge; 167 1.1 thorpej int sock, ch; 168 1.1 thorpej 169 1.1 thorpej if (argc < 2) 170 1.1 thorpej usage(); 171 1.1 thorpej 172 1.1 thorpej sock = socket(AF_INET, SOCK_DGRAM, 0); 173 1.1 thorpej if (sock < 0) 174 1.1 thorpej err(1, "socket"); 175 1.1 thorpej 176 1.1 thorpej while ((ch = getopt(argc, argv, "a")) != -1) { 177 1.1 thorpej switch (ch) { 178 1.1 thorpej case 'a': 179 1.1 thorpej aflag = 1; 180 1.1 thorpej break; 181 1.1 thorpej 182 1.1 thorpej default: 183 1.1 thorpej usage(); 184 1.1 thorpej } 185 1.1 thorpej } 186 1.1 thorpej 187 1.1 thorpej argc -= optind; 188 1.1 thorpej argv += optind; 189 1.1 thorpej 190 1.1 thorpej if (aflag) { 191 1.1 thorpej if (argc != 0) 192 1.1 thorpej usage(); 193 1.1 thorpej printall(sock); 194 1.1 thorpej exit(0); 195 1.1 thorpej } 196 1.1 thorpej 197 1.1 thorpej if (argc == 0) 198 1.1 thorpej usage(); 199 1.1 thorpej 200 1.1 thorpej bridge = argv[0]; 201 1.1 thorpej 202 1.1 thorpej if (is_bridge(bridge) == 0) 203 1.1 thorpej errx(1, "%s is not a bridge", bridge); 204 1.1 thorpej 205 1.1 thorpej /* Get a copy of the interface flags. */ 206 1.1 thorpej strlcpy(g_ifr.ifr_name, bridge, sizeof(g_ifr.ifr_name)); 207 1.1 thorpej if (ioctl(sock, SIOCGIFFLAGS, &g_ifr) < 0) 208 1.1 thorpej err(1, "unable to get interface flags"); 209 1.1 thorpej 210 1.1 thorpej argc--; 211 1.1 thorpej argv++; 212 1.1 thorpej 213 1.1 thorpej if (argc == 0) { 214 1.1 thorpej status(sock, bridge); 215 1.1 thorpej exit(0); 216 1.1 thorpej } 217 1.1 thorpej 218 1.1 thorpej while (argc != 0) { 219 1.1 thorpej for (cmd = command_table; cmd->cmd_keyword != NULL; cmd++) { 220 1.1 thorpej if (strcmp(cmd->cmd_keyword, argv[0]) == 0) 221 1.1 thorpej break; 222 1.1 thorpej } 223 1.1 thorpej if (cmd->cmd_keyword == NULL) 224 1.1 thorpej errx(1, "unknown command: %s", argv[0]); 225 1.1 thorpej 226 1.1 thorpej argc--; 227 1.1 thorpej argv++; 228 1.1 thorpej 229 1.1 thorpej if (argc < cmd->cmd_argcnt) 230 1.1 thorpej errx(1, "command %s requires %d argument%s", 231 1.1 thorpej cmd->cmd_keyword, cmd->cmd_argcnt, 232 1.1 thorpej cmd->cmd_argcnt == 1 ? "" : "s"); 233 1.1 thorpej 234 1.1 thorpej (*cmd->cmd_func)(cmd, sock, bridge, argv); 235 1.1 thorpej 236 1.1 thorpej argc -= cmd->cmd_argcnt; 237 1.1 thorpej argv += cmd->cmd_argcnt; 238 1.1 thorpej } 239 1.1 thorpej 240 1.1 thorpej /* If the flags changed, update them. */ 241 1.1 thorpej if (g_ifr_updated && ioctl(sock, SIOCSIFFLAGS, &g_ifr) < 0) 242 1.1 thorpej err(1, "unable to set interface flags"); 243 1.1 thorpej 244 1.1 thorpej exit (0); 245 1.1 thorpej } 246 1.1 thorpej 247 1.13 joerg static void 248 1.1 thorpej usage(void) 249 1.1 thorpej { 250 1.1 thorpej static const char *usage_strings[] = { 251 1.1 thorpej "-a", 252 1.1 thorpej "<bridge>", 253 1.1 thorpej "<bridge> up|down", 254 1.1 thorpej "<bridge> addr", 255 1.1 thorpej "<bridge> add <interface>", 256 1.1 thorpej "<bridge> delete <interface>", 257 1.1 thorpej "<bridge> maxaddr <size>", 258 1.1 thorpej "<bridge> timeout <time>", 259 1.1 thorpej "<bridge> static <interface> <address>", 260 1.1 thorpej "<bridge> deladdr <address>", 261 1.1 thorpej "<bridge> flush", 262 1.1 thorpej "<bridge> flushall", 263 1.3 perseant "<bridge> ipf|-ipf", 264 1.1 thorpej "<bridge> discover|-discover <interface>", 265 1.1 thorpej "<bridge> learn|-learn <interface>", 266 1.1 thorpej "<bridge> stp|-stp <interface>", 267 1.1 thorpej "<bridge> maxage <time>", 268 1.1 thorpej "<bridge> fwddelay <time>", 269 1.1 thorpej "<bridge> hellotime <time>", 270 1.1 thorpej "<bridge> priority <value>", 271 1.1 thorpej "<bridge> ifpriority <interface> <value>", 272 1.5 bouyer "<bridge> ifpathcost <interface> <value>", 273 1.1 thorpej NULL, 274 1.1 thorpej }; 275 1.1 thorpej extern const char *__progname; 276 1.1 thorpej int i; 277 1.1 thorpej 278 1.1 thorpej for (i = 0; usage_strings[i] != NULL; i++) 279 1.1 thorpej fprintf(stderr, "%s %s %s\n", 280 1.1 thorpej i == 0 ? "usage:" : " ", 281 1.1 thorpej __progname, usage_strings[i]); 282 1.1 thorpej 283 1.1 thorpej exit(1); 284 1.1 thorpej } 285 1.1 thorpej 286 1.13 joerg static int 287 1.1 thorpej is_bridge(const char *bridge) 288 1.1 thorpej { 289 1.1 thorpej 290 1.1 thorpej if (strncmp(bridge, "bridge", 6) != 0 || 291 1.8 dsl isdigit((unsigned char)bridge[6]) == 0) 292 1.1 thorpej return (0); 293 1.1 thorpej 294 1.1 thorpej return (1); 295 1.1 thorpej } 296 1.1 thorpej 297 1.13 joerg static void 298 1.1 thorpej printb(const char *s, u_int v, const char *bits) 299 1.1 thorpej { 300 1.1 thorpej int i, any = 0; 301 1.1 thorpej char c; 302 1.1 thorpej 303 1.1 thorpej if (bits && *bits == 8) 304 1.1 thorpej printf("%s=%o", s, v); 305 1.1 thorpej else 306 1.1 thorpej printf("%s=%x", s, v); 307 1.1 thorpej if (bits) { 308 1.11 christos bits++; 309 1.1 thorpej putchar('<'); 310 1.1 thorpej while ((i = *bits++) != 0) { 311 1.1 thorpej if (v & (1 << (i-1))) { 312 1.1 thorpej if (any) 313 1.1 thorpej putchar(','); 314 1.1 thorpej any = 1; 315 1.1 thorpej for (; (c = *bits) > 32; bits++) 316 1.1 thorpej putchar(c); 317 1.1 thorpej } else 318 1.1 thorpej for (; *bits > 32; bits++) 319 1.1 thorpej ; 320 1.1 thorpej } 321 1.1 thorpej putchar('>'); 322 1.1 thorpej } 323 1.1 thorpej } 324 1.1 thorpej 325 1.13 joerg static void 326 1.1 thorpej printall(int sock) 327 1.1 thorpej { 328 1.1 thorpej struct ifaddrs *ifap, *ifa; 329 1.1 thorpej char *p; 330 1.1 thorpej 331 1.1 thorpej if (getifaddrs(&ifap) != 0) 332 1.1 thorpej err(1, "getifaddrs"); 333 1.1 thorpej p = NULL; 334 1.1 thorpej for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) { 335 1.1 thorpej if (is_bridge(ifa->ifa_name) == 0) 336 1.1 thorpej continue; 337 1.1 thorpej if (p != NULL && strcmp(p, ifa->ifa_name) == 0) 338 1.1 thorpej continue; 339 1.1 thorpej p = ifa->ifa_name; 340 1.1 thorpej status(sock, ifa->ifa_name); 341 1.1 thorpej } 342 1.1 thorpej 343 1.1 thorpej freeifaddrs(ifap); 344 1.1 thorpej } 345 1.1 thorpej 346 1.13 joerg static void 347 1.1 thorpej status(int sock, const char *bridge) 348 1.1 thorpej { 349 1.1 thorpej struct ifreq ifr; 350 1.1 thorpej struct ifbrparam bp1, bp2; 351 1.1 thorpej 352 1.1 thorpej memset(&ifr, 0, sizeof(ifr)); 353 1.1 thorpej 354 1.1 thorpej strlcpy(ifr.ifr_name, bridge, sizeof(ifr.ifr_name)); 355 1.1 thorpej if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) 356 1.1 thorpej err(1, "unable to get flags"); 357 1.1 thorpej 358 1.1 thorpej printf("%s: ", bridge); 359 1.1 thorpej printb("flags", ifr.ifr_flags, IFFBITS); 360 1.1 thorpej printf("\n"); 361 1.1 thorpej 362 1.1 thorpej printf("\tConfiguration:\n"); 363 1.1 thorpej show_config(sock, bridge, "\t\t"); 364 1.1 thorpej 365 1.1 thorpej printf("\tInterfaces:\n"); 366 1.1 thorpej show_interfaces(sock, bridge, "\t\t"); 367 1.1 thorpej 368 1.1 thorpej if (do_cmd(sock, bridge, BRDGGCACHE, &bp1, sizeof(bp1), 0) < 0) 369 1.1 thorpej err(1, "unable to get address cache size"); 370 1.1 thorpej if (do_cmd(sock, bridge, BRDGGTO, &bp2, sizeof(bp2), 0) < 0) 371 1.1 thorpej err(1, "unable to get address timeout"); 372 1.1 thorpej 373 1.1 thorpej printf("\tAddress cache (max cache: %u, timeout: %u):\n", 374 1.1 thorpej bp1.ifbrp_csize, bp2.ifbrp_ctime); 375 1.1 thorpej show_addresses(sock, bridge, "\t\t"); 376 1.1 thorpej } 377 1.1 thorpej 378 1.13 joerg static void 379 1.1 thorpej show_config(int sock, const char *bridge, const char *prefix) 380 1.1 thorpej { 381 1.1 thorpej struct ifbrparam param; 382 1.4 perseant u_int32_t ipfflags; 383 1.1 thorpej u_int16_t pri; 384 1.1 thorpej u_int8_t ht, fd, ma; 385 1.1 thorpej 386 1.1 thorpej if (do_cmd(sock, bridge, BRDGGPRI, ¶m, sizeof(param), 0) < 0) 387 1.1 thorpej err(1, "unable to get bridge priority"); 388 1.1 thorpej pri = param.ifbrp_prio; 389 1.1 thorpej 390 1.1 thorpej if (do_cmd(sock, bridge, BRDGGHT, ¶m, sizeof(param), 0) < 0) 391 1.1 thorpej err(1, "unable to get hellotime"); 392 1.1 thorpej ht = param.ifbrp_hellotime; 393 1.1 thorpej 394 1.1 thorpej if (do_cmd(sock, bridge, BRDGGFD, ¶m, sizeof(param), 0) < 0) 395 1.1 thorpej err(1, "unable to get forward delay"); 396 1.1 thorpej fd = param.ifbrp_fwddelay; 397 1.1 thorpej 398 1.1 thorpej if (do_cmd(sock, bridge, BRDGGMA, ¶m, sizeof(param), 0) < 0) 399 1.1 thorpej err(1, "unable to get max age"); 400 1.1 thorpej ma = param.ifbrp_maxage; 401 1.1 thorpej 402 1.1 thorpej printf("%spriority %u hellotime %u fwddelay %u maxage %u\n", 403 1.1 thorpej prefix, pri, ht, fd, ma); 404 1.4 perseant 405 1.4 perseant if (do_cmd(sock, bridge, BRDGGFILT, ¶m, sizeof(param), 0) < 0) { 406 1.4 perseant /* err(1, "unable to get ipfilter status"); */ 407 1.4 perseant param.ifbrp_filter = 0; 408 1.4 perseant } 409 1.4 perseant 410 1.4 perseant ipfflags = param.ifbrp_filter; 411 1.4 perseant printf("%sipfilter %s flags 0x%x\n", prefix, 412 1.4 perseant (ipfflags & IFBF_FILT_USEIPF) ? "enabled" : "disabled", 413 1.4 perseant ipfflags); 414 1.1 thorpej } 415 1.1 thorpej 416 1.13 joerg static void 417 1.1 thorpej show_interfaces(int sock, const char *bridge, const char *prefix) 418 1.1 thorpej { 419 1.16 joerg static const char stpstates[][11] = { 420 1.1 thorpej "disabled", 421 1.1 thorpej "listening", 422 1.1 thorpej "learning", 423 1.1 thorpej "forwarding", 424 1.1 thorpej "blocking", 425 1.1 thorpej }; 426 1.1 thorpej struct ifbreq *req; 427 1.7 itojun char *inbuf = NULL, *ninbuf; 428 1.17 matt size_t len = 8192, nlen; 429 1.1 thorpej 430 1.17 matt do { 431 1.17 matt nlen = len; 432 1.17 matt ninbuf = realloc(inbuf, nlen); 433 1.7 itojun if (ninbuf == NULL) 434 1.7 itojun err(1, "unable to allocate interface buffer"); 435 1.17 matt inbuf = ninbuf; 436 1.17 matt if (do_cmd2(sock, bridge, BRDGGIFS, inbuf, nlen, &len, 0) < 0) 437 1.1 thorpej err(1, "unable to get interface list"); 438 1.17 matt } while (len > nlen); 439 1.1 thorpej 440 1.17 matt for (size_t i = 0; i < len / sizeof(*req); i++) { 441 1.17 matt req = (struct ifbreq *)inbuf + i; 442 1.1 thorpej printf("%s%s ", prefix, req->ifbr_ifsname); 443 1.1 thorpej printb("flags", req->ifbr_ifsflags, IFBIFBITS); 444 1.1 thorpej printf("\n"); 445 1.1 thorpej printf("%s\t", prefix); 446 1.1 thorpej printf("port %u priority %u", 447 1.1 thorpej req->ifbr_portno, req->ifbr_priority); 448 1.1 thorpej if (req->ifbr_ifsflags & IFBIF_STP) { 449 1.5 bouyer printf(" path cost %u", req->ifbr_path_cost); 450 1.1 thorpej if (req->ifbr_state < 451 1.1 thorpej sizeof(stpstates) / sizeof(stpstates[0])) 452 1.1 thorpej printf(" %s", stpstates[req->ifbr_state]); 453 1.1 thorpej else 454 1.1 thorpej printf(" <unknown state %d>", 455 1.1 thorpej req->ifbr_state); 456 1.1 thorpej } 457 1.1 thorpej printf("\n"); 458 1.1 thorpej } 459 1.1 thorpej 460 1.1 thorpej free(inbuf); 461 1.1 thorpej } 462 1.1 thorpej 463 1.13 joerg static void 464 1.1 thorpej show_addresses(int sock, const char *bridge, const char *prefix) 465 1.1 thorpej { 466 1.1 thorpej struct ifbareq *ifba; 467 1.7 itojun char *inbuf = NULL, *ninbuf; 468 1.1 thorpej struct ether_addr ea; 469 1.17 matt size_t len = 8192, nlen; 470 1.1 thorpej 471 1.17 matt do { 472 1.17 matt nlen = len; 473 1.17 matt ninbuf = realloc(inbuf, nlen); 474 1.7 itojun if (ninbuf == NULL) 475 1.7 itojun err(1, "unable to allocate address buffer"); 476 1.17 matt inbuf = ninbuf; 477 1.17 matt if (do_cmd2(sock, bridge, BRDGRTS, inbuf, nlen, &len, 0) < 0) 478 1.1 thorpej err(1, "unable to get address cache"); 479 1.17 matt } while (len > nlen); 480 1.1 thorpej 481 1.17 matt for (size_t i = 0; i < len / sizeof(*ifba); i++) { 482 1.17 matt ifba = (struct ifbareq *)inbuf + i; 483 1.1 thorpej memcpy(ea.ether_addr_octet, ifba->ifba_dst, 484 1.1 thorpej sizeof(ea.ether_addr_octet)); 485 1.17 matt printf("%s%s %s %jd ", prefix, ether_ntoa(&ea), 486 1.17 matt ifba->ifba_ifsname, (uintmax_t)ifba->ifba_expire); 487 1.1 thorpej printb("flags", ifba->ifba_flags, IFBAFBITS); 488 1.1 thorpej printf("\n"); 489 1.1 thorpej } 490 1.1 thorpej 491 1.1 thorpej free(inbuf); 492 1.1 thorpej } 493 1.1 thorpej 494 1.13 joerg static int 495 1.1 thorpej get_val(const char *cp, u_long *valp) 496 1.1 thorpej { 497 1.1 thorpej char *endptr; 498 1.1 thorpej u_long val; 499 1.1 thorpej 500 1.1 thorpej errno = 0; 501 1.1 thorpej val = strtoul(cp, &endptr, 0); 502 1.1 thorpej if (cp[0] == '\0' || endptr[0] != '\0' || errno == ERANGE) 503 1.1 thorpej return (-1); 504 1.1 thorpej 505 1.1 thorpej *valp = val; 506 1.1 thorpej return (0); 507 1.1 thorpej } 508 1.1 thorpej 509 1.13 joerg static int 510 1.17 matt do_cmd2(int sock, const char *bridge, u_long op, void *arg, size_t argsize, 511 1.17 matt size_t *outsizep, int set) 512 1.1 thorpej { 513 1.1 thorpej struct ifdrv ifd; 514 1.17 matt int error; 515 1.1 thorpej 516 1.1 thorpej memset(&ifd, 0, sizeof(ifd)); 517 1.1 thorpej 518 1.1 thorpej strlcpy(ifd.ifd_name, bridge, sizeof(ifd.ifd_name)); 519 1.1 thorpej ifd.ifd_cmd = op; 520 1.1 thorpej ifd.ifd_len = argsize; 521 1.1 thorpej ifd.ifd_data = arg; 522 1.1 thorpej 523 1.17 matt error = ioctl(sock, set ? SIOCSDRVSPEC : SIOCGDRVSPEC, &ifd); 524 1.17 matt 525 1.17 matt if (outsizep) 526 1.17 matt *outsizep = ifd.ifd_len; 527 1.17 matt 528 1.17 matt return error; 529 1.1 thorpej } 530 1.1 thorpej 531 1.13 joerg static void 532 1.1 thorpej do_ifflag(int sock, const char *bridge, int flag, int set) 533 1.1 thorpej { 534 1.1 thorpej 535 1.1 thorpej if (set) 536 1.1 thorpej g_ifr.ifr_flags |= flag; 537 1.1 thorpej else 538 1.1 thorpej g_ifr.ifr_flags &= ~flag; 539 1.1 thorpej 540 1.1 thorpej g_ifr_updated = 1; 541 1.1 thorpej } 542 1.1 thorpej 543 1.13 joerg static void 544 1.1 thorpej do_bridgeflag(int sock, const char *bridge, const char *ifs, int flag, 545 1.1 thorpej int set) 546 1.1 thorpej { 547 1.1 thorpej struct ifbreq req; 548 1.1 thorpej 549 1.1 thorpej strlcpy(req.ifbr_ifsname, ifs, sizeof(req.ifbr_ifsname)); 550 1.1 thorpej 551 1.1 thorpej if (do_cmd(sock, bridge, BRDGGIFFLGS, &req, sizeof(req), 0) < 0) 552 1.1 thorpej err(1, "unable to get bridge flags"); 553 1.1 thorpej 554 1.1 thorpej if (set) 555 1.1 thorpej req.ifbr_ifsflags |= flag; 556 1.1 thorpej else 557 1.1 thorpej req.ifbr_ifsflags &= ~flag; 558 1.1 thorpej 559 1.1 thorpej if (do_cmd(sock, bridge, BRDGSIFFLGS, &req, sizeof(req), 1) < 0) 560 1.1 thorpej err(1, "unable to set bridge flags"); 561 1.1 thorpej } 562 1.1 thorpej 563 1.13 joerg static void 564 1.1 thorpej cmd_add(const struct command *cmd, int sock, const char *bridge, 565 1.1 thorpej char **argv) 566 1.1 thorpej { 567 1.1 thorpej struct ifbreq req; 568 1.1 thorpej 569 1.1 thorpej memset(&req, 0, sizeof(req)); 570 1.1 thorpej 571 1.1 thorpej strlcpy(req.ifbr_ifsname, argv[0], sizeof(req.ifbr_ifsname)); 572 1.1 thorpej if (do_cmd(sock, bridge, BRDGADD, &req, sizeof(req), 1) < 0) 573 1.1 thorpej err(1, "%s %s", cmd->cmd_keyword, argv[0]); 574 1.1 thorpej } 575 1.1 thorpej 576 1.13 joerg static void 577 1.1 thorpej cmd_delete(const struct command *cmd, int sock, const char *bridge, 578 1.1 thorpej char **argv) 579 1.1 thorpej { 580 1.1 thorpej struct ifbreq req; 581 1.1 thorpej 582 1.1 thorpej memset(&req, 0, sizeof(req)); 583 1.1 thorpej strlcpy(req.ifbr_ifsname, argv[0], sizeof(req.ifbr_ifsname)); 584 1.1 thorpej if (do_cmd(sock, bridge, BRDGDEL, &req, sizeof(req), 1) < 0) 585 1.1 thorpej err(1, "%s %s", cmd->cmd_keyword, argv[0]); 586 1.1 thorpej } 587 1.1 thorpej 588 1.13 joerg static void 589 1.1 thorpej cmd_up(const struct command *cmd, int sock, const char *bridge, 590 1.1 thorpej char **argv) 591 1.1 thorpej { 592 1.1 thorpej 593 1.1 thorpej do_ifflag(sock, bridge, IFF_UP, 1); 594 1.1 thorpej } 595 1.1 thorpej 596 1.13 joerg static void 597 1.1 thorpej cmd_down(const struct command *cmd, int sock, const char *bridge, 598 1.1 thorpej char **argv) 599 1.1 thorpej { 600 1.1 thorpej 601 1.1 thorpej do_ifflag(sock, bridge, IFF_UP, 0); 602 1.1 thorpej } 603 1.1 thorpej 604 1.13 joerg static void 605 1.1 thorpej cmd_discover(const struct command *cmd, int sock, const char *bridge, 606 1.1 thorpej char **argv) 607 1.1 thorpej { 608 1.1 thorpej 609 1.1 thorpej do_bridgeflag(sock, bridge, argv[0], IFBIF_DISCOVER, 610 1.1 thorpej (cmd->cmd_flags & CMD_INVERT) ? 0 : 1); 611 1.1 thorpej } 612 1.1 thorpej 613 1.13 joerg static void 614 1.1 thorpej cmd_learn(const struct command *cmd, int sock, const char *bridge, 615 1.1 thorpej char **argv) 616 1.1 thorpej { 617 1.1 thorpej 618 1.1 thorpej do_bridgeflag(sock, bridge, argv[0], IFBIF_LEARNING, 619 1.1 thorpej (cmd->cmd_flags & CMD_INVERT) ? 0 : 1); 620 1.1 thorpej } 621 1.1 thorpej 622 1.13 joerg static void 623 1.1 thorpej cmd_stp(const struct command *cmd, int sock, const char *bridge, 624 1.1 thorpej char **argv) 625 1.1 thorpej { 626 1.1 thorpej 627 1.1 thorpej do_bridgeflag(sock, bridge, argv[0], IFBIF_STP, 628 1.1 thorpej (cmd->cmd_flags & CMD_INVERT) ? 0 : 1); 629 1.1 thorpej } 630 1.1 thorpej 631 1.13 joerg static void 632 1.18 ozaki cmd_protect(const struct command *cmd, int sock, const char *bridge, 633 1.18 ozaki char **argv) 634 1.18 ozaki { 635 1.18 ozaki 636 1.18 ozaki do_bridgeflag(sock, bridge, argv[0], IFBIF_PROTECTED, 637 1.18 ozaki (cmd->cmd_flags & CMD_INVERT) ? 0 : 1); 638 1.18 ozaki } 639 1.18 ozaki 640 1.18 ozaki static void 641 1.1 thorpej cmd_flush(const struct command *cmd, int sock, const char *bridge, 642 1.1 thorpej char **argv) 643 1.1 thorpej { 644 1.1 thorpej struct ifbreq req; 645 1.1 thorpej 646 1.1 thorpej memset(&req, 0, sizeof(req)); 647 1.1 thorpej req.ifbr_ifsflags = IFBF_FLUSHDYN; 648 1.1 thorpej if (do_cmd(sock, bridge, BRDGFLUSH, &req, sizeof(req), 1) < 0) 649 1.1 thorpej err(1, "%s", cmd->cmd_keyword); 650 1.1 thorpej } 651 1.1 thorpej 652 1.13 joerg static void 653 1.1 thorpej cmd_flushall(const struct command *cmd, int sock, const char *bridge, 654 1.1 thorpej char **argv) 655 1.1 thorpej { 656 1.1 thorpej struct ifbreq req; 657 1.1 thorpej 658 1.1 thorpej memset(&req, 0, sizeof(req)); 659 1.1 thorpej req.ifbr_ifsflags = IFBF_FLUSHALL; 660 1.1 thorpej if (do_cmd(sock, bridge, BRDGFLUSH, &req, sizeof(req), 1) < 0) 661 1.1 thorpej err(1, "%s", cmd->cmd_keyword); 662 1.1 thorpej } 663 1.1 thorpej 664 1.13 joerg static void 665 1.1 thorpej cmd_static(const struct command *cmd, int sock, const char *bridge, 666 1.1 thorpej char **argv) 667 1.1 thorpej { 668 1.1 thorpej struct ifbareq req; 669 1.1 thorpej struct ether_addr *ea; 670 1.1 thorpej 671 1.1 thorpej memset(&req, 0, sizeof(req)); 672 1.1 thorpej strlcpy(req.ifba_ifsname, argv[0], sizeof(req.ifba_ifsname)); 673 1.1 thorpej 674 1.1 thorpej ea = ether_aton(argv[1]); 675 1.1 thorpej if (ea == NULL) 676 1.1 thorpej errx(1, "%s: invalid address: %s", cmd->cmd_keyword, argv[1]); 677 1.1 thorpej 678 1.1 thorpej memcpy(req.ifba_dst, ea->ether_addr_octet, sizeof(req.ifba_dst)); 679 1.1 thorpej req.ifba_flags = IFBAF_STATIC; 680 1.1 thorpej 681 1.1 thorpej if (do_cmd(sock, bridge, BRDGSADDR, &req, sizeof(req), 1) < 0) 682 1.1 thorpej err(1, "%s %s %s", cmd->cmd_keyword, argv[0], argv[1]); 683 1.1 thorpej } 684 1.1 thorpej 685 1.13 joerg static void 686 1.1 thorpej cmd_deladdr(const struct command *cmd, int sock, const char *bridge, 687 1.1 thorpej char **argv) 688 1.1 thorpej { 689 1.1 thorpej struct ifbareq req; 690 1.1 thorpej struct ether_addr *ea; 691 1.1 thorpej 692 1.1 thorpej memset(&req, 0, sizeof(req)); 693 1.1 thorpej 694 1.1 thorpej ea = ether_aton(argv[0]); 695 1.1 thorpej if (ea == NULL) 696 1.1 thorpej errx(1, "%s: invalid address: %s", cmd->cmd_keyword, argv[0]); 697 1.1 thorpej 698 1.1 thorpej memcpy(req.ifba_dst, ea->ether_addr_octet, sizeof(req.ifba_dst)); 699 1.1 thorpej 700 1.1 thorpej if (do_cmd(sock, bridge, BRDGDADDR, &req, sizeof(req), 1) < 0) 701 1.1 thorpej err(1, "%s %s", cmd->cmd_keyword, argv[0]); 702 1.1 thorpej } 703 1.1 thorpej 704 1.13 joerg static void 705 1.1 thorpej cmd_addr(const struct command *cmd, int sock, const char *bridge, 706 1.1 thorpej char **argv) 707 1.1 thorpej { 708 1.1 thorpej 709 1.1 thorpej show_addresses(sock, bridge, "\t"); 710 1.1 thorpej } 711 1.1 thorpej 712 1.13 joerg static void 713 1.1 thorpej cmd_maxaddr(const struct command *cmd, int sock, const char *bridge, 714 1.1 thorpej char **argv) 715 1.1 thorpej { 716 1.1 thorpej struct ifbrparam param; 717 1.1 thorpej u_long val; 718 1.1 thorpej 719 1.1 thorpej if (get_val(argv[0], &val) < 0 || (val & ~0xffffffff) != 0) 720 1.1 thorpej errx(1, "%s: invalid value: %s", cmd->cmd_keyword, argv[0]); 721 1.1 thorpej 722 1.1 thorpej param.ifbrp_csize = val & 0xffffffff; 723 1.1 thorpej 724 1.1 thorpej if (do_cmd(sock, bridge, BRDGSCACHE, ¶m, sizeof(param), 1) < 0) 725 1.1 thorpej err(1, "%s %s", cmd->cmd_keyword, argv[0]); 726 1.1 thorpej } 727 1.1 thorpej 728 1.13 joerg static void 729 1.1 thorpej cmd_hellotime(const struct command *cmd, int sock, const char *bridge, 730 1.1 thorpej char **argv) 731 1.1 thorpej { 732 1.1 thorpej struct ifbrparam param; 733 1.1 thorpej u_long val; 734 1.1 thorpej 735 1.1 thorpej if (get_val(argv[0], &val) < 0 || (val & ~0xff) != 0) 736 1.1 thorpej errx(1, "%s: invalid value: %s", cmd->cmd_keyword, argv[0]); 737 1.1 thorpej 738 1.1 thorpej param.ifbrp_hellotime = val & 0xff; 739 1.1 thorpej 740 1.1 thorpej if (do_cmd(sock, bridge, BRDGSHT, ¶m, sizeof(param), 1) < 0) 741 1.1 thorpej err(1, "%s %s", cmd->cmd_keyword, argv[0]); 742 1.1 thorpej } 743 1.1 thorpej 744 1.13 joerg static void 745 1.1 thorpej cmd_fwddelay(const struct command *cmd, int sock, const char *bridge, 746 1.1 thorpej char **argv) 747 1.1 thorpej { 748 1.1 thorpej struct ifbrparam param; 749 1.1 thorpej u_long val; 750 1.1 thorpej 751 1.1 thorpej if (get_val(argv[0], &val) < 0 || (val & ~0xff) != 0) 752 1.1 thorpej errx(1, "%s: invalid value: %s", cmd->cmd_keyword, argv[0]); 753 1.1 thorpej 754 1.1 thorpej param.ifbrp_fwddelay = val & 0xff; 755 1.1 thorpej 756 1.1 thorpej if (do_cmd(sock, bridge, BRDGSFD, ¶m, sizeof(param), 1) < 0) 757 1.1 thorpej err(1, "%s %s", cmd->cmd_keyword, argv[0]); 758 1.1 thorpej } 759 1.1 thorpej 760 1.13 joerg static void 761 1.1 thorpej cmd_maxage(const struct command *cmd, int sock, const char *bridge, 762 1.1 thorpej char **argv) 763 1.1 thorpej { 764 1.1 thorpej struct ifbrparam param; 765 1.1 thorpej u_long val; 766 1.1 thorpej 767 1.1 thorpej if (get_val(argv[0], &val) < 0 || (val & ~0xff) != 0) 768 1.1 thorpej errx(1, "%s: invalid value: %s", cmd->cmd_keyword, argv[0]); 769 1.1 thorpej 770 1.1 thorpej param.ifbrp_maxage = val & 0xff; 771 1.1 thorpej 772 1.1 thorpej if (do_cmd(sock, bridge, BRDGSMA, ¶m, sizeof(param), 1) < 0) 773 1.1 thorpej err(1, "%s %s", cmd->cmd_keyword, argv[0]); 774 1.1 thorpej } 775 1.1 thorpej 776 1.13 joerg static void 777 1.1 thorpej cmd_priority(const struct command *cmd, int sock, const char *bridge, 778 1.1 thorpej char **argv) 779 1.1 thorpej { 780 1.1 thorpej struct ifbrparam param; 781 1.1 thorpej u_long val; 782 1.1 thorpej 783 1.1 thorpej if (get_val(argv[0], &val) < 0 || (val & ~0xffff) != 0) 784 1.1 thorpej errx(1, "%s: invalid value: %s", cmd->cmd_keyword, argv[0]); 785 1.1 thorpej 786 1.1 thorpej param.ifbrp_prio = val & 0xffff; 787 1.1 thorpej 788 1.1 thorpej if (do_cmd(sock, bridge, BRDGSPRI, ¶m, sizeof(param), 1) < 0) 789 1.1 thorpej err(1, "%s %s", cmd->cmd_keyword, argv[0]); 790 1.1 thorpej } 791 1.1 thorpej 792 1.13 joerg static void 793 1.1 thorpej cmd_ifpriority(const struct command *cmd, int sock, const char *bridge, 794 1.1 thorpej char **argv) 795 1.1 thorpej { 796 1.1 thorpej struct ifbreq req; 797 1.1 thorpej u_long val; 798 1.1 thorpej 799 1.1 thorpej memset(&req, 0, sizeof(req)); 800 1.1 thorpej 801 1.1 thorpej if (get_val(argv[1], &val) < 0 || (val & ~0xff) != 0) 802 1.1 thorpej errx(1, "%s: invalid value: %s", cmd->cmd_keyword, argv[1]); 803 1.1 thorpej 804 1.1 thorpej strlcpy(req.ifbr_ifsname, argv[0], sizeof(req.ifbr_ifsname)); 805 1.1 thorpej req.ifbr_priority = val & 0xff; 806 1.1 thorpej 807 1.5 bouyer if (do_cmd(sock, bridge, BRDGSIFPRIO, &req, sizeof(req), 1) < 0) 808 1.5 bouyer err(1, "%s %s", cmd->cmd_keyword, argv[0]); 809 1.5 bouyer } 810 1.5 bouyer 811 1.13 joerg static void 812 1.5 bouyer cmd_ifpathcost(const struct command *cmd, int sock, const char *bridge, 813 1.5 bouyer char **argv) 814 1.5 bouyer { 815 1.5 bouyer struct ifbreq req; 816 1.5 bouyer u_long val; 817 1.5 bouyer 818 1.5 bouyer memset(&req, 0, sizeof(req)); 819 1.5 bouyer 820 1.5 bouyer if (get_val(argv[1], &val) < 0 || (val & ~0xff) != 0) 821 1.5 bouyer errx(1, "%s: invalid value: %s", cmd->cmd_keyword, argv[1]); 822 1.5 bouyer 823 1.5 bouyer strlcpy(req.ifbr_ifsname, argv[0], sizeof(req.ifbr_ifsname)); 824 1.5 bouyer req.ifbr_path_cost = val & 0xffff; 825 1.5 bouyer 826 1.5 bouyer if (do_cmd(sock, bridge, BRDGSIFCOST, &req, sizeof(req), 1) < 0) 827 1.1 thorpej err(1, "%s %s", cmd->cmd_keyword, argv[0]); 828 1.1 thorpej } 829 1.1 thorpej 830 1.13 joerg static void 831 1.1 thorpej cmd_timeout(const struct command *cmd, int sock, const char *bridge, 832 1.1 thorpej char **argv) 833 1.1 thorpej { 834 1.1 thorpej struct ifbrparam param; 835 1.1 thorpej u_long val; 836 1.1 thorpej 837 1.1 thorpej if (get_val(argv[0], &val) < 0 || (val & ~0xffffffff) != 0) 838 1.1 thorpej errx(1, "%s: invalid value: %s", cmd->cmd_keyword, argv[0]); 839 1.1 thorpej 840 1.1 thorpej param.ifbrp_ctime = val & 0xffffffff; 841 1.1 thorpej 842 1.1 thorpej if (do_cmd(sock, bridge, BRDGSTO, ¶m, sizeof(param), 1) < 0) 843 1.1 thorpej err(1, "%s %s", cmd->cmd_keyword, argv[0]); 844 1.3 perseant } 845 1.3 perseant 846 1.13 joerg static void 847 1.3 perseant cmd_ipf(const struct command *cmd, int sock, const char *bridge, 848 1.3 perseant char **argv) 849 1.3 perseant { 850 1.3 perseant struct ifbrparam param; 851 1.3 perseant 852 1.3 perseant if (do_cmd(sock, bridge, BRDGGFILT, ¶m, sizeof(param), 0) < 0) 853 1.3 perseant err(1, "%s", cmd->cmd_keyword); 854 1.3 perseant 855 1.3 perseant param.ifbrp_filter &= ~IFBF_FILT_USEIPF; 856 1.3 perseant param.ifbrp_filter |= (cmd->cmd_flags & CMD_INVERT) ? 0 : IFBF_FILT_USEIPF; 857 1.3 perseant if (do_cmd(sock, bridge, BRDGSFILT, ¶m, sizeof(param), 1) < 0) 858 1.3 perseant err(1, "%s %x", cmd->cmd_keyword, param.ifbrp_filter); 859 1.1 thorpej } 860