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