Configuration utility for bridge(4) devices.

This commit is contained in:
thorpej 2001-08-17 21:42:10 +00:00
parent 460da35f85
commit 7ac7787048
3 changed files with 1037 additions and 0 deletions

6
sbin/brconfig/Makefile Normal file
View File

@ -0,0 +1,6 @@
# $NetBSD: Makefile,v 1.1 2001/08/17 21:42:10 thorpej Exp $
PROG= brconfig
MAN= brconfig.8
.include <bsd.prog.mk>

241
sbin/brconfig/brconfig.8 Normal file
View File

@ -0,0 +1,241 @@
.\" $NetBSD: brconfig.8,v 1.1 2001/08/17 21:42:11 thorpej Exp $
.\"
.\" Copyright 2001 Wasabi Systems, Inc.
.\" All rights reserved.
.\"
.\" Written by Jason R. Thorpe for Wasabi Systems, Inc.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\" 3. All advertising materials mentioning features or use of this software
.\" must display the following acknowledgement:
.\" This product includes software developed for the NetBSD Project by
.\" Wasabi Systems, Inc.
.\" 4. The name of Wasabi Systems, Inc. may not be used to endorse
.\" or promote products derived from this software without specific prior
.\" written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
.Dd August 17, 2001
.Dt BRCONFIG 8
.Os
.Sh NAME
.Nm brconfig
.Nd configure network bridge parameters
.Sh SYNOPSIS
.Nm ""
.Fl a
.Nm ""
.Ar bridge
.Nm ""
.Ar bridge
.Ar command
.Op Ar args ...
.Sh DESCRIPTION
The
.Nm
utility is used to configure network bridge parameters and retrieve
network bridge parameters and status from the kernel. The bridging
function is implemented by the
.Xr bridge 4
driver.
.Pp
A network bridge creates a logical link between two or more
IEEE 802 networks that use the same (or
.Dq similar enough )
framing format. For example, it is possible to bridge Ethernet
and 802.11 networks together, but it is not possible to bridge
Ethernet and Token Ring together.
.Pp
Bridge interfaces are created using the
.Xr ifconfig 8
command's
.Dq create
sub-command. All other bridge configuration is performed using
.Nm "" .
.Pp
The options are as follows:
.Bl -tag -width indent
.It Fl a
Display the status of all bridge devices present on the system. This
flag is mutually exclusive with all other sub-commands.
.El
.Pp
All other operations require that a bridge be specified. If a
bridge is specified with no sub-commands, the status of that bridge
is displayed. The following sub-commands are available:
.Pp
.Bl -tag -width indent
.It Cm up
Start forwarding packets on the bridge.
.It Cm down
Stop forwarding packets on the bridge.
.It Cm add Ar interface
Add the interface named by
.Ar interface
as a member of the bridge. The interface is put into promiscuous mode
so that it can receive every packet sent on the network.
.It Cm delete Ar interface
Remove the interface named by
.Ar interface
from the bridge. Promiscuous mode is disabled on the interface when
it is removed from the bridge.
.It Cm maxaddr Ar size
Set the size of the bridge address cache to
.Ar size .
The default is 100 entries.
.It Cm timeout Ar seconds
Set the timeout of address cache entries to
.Ar seconds
seconds. If
.Ar seconds
is zero, then address cache entries will not be expired. The
default is 240 seconds.
.It Cm deladdr Ar address
Delete
.Ar address
from the address cache.
.It Cm flush
Delete all dynamically-learned addresses from the address cache.
.It Cm flushall
Delete all addresses, including static addresses, from the address cache.
.It Cm discover Ar interface
Mark an interface as a
.Dq discovering
interface. When the bridge has no
address cache entry (either dynamic or static) for the destination address
of a packet, the bridge will forward the packet to all member interfaces
marked as
.Dq discovering .
This is the default for all interfaces added to a bridge.
.It Cm -discover Ar interface
Clear the
.Dq discovering
attribute on a member interface. For packets without the
.Dq discovering
attribute, the only packets forwarded on the interface are broadcast
or multicast packets and packets for which the destination address
is known to be on the interface's segment.
.It Cm learn Ar interface
Mark an interface as a
.Dq learning
interface. When a packet arrives on such an interface, the source
address of the packet is entered into the address cache as being a
destination address on the interface's segment. This is the default
for all interfaces added to a bridge.
.It Cm -learn Ar interface
Clear the
.Dq learning
attribute on a member interface.
.It Cm stp Ar interface
Enable Spanning Tree protocol on
.Ar interface .
The
.Xr bridge 4
driver has support for the IEEE 802.1D Spanning Tree protocol (STP).
Spanning Tree is used to detect and remove loops in a network topology.
.It Cm -stp Ar interface
Disable Spanning Tree protocol on
.Ar interface .
This is the default for all interfaces added to a bridge.
.It Cm maxage Ar seconds
Set the time that a Spanning Tree protocol configuration is valid. The
default is 20 seconds. The mininum is 1 second and the maximum is 255
seconds.
.It Cm fwddelay Ar seconds
Set the time that must pass before an interface begins forwarding
packets when Spanning Tree is enabled. The default is 15 seconds. The
mininum is 1 second and the maximum is 255 seconds.
.It Cm hellotime Ar seconds
Set the time between broadcasting of Spanning Tree protocol
configuration messages. The default is 2 seconds. The minimum is 1
second and the maximum is 255 seconds.
.It Cm priority Ar value
Set the bridge priority for Spanning Tree. The default is 32768.
The minimum is 0 and the maximum is 65536.
.It Cm ifpriority Ar interface Ar value
Set the Spanning Tree priority of
.Ar interface
to
.Ar value .
The default is 128. The minimum is 0 and the maximum is 255.
.El
.Sh EXAMPLES
The following then placed in the file
.Pa /etc/ifconfig.bridge0
will cause the a bridge called
.Sq bridge0
to be created, and will add the interfaces
.Sq ray0
and
.Sq fxp0
to the bridge, and then enable packet forwarding. Such a
configuration could be used to implement a simple
802.11-to-Ethernet bridge (assuming the 802.11 interface is
in ad-hoc mode).
.Bd -literal -offset indent
create
!brconfig $int add ray0 add fxp0 up
.Ed
.Pp
Consider a system with two 4-port Ethernet boards. The following
placed in the file
.Pa /etc/ifconfig.bridge0
will cause a bridge consisting of all 8 ports with Spanning Tree
enabled to be created:
.Bd -literal -offset indent
create
!brconfig $int \e
add tlp0 stp tlp0 \e
add tlp1 stp tlp1 \e
add tlp2 stp tlp2 \e
add tlp3 stp tlp3 \e
add tlp4 stp tlp4 \e
add tlp5 stp tlp5 \e
add tlp6 stp tlp6 \e
add tlp7 stp tlp7 \e
up
.Ed
.Pp
.Sh SEE ALSO
.Xr bridge 4 ,
.Xr ifconfig.if 5 ,
.Xr ifconfig 8
.Sh AUTHOR
The
.Xr bridge 4
driver and
.Nm
utility were originally written by
.An Jason L. Wright
.Aq jason@thought.net
as part of an undergraduate independent study at the
University of North Carolina at Greensboro.
.Pp
This version of the
.Nm
utility was written from scratch by
.An Jason R. Thorpe
.Aq thorpej@wasabisystems.com .
.Sh HISTORY
The
.Nm
utility first appeared in
.Nx 1.6 .

