summaryrefslogtreecommitdiff
path: root/sbin/brconfig
diff options
context:
space:
mode:
authorTheo de Raadt <deraadt@cvs.openbsd.org>1999-09-01 03:28:02 +0000
committerTheo de Raadt <deraadt@cvs.openbsd.org>1999-09-01 03:28:02 +0000
commitca4dd3ababefc527f20eea2d6acde35d097cbe6a (patch)
tree1ed5b9b9664ee382cdf34f7160151786c9aa08e7 /sbin/brconfig
parentfd7cb7278c603ed8c4c5a78803c7fc50505af140 (diff)
move brconfig to /sbin, where it belongs
Diffstat (limited to 'sbin/brconfig')
-rw-r--r--sbin/brconfig/Makefile7
-rw-r--r--sbin/brconfig/brconfig.8215
-rw-r--r--sbin/brconfig/brconfig.c786
3 files changed, 1008 insertions, 0 deletions
diff --git a/sbin/brconfig/Makefile b/sbin/brconfig/Makefile
new file mode 100644
index 00000000000..3409da399c6
--- /dev/null
+++ b/sbin/brconfig/Makefile
@@ -0,0 +1,7 @@
+# $OpenBSD: Makefile,v 1.1 1999/09/01 03:28:01 deraadt Exp $
+
+PROG= brconfig
+MAN= brconfig.8
+COPTS+= -Wall
+
+.include <bsd.prog.mk>
diff --git a/sbin/brconfig/brconfig.8 b/sbin/brconfig/brconfig.8
new file mode 100644
index 00000000000..bb44a598e22
--- /dev/null
+++ b/sbin/brconfig/brconfig.8
@@ -0,0 +1,215 @@
+.\" $OpenBSD: brconfig.8,v 1.1 1999/09/01 03:28:01 deraadt Exp $
+.\"
+.\" Copyright (c) 1999 Jason L. Wright (jason@thought.net)
+.\" All rights reserved.
+.\"
+.\" 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 by Jason L. Wright
+.\" 4. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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 February 26, 1999
+.Dt BRCONFIG 8
+.Os
+.Sh NAME
+.Nm brconfig
+.Nd manipulate bridge interfaces
+.Sh SYNOPSIS
+.Nm brconfig
+.Ar -a
+.Nm brconfig
+.Ar bridge-name
+.Op Ar up
+.Op Ar down
+.Op Ar addr
+.Op Ar add interface-name
+.Op Ar delete interface-name
+.Op Ar maxaddr size
+.Op Ar timeout time
+.Op Ar static interface-name address
+.Op Ar deladdr address
+.Op Ar flush
+.Op Ar flushall
+.Op Ar discover interface-name
+.Op Ar -discover interface-name
+.Op Ar learn interface-name
+.Op Ar -learn interface-name
+.Op Ar link0
+.Op Ar link1
+.Op Ar -link0
+.Op Ar -link1
+.Op Ar ...
+.Sh DESCRIPTION
+The
+.Nm brconfig
+utility retrieves kernel state of bridge interfaces and allows
+user control of these bridges. In the first synopsis, the command
+will list the status of all bridges in the system.
+In the second, its command line consists
+of the name of a bridge and a set of operations to be
+performed on that bridge. The commands are executed in
+the order they were specified. If no command is specified in
+the second synopsis, the
+.Nm brconfig
+will display status information about the bridge.
+.Pp
+The available commands are:
+.Bl -tag -width Ds
+.It Ar up
+Start the bridge forwarding packets.
+.It Ar down
+Stop the bridge from forwarding packets.
+.It Ar addr
+Display the addresses that have been learned by the bridge.
+.It Ar add interface-name
+Add the interface named by
+.Ar interface-name
+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 Ar delete interface-name
+Remove the interface named by
+.Ar interface-name
+from the bridge.
+Promiscuous mode is turned off for the interface when it is
+removed from the bridge.
+.It Ar del
+Alias for `delete'.
+.It Ar maxaddr size
+Set the address cache size to
+.Cm size .
+The default is 100 entries.
+.It Ar timeout time
+Set the timeout, in seconds, for addresses in the cache to
+.Cm time .
+The default is 240 seconds.
+If
+.Cm time
+is set to zero, then entries will not be expired.
+.It Ar static interface-name address
+Add a static entry into the address cache pointing to
+.Cm interface-name .
+Static entries are never aged out of the cache or replaced if the address
+is seen on a different interface.
+.It Ar deladdr address
+Delete an address from the cache.
+.It Ar flush
+Remove all dynamically learned addresses from the cache.
+.It Ar flushall
+Remove all addresses from the cache including static addresses.
+.It Ar discover interface
+Mark an interface so that packets are sent out of the interface
+if the destination port of the packet is unknown.
+If the bridge has no address cache entry for the destination of
+a packet, meaning that there is no static entry and no dynamically learned
+entry for the destination, the bridge will forward the packet to all member
+interfaces that have this flag set.
+This is the default for interfaces added to the bridge.
+.It Ar -discover interface
+Mark an interface so that packets are not sent out of the interface
+if the destination port of the packet is unknown. Turning this flag
+off means that the bridge will not send packets out of this interface
+unless the packet is a broadcast packet, multicast packet, or a
+packet with a destination address found on the interface's segment.
+This, in combination with static address cache entries,
+prevents potentially sensitive packets from being sent on
+segments that have no need to see the packet.
+.It Ar learn interface
+Mark an interface so that the source address of packets received from
+.Cm interface
+are entered into the address cache.
+This is the default for interfaces added to the bridge.
+.It Ar -learn interface
+Mark an interface so that the source address of packets received from
+.Cm interface
+are not entered into the address cache.
+.It Ar link0
+Setting this flag stops all non-IP multicast packets from
+being forwarded by the bridge.
+.It Ar -link0
+Clear the
+.Ar link0
+flag on the bridge interface.
+.It Ar link1
+Setting this flags stops all IP multicast packets from
+being forwarded by the bridge.
+.It Ar -link0
+Clear the
+.Ar link1
+flag on the bridge interface.
+.El
+.Sh EXAMPLES
+.Bl -tag -width brconfig
+.It Cm brconfig bridge0 add rl0 add xl0 up
+Add the Ethernet interfaces rl0 and xl0 to the bridge bridge0, and
+start the bridge forwarding packets.
+.It Cm brconfig bridge0
+Retrieve a list of interfaces that are members of bridge0, and the addresses
+learned by the bridge.
+.It Cm brconfig bridge0 down
+Stop bridge0 from forwarding packets.
+.It Cm brconfig bridge0 delete xl0
+Remove the interface xl0 from the bridge bridge0.
+.It Cm brconfig bridge0 flush
+Flush all dynamically learned addresses from the address cache.
+.It Cm brconfig bridge0 flushall
+Remove all addresses, including static addresses, from the address cache.
+.It Cm brconfig bridge0 -learn xl0 static xl0 8:0:20:1e:2f:2b
+.It Cm brconfig bridge0 -discover xl0
+The examples above mark the xl0 interface so that it will not learn
+addresses and adds a static entry for the host 8:0:20:1e:2f:2b on the xl0
+segment.
+Finally, xl0 is marked so that it will not receive packets with
+destinations not found in the address cache of bridge0.
+This setup is the most secure,
+and means that bogus MAC addresses seen by the xl0 side of the bridge
+will not be propogated to the rest of the network.
+Also, no packets will be sent on xl0 segment by the bridge unless they are
+broadcast packets or are for 8:0:20:1e:2f:2b.
+.El
+.Sh SEE ALSO
+.Xr bridge 4 ,
+.Xr ifconfig 8
+.Sh HISTORY
+.Nm brconfig
+first appeared in
+.Ox 2.5 .
+.Sh AUTHOR
+The
+.Xr brconfig 8
+command and the
+.Xr bridge 4
+kernel interface were written by Jason L. Wright <jason@thought.net> as
+part of an undergraduate independent study
+at the University of North Carolina at Greensboro.
+.Sh BUGS
+There are some rather special network interface chipsets which will
+not work in a bridge configuration. Some, like the Lite-On PNIC (see
+.Xr pn 4 ),
+have serious flaws when running in promiscuous mode, and others, like the
+TI ThunderLAN (see
+.Xr tl 4 ),
+receive their own transmissions, which makes the address learning code
+ineffective. Most other chipsets work fine though.
diff --git a/sbin/brconfig/brconfig.c b/sbin/brconfig/brconfig.c
new file mode 100644
index 00000000000..786d9a925df
--- /dev/null
+++ b/sbin/brconfig/brconfig.c
@@ -0,0 +1,786 @@
+/* $OpenBSD: brconfig.c,v 1.1 1999/09/01 03:28:01 deraadt Exp $ */
+
+/*
+ * Copyright (c) 1999 Jason L. Wright (jason@thought.net)
+ * All rights reserved.
+ *
+ * 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 by Jason L. Wright
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#include <net/if_bridge.h>
+#include <sys/errno.h>
+#include <string.h>
+#include <err.h>
+#include <sysexits.h>
+#include <stdlib.h>
+#include <limits.h>
+
+void usage __P((void));
+int main __P((int, char **));
+int bridge_setflag __P((int, char *, short));
+int bridge_clrflag __P((int, char *, short));
+int bridge_ifsetflag __P((int, char *, char *, u_int32_t));
+int bridge_ifclrflag __P((int, char *, char *, u_int32_t));
+int bridge_list __P((int, char *, char *));
+int bridge_addrs __P((int, char *, char *));
+int bridge_addaddr __P((int, char *, char *, char *));
+int bridge_deladdr __P((int, char *, char *));
+int bridge_maxaddr __P((int, char *, char *));
+int bridge_timeout __P((int, char *, char *));
+int bridge_flush __P((int, char *));
+int bridge_flushall __P((int, char *));
+int bridge_add __P((int, char *, char *));
+int bridge_delete __P((int, char *, char *));
+int bridge_status __P((int, char *));
+int is_bridge __P((int, char *));
+int bridge_show_all __P((int));
+void printb __P((char *, unsigned short, char *));
+
+/* if_flags bits: borrowed from ifconfig.c */
+#define IFFBITS \
+"\020\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5POINTOPOINT\6NOTRAILERS\7RUNNING\10NOARP\
+\11PROMISC\12ALLMULTI\13OACTIVE\14SIMPLEX\15LINK0\16LINK1\17LINK2\20MULTICAST"
+
+#define IFBAFBITS "\020\1STATIC"
+#define IFBIFBITS "\020\1LEARNING\2DISCOVER"
+
+void
+usage()
+{
+ fprintf(stderr, "usage: brconfig -a\n");
+ fprintf(stderr,
+ "usage: brconfig interface [up] [down] [add if] [del if] ...\n");
+}
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int error = 0, sock;
+ char *brdg;
+
+ if (argc < 2) {
+ usage();
+ return (EX_USAGE);
+ }
+
+ sock = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sock < 0)
+ err(1, "socket");
+
+ argc--; argv++;
+ brdg = argv[0];
+
+ if (strcmp(brdg, "-a") == 0)
+ return bridge_show_all(sock);
+
+ if (!is_bridge(sock, brdg)) {
+ warnx("%s is not a bridge", brdg);
+ return (EX_USAGE);
+ }
+
+ if (argc == 1) {
+ error = bridge_status(sock, brdg);
+ return (error);
+ }
+
+ for (argc--, argv++; argc != 0; argc--, argv++) {
+ if (strcmp("add", argv[0]) == 0) {
+ argc--; argv++;
+ if (argc == 0) {
+ warnx("add requires an argument");
+ return (EX_USAGE);
+ }
+ error = bridge_add(sock, brdg, argv[0]);
+ if (error)
+ return (error);
+ }
+ else if (strcmp("delete", argv[0]) == 0 ||
+ strcmp("del", argv[0]) == 0) {
+ argc--; argv++;
+ if (argc == 0) {
+ warnx("delete requires an argument");
+ return (EX_USAGE);
+ }
+ error = bridge_delete(sock, brdg, argv[0]);
+ if (error)
+ return (error);
+ }
+ else if (strcmp("up", argv[0]) == 0) {
+ error = bridge_setflag(sock, brdg, IFF_UP);
+ if (error)
+ return (error);
+ }
+ else if (strcmp("down", argv[0]) == 0) {
+ error = bridge_clrflag(sock, brdg, IFF_UP);
+ if (error)
+ return (error);
+ }
+ else if (strcmp("discover", argv[0]) == 0) {
+ argc--; argv++;
+ if (argc == 0) {
+ warnx("discover requires an argument");
+ return (EX_USAGE);
+ }
+ error = bridge_ifsetflag(sock, brdg, argv[0],
+ IFBIF_DISCOVER);
+ if (error)
+ return (error);
+ }
+ else if (strcmp("-discover", argv[0]) == 0) {
+ argc--; argv++;
+ if (argc == 0) {
+ warnx("-discover requires an argument");
+ return (EX_USAGE);
+ }
+ error = bridge_ifclrflag(sock, brdg, argv[0],
+ IFBIF_DISCOVER);
+ if (error)
+ return (error);
+ }
+ else if (strcmp("learn", argv[0]) == 0) {
+ argc--; argv++;
+ if (argc == 0) {
+ warnx("learn requires an argument");
+ return (EX_USAGE);
+ }
+ error = bridge_ifsetflag(sock, brdg, argv[0],
+ IFBIF_LEARNING);
+ if (error)
+ return (error);
+ }
+ else if (strcmp("-learn", argv[0]) == 0) {
+ argc--; argv++;
+ if (argc == 0) {
+ warnx("-learn requires an argument");
+ return (EX_USAGE);
+ }
+ error = bridge_ifclrflag(sock, brdg, argv[0],
+ IFBIF_LEARNING);
+ if (error)
+ return (error);
+ }
+ else if (strcmp("flush", argv[0]) == 0) {
+ error = bridge_flush(sock, brdg);
+ if (error)
+ return (error);
+ }
+ else if (strcmp("flushall", argv[0]) == 0) {
+ error = bridge_flushall(sock, brdg);
+ if (error)
+ return (error);
+ }
+ else if (strcmp("static", argv[0]) == 0) {
+ argc--; argv++;
+ if (argc < 2) {
+ warnx("static requires 2 arguments");
+ return (EX_USAGE);
+ }
+ error = bridge_addaddr(sock, brdg, argv[0], argv[1]);
+ if (error)
+ return (error);
+ argc--; argv++;
+ }
+ else if (strcmp("deladdr", argv[0]) == 0) {
+ argc--; argv++;
+ if (argc == 0) {
+ warnx("deladdr requires an argument");
+ return (EX_USAGE);
+ }
+ error = bridge_deladdr(sock, brdg, argv[0]);
+ if (error)
+ return (error);
+ }
+ else if (strcmp("link0", argv[0]) == 0) {
+ error = bridge_setflag(sock, brdg, IFF_LINK0);
+ if (error)
+ return (error);
+ }
+ else if (strcmp("-link0", argv[0]) == 0) {
+ error = bridge_clrflag(sock, brdg, IFF_LINK0);
+ if (error)
+ return (error);
+ }
+ else if (strcmp("link1", argv[0]) == 0) {
+ error = bridge_setflag(sock, brdg, IFF_LINK1);
+ if (error)
+ return (error);
+ }
+ else if (strcmp("-link1", argv[0]) == 0) {
+ error = bridge_clrflag(sock, brdg, IFF_LINK1);
+ if (error)
+ return (error);
+ }
+ else if (strcmp("addr", argv[0]) == 0) {
+ error = bridge_addrs(sock, brdg, "");
+ if (error)
+ return (error);
+ }
+ else if (strcmp("maxaddr", argv[0]) == 0) {
+ argc--; argv++;
+ if (argc == 0) {
+ warnx("maxaddr requires an argument");
+ return (EX_USAGE);
+ }
+ error = bridge_maxaddr(sock, brdg, argv[0]);
+ if (error)
+ return (error);
+ }
+ else if (strcmp("timeout", argv[0]) == 0) {
+ argc--; argv++;
+ if (argc == 0) {
+ warnx("timeout requires an argument");
+ return (EX_USAGE);
+ }
+ error = bridge_timeout(sock, brdg, argv[0]);
+ if (error)
+ return (error);
+ }
+ else {
+ warnx("unrecognized option: %s", argv[0]);
+ return (EX_USAGE);
+ }
+ }
+
+ return (0);
+}
+
+int
+bridge_ifsetflag(s, brdg, ifsname, flag)
+ int s;
+ char *brdg, *ifsname;
+ u_int32_t flag;
+{
+ struct ifbreq req;
+
+ strlcpy(req.ifbr_name, brdg, sizeof(req.ifbr_name));
+ strlcpy(req.ifbr_ifsname, ifsname, sizeof(req.ifbr_ifsname));
+ if (ioctl(s, SIOCBRDGGIFFLGS, (caddr_t)&req) < 0) {
+ warn("ioctl(SIOCBRDGGIFFLGS)");
+ return (EX_IOERR);
+ }
+
+ req.ifbr_ifsflags |= flag;
+
+ if (ioctl(s, SIOCBRDGSIFFLGS, (caddr_t)&req) < 0) {
+ warn("ioctl(SIOCBRDGSIFFLGS)");
+ return (EX_IOERR);
+ }
+ return (0);
+}
+
+int
+bridge_ifclrflag(s, brdg, ifsname, flag)
+ int s;
+ char *brdg, *ifsname;
+ u_int32_t flag;
+{
+ struct ifbreq req;
+
+ strlcpy(req.ifbr_name, brdg, sizeof(req.ifbr_name));
+ strlcpy(req.ifbr_ifsname, ifsname, sizeof(req.ifbr_ifsname));
+
+ if (ioctl(s, SIOCBRDGGIFFLGS, (caddr_t)&req) < 0) {
+ warn("ioctl(SIOCBRDGGIFFLGS)");
+ return (EX_IOERR);
+ }
+
+ req.ifbr_ifsflags &= ~flag;
+
+ if (ioctl(s, SIOCBRDGSIFFLGS, (caddr_t)&req) < 0) {
+ warn("ioctl(SIOCBRDGSIFFLGS)");
+ return (EX_IOERR);
+ }
+ return (0);
+}
+
+int
+bridge_show_all(s)
+ int s;
+{
+ char *inbuf = NULL;
+ struct ifconf ifc;
+ struct ifreq *ifrp, ifreq;
+ int len = 8192, i;
+
+ while (1) {
+ ifc.ifc_len = len;
+ ifc.ifc_buf = inbuf = realloc(inbuf, len);
+ if (inbuf == NULL)
+ err(1, "malloc");
+ if (ioctl(s, SIOCGIFCONF, &ifc) < 0)
+ err(1, "ioctl(SIOCGIFCONF)");
+ if (ifc.ifc_len + sizeof(struct ifreq) < len)
+ break;
+ len *= 2;
+ }
+ ifrp = ifc.ifc_req;
+ ifreq.ifr_name[0] = '\0';
+ for (i = 0; i < ifc.ifc_len; ) {
+ ifrp = (struct ifreq *)((caddr_t)ifc.ifc_req + i);
+ i += sizeof(ifrp->ifr_name) +
+ (ifrp->ifr_addr.sa_len > sizeof(struct sockaddr) ?
+ ifrp->ifr_addr.sa_len : sizeof(struct sockaddr));
+ if (ifrp->ifr_addr.sa_family != AF_LINK)
+ continue;
+ if (!is_bridge(s, ifrp->ifr_name))
+ continue;
+ bridge_status(s, ifrp->ifr_name);
+ }
+ return (0);
+}
+
+int
+bridge_setflag(s, brdg, f)
+ int s;
+ char *brdg;
+ short f;
+{
+ struct ifreq ifr;
+
+ strlcpy(ifr.ifr_name, brdg, sizeof(ifr.ifr_name));
+
+ if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) {
+ warn("ioctl(SIOCGIFFLAGS)");
+ if (errno == EPERM)
+ return (EX_NOPERM);
+ return (EX_IOERR);
+ }
+
+ ifr.ifr_flags |= f;
+
+ if (ioctl(s, SIOCSIFFLAGS, (caddr_t)&ifr) < 0) {
+ warn("ioctl(SIOCSIFFLAGS)");
+ if (errno == EPERM)
+ return (EX_NOPERM);
+ return (EX_IOERR);
+ }
+
+ return (0);
+}
+
+int
+bridge_clrflag(s, brdg, f)
+ int s;
+ char *brdg;
+ short f;
+{
+ struct ifreq ifr;
+
+ strlcpy(ifr.ifr_name, brdg, sizeof(ifr.ifr_name));
+
+ if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) {
+ warn("ioctl(SIOCGIFFLAGS)");
+ if (errno == EPERM)
+ return (EX_NOPERM);
+ return (EX_IOERR);
+ }
+
+ ifr.ifr_flags &= ~(f);
+
+ if (ioctl(s, SIOCSIFFLAGS, (caddr_t)&ifr) < 0) {
+ warn("ioctl(SIOCSIFFLAGS)");
+ if (errno == EPERM)
+ return (EX_NOPERM);
+ return (EX_IOERR);
+ }
+
+ return (0);
+}
+
+int
+bridge_flushall(s, brdg)
+ int s;
+ char *brdg;
+{
+ struct ifreq ifr;
+
+ strlcpy(ifr.ifr_name, brdg, sizeof(ifr.ifr_name));
+ if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) {
+ warn("ioctl(SIOCGIFFLAGS)");
+ return (EX_IOERR);
+ }
+
+ if ((ifr.ifr_flags & IFF_UP) == 0)
+ return (0);
+
+ strlcpy(ifr.ifr_name, brdg, sizeof(ifr.ifr_name));
+ ifr.ifr_flags &= ~IFF_UP;
+ if (ioctl(s, SIOCSIFFLAGS, (caddr_t)&ifr) < 0) {
+ warn("ioctl(SIOCSIFFLAGS)");
+ return (EX_IOERR);
+ }
+
+ strlcpy(ifr.ifr_name, brdg, sizeof(ifr.ifr_name));
+ ifr.ifr_flags |= IFF_UP;
+ if (ioctl(s, SIOCSIFFLAGS, (caddr_t)&ifr) < 0) {
+ warn("ioctl(SIOCSIFFLAGS)");
+ return (EX_IOERR);
+ }
+
+ return (0);
+}
+
+int
+bridge_flush(s, brdg)
+ int s;
+ char *brdg;
+{
+ struct ifbreq req;
+
+ strlcpy(req.ifbr_name, brdg, sizeof(req.ifbr_name));
+ if (ioctl(s, SIOCBRDGFLUSH, &req) < 0) {
+ warn("ioctl(SIOCBRDGFLUSH)");
+ return (EX_IOERR);
+ }
+ return (0);
+}
+
+int
+bridge_list(s, brdg, delim)
+ int s;
+ char *brdg, *delim;
+{
+ struct ifbreq *reqp;
+ struct ifbifconf bifc;
+ int i, len = 8192;
+ char buf[sizeof(reqp->ifbr_ifsname) + 1], *inbuf = NULL;
+
+ while (1) {
+ strlcpy(bifc.ifbic_name, brdg, sizeof(bifc.ifbic_name));
+ bifc.ifbic_len = len;
+ bifc.ifbic_buf = inbuf = realloc(inbuf, len);
+ if (inbuf == NULL)
+ err(1, "malloc");
+ if (ioctl(s, SIOCBRDGIFS, &bifc) < 0)
+ err(1, "ioctl(SIOCBRDGIFS)");
+ if (bifc.ifbic_len + sizeof(*reqp) < len)
+ break;
+ len *= 2;
+ }
+ for (i = 0; i < bifc.ifbic_len / sizeof(*reqp); i++) {
+ reqp = bifc.ifbic_req + i;
+ strlcpy(buf, reqp->ifbr_ifsname, sizeof(buf));
+ printf("%s%s ", delim, buf);
+ printb("flags", reqp->ifbr_ifsflags, IFBIFBITS);
+ printf("\n");
+ }
+ free(bifc.ifbic_buf);
+ return (0); /* NOTREACHED */
+}
+
+int
+bridge_add(s, brdg, ifn)
+ int s;
+ char *brdg, *ifn;
+{
+ struct ifbreq req;
+
+ strlcpy(req.ifbr_name, brdg, sizeof(req.ifbr_name));
+ strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname));
+ if (ioctl(s, SIOCBRDGADD, &req) < 0) {
+ warn("ioctl(SIOCADDBRDG)");
+ if (errno == EPERM)
+ return (EX_NOPERM);
+ return (EX_IOERR);
+ }
+ return (0);
+}
+
+int
+bridge_delete(s, brdg, ifn)
+ int s;
+ char *brdg, *ifn;
+{
+ struct ifbreq req;
+
+ strlcpy(req.ifbr_name, brdg, sizeof(req.ifbr_name));
+ strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname));
+ if (ioctl(s, SIOCBRDGDEL, &req) < 0) {
+ warn("ioctl(SIOCDELBRDG)");
+ if (errno == EPERM)
+ return (EX_NOPERM);
+ return (EX_IOERR);
+ }
+ return (0);
+}
+
+int
+bridge_timeout(s, brdg, arg)
+ int s;
+ char *brdg, *arg;
+{
+ struct ifbcachetoreq ifbct;
+ u_int32_t newtime;
+ char *endptr;
+
+ newtime = strtoul(arg, &endptr, 0);
+ if (arg[0] == '\0' || endptr[0] != '\0') {
+ printf("invalid arg for timeout: %s\n", arg);
+ return (EX_USAGE);
+ }
+
+ strlcpy(ifbct.ifbct_name, brdg, sizeof(ifbct.ifbct_name));
+ ifbct.ifbct_time = newtime;
+ if (ioctl(s, SIOCBRDGSTO, (caddr_t)&ifbct) < 0) {
+ warn("ioctl(SIOCBRDGGCACHE)");
+ return (EX_IOERR);
+ }
+ return (0);
+}
+
+int
+bridge_maxaddr(s, brdg, arg)
+ int s;
+ char *brdg, *arg;
+{
+ struct ifbcachereq ifbc;
+ u_int32_t newsize;
+ char *endptr;
+
+ newsize = strtoul(arg, &endptr, 0);
+ if (arg[0] == '\0' || endptr[0] != '\0') {
+ printf("invalid arg for maxaddr: %s\n", arg);
+ return (EX_USAGE);
+ }
+
+ strlcpy(ifbc.ifbc_name, brdg, sizeof(ifbc.ifbc_name));
+ ifbc.ifbc_size = newsize;
+ if (ioctl(s, SIOCBRDGSCACHE, (caddr_t)&ifbc) < 0) {
+ warn("ioctl(SIOCBRDGGCACHE)");
+ return (EX_IOERR);
+ }
+ return (0);
+}
+
+int
+bridge_deladdr(s, brdg, addr)
+ int s;
+ char *brdg, *addr;
+{
+ struct ifbareq ifba;
+ struct ether_addr *ea;
+
+ strlcpy(ifba.ifba_name, brdg, sizeof(ifba.ifba_name));
+ ea = ether_aton(addr);
+ if (ea == NULL) {
+ warnx("Invalid address: %s", addr);
+ return (EX_USAGE);
+ }
+ bcopy(ea, &ifba.ifba_dst, sizeof(struct ether_addr));
+
+ if (ioctl(s, SIOCBRDGDADDR, &ifba) < 0) {
+ warn("ioctl(SIOCBRDGDADDR)");
+ return (EX_IOERR);
+ }
+
+ return (0);
+}
+
+int
+bridge_addaddr(s, brdg, ifname, addr)
+ int s;
+ char *brdg, *ifname, *addr;
+{
+ struct ifbareq ifba;
+ struct ether_addr *ea;
+
+ strlcpy(ifba.ifba_name, brdg, sizeof(ifba.ifba_name));
+ strlcpy(ifba.ifba_ifsname, ifname, sizeof(ifba.ifba_ifsname));
+
+ ea = ether_aton(addr);
+ if (ea == NULL) {
+ warnx("Invalid address: %s", addr);
+ return (EX_USAGE);
+ }
+ bcopy(ea, &ifba.ifba_dst, sizeof(struct ether_addr));
+ ifba.ifba_flags = IFBAF_STATIC;
+
+ if (ioctl(s, SIOCBRDGSADDR, &ifba) < 0) {
+ warn("ioctl(SIOCBRDGSADDR)");
+ return (EX_IOERR);
+ }
+
+ return (0);
+}
+
+int
+bridge_addrs(s, brdg, delim)
+ int s;
+ char *brdg, *delim;
+{
+ struct ifbaconf ifbac;
+ struct ifbareq *ifba;
+ char *inbuf = NULL, buf[sizeof(ifba->ifba_ifsname) + 1];
+ int i, len = 8192;
+
+ while (1) {
+ ifbac.ifbac_len = len;
+ ifbac.ifbac_buf = inbuf = realloc(inbuf, len);
+ strlcpy(ifbac.ifbac_name, brdg, sizeof(ifbac.ifbac_name));
+ if (inbuf == NULL)
+ err(EX_IOERR, "malloc");
+ if (ioctl(s, SIOCBRDGRTS, &ifbac) < 0) {
+ if (errno == ENETDOWN)
+ return (0);
+ err(EX_IOERR, "ioctl(SIOCBRDGRTS)");
+ }
+ 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;
+ strlcpy(buf, ifba->ifba_ifsname, sizeof(buf));
+ printf("%s%s %s %u ", delim, ether_ntoa(&ifba->ifba_dst),
+ buf, ifba->ifba_age);
+ printb("flags", ifba->ifba_flags, IFBAFBITS);
+ printf("\n");
+ }
+
+ return (0);
+}
+
+/*
+ * Check to make sure 'brdg' is really a bridge interface.
+ */
+int
+is_bridge(s, brdg)
+ int s;
+ char *brdg;
+{
+ struct ifreq ifr;
+ struct ifbaconf ifbac;
+
+ strlcpy(ifr.ifr_name, brdg, sizeof(ifr.ifr_name));
+
+ if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0)
+ return (0);
+
+ ifbac.ifbac_len = 0;
+ strlcpy(ifbac.ifbac_name, brdg, sizeof(ifbac.ifbac_name));
+ if (ioctl(s, SIOCBRDGRTS, (caddr_t)&ifbac) < 0) {
+ if (errno == ENETDOWN)
+ return (1);
+ return (0);
+ }
+ return (1);
+}
+
+int
+bridge_status(s, brdg)
+ int s;
+ char *brdg;
+{
+ struct ifreq ifr;
+ struct ifbcachereq ifbc;
+ struct ifbcachetoreq ifbct;
+ int err;
+
+ strlcpy(ifr.ifr_name, brdg, sizeof(ifr.ifr_name));
+ if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) {
+ warn("ioctl(SIOCGIFFLAGS)");
+ if (errno == EPERM)
+ return (EX_NOPERM);
+ return (EX_IOERR);
+ }
+
+ printf("%s: ", brdg);
+ printb("flags", ifr.ifr_flags, IFFBITS);
+ printf("\n");
+
+ printf("\tInterfaces:\n");
+ err = bridge_list(s, brdg, "\t\t");
+ if (err)
+ return (err);
+
+ strlcpy(ifbc.ifbc_name, brdg, sizeof(ifbc.ifbc_name));
+ if (ioctl(s, SIOCBRDGGCACHE, (caddr_t)&ifbc) < 0) {
+ warn("ioctl(SIOCBRDGGCACHE)");
+ return (EX_IOERR);
+ }
+
+ strlcpy(ifbct.ifbct_name, brdg, sizeof(ifbct.ifbct_name));
+ if (ioctl(s, SIOCBRDGGTO, (caddr_t)&ifbct) < 0) {
+ warn("ioctl(SIOCBRDGGTO)");
+ return (EX_IOERR);
+ }
+
+ printf("\tAddresses (max cache: %u, timeout: %u):\n",
+ ifbc.ifbc_size, ifbct.ifbct_time);
+
+ err = bridge_addrs(s, brdg, "\t\t");
+ return (err);
+}
+
+/*
+ * Print a value a la the %b format of the kernel's printf
+ * (borrowed from ifconfig.c)
+ */
+void
+printb(s, v, bits)
+ char *s;
+ char *bits;
+ unsigned short v;
+{
+ register int i, any = 0;
+ register char c;
+
+ if (bits && *bits == 8)
+ printf("%s=%o", s, v);
+ else
+ printf("%s=%x", s, v);
+ bits++;
+ if (bits) {
+ putchar('<');
+ while ((i = *bits++)) {
+ if (v & (1 << (i-1))) {
+ if (any)
+ putchar(',');
+ any = 1;
+ for (; (c = *bits) > 32; bits++)
+ putchar(c);
+ } else
+ for (; *bits > 32; bits++)
+ ;
+ }
+ putchar('>');
+ }
+}