790
sbin/brconfig/brconfig.c Normal file
View File

@ -0,0 +1,790 @@
/* $NetBSD: brconfig.c,v 1.1 2001/08/17 21:42:11 thorpej Exp $ */
/*
* Copyright 2001 Wasabi Systems, Inc.
* All rights reserved.
*
* Written by Jason R. Thorpe for Wasabi Systems, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed for the NetBSD Project by
* Wasabi Systems, Inc.
* 4. The name of Wasabi Systems, Inc. may not be used to endorse
* or promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* brconfig(8) --
*
* Configuration utility for the bridge(4) driver.
*/
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <net/if_ether.h>
#include <net/if_bridgevar.h>
#include <ctype.h>
#include <err.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <ifaddrs.h>
struct command {
const char *cmd_keyword;
int cmd_argcnt;
int cmd_flags;
void (*cmd_func)(const struct command *, int, const char *,
char **);
};
#define CMD_INVERT 0x01 /* "invert" the sense of the command */
void cmd_add(const struct command *, int, const char *, char **);
void cmd_delete(const struct command *, int, const char *, char **);
void cmd_up(const struct command *, int, const char *, char **);
void cmd_down(const struct command *, int, const char *, char **);
void cmd_discover(const struct command *, int, const char *, char **);
void cmd_learn(const struct command *, int, const char *, char **);
void cmd_flush(const struct command *, int, const char *, char **);
void cmd_flushall(const struct command *, int, const char *, char **);
void cmd_static(const struct command *, int, const char *, char **);
void cmd_deladdr(const struct command *, int, const char *, char **);
void cmd_addr(const struct command *, int, const char *, char **);
void cmd_maxaddr(const struct command *, int, const char *, char **);
void cmd_hellotime(const struct command *, int, const char *, char **);
void cmd_fwddelay(const struct command *, int, const char *, char **);
void cmd_maxage(const struct command *, int, const char *, char **);
void cmd_priority(const struct command *, int, const char *, char **);
void cmd_ifpriority(const struct command *, int, const char *, char **);
void cmd_timeout(const struct command *, int, const char *, char **);
void cmd_stp(const struct command *, int, const char *, char **);
const struct command command_table[] = {
{ "add", 1, 0, cmd_add },
{ "delete", 1, 0, cmd_delete },
{ "up", 0, 0, cmd_up },
{ "down", 0, 0, cmd_down },
{ "discover", 1, 0, cmd_discover },
{ "-discover", 1, CMD_INVERT, cmd_discover },
{ "learn", 1, 0, cmd_learn },
{ "-learn", 1, CMD_INVERT, cmd_learn },
{ "flush", 0, 0, cmd_flush },
{ "flushall", 0, 0, cmd_flushall },
{ "static", 2, 0, cmd_static },
{ "deladdr", 1, 0, cmd_deladdr },
{ "addr", 0, 0, cmd_addr },
{ "maxaddr", 1, 0, cmd_maxaddr },
{ "hellotime", 1, 0, cmd_hellotime },
{ "fwddelay", 1, 0, cmd_fwddelay },
{ "maxage", 1, 0, cmd_maxage },
{ "priority", 1, 0, cmd_priority },
{ "ifpriority", 2, 0, cmd_ifpriority },
{ "timeout", 1, 0, cmd_timeout },
{ "stp", 1, 0, cmd_stp },
{ "-stp", 1, CMD_INVERT, cmd_stp },
{ NULL, 0, 0, NULL },
};
void printall(int);
void status(int, const char *);
int is_bridge(const char *);
void show_config(int, const char *, const char *);
void show_interfaces(int, const char *, const char *);
void show_addresses(int, const char *, const char *);
int get_val(const char *, u_long *);
int do_cmd(int, const char *, u_long, void *, size_t, int);
void do_ifflag(int, const char *, int, int);
void do_bridgeflag(int, const char *, const char *, int, int);
void printb(const char *, u_int, const char *);
int main(int, char *[]);
void usage(void);
int aflag;
struct ifreq g_ifr;
int g_ifr_updated;
#define IFFBITS \
"\020\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5POINTOPOINT\6NOTRAILERS\7RUNNING\10NOARP\
\11PROMISC\12ALLMULTI\13OACTIVE\14SIMPLEX\15LINK0\16LINK1\17LINK2\20MULTICAST"
int
main(int argc, char *argv[])
{
const struct command *cmd;
char *bridge;
int sock, ch;
if (argc < 2)
usage();
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0)
err(1, "socket");
while ((ch = getopt(argc, argv, "a")) != -1) {
switch (ch) {
case 'a':
aflag = 1;
break;
default:
usage();
}
}
argc -= optind;
argv += optind;
if (aflag) {
if (argc != 0)
usage();
printall(sock);
exit(0);
}
if (argc == 0)
usage();
bridge = argv[0];
if (is_bridge(bridge) == 0)
errx(1, "%s is not a bridge", bridge);
/* Get a copy of the interface flags. */
strlcpy(g_ifr.ifr_name, bridge, sizeof(g_ifr.ifr_name));
if (ioctl(sock, SIOCGIFFLAGS, &g_ifr) < 0)
err(1, "unable to get interface flags");
argc--;
argv++;
if (argc == 0) {
status(sock, bridge);
exit(0);
}
while (argc != 0) {
for (cmd = command_table; cmd->cmd_keyword != NULL; cmd++) {
if (strcmp(cmd->cmd_keyword, argv[0]) == 0)
break;
}
if (cmd->cmd_keyword == NULL)
errx(1, "unknown command: %s", argv[0]);
argc--;
argv++;
if (argc < cmd->cmd_argcnt)
errx(1, "command %s requires %d argument%s",
cmd->cmd_keyword, cmd->cmd_argcnt,
cmd->cmd_argcnt == 1 ? "" : "s");
(*cmd->cmd_func)(cmd, sock, bridge, argv);
argc -= cmd->cmd_argcnt;
argv += cmd->cmd_argcnt;
}
/* If the flags changed, update them. */
if (g_ifr_updated && ioctl(sock, SIOCSIFFLAGS, &g_ifr) < 0)
err(1, "unable to set interface flags");
exit (0);
}
void
usage(void)
{
static const char *usage_strings[] = {
"-a",
"<bridge>",
"<bridge> up|down",
"<bridge> addr",
"<bridge> add <interface>",
"<bridge> delete <interface>",
"<bridge> maxaddr <size>",
"<bridge> timeout <time>",
"<bridge> static <interface> <address>",
"<bridge> deladdr <address>",
"<bridge> flush",
"<bridge> flushall",
"<bridge> discover|-discover <interface>",
"<bridge> learn|-learn <interface>",
"<bridge> stp|-stp <interface>",
"<bridge> maxage <time>",
"<bridge> fwddelay <time>",
"<bridge> hellotime <time>",
"<bridge> priority <value>",
"<bridge> ifpriority <interface> <value>",
NULL,
};
extern const char *__progname;
int i;
for (i = 0; usage_strings[i] != NULL; i++)
fprintf(stderr, "%s %s %s\n",
i == 0 ? "usage:" : " ",
__progname, usage_strings[i]);
exit(1);
}
int
is_bridge(const char *bridge)
{
if (strncmp(bridge, "bridge", 6) != 0 ||
isdigit(bridge[6]) == 0)
return (0);
return (1);
}
void
printb(const char *s, u_int v, const char *bits)
{
int i, any = 0;
char c;
if (bits && *bits == 8)
printf("%s=%o", s, v);
else
printf("%s=%x", s, v);
bits++;
if (bits) {
putchar('<');
while ((i = *bits++) != 0) {
if (v & (1 << (i-1))) {
if (any)
putchar(',');
any = 1;
for (; (c = *bits) > 32; bits++)
putchar(c);
} else
for (; *bits > 32; bits++)
;
}
putchar('>');
}
}
void
printall(int sock)
{
struct ifaddrs *ifap, *ifa;
char *p;
if (getifaddrs(&ifap) != 0)
err(1, "getifaddrs");
p = NULL;
for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
if (is_bridge(ifa->ifa_name) == 0)
continue;
if (p != NULL && strcmp(p, ifa->ifa_name) == 0)
continue;
p = ifa->ifa_name;
status(sock, ifa->ifa_name);
}
freeifaddrs(ifap);
}
void
status(int sock, const char *bridge)
{
struct ifreq ifr;
struct ifbrparam bp1, bp2;
memset(&ifr, 0, sizeof(ifr));
strlcpy(ifr.ifr_name, bridge, sizeof(ifr.ifr_name));
if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0)
err(1, "unable to get flags");
printf("%s: ", bridge);
printb("flags", ifr.ifr_flags, IFFBITS);
printf("\n");
printf("\tConfiguration:\n");
show_config(sock, bridge, "\t\t");
printf("\tInterfaces:\n");
show_interfaces(sock, bridge, "\t\t");
if (do_cmd(sock, bridge, BRDGGCACHE, &bp1, sizeof(bp1), 0) < 0)
err(1, "unable to get address cache size");
if (do_cmd(sock, bridge, BRDGGTO, &bp2, sizeof(bp2), 0) < 0)
err(1, "unable to get address timeout");
printf("\tAddress cache (max cache: %u, timeout: %u):\n",
bp1.ifbrp_csize, bp2.ifbrp_ctime);
show_addresses(sock, bridge, "\t\t");
}
void
show_config(int sock, const char *bridge, const char *prefix)
{
struct ifbrparam param;
u_int16_t pri;
u_int8_t ht, fd, ma;
if (do_cmd(sock, bridge, BRDGGPRI, &param, sizeof(param), 0) < 0)
err(1, "unable to get bridge priority");
pri = param.ifbrp_prio;
if (do_cmd(sock, bridge, BRDGGHT, &param, sizeof(param), 0) < 0)
err(1, "unable to get hellotime");
ht = param.ifbrp_hellotime;
if (do_cmd(sock, bridge, BRDGGFD, &param, sizeof(param), 0) < 0)
err(1, "unable to get forward delay");
fd = param.ifbrp_fwddelay;
if (do_cmd(sock, bridge, BRDGGMA, &param, sizeof(param), 0) < 0)
err(1, "unable to get max age");
ma = param.ifbrp_maxage;
printf("%spriority %u hellotime %u fwddelay %u maxage %u\n",
prefix, pri, ht, fd, ma);
}
void
show_interfaces(int sock, const char *bridge, const char *prefix)
{
static const char *stpstates[] = {
"disabled",
"listening",
"learning",
"forwarding",
"blocking",
};
struct ifbifconf bifc;
struct ifbreq *req;
char *inbuf = NULL;
int i, len = 8192;
for (;;) {
bifc.ifbic_len = len;
bifc.ifbic_buf = inbuf = realloc(inbuf, len);
if (inbuf == NULL)
err(1, "unabel to allocate interface buffer");
if (do_cmd(sock, bridge, BRDGGIFS, &bifc, sizeof(bifc), 0) < 0)
err(1, "unable to get interface list");
if ((bifc.ifbic_len + sizeof(*req)) < len)
break;
len *= 2;
}
for (i = 0; i < bifc.ifbic_len / sizeof(*req); i++) {
req = bifc.ifbic_req + i;
printf("%s%s ", prefix, req->ifbr_ifsname);
printb("flags", req->ifbr_ifsflags, IFBIFBITS);
printf("\n");
printf("%s\t", prefix);
printf("port %u priority %u",
req->ifbr_portno, req->ifbr_priority);
if (req->ifbr_ifsflags & IFBIF_STP) {
if (req->ifbr_state <
sizeof(stpstates) / sizeof(stpstates[0]))
printf(" %s", stpstates[req->ifbr_state]);
else
printf(" <unknown state %d>",
req->ifbr_state);
}
printf("\n");
}
free(inbuf);
}
void
show_addresses(int sock, const char *bridge, const char *prefix)
{
struct ifbaconf ifbac;
struct ifbareq *ifba;
char *inbuf = NULL;
int i, len = 8192;
struct ether_addr ea;
for (;;) {
ifbac.ifbac_len = len;
ifbac.ifbac_buf = inbuf = realloc(inbuf, len);
if (inbuf == NULL)
err(1, "unable to allocate address buffer");
if (do_cmd(sock, bridge, BRDGRTS, &ifbac, sizeof(ifbac), 0) < 0)
err(1, "unable to get address cache");
if ((ifbac.ifbac_len + sizeof(*ifba)) < len)
break;
len *= 2;
}
for (i = 0; i < ifbac.ifbac_len / sizeof(*ifba); i++) {
ifba = ifbac.ifbac_req + i;
memcpy(ea.ether_addr_octet, ifba->ifba_dst,
sizeof(ea.ether_addr_octet));
printf("%s%s %s %lu ", prefix, ether_ntoa(&ea),
ifba->ifba_ifsname, ifba->ifba_expire);
printb("flags", ifba->ifba_flags, IFBAFBITS);
printf("\n");
}
free(inbuf);
}
int
get_val(const char *cp, u_long *valp)
{
char *endptr;
u_long val;
errno = 0;
val = strtoul(cp, &endptr, 0);
if (cp[0] == '\0' || endptr[0] != '\0' || errno == ERANGE)
return (-1);
*valp = val;
return (0);
}
int
do_cmd(int sock, const char *bridge, u_long op, void *arg, size_t argsize,
int set)
{
struct ifdrv ifd;
memset(&ifd, 0, sizeof(ifd));
strlcpy(ifd.ifd_name, bridge, sizeof(ifd.ifd_name));
ifd.ifd_cmd = op;
ifd.ifd_len = argsize;
ifd.ifd_data = arg;
return (ioctl(sock, set ? SIOCSDRVSPEC : SIOCGDRVSPEC, &ifd));
}
void
do_ifflag(int sock, const char *bridge, int flag, int set)
{
if (set)
g_ifr.ifr_flags |= flag;
else
g_ifr.ifr_flags &= ~flag;
g_ifr_updated = 1;
}
void
do_bridgeflag(int sock, const char *bridge, const char *ifs, int flag,
int set)
{
struct ifbreq req;
strlcpy(req.ifbr_ifsname, ifs, sizeof(req.ifbr_ifsname));
if (do_cmd(sock, bridge, BRDGGIFFLGS, &req, sizeof(req), 0) < 0)
err(1, "unable to get bridge flags");
if (set)
req.ifbr_ifsflags |= flag;
else
req.ifbr_ifsflags &= ~flag;
if (do_cmd(sock, bridge, BRDGSIFFLGS, &req, sizeof(req), 1) < 0)
err(1, "unable to set bridge flags");
}
void
cmd_add(const struct command *cmd, int sock, const char *bridge,
char **argv)
{
struct ifbreq req;
memset(&req, 0, sizeof(req));
strlcpy(req.ifbr_ifsname, argv[0], sizeof(req.ifbr_ifsname));
if (do_cmd(sock, bridge, BRDGADD, &req, sizeof(req), 1) < 0)
err(1, "%s %s", cmd->cmd_keyword, argv[0]);
}
void
cmd_delete(const struct command *cmd, int sock, const char *bridge,
char **argv)
{
struct ifbreq req;
memset(&req, 0, sizeof(req));
strlcpy(req.ifbr_ifsname, argv[0], sizeof(req.ifbr_ifsname));
if (do_cmd(sock, bridge, BRDGDEL, &req, sizeof(req), 1) < 0)
err(1, "%s %s", cmd->cmd_keyword, argv[0]);
}
void
cmd_up(const struct command *cmd, int sock, const char *bridge,
char **argv)
{
do_ifflag(sock, bridge, IFF_UP, 1);
}
void
cmd_down(const struct command *cmd, int sock, const char *bridge,
char **argv)
{
do_ifflag(sock, bridge, IFF_UP, 0);
}
void
cmd_discover(const struct command *cmd, int sock, const char *bridge,
char **argv)
{
do_bridgeflag(sock, bridge, argv[0], IFBIF_DISCOVER,
(cmd->cmd_flags & CMD_INVERT) ? 0 : 1);
}
void
cmd_learn(const struct command *cmd, int sock, const char *bridge,
char **argv)
{
do_bridgeflag(sock, bridge, argv[0], IFBIF_LEARNING,
(cmd->cmd_flags & CMD_INVERT) ? 0 : 1);
}
void
cmd_stp(const struct command *cmd, int sock, const char *bridge,
char **argv)
{
do_bridgeflag(sock, bridge, argv[0], IFBIF_STP,
(cmd->cmd_flags & CMD_INVERT) ? 0 : 1);
}
void
cmd_flush(const struct command *cmd, int sock, const char *bridge,
char **argv)
{
struct ifbreq req;
memset(&req, 0, sizeof(req));
req.ifbr_ifsflags = IFBF_FLUSHDYN;
if (do_cmd(sock, bridge, BRDGFLUSH, &req, sizeof(req), 1) < 0)
err(1, "%s", cmd->cmd_keyword);
}
void
cmd_flushall(const struct command *cmd, int sock, const char *bridge,
char **argv)
{
struct ifbreq req;
memset(&req, 0, sizeof(req));
req.ifbr_ifsflags = IFBF_FLUSHALL;
if (do_cmd(sock, bridge, BRDGFLUSH, &req, sizeof(req), 1) < 0)
err(1, "%s", cmd->cmd_keyword);
}
void
cmd_static(const struct command *cmd, int sock, const char *bridge,
char **argv)
{
struct ifbareq req;
struct ether_addr *ea;
memset(&req, 0, sizeof(req));
strlcpy(req.ifba_ifsname, argv[0], sizeof(req.ifba_ifsname));
ea = ether_aton(argv[1]);
if (ea == NULL)
errx(1, "%s: invalid address: %s", cmd->cmd_keyword, argv[1]);
memcpy(req.ifba_dst, ea->ether_addr_octet, sizeof(req.ifba_dst));
req.ifba_flags = IFBAF_STATIC;
if (do_cmd(sock, bridge, BRDGSADDR, &req, sizeof(req), 1) < 0)
err(1, "%s %s %s", cmd->cmd_keyword, argv[0], argv[1]);
}
void
cmd_deladdr(const struct command *cmd, int sock, const char *bridge,
char **argv)
{
struct ifbareq req;
struct ether_addr *ea;
memset(&req, 0, sizeof(req));
ea = ether_aton(argv[0]);
if (ea == NULL)
errx(1, "%s: invalid address: %s", cmd->cmd_keyword, argv[0]);
memcpy(req.ifba_dst, ea->ether_addr_octet, sizeof(req.ifba_dst));
if (do_cmd(sock, bridge, BRDGDADDR, &req, sizeof(req), 1) < 0)
err(1, "%s %s", cmd->cmd_keyword, argv[0]);
}
void
cmd_addr(const struct command *cmd, int sock, const char *bridge,
char **argv)
{
show_addresses(sock, bridge, "\t");
}
void
cmd_maxaddr(const struct command *cmd, int sock, const char *bridge,
char **argv)
{
struct ifbrparam param;
u_long val;
if (get_val(argv[0], &val) < 0 || (val & ~0xffffffff) != 0)
errx(1, "%s: invalid value: %s", cmd->cmd_keyword, argv[0]);
param.ifbrp_csize = val & 0xffffffff;
if (do_cmd(sock, bridge, BRDGSCACHE, &param, sizeof(param), 1) < 0)
err(1, "%s %s", cmd->cmd_keyword, argv[0]);
}
void
cmd_hellotime(const struct command *cmd, int sock, const char *bridge,
char **argv)
{
struct ifbrparam param;
u_long val;
if (get_val(argv[0], &val) < 0 || (val & ~0xff) != 0)
errx(1, "%s: invalid value: %s", cmd->cmd_keyword, argv[0]);
param.ifbrp_hellotime = val & 0xff;
if (do_cmd(sock, bridge, BRDGSHT, &param, sizeof(param), 1) < 0)
err(1, "%s %s", cmd->cmd_keyword, argv[0]);
}
void
cmd_fwddelay(const struct command *cmd, int sock, const char *bridge,
char **argv)
{
struct ifbrparam param;
u_long val;
if (get_val(argv[0], &val) < 0 || (val & ~0xff) != 0)
errx(1, "%s: invalid value: %s", cmd->cmd_keyword, argv[0]);
param.ifbrp_fwddelay = val & 0xff;
if (do_cmd(sock, bridge, BRDGSFD, &param, sizeof(param), 1) < 0)
err(1, "%s %s", cmd->cmd_keyword, argv[0]);
}
void
cmd_maxage(const struct command *cmd, int sock, const char *bridge,
char **argv)
{
struct ifbrparam param;
u_long val;
if (get_val(argv[0], &val) < 0 || (val & ~0xff) != 0)
errx(1, "%s: invalid value: %s", cmd->cmd_keyword, argv[0]);
param.ifbrp_maxage = val & 0xff;
if (do_cmd(sock, bridge, BRDGSMA, &param, sizeof(param), 1) < 0)
err(1, "%s %s", cmd->cmd_keyword, argv[0]);
}
void
cmd_priority(const struct command *cmd, int sock, const char *bridge,
char **argv)
{
struct ifbrparam param;
u_long val;
if (get_val(argv[0], &val) < 0 || (val & ~0xffff) != 0)
errx(1, "%s: invalid value: %s", cmd->cmd_keyword, argv[0]);
param.ifbrp_prio = val & 0xffff;
if (do_cmd(sock, bridge, BRDGSPRI, &param, sizeof(param), 1) < 0)
err(1, "%s %s", cmd->cmd_keyword, argv[0]);
}
void
cmd_ifpriority(const struct command *cmd, int sock, const char *bridge,
char **argv)
{
struct ifbreq req;
u_long val;
memset(&req, 0, sizeof(req));
if (get_val(argv[1], &val) < 0 || (val & ~0xff) != 0)
errx(1, "%s: invalid value: %s", cmd->cmd_keyword, argv[1]);
strlcpy(req.ifbr_ifsname, argv[0], sizeof(req.ifbr_ifsname));
req.ifbr_priority = val & 0xff;
if (do_cmd(sock, bridge, BRDGSPRI, &req, sizeof(req), 1) < 0)
err(1, "%s %s", cmd->cmd_keyword, argv[0]);
}
void
cmd_timeout(const struct command *cmd, int sock, const char *bridge,
char **argv)
{
struct ifbrparam param;
u_long val;
if (get_val(argv[0], &val) < 0 || (val & ~0xffffffff) != 0)
errx(1, "%s: invalid value: %s", cmd->cmd_keyword, argv[0]);
param.ifbrp_ctime = val & 0xffffffff;
if (do_cmd(sock, bridge, BRDGSTO, &param, sizeof(param), 1) < 0)
err(1, "%s %s", cmd->cmd_keyword, argv[0]);
}