summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Wright <jason@cvs.openbsd.org>2000-12-12 03:41:24 +0000
committerJason Wright <jason@cvs.openbsd.org>2000-12-12 03:41:24 +0000
commit5a53d8dda0dd91cd81560b9dc02455aa84e92a8c (patch)
tree80ce8558686b03696ee417414ae6da8652d89697
parent8cc674d0f6c120063aaa7e749cd49c28d75a0abc (diff)
Add support for 802.1D spanning tree protocol.
NOTE: this requires recompiling brconfig with updated include files.
-rw-r--r--sbin/brconfig/brconfig.841
-rw-r--r--sbin/brconfig/brconfig.c313
-rw-r--r--sys/conf/files3
-rw-r--r--sys/net/bridgestp.c1294
-rw-r--r--sys/net/if_bridge.c209
-rw-r--r--sys/net/if_bridge.h162
-rw-r--r--sys/net/if_ethersubr.c3
-rw-r--r--sys/sys/sockio.h48
8 files changed, 1951 insertions, 122 deletions
diff --git a/sbin/brconfig/brconfig.8 b/sbin/brconfig/brconfig.8
index 94b3c5c420b..194f8383352 100644
--- a/sbin/brconfig/brconfig.8
+++ b/sbin/brconfig/brconfig.8
@@ -1,4 +1,4 @@
-.\" $OpenBSD: brconfig.8,v 1.18 2000/11/06 01:08:06 aaron Exp $
+.\" $OpenBSD: brconfig.8,v 1.19 2000/12/12 03:41:21 jason Exp $
.\"
.\" Copyright (c) 1999, 2000 Jason L. Wright (jason@thought.net)
.\" All rights reserved.
@@ -187,6 +187,32 @@ rule will match all frames (good for creating a catchall policy).
.It Cm rulefile Ar filename
Load a set of rules from the file
.Ar filename .
+.It Cm stp Ar interface
+Enable spanning tree protocol on
+.Ar interface .
+.It Cm -stp Ar interface
+Disable spanning tree protocol on
+.Ar interface .
+.It Cm maxage Ar time
+Set the time (in seconds) that a spanning tree protocol configuration is valid.
+Defaults to 20 seconds, minimum of 1, maximum of 255.
+.It Cm fwddelay Ar time
+Set the time (in seconds) before an interface begins forwarding packets.
+Defaults to 15 seconds, minimum of 1, maximum of 255.
+.It Cm hellotime Ar time
+Set the time (in seconds) between broadcasting spanning tree protocol
+configuration packets.
+Defaults to 2 seconds, minimum of 1, maximum of 255.
+.It Cm priority Ar num
+Set the spanning priority of this bridge to
+.Ar num .
+Defaults to 32768, minimum of 0, maximum of 65535.
+.It Cm ifpriority Ar interface Ar num
+Set the spanning tree priority of
+.Ar interface
+to
+.Ar num .
+Defaults to 128, minimum of 0, maximum of 255.
.El
.Sh EXAMPLES
.Bl -tag -width brconfig
@@ -310,6 +336,19 @@ Note: It is possible to put all the following commands in the
and
.Xr bridgename.if 8
files, using the ! operator.
+.Sh SPANNING TREE
+The bridge has support for 802.1D Spanning Tree Protocol (STP), which can
+be used to detect and remove loops in a network topology. Using the
+.Cm stp
+or
+.Cm -stp
+commands
+to
+.Nm brconfig
+STP can be enabled or disabled on each port.
+STP will not work on
+.Xr enc 4
+members because they lack a hardware MAC address.
.Sh SEE ALSO
.Xr bridge 4 ,
.Xr enc 4 ,
diff --git a/sbin/brconfig/brconfig.c b/sbin/brconfig/brconfig.c
index 0848c608fc2..7ff120181d8 100644
--- a/sbin/brconfig/brconfig.c
+++ b/sbin/brconfig/brconfig.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: brconfig.c,v 1.9 2000/11/10 04:42:13 jason Exp $ */
+/* $OpenBSD: brconfig.c,v 1.10 2000/12/12 03:41:22 jason Exp $ */
/*
* Copyright (c) 1999, 2000 Jason L. Wright (jason@thought.net)
@@ -57,10 +57,16 @@ 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_cfg __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_maxage __P((int, char *, char *));
+int bridge_priority __P((int, char *, char *));
+int bridge_fwddelay __P((int, char *, char *));
+int bridge_hellotime __P((int, char *, char *));
+int bridge_ifprio __P((int, char *, char *, char *));
int bridge_timeout __P((int, char *, char *));
int bridge_flush __P((int, char *));
int bridge_flushall __P((int, char *));
@@ -83,7 +89,15 @@ int bridge_rulefile __P((int, char *, char *));
\11PROMISC\12ALLMULTI\13OACTIVE\14SIMPLEX\15LINK0\16LINK1\17LINK2\20MULTICAST"
#define IFBAFBITS "\020\1STATIC"
-#define IFBIFBITS "\020\1LEARNING\2DISCOVER\3BLOCKNONIP"
+#define IFBIFBITS "\020\1LEARNING\2DISCOVER\3BLOCKNONIP\4STP"
+
+char *stpstates[] = {
+ "disabled",
+ "listening",
+ "learning",
+ "forwarding",
+ "blocking",
+};
void
usage()
@@ -300,6 +314,57 @@ main(argc, argv)
if (error)
return (error);
}
+ else if (strcmp("hellotime", argv[0]) == 0) {
+ argc--; argv++;
+ if (argc == 0) {
+ warnx("hellotime requires an argument");
+ return (EX_USAGE);
+ }
+ error = bridge_hellotime(sock, brdg, argv[0]);
+ if (error)
+ return (error);
+ }
+ else if (strcmp("fwddelay", argv[0]) == 0) {
+ argc--; argv++;
+ if (argc == 0) {
+ warnx("fwddelay requires an argument");
+ return (EX_USAGE);
+ }
+ error = bridge_fwddelay(sock, brdg, argv[0]);
+ if (error)
+ return (error);
+ }
+ else if (strcmp("maxage", argv[0]) == 0) {
+ argc--; argv++;
+ if (argc == 0) {
+ warnx("maxage requires an argument");
+ return (EX_USAGE);
+ }
+ error = bridge_maxage(sock, brdg, argv[0]);
+ if (error)
+ return (error);
+ }
+ else if (strcmp("priority", argv[0]) == 0) {
+ argc--; argv++;
+ if (argc == 0) {
+ warnx("priority requires an argument");
+ return (EX_USAGE);
+ }
+ error = bridge_priority(sock, brdg, argv[0]);
+ if (error)
+ return (error);
+ }
+ else if (strcmp("ifpriority", argv[0]) == 0) {
+ argc--; argv++;
+ if (argc < 2) {
+ warnx("ifpriority requires 2 arguments");
+ return (EX_USAGE);
+ }
+ error = bridge_ifprio(sock, brdg, argv[0], argv[1]);
+ if (error)
+ return (error);
+ argc--; argv++;
+ }
else if (strcmp("rules", argv[0]) == 0) {
argc--; argv++;
if (argc == 0) {
@@ -344,6 +409,28 @@ main(argc, argv)
if (error)
return (error);
}
+ else if (strcmp("stp", argv[0]) == 0) {
+ argc--; argv++;
+ if (argc == 0) {
+ warnx("stp requires an argument");
+ return (EX_USAGE);
+ }
+ error = bridge_ifsetflag(sock, brdg, argv[0],
+ IFBIF_STP);
+ if (error)
+ return (error);
+ }
+ else if (strcmp("-stp", argv[0]) == 0) {
+ argc--; argv++;
+ if (argc == 0) {
+ warnx("-stp requires an argument");
+ return (EX_USAGE);
+ }
+ error = bridge_ifclrflag(sock, brdg, argv[0],
+ IFBIF_STP);
+ if (error)
+ return (error);
+ }
else {
warnx("unrecognized option: %s", argv[0]);
return (EX_USAGE);
@@ -530,6 +617,46 @@ bridge_flush(s, brdg)
}
int
+bridge_cfg(s, brdg, delim)
+ int s;
+ char *brdg, *delim;
+{
+ struct ifbrparam ifbp;
+ u_int16_t pri;
+ u_int8_t ht, fd, ma;
+
+ strlcpy(ifbp.ifbrp_name, brdg, sizeof(ifbp.ifbrp_name));
+ if (ioctl(s, SIOCBRDGGPRI, (caddr_t)&ifbp)) {
+ warn("%s", brdg);
+ return (EX_IOERR);
+ }
+ pri = ifbp.ifbrp_prio;
+
+ if (ioctl(s, SIOCBRDGGHT, (caddr_t)&ifbp)) {
+ warn("%s", brdg);
+ return (EX_IOERR);
+ }
+ ht = ifbp.ifbrp_hellotime;
+
+ if (ioctl(s, SIOCBRDGGFD, (caddr_t)&ifbp)) {
+ warn("%s", brdg);
+ return (EX_IOERR);
+ }
+ fd = ifbp.ifbrp_fwddelay;
+
+ if (ioctl(s, SIOCBRDGGFD, (caddr_t)&ifbp)) {
+ warn("%s", brdg);
+ return (EX_IOERR);
+ }
+ ma = ifbp.ifbrp_maxage;
+
+ printf("%spriority %u hellotime %u fwddelay %u maxage: %u\n",
+ delim, pri, ht, fd, ma);
+
+ return (0);
+}
+
+int
bridge_list(s, brdg, delim)
int s;
char *brdg, *delim;
@@ -556,6 +683,11 @@ bridge_list(s, brdg, delim)
strlcpy(buf, reqp->ifbr_ifsname, sizeof(buf));
printf("%s%s ", delim, buf);
printb("flags", reqp->ifbr_ifsflags, IFBIFBITS);
+ printf("\n\t\t\t");
+ printf("port %u priority %u",
+ reqp->ifbr_portno, reqp->ifbr_priority);
+ if (reqp->ifbr_ifsflags & IFBIF_STP)
+ printf(" %s", stpstates[reqp->ifbr_state]);
printf("\n");
bridge_rules(s, brdg, buf, delim);
}
@@ -604,19 +736,21 @@ bridge_timeout(s, brdg, arg)
int s;
char *brdg, *arg;
{
- struct ifbcachetoreq ifbct;
+ struct ifbrparam bp;
u_int32_t newtime;
char *endptr;
+ errno = 0;
newtime = strtoul(arg, &endptr, 0);
- if (arg[0] == '\0' || endptr[0] != '\0') {
+ if (arg[0] == '\0' || endptr[0] != '\0' ||
+ (errno == ERANGE && newtime == ULONG_MAX)) {
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) {
+ strlcpy(bp.ifbrp_name, brdg, sizeof(bp.ifbrp_name));
+ bp.ifbrp_ctime = newtime;
+ if (ioctl(s, SIOCBRDGSTO, (caddr_t)&bp) < 0) {
warn("%s", brdg);
return (EX_IOERR);
}
@@ -624,23 +758,132 @@ bridge_timeout(s, brdg, arg)
}
int
+bridge_maxage(s, brdg, arg)
+ int s;
+ char *brdg, *arg;
+{
+ struct ifbrparam bp;
+ u_int32_t v;
+ char *endptr;
+
+ errno = 0;
+ v = strtoul(arg, &endptr, 0);
+ if (arg[0] == '\0' || endptr[0] != '\0' ||
+ (errno == ERANGE && v == ULONG_MAX) || (v > 0xff)) {
+ printf("invalid arg for maxage: %s\n", arg);
+ return (EX_USAGE);
+ }
+
+ strlcpy(bp.ifbrp_name, brdg, sizeof(bp.ifbrp_name));
+ bp.ifbrp_maxage = v;
+ if (ioctl(s, SIOCBRDGSMA, (caddr_t)&bp) < 0) {
+ warn("%s", brdg);
+ return (EX_IOERR);
+ }
+ return (0);
+
+}
+
+int
+bridge_priority(s, brdg, arg)
+ int s;
+ char *brdg, *arg;
+{
+ struct ifbrparam bp;
+ u_int32_t v;
+ char *endptr;
+
+ errno = 0;
+ v = strtoul(arg, &endptr, 0);
+ if (arg[0] == '\0' || endptr[0] != '\0' ||
+ (errno == ERANGE && v == ULONG_MAX) || (v > 0xffff)) {
+ printf("invalid arg for maxage: %s\n", arg);
+ return (EX_USAGE);
+ }
+
+ strlcpy(bp.ifbrp_name, brdg, sizeof(bp.ifbrp_name));
+ bp.ifbrp_prio = v;
+ if (ioctl(s, SIOCBRDGSPRI, (caddr_t)&bp) < 0) {
+ warn("%s", brdg);
+ return (EX_IOERR);
+ }
+ return (0);
+}
+
+int
+bridge_fwddelay(s, brdg, arg)
+ int s;
+ char *brdg, *arg;
+{
+ struct ifbrparam bp;
+ u_int32_t v;
+ char *endptr;
+
+ errno = 0;
+ v = strtoul(arg, &endptr, 0);
+ if (arg[0] == '\0' || endptr[0] != '\0' ||
+ (errno == ERANGE && v == ULONG_MAX) || (v > 0xff)) {
+ printf("invalid arg for fwddelay: %s\n", arg);
+ return (EX_USAGE);
+ }
+
+ strlcpy(bp.ifbrp_name, brdg, sizeof(bp.ifbrp_name));
+ bp.ifbrp_fwddelay = v;
+ if (ioctl(s, SIOCBRDGSFD, (caddr_t)&bp) < 0) {
+ warn("%s", brdg);
+ return (EX_IOERR);
+ }
+ return (0);
+
+}
+
+int
+bridge_hellotime(s, brdg, arg)
+ int s;
+ char *brdg, *arg;
+{
+ struct ifbrparam bp;
+ u_int32_t v;
+ char *endptr;
+
+ errno = 0;
+ v = strtoul(arg, &endptr, 0);
+ if (arg[0] == '\0' || endptr[0] != '\0' ||
+ (errno == ERANGE && v == ULONG_MAX) || (v > 0xff)) {
+ printf("invalid arg for hellotime: %s\n", arg);
+ return (EX_USAGE);
+ }
+
+ strlcpy(bp.ifbrp_name, brdg, sizeof(bp.ifbrp_name));
+ bp.ifbrp_hellotime = v;
+ if (ioctl(s, SIOCBRDGSHT, (caddr_t)&bp) < 0) {
+ warn("%s", brdg);
+ return (EX_IOERR);
+ }
+ return (0);
+
+}
+
+int
bridge_maxaddr(s, brdg, arg)
int s;
char *brdg, *arg;
{
- struct ifbcachereq ifbc;
+ struct ifbrparam bp;
u_int32_t newsize;
char *endptr;
+ errno = 0;
newsize = strtoul(arg, &endptr, 0);
- if (arg[0] == '\0' || endptr[0] != '\0') {
+ if (arg[0] == '\0' || endptr[0] != '\0' ||
+ (errno == ERANGE && newsize == ULONG_MAX)) {
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) {
+ strlcpy(bp.ifbrp_name, brdg, sizeof(bp.ifbrp_name));
+ bp.ifbrp_csize = newsize;
+ if (ioctl(s, SIOCBRDGSCACHE, (caddr_t)&bp) < 0) {
warn("%s", brdg);
return (EX_IOERR);
}
@@ -672,6 +915,34 @@ bridge_deladdr(s, brdg, addr)
}
int
+bridge_ifprio(s, brdg, ifname, val)
+ int s;
+ char *brdg, *ifname, *val;
+{
+ struct ifbreq breq;
+ u_int32_t v;
+ char *endptr;
+
+ strlcpy(breq.ifbr_name, brdg, sizeof(breq.ifbr_name));
+ strlcpy(breq.ifbr_ifsname, ifname, sizeof(breq.ifbr_ifsname));
+
+ errno = 0;
+ v = strtoul(val, &endptr, 0);
+ if (val[0] == '\0' || endptr[0] != '\0' ||
+ (errno == ERANGE && v == ULONG_MAX) || (v > 0xff)) {
+ printf("invalid arg for ifpriority: %s\n", val);
+ return (EX_USAGE);
+ }
+ breq.ifbr_priority = v;
+
+ if (ioctl(s, SIOCBRDGSIFPRIO, (caddr_t)&breq) < 0) {
+ warn("%s: %s", brdg, val);
+ return (EX_IOERR);
+ }
+ return (0);
+}
+
+int
bridge_addaddr(s, brdg, ifname, addr)
int s;
char *brdg, *ifname, *addr;
@@ -768,8 +1039,7 @@ bridge_status(s, brdg)
char *brdg;
{
struct ifreq ifr;
- struct ifbcachereq ifbc;
- struct ifbcachetoreq ifbct;
+ struct ifbrparam bp1, bp2;
int err;
strlcpy(ifr.ifr_name, brdg, sizeof(ifr.ifr_name));
@@ -784,25 +1054,30 @@ bridge_status(s, brdg)
printb("flags", ifr.ifr_flags, IFFBITS);
printf("\n");
+ printf("\tConfiguration:\n");
+ err = bridge_cfg(s, brdg, "\t\t");
+ if (err)
+ return (err);
+
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) {
+ strlcpy(bp1.ifbrp_name, brdg, sizeof(bp1.ifbrp_name));
+ if (ioctl(s, SIOCBRDGGCACHE, (caddr_t)&bp1) < 0) {
warn("%s", brdg);
return (EX_IOERR);
}
- strlcpy(ifbct.ifbct_name, brdg, sizeof(ifbct.ifbct_name));
- if (ioctl(s, SIOCBRDGGTO, (caddr_t)&ifbct) < 0) {
+ strlcpy(bp2.ifbrp_name, brdg, sizeof(bp2.ifbrp_name));
+ if (ioctl(s, SIOCBRDGGTO, (caddr_t)&bp2) < 0) {
warn("%s", brdg);
return (EX_IOERR);
}
printf("\tAddresses (max cache: %u, timeout: %u):\n",
- ifbc.ifbc_size, ifbct.ifbct_time);
+ bp1.ifbrp_csize, bp2.ifbrp_ctime);
err = bridge_addrs(s, brdg, "\t\t");
return (err);
diff --git a/sys/conf/files b/sys/conf/files
index 639d057c205..58cae074312 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -1,4 +1,4 @@
-# $OpenBSD: files,v 1.180 2000/11/16 20:02:21 provos Exp $
+# $OpenBSD: files,v 1.181 2000/12/12 03:41:22 jason Exp $
# $NetBSD: files,v 1.87 1996/05/19 17:17:50 jonathan Exp $
# @(#)files.newconf 7.5 (Berkeley) 5/10/93
@@ -502,6 +502,7 @@ file net/zlib.c ppp_deflate
file net/if_tokensubr.c token needs-flag
file net/if_tun.c tun needs-count
file net/if_bridge.c bridge needs-count
+file net/bridgestp.c bridge
file net/if_vlan.c vlan needs-count
file net/radix.c
file net/raw_cb.c
diff --git a/sys/net/bridgestp.c b/sys/net/bridgestp.c
new file mode 100644
index 00000000000..14a4e4a02be
--- /dev/null
+++ b/sys/net/bridgestp.c
@@ -0,0 +1,1294 @@
+/* $OpenBSD: bridgestp.c,v 1.1 2000/12/12 03:41:22 jason Exp $ */
+
+/*
+ * Copyright (c) 2000 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.
+ */
+
+/*
+ * Implementation of the spanning tree protocol as defined in
+ * ISO/IEC Final DIS 15802-3 (IEEE P802.1D/D17), May 25, 1998.
+ * (In English: IEEE 802.1D, Draft 17, 1998)
+ */
+
+#include "bridge.h"
+
+#if NBRIDGE > 0
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/device.h>
+#include <sys/kernel.h>
+
+#include <net/if.h>
+#include <net/if_types.h>
+#include <net/if_llc.h>
+#include <net/if_media.h>
+#include <net/route.h>
+#include <net/netisr.h>
+
+#ifdef INET
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/ip.h>
+#include <netinet/if_ether.h>
+
+#ifdef IPFILTER
+#include <netinet/ip_fil_compat.h>
+#include <netinet/ip_fil.h>
+#endif
+#endif
+
+#if NBPFILTER > 0
+#include <net/bpf.h>
+#endif
+
+#include <net/if_bridge.h>
+
+/* BPDU message types */
+#define BSTP_MSGTYPE_CFG 0x00 /* Configuration */
+#define BSTP_MSGTYPE_TCN 0x80 /* Topology chg notification */
+
+/* BPDU flags */
+#define BSTP_FLAG_TC 0x01 /* Topology change */
+#define BSTP_FLAG_TCA 0x80 /* Topology change ack */
+
+#define BSTP_MESSAGE_AGE_INCR (1 * 256) /* in 256ths of a second */
+#define BSTP_TICK_VAL (1 * 256) /* in 256ths of a second */
+
+/*
+ * Because BPDU's do not make nicely aligned structures, two different
+ * declarations are used: bstp_?bpdu (wire representation, packed) and
+ * bstp_*_unit (internal, nicely aligned version).
+ */
+
+/* configuration bridge protocol data unit */
+struct bstp_cbpdu {
+ u_int8_t cbu_dsap; /* LLC: destination sap */
+ u_int8_t cbu_ssap; /* LLC: source sap */
+ u_int8_t cbu_ctl; /* LLC: control */
+ u_int16_t cbu_protoid; /* protocol id */
+ u_int8_t cbu_protover; /* protocol version */
+ u_int8_t cbu_bpdutype; /* message type */
+ u_int8_t cbu_flags; /* flags (below) */
+
+ /* root id */
+ u_int16_t cbu_rootpri; /* root priority */
+ u_int8_t cbu_rootaddr[6]; /* root address */
+
+ u_int32_t cbu_rootpathcost; /* root path cost */
+
+ /* bridge id */
+ u_int16_t cbu_bridgepri; /* bridge priority */
+ u_int8_t cbu_bridgeaddr[6]; /* bridge address */
+
+ u_int16_t cbu_portid; /* port id */
+ u_int16_t cbu_messageage; /* current message age */
+ u_int16_t cbu_maxage; /* maximum age */
+ u_int16_t cbu_hellotime; /* hello time */
+ u_int16_t cbu_forwarddelay; /* forwarding delay */
+} __attribute__((__packed__));
+
+/* topology change notification bridge protocol data unit */
+struct bstp_tbpdu {
+ u_int8_t tbu_dsap; /* LLC: destination sap */
+ u_int8_t tbu_ssap; /* LLC: source sap */
+ u_int8_t tbu_ctl; /* LLC: control */
+ u_int16_t tbu_protoid; /* protocol id */
+ u_int8_t tbu_protover; /* protocol version */
+ u_int8_t tbu_bpdutype; /* message type */
+} __attribute__((__packed__));
+
+u_int8_t bstp_etheraddr[] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 };
+
+void bstp_initialization __P((struct bridge_softc *));
+void bstp_stop __P((struct bridge_softc *));
+void bstp_initialize_port __P((struct bridge_softc *, struct bridge_iflist *));
+void bstp_ifupdstatus __P((struct bridge_softc *, struct bridge_iflist *));
+void bstp_enable_port __P((struct bridge_softc *, struct bridge_iflist *));
+void bstp_disable_port __P((struct bridge_softc *, struct bridge_iflist *));
+void bstp_enable_change_detection __P((struct bridge_iflist *));
+void bstp_disable_change_detection __P((struct bridge_iflist *));
+int bstp_root_bridge __P((struct bridge_softc *sc));
+int bstp_supersedes_port_info __P((struct bridge_softc *, struct bridge_iflist *, struct bstp_config_unit *));
+int bstp_designated_port __P((struct bridge_softc *, struct bridge_iflist *));
+int bstp_designated_for_some_port __P((struct bridge_softc *));
+void bstp_transmit_config __P((struct bridge_softc *, struct bridge_iflist *));
+void bstp_transmit_tcn __P((struct bridge_softc *));
+struct mbuf *bstp_input __P((struct bridge_softc *, struct ifnet *,
+ struct ether_header *, struct mbuf *));
+void bstp_received_config_bpdu __P((struct bridge_softc *, struct bridge_iflist *, struct bstp_config_unit *));
+void bstp_received_tcn_bpdu __P((struct bridge_softc *, struct bridge_iflist *, struct bstp_tcn_unit *));
+void bstp_record_config_information __P((struct bridge_softc *, struct bridge_iflist *, struct bstp_config_unit *));
+void bstp_record_config_timeout_values __P((struct bridge_softc *, struct bstp_config_unit *));
+void bstp_config_bpdu_generation __P((struct bridge_softc *));
+void bstp_send_config_bpdu __P((struct bridge_iflist *, struct bstp_config_unit *));
+void bstp_send_tcn_bpdu __P((struct bridge_softc *, struct bridge_iflist *, struct bstp_tcn_unit *));
+void bstp_configuration_update __P((struct bridge_softc *));
+void bstp_root_selection __P((struct bridge_softc *));
+void bstp_designated_port_selection __P((struct bridge_softc *));
+void bstp_become_designated_port __P((struct bridge_softc *, struct bridge_iflist *));
+void bstp_port_state_selection __P((struct bridge_softc *));
+void bstp_make_forwarding __P((struct bridge_softc *, struct bridge_iflist *));
+void bstp_make_blocking __P((struct bridge_softc *, struct bridge_iflist *));
+void bstp_set_port_state __P((struct bridge_iflist *, u_int8_t));
+void bstp_set_bridge_priority __P((struct bridge_softc *, u_int64_t));
+void bstp_set_port_priority __P((struct bridge_softc *, struct bridge_iflist *, u_int16_t));
+void bstp_set_path_cost __P((struct bridge_softc *, struct bridge_iflist *, u_int32_t));
+void bstp_topology_change_detection __P((struct bridge_softc *));
+void bstp_topology_change_acknowledged __P((struct bridge_softc *));
+void bstp_acknowledge_topology_change __P((struct bridge_softc *, struct bridge_iflist *));
+
+void bstp_tick __P((void *));
+void bstp_timer_start __P((struct bridge_timer *, u_int16_t));
+void bstp_timer_stop __P((struct bridge_timer *));
+int bstp_timer_expired __P((struct bridge_timer *, u_int16_t));
+
+void bstp_hold_timer_expiry __P((struct bridge_softc *, struct bridge_iflist *));
+void bstp_message_age_timer_expiry __P((struct bridge_softc *, struct bridge_iflist *));
+void bstp_forward_delay_timer_expiry __P((struct bridge_softc *, struct bridge_iflist *));
+void bstp_topology_change_timer_expiry __P((struct bridge_softc *));
+void bstp_tcn_timer_expiry __P((struct bridge_softc *));
+void bstp_hello_timer_expiry __P((struct bridge_softc *));
+
+void
+bstp_transmit_config(sc, bif)
+ struct bridge_softc *sc;
+ struct bridge_iflist *bif;
+{
+ if (bif->bif_hold_timer.active) {
+ bif->bif_config_pending = 1;
+ return;
+ }
+
+ bif->bif_config_bpdu.cu_message_type = BSTP_MSGTYPE_CFG;
+ bif->bif_config_bpdu.cu_rootid = sc->sc_designated_root;
+ bif->bif_config_bpdu.cu_root_path_cost = sc->sc_root_path_cost;
+ bif->bif_config_bpdu.cu_bridge_id = sc->sc_bridge_id;
+ bif->bif_config_bpdu.cu_port_id = bif->bif_port_id;
+
+ if (bstp_root_bridge(sc))
+ bif->bif_config_bpdu.cu_message_age = 0;
+ else
+ bif->bif_config_bpdu.cu_message_age =
+ sc->sc_root_port->bif_message_age_timer.value +
+ BSTP_MESSAGE_AGE_INCR;
+
+ bif->bif_config_bpdu.cu_max_age = sc->sc_max_age;
+ bif->bif_config_bpdu.cu_hello_time = sc->sc_hello_time;
+ bif->bif_config_bpdu.cu_forward_delay = sc->sc_forward_delay;
+ bif->bif_config_bpdu.cu_topology_change_acknowledgment
+ = bif->bif_topology_change_acknowledge;
+ bif->bif_config_bpdu.cu_topology_change = sc->sc_topology_change;
+
+ if (bif->bif_config_bpdu.cu_message_age < sc->sc_max_age) {
+ bif->bif_topology_change_acknowledge = 0;
+ bif->bif_config_pending = 0;
+ bstp_send_config_bpdu(bif, &bif->bif_config_bpdu);
+ bstp_timer_start(&bif->bif_hold_timer, 0);
+ }
+}
+
+void
+bstp_send_config_bpdu(bif, cu)
+ struct bridge_iflist *bif;
+ struct bstp_config_unit *cu;
+{
+ struct arpcom *arp;
+ struct ifnet *ifp;
+ struct mbuf *m;
+ struct ether_header eh;
+ struct bstp_cbpdu bpdu;
+ int s;
+
+ s = splimp();
+ ifp = bif->ifp;
+ arp = (struct arpcom *)ifp;
+
+ if ((ifp->if_flags & IFF_RUNNING) == 0) {
+ splx(s);
+ return;
+ }
+ if (IF_QFULL(&ifp->if_snd)) {
+ splx(s);
+ return;
+ }
+
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+ if (m == NULL) {
+ splx(s);
+ return;
+ }
+ m->m_pkthdr.rcvif = ifp;
+ m->m_pkthdr.len = sizeof(eh) + sizeof(bpdu);
+ m->m_len = m->m_pkthdr.len;
+
+ bpdu.cbu_ssap = bpdu.cbu_dsap = LLC_8021D_LSAP;
+ bpdu.cbu_ctl = LLC_UI;
+ bpdu.cbu_protoid = htons(0);
+ bpdu.cbu_protover = 0;
+ bpdu.cbu_bpdutype = cu->cu_message_type;
+ bpdu.cbu_flags = (cu->cu_topology_change ? BSTP_FLAG_TC : 0) |
+ (cu->cu_topology_change_acknowledgment ? BSTP_FLAG_TCA : 0);
+
+ bpdu.cbu_rootpri = htons(cu->cu_rootid >> 48);
+ bpdu.cbu_rootaddr[0] = cu->cu_rootid >> 40;
+ bpdu.cbu_rootaddr[1] = cu->cu_rootid >> 32;
+ bpdu.cbu_rootaddr[2] = cu->cu_rootid >> 24;
+ bpdu.cbu_rootaddr[3] = cu->cu_rootid >> 16;
+ bpdu.cbu_rootaddr[4] = cu->cu_rootid >> 8;
+ bpdu.cbu_rootaddr[5] = cu->cu_rootid >> 0;
+
+ bpdu.cbu_rootpathcost = htonl(cu->cu_root_path_cost);
+
+ bpdu.cbu_bridgepri = htons(cu->cu_rootid >> 48);
+ bpdu.cbu_bridgeaddr[0] = cu->cu_rootid >> 40;
+ bpdu.cbu_bridgeaddr[1] = cu->cu_rootid >> 32;
+ bpdu.cbu_bridgeaddr[2] = cu->cu_rootid >> 24;
+ bpdu.cbu_bridgeaddr[3] = cu->cu_rootid >> 16;
+ bpdu.cbu_bridgeaddr[4] = cu->cu_rootid >> 8;
+ bpdu.cbu_bridgeaddr[5] = cu->cu_rootid >> 0;
+
+ bpdu.cbu_portid = htons(cu->cu_port_id);
+ bpdu.cbu_messageage = htons(cu->cu_message_age);
+ bpdu.cbu_maxage = htons(cu->cu_max_age);
+ bpdu.cbu_hellotime = htons(cu->cu_hello_time);
+ bpdu.cbu_forwarddelay = htons(cu->cu_forward_delay);
+
+ bcopy(arp->ac_enaddr, eh.ether_shost, ETHER_ADDR_LEN);
+ bcopy(bstp_etheraddr, eh.ether_dhost, ETHER_ADDR_LEN);
+ eh.ether_type = htons(sizeof(bpdu));
+
+ bcopy(&eh, m->m_data, sizeof(eh));
+ bcopy(&bpdu, m->m_data + sizeof(eh), sizeof(bpdu));
+
+ IF_ENQUEUE(&ifp->if_snd, m);
+ if ((ifp->if_flags & IFF_OACTIVE) == 0)
+ (*ifp->if_start)(ifp);
+ splx(s);
+}
+
+int
+bstp_root_bridge(sc)
+ struct bridge_softc *sc;
+{
+ return (sc->sc_designated_root == sc->sc_bridge_id);
+}
+
+int
+bstp_supersedes_port_info(sc, bif, cu)
+ struct bridge_softc *sc;
+ struct bridge_iflist *bif;
+ struct bstp_config_unit *cu;
+{
+ if (cu->cu_rootid < bif->bif_designated_root)
+ return (1);
+ if (cu->cu_rootid > bif->bif_designated_root)
+ return (0);
+
+ if (cu->cu_root_path_cost < bif->bif_designated_cost)
+ return (1);
+ if (cu->cu_root_path_cost > bif->bif_designated_cost)
+ return (0);
+
+ if (cu->cu_bridge_id < bif->bif_designated_bridge)
+ return (1);
+ if (cu->cu_bridge_id > bif->bif_designated_bridge)
+ return (0);
+
+ if (sc->sc_bridge_id != cu->cu_bridge_id)
+ return (1);
+ if (cu->cu_port_id <= bif->bif_designated_port)
+ return (1);
+ return (0);
+}
+
+void
+bstp_record_config_information(sc, bif, cu)
+ struct bridge_softc *sc;
+ struct bridge_iflist *bif;
+ struct bstp_config_unit *cu;
+{
+ bif->bif_designated_root = cu->cu_rootid;
+ bif->bif_designated_cost = cu->cu_root_path_cost;
+ bif->bif_designated_bridge = cu->cu_bridge_id;
+ bif->bif_designated_port = cu->cu_port_id;
+ bstp_timer_start(&bif->bif_message_age_timer, cu->cu_message_age);
+}
+
+void
+bstp_record_config_timeout_values(sc, config)
+ struct bridge_softc *sc;
+ struct bstp_config_unit *config;
+{
+ sc->sc_max_age = config->cu_max_age;
+ sc->sc_hello_time = config->cu_hello_time;
+ sc->sc_forward_delay = config->cu_forward_delay;
+ sc->sc_topology_change = config->cu_topology_change;
+}
+
+void
+bstp_config_bpdu_generation(sc)
+ struct bridge_softc *sc;
+{
+ struct bridge_iflist *bif;
+
+ LIST_FOREACH(bif, &sc->sc_iflist, next) {
+ if (!(bif->bif_flags & IFBIF_STP))
+ continue;
+ if (bstp_designated_port(sc, bif) &&
+ (bif->bif_state != BSTP_IFSTATE_DISABLED))
+ bstp_transmit_config(sc, bif);
+ }
+}
+
+int
+bstp_designated_port(sc, bif)
+ struct bridge_softc *sc;
+ struct bridge_iflist *bif;
+{
+ return ((bif->bif_designated_bridge == sc->sc_bridge_id)
+ && (bif->bif_designated_port == bif->bif_port_id));
+}
+
+void
+bstp_transmit_tcn(sc)
+ struct bridge_softc *sc;
+{
+ struct bridge_iflist *bif;
+
+ bif = sc->sc_root_port;
+ bif->bif_tcn_bpdu.tu_message_type = BSTP_MSGTYPE_TCN;
+ bstp_send_tcn_bpdu(sc, bif, &bif->bif_tcn_bpdu);
+}
+
+void
+bstp_send_tcn_bpdu(sc, bif, tu)
+ struct bridge_softc *sc;
+ struct bridge_iflist *bif;
+ struct bstp_tcn_unit *tu;
+{
+ struct arpcom *arp;
+ struct ifnet *ifp;
+ struct mbuf *m;
+ struct ether_header eh;
+ struct bstp_tbpdu bpdu;
+ int s;
+
+ s = splimp();
+ ifp = bif->ifp;
+ arp = (struct arpcom *)ifp;
+
+ if ((ifp->if_flags & IFF_RUNNING) == 0) {
+ splx(s);
+ return;
+ }
+ if (IF_QFULL(&ifp->if_snd)) {
+ splx(s);
+ return;
+ }
+
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+ if (m == NULL) {
+ splx(s);
+ return;
+ }
+ m->m_pkthdr.rcvif = ifp;
+ m->m_pkthdr.len = sizeof(eh) + sizeof(bpdu);
+ m->m_len = m->m_pkthdr.len;
+
+ bpdu.tbu_ssap = bpdu.tbu_dsap = LLC_8021D_LSAP;
+ bpdu.tbu_ctl = LLC_UI;
+ bpdu.tbu_protoid = 0;
+ bpdu.tbu_protover = 0;
+ bpdu.tbu_bpdutype = tu->tu_message_type;
+
+ bcopy(arp->ac_enaddr, eh.ether_shost, ETHER_ADDR_LEN);
+ bcopy(bstp_etheraddr, eh.ether_dhost, ETHER_ADDR_LEN);
+ eh.ether_type = htons(sizeof(bpdu));
+
+ bcopy(&eh, m->m_data, sizeof(eh));
+ bcopy(&bpdu, m->m_data + sizeof(eh), sizeof(bpdu));
+
+ IF_ENQUEUE(&ifp->if_snd, m);
+ if ((ifp->if_flags & IFF_OACTIVE) == 0)
+ (*ifp->if_start)(ifp);
+ splx(s);
+}
+
+void
+bstp_configuration_update(sc)
+ struct bridge_softc *sc;
+{
+ bstp_root_selection(sc);
+ bstp_designated_port_selection(sc);
+}
+
+void
+bstp_root_selection(sc)
+ struct bridge_softc *sc;
+{
+ struct bridge_iflist *root_port = NULL, *bif;
+
+ LIST_FOREACH(bif, &sc->sc_iflist, next) {
+ if (!(bif->bif_flags & IFBIF_STP))
+ continue;
+ if (bstp_designated_port(sc, bif))
+ continue;
+ if (bif->bif_state == BSTP_IFSTATE_DISABLED)
+ continue;
+ if (bif->bif_designated_root >= sc->sc_bridge_id)
+ continue;
+ if (root_port == NULL)
+ goto set_port;
+
+ if (bif->bif_designated_root < root_port->bif_designated_root)
+ goto set_port;
+ if (bif->bif_designated_root > root_port->bif_designated_root)
+ continue;
+
+ if ((bif->bif_designated_cost + bif->bif_path_cost) <
+ (root_port->bif_designated_cost + root_port->bif_path_cost))
+ goto set_port;
+ if ((bif->bif_designated_cost + bif->bif_path_cost) >
+ (root_port->bif_designated_cost + root_port->bif_path_cost))
+ continue;
+
+ if (bif->bif_designated_bridge < root_port->bif_designated_bridge)
+ goto set_port;
+ if (bif->bif_designated_bridge > root_port->bif_designated_bridge)
+ continue;
+
+ if (bif->bif_designated_port < root_port->bif_designated_port)
+ goto set_port;
+ if (bif->bif_designated_port > root_port->bif_designated_port)
+ continue;
+
+ if (bif->bif_port_id >= root_port->bif_port_id)
+ continue;
+set_port:
+ root_port = bif;
+ }
+
+ sc->sc_root_port = root_port;
+ if (root_port == NULL) {
+ sc->sc_designated_root = sc->sc_bridge_id;
+ sc->sc_root_path_cost = 0;
+ } else {
+ sc->sc_designated_root = root_port->bif_designated_root;
+ sc->sc_root_path_cost = root_port->bif_designated_cost +
+ root_port->bif_path_cost;
+ }
+}
+
+void
+bstp_designated_port_selection(sc)
+ struct bridge_softc *sc;
+{
+ struct bridge_iflist *bif;
+
+ LIST_FOREACH(bif, &sc->sc_iflist, next) {
+ if (!(bif->bif_flags & IFBIF_STP))
+ continue;
+ if (bstp_designated_port(sc, bif))
+ goto designated;
+ if (bif->bif_designated_root != sc->sc_designated_root)
+ goto designated;
+
+ if (sc->sc_root_path_cost < bif->bif_designated_cost)
+ goto designated;
+ if (sc->sc_root_path_cost > bif->bif_designated_cost)
+ continue;
+
+ if (sc->sc_bridge_id < bif->bif_designated_bridge)
+ goto designated;
+ if (sc->sc_bridge_id > bif->bif_designated_bridge)
+ continue;
+
+ if (bif->bif_port_id > bif->bif_designated_port)
+ continue;
+designated:
+ bstp_become_designated_port(sc, bif);
+ }
+}
+
+void
+bstp_become_designated_port(sc, bif)
+ struct bridge_softc *sc;
+ struct bridge_iflist *bif;
+{
+ bif->bif_designated_root = sc->sc_designated_root;
+ bif->bif_designated_cost = sc->sc_root_path_cost;
+ bif->bif_designated_bridge = sc->sc_bridge_id;
+ bif->bif_designated_port = bif->bif_port_id;
+}
+
+void
+bstp_port_state_selection(sc)
+ struct bridge_softc *sc;
+{
+ struct bridge_iflist *bif;
+
+ LIST_FOREACH(bif, &sc->sc_iflist, next) {
+ if (!(bif->bif_flags & IFBIF_STP))
+ continue;
+ if (bif == sc->sc_root_port) {
+ bif->bif_config_pending = 0;
+ bif->bif_topology_change_acknowledge = 0;
+ bstp_make_forwarding(sc, bif);
+ } else if (bstp_designated_port(sc, bif)) {
+ bstp_timer_stop(&bif->bif_message_age_timer);
+ bstp_make_forwarding(sc, bif);
+ } else {
+ bif->bif_config_pending = 0;
+ bif->bif_topology_change_acknowledge = 0;
+ bstp_make_blocking(sc, bif);
+ }
+ }
+}
+
+void
+bstp_make_forwarding(sc, bif)
+ struct bridge_softc *sc;
+ struct bridge_iflist *bif;
+{
+ if (bif->bif_state == BSTP_IFSTATE_BLOCKING) {
+ bstp_set_port_state(bif, BSTP_IFSTATE_LISTENING);
+ bstp_timer_start(&bif->bif_forward_delay_timer, 0);
+ }
+}
+
+void
+bstp_make_blocking(sc, bif)
+ struct bridge_softc *sc;
+ struct bridge_iflist *bif;
+{
+ if ((bif->bif_state != BSTP_IFSTATE_DISABLED) &&
+ (bif->bif_state != BSTP_IFSTATE_BLOCKING)) {
+ if ((bif->bif_state == BSTP_IFSTATE_FORWARDING) ||
+ (bif->bif_state == BSTP_IFSTATE_LEARNING)) {
+ if (bif->bif_change_detection_enabled) {
+ bstp_topology_change_detection(sc);
+ }
+ }
+ bstp_set_port_state(bif, BSTP_IFSTATE_BLOCKING);
+ bstp_timer_stop(&bif->bif_forward_delay_timer);
+ }
+}
+
+void
+bstp_set_port_state(bif, state)
+ struct bridge_iflist *bif;
+ u_int8_t state;
+{
+ bif->bif_state = state;
+}
+
+void
+bstp_topology_change_detection(sc)
+ struct bridge_softc *sc;
+{
+ if (bstp_root_bridge(sc)) {
+ sc->sc_topology_change = 1;
+ bstp_timer_start(&sc->sc_topology_change_timer, 0);
+ } else if (!sc->sc_topology_change_detected) {
+ bstp_transmit_tcn(sc);
+ bstp_timer_start(&sc->sc_tcn_timer, 0);
+ }
+ sc->sc_topology_change_detected = 1;
+}
+
+void
+bstp_topology_change_acknowledged(sc)
+ struct bridge_softc *sc;
+{
+ sc->sc_topology_change_detected = 0;
+ bstp_timer_stop(&sc->sc_tcn_timer);
+}
+
+void
+bstp_acknowledge_topology_change(sc, bif)
+ struct bridge_softc *sc;
+ struct bridge_iflist *bif;
+{
+ bif->bif_topology_change_acknowledge = 1;
+ bstp_transmit_config(sc, bif);
+}
+
+struct mbuf *
+bstp_input(sc, ifp, eh, m)
+ struct bridge_softc *sc;
+ struct ifnet *ifp;
+ struct ether_header *eh;
+ struct mbuf *m;
+{
+ struct bridge_iflist *bif = NULL;
+ struct bstp_tbpdu tpdu;
+ struct bstp_cbpdu cpdu;
+ struct bstp_config_unit cu;
+ struct bstp_tcn_unit tu;
+ u_int16_t len;
+
+ LIST_FOREACH(bif, &sc->sc_iflist, next) {
+ if (!(bif->bif_flags & IFBIF_STP))
+ continue;
+ if (bif->ifp == ifp)
+ break;
+ }
+ if (bif == NULL)
+ goto out;
+
+ len = ntohs(eh->ether_type);
+ if (len < sizeof(tpdu))
+ goto out;
+ if (m->m_pkthdr.len > len)
+ m_adj(m, len - m->m_pkthdr.len);
+ if ((m = m_pullup(m, sizeof(tpdu))) == NULL)
+ goto out;
+ bcopy(mtod(m, struct tpdu *), &tpdu, sizeof(tpdu));
+
+ if (tpdu.tbu_dsap != LLC_8021D_LSAP ||
+ tpdu.tbu_ssap != LLC_8021D_LSAP ||
+ tpdu.tbu_ctl != LLC_UI)
+ goto out;
+ if (tpdu.tbu_protoid != 0 || tpdu.tbu_protover != 0)
+ goto out;
+
+ switch (tpdu.tbu_bpdutype) {
+ case BSTP_MSGTYPE_TCN:
+ tu.tu_message_type = tpdu.tbu_bpdutype;
+ bstp_received_tcn_bpdu(sc, bif, &tu);
+ break;
+ case BSTP_MSGTYPE_CFG:
+ if ((m = m_pullup(m, sizeof(cpdu))) == NULL)
+ goto out;
+ bcopy(mtod(m, struct bstp_cpdu *), &cpdu, sizeof(cpdu));
+
+ cu.cu_rootid =
+ (((u_int64_t)ntohs(cpdu.cbu_rootpri)) << 48) |
+ (((u_int64_t)cpdu.cbu_rootaddr[0]) << 40) |
+ (((u_int64_t)cpdu.cbu_rootaddr[1]) << 32) |
+ (((u_int64_t)cpdu.cbu_rootaddr[2]) << 24) |
+ (((u_int64_t)cpdu.cbu_rootaddr[3]) << 16) |
+ (((u_int64_t)cpdu.cbu_rootaddr[4]) << 8) |
+ (((u_int64_t)cpdu.cbu_rootaddr[5]) << 0);
+
+ cu.cu_bridge_id =
+ (((u_int64_t)ntohs(cpdu.cbu_bridgepri)) << 48) |
+ (((u_int64_t)cpdu.cbu_bridgeaddr[0]) << 40) |
+ (((u_int64_t)cpdu.cbu_bridgeaddr[1]) << 32) |
+ (((u_int64_t)cpdu.cbu_bridgeaddr[2]) << 24) |
+ (((u_int64_t)cpdu.cbu_bridgeaddr[3]) << 16) |
+ (((u_int64_t)cpdu.cbu_bridgeaddr[4]) << 8) |
+ (((u_int64_t)cpdu.cbu_bridgeaddr[5]) << 0);
+
+ cu.cu_root_path_cost = ntohl(cpdu.cbu_rootpathcost);
+ cu.cu_message_age = ntohs(cpdu.cbu_messageage);
+ cu.cu_max_age = ntohs(cpdu.cbu_maxage);
+ cu.cu_hello_time = ntohs(cpdu.cbu_hellotime);
+ cu.cu_forward_delay = ntohs(cpdu.cbu_forwarddelay);
+ cu.cu_port_id = ntohs(cpdu.cbu_portid);
+ cu.cu_message_type = cpdu.cbu_bpdutype;
+ cu.cu_topology_change_acknowledgment =
+ (cpdu.cbu_flags & BSTP_FLAG_TCA) ? 1 : 0;
+ cu.cu_topology_change =
+ (cpdu.cbu_flags & BSTP_FLAG_TC) ? 1 : 0;
+ bstp_received_config_bpdu(sc, bif, &cu);
+ break;
+ default:
+ goto out;
+ }
+
+out:
+ if (m)
+ m_freem(m);
+ return (NULL);
+}
+
+void
+bstp_received_config_bpdu(sc, bif, cu)
+ struct bridge_softc *sc;
+ struct bridge_iflist *bif;
+ struct bstp_config_unit *cu;
+{
+ int root;
+
+ root = bstp_root_bridge(sc);
+
+ if (bif->bif_state != BSTP_IFSTATE_DISABLED) {
+ if (bstp_supersedes_port_info(sc, bif, cu)) {
+ bstp_record_config_information(sc, bif, cu);
+ bstp_configuration_update(sc);
+ bstp_port_state_selection(sc);
+
+ if ((!bstp_root_bridge(sc)) && root) {
+ bstp_timer_stop(&sc->sc_hello_timer);
+
+ if (sc->sc_topology_change_detected) {
+ bstp_timer_stop(&sc->sc_topology_change_timer);
+ bstp_transmit_tcn(sc);
+ bstp_timer_start(&sc->sc_tcn_timer, 0);
+ }
+ }
+
+ if (bif == sc->sc_root_port) {
+ bstp_record_config_timeout_values(sc, cu);
+ bstp_config_bpdu_generation(sc);
+
+ if (cu->cu_topology_change_acknowledgment)
+ bstp_topology_change_acknowledged(sc);
+ }
+ }
+ else if (bstp_designated_port(sc, bif))
+ bstp_transmit_config(sc, bif);
+ }
+}
+
+void
+bstp_received_tcn_bpdu(sc, bif, tcn)
+ struct bridge_softc *sc;
+ struct bridge_iflist *bif;
+ struct bstp_tcn_unit *tcn;
+{
+ if (bif->bif_state != BSTP_IFSTATE_DISABLED &&
+ bstp_designated_port(sc, bif)) {
+ bstp_topology_change_detection(sc);
+ bstp_acknowledge_topology_change(sc, bif);
+ }
+}
+
+void
+bstp_hello_timer_expiry(sc)
+ struct bridge_softc *sc;
+{
+ bstp_config_bpdu_generation(sc);
+ bstp_timer_start(&sc->sc_hello_timer, 0);
+}
+
+void
+bstp_message_age_timer_expiry(sc, bif)
+ struct bridge_softc *sc;
+ struct bridge_iflist *bif;
+{
+ int root;
+
+ root = bstp_root_bridge(sc);
+ bstp_become_designated_port(sc, bif);
+ bstp_configuration_update(sc);
+ bstp_port_state_selection(sc);
+
+ if ((bstp_root_bridge(sc)) && (!root)) {
+ sc->sc_max_age = sc->sc_bridge_max_age;
+ sc->sc_hello_time = sc->sc_bridge_hello_time;
+ sc->sc_forward_delay = sc->sc_bridge_forward_delay;
+
+ bstp_topology_change_detection(sc);
+ bstp_timer_stop(&sc->sc_tcn_timer);
+ bstp_config_bpdu_generation(sc);
+ bstp_timer_start(&sc->sc_hello_timer, 0);
+ }
+}
+
+void
+bstp_forward_delay_timer_expiry(sc, bif)
+ struct bridge_softc *sc;
+ struct bridge_iflist *bif;
+{
+ if (bif->bif_state == BSTP_IFSTATE_LISTENING) {
+ bstp_set_port_state(bif, BSTP_IFSTATE_LEARNING);
+ bstp_timer_start(&bif->bif_forward_delay_timer, 0);
+ } else if (bif->bif_state == BSTP_IFSTATE_LEARNING) {
+ bstp_set_port_state(bif, BSTP_IFSTATE_FORWARDING);
+ if (bstp_designated_for_some_port(sc) &&
+ bif->bif_change_detection_enabled)
+ bstp_topology_change_detection(sc);
+ }
+}
+
+int
+bstp_designated_for_some_port(sc)
+ struct bridge_softc *sc;
+{
+
+ struct bridge_iflist *bif;
+
+ LIST_FOREACH(bif, &sc->sc_iflist, next) {
+ if (!(bif->bif_flags & IFBIF_STP))
+ continue;
+ if (bif->bif_designated_bridge == sc->sc_bridge_id)
+ return (1);
+ }
+ return (0);
+}
+
+void
+bstp_tcn_timer_expiry(sc)
+ struct bridge_softc *sc;
+{
+ bstp_transmit_tcn(sc);
+ bstp_timer_start(&sc->sc_tcn_timer, 0);
+}
+
+void
+bstp_topology_change_timer_expiry(sc)
+ struct bridge_softc *sc;
+{
+ sc->sc_topology_change_detected = 0;
+ sc->sc_topology_change = 0;
+}
+
+void
+bstp_hold_timer_expiry(sc, bif)
+ struct bridge_softc *sc;
+ struct bridge_iflist *bif;
+{
+ if (bif->bif_config_pending)
+ bstp_transmit_config(sc, bif);
+}
+
+void
+bstp_initialization(sc)
+ struct bridge_softc *sc;
+{
+ struct bridge_iflist *bif, *mif;
+ struct arpcom *ac, *mac;
+
+ mif = NULL; mac = NULL;
+ LIST_FOREACH(bif, &sc->sc_iflist, next) {
+ if (!(bif->bif_flags & IFBIF_STP))
+ continue;
+ if (bif->ifp->if_type != IFT_ETHER)
+ continue;
+ bif->bif_port_id = (bif->bif_priority << 8) |
+ (bif->ifp->if_index & 0xff);
+
+ if (mif == NULL) {
+ mif = bif;
+ mac = (struct arpcom *)bif->ifp;
+ continue;
+ }
+ ac = (struct arpcom *)bif->ifp;
+ if (memcmp(ac->ac_enaddr, mac->ac_enaddr, ETHER_ADDR_LEN) < 0) {
+ mif = bif;
+ mac = (struct arpcom *)bif->ifp;
+ continue;
+ }
+ }
+ if (mif == NULL) {
+ bstp_stop(sc);
+ return;
+ }
+
+ sc->sc_bridge_id =
+ (((u_int64_t)sc->sc_bridge_priority) << 48) |
+ (((u_int64_t)mac->ac_enaddr[0]) << 40) |
+ (((u_int64_t)mac->ac_enaddr[1]) << 32) |
+ (mac->ac_enaddr[2] << 24) | (mac->ac_enaddr[3] << 16) |
+ (mac->ac_enaddr[4] << 8) | (mac->ac_enaddr[5]);
+
+ sc->sc_designated_root = sc->sc_bridge_id;
+ sc->sc_root_path_cost = 0;
+ sc->sc_root_port = NULL;
+
+ sc->sc_max_age = sc->sc_bridge_max_age;
+ sc->sc_hello_time = sc->sc_bridge_hello_time;
+ sc->sc_forward_delay = sc->sc_bridge_forward_delay;
+ sc->sc_topology_change_detected = 0;
+ sc->sc_topology_change = 0;
+ bstp_timer_stop(&sc->sc_tcn_timer);
+ bstp_timer_stop(&sc->sc_topology_change_timer);
+
+ if (!timeout_initialized(&sc->sc_bstptimeout))
+ timeout_set(&sc->sc_bstptimeout, bstp_tick, sc);
+ if (!timeout_pending(&sc->sc_bstptimeout))
+ timeout_add(&sc->sc_bstptimeout, hz);
+
+ LIST_FOREACH(bif, &sc->sc_iflist, next) {
+ if (bif->bif_flags & IFBIF_STP)
+ bstp_enable_port(sc, bif);
+ else
+ bstp_disable_port(sc, bif);
+ }
+
+ bstp_port_state_selection(sc);
+ bstp_config_bpdu_generation(sc);
+ bstp_timer_start(&sc->sc_hello_timer, 0);
+}
+
+void
+bstp_stop(sc)
+ struct bridge_softc *sc;
+{
+
+ struct bridge_iflist *bif;
+
+ LIST_FOREACH(bif, &sc->sc_iflist, next) {
+ bstp_set_port_state(bif, BSTP_IFSTATE_DISABLED);
+ bstp_timer_stop(&bif->bif_hold_timer);
+ bstp_timer_stop(&bif->bif_message_age_timer);
+ bstp_timer_stop(&bif->bif_forward_delay_timer);
+ }
+
+ if (timeout_initialized(&sc->sc_bstptimeout) &&
+ timeout_pending(&sc->sc_bstptimeout))
+ timeout_del(&sc->sc_bstptimeout);
+
+ bstp_timer_stop(&sc->sc_topology_change_timer);
+ bstp_timer_stop(&sc->sc_tcn_timer);
+ bstp_timer_stop(&sc->sc_hello_timer);
+
+}
+
+void
+bstp_initialize_port(sc, bif)
+ struct bridge_softc *sc;
+ struct bridge_iflist *bif;
+{
+ bstp_become_designated_port(sc, bif);
+ bstp_set_port_state(bif, BSTP_IFSTATE_BLOCKING);
+ bif->bif_topology_change_acknowledge = 0;
+ bif->bif_config_pending = 0;
+ bif->bif_change_detection_enabled = 1;
+ bstp_timer_stop(&bif->bif_message_age_timer);
+ bstp_timer_stop(&bif->bif_forward_delay_timer);
+ bstp_timer_stop(&bif->bif_hold_timer);
+}
+
+void
+bstp_enable_port(sc, bif)
+ struct bridge_softc *sc;
+ struct bridge_iflist *bif;
+{
+ bstp_initialize_port(sc, bif);
+ bstp_port_state_selection(sc);
+}
+
+void
+bstp_disable_port(sc, bif)
+ struct bridge_softc *sc;
+ struct bridge_iflist *bif;
+{
+ int root;
+
+ root = bstp_root_bridge(sc);
+ bstp_become_designated_port(sc, bif);
+ bstp_set_port_state(bif, BSTP_IFSTATE_DISABLED);
+ bif->bif_topology_change_acknowledge = 0;
+ bif->bif_config_pending = 0;
+ bstp_timer_stop(&bif->bif_message_age_timer);
+ bstp_timer_stop(&bif->bif_forward_delay_timer);
+ bstp_configuration_update(sc);
+ bstp_port_state_selection(sc);
+
+ if (bstp_root_bridge(sc) && (!root)) {
+ sc->sc_max_age = sc->sc_bridge_max_age;
+ sc->sc_hello_time = sc->sc_bridge_hello_time;
+ sc->sc_forward_delay = sc->sc_bridge_forward_delay;
+
+ bstp_topology_change_detection(sc);
+ bstp_timer_stop(&sc->sc_tcn_timer);
+ bstp_config_bpdu_generation(sc);
+ bstp_timer_start(&sc->sc_hello_timer, 0);
+ }
+}
+
+void
+bstp_set_bridge_priority(sc, new_bridge_id)
+ struct bridge_softc *sc;
+ u_int64_t new_bridge_id;
+{
+ int root;
+ struct bridge_iflist *bif;
+
+ root = bstp_root_bridge(sc);
+
+ LIST_FOREACH(bif, &sc->sc_iflist, next) {
+ if (!(bif->bif_flags & IFBIF_STP))
+ continue;
+ if (bstp_designated_port(sc, bif))
+ bif->bif_designated_bridge = new_bridge_id;
+ }
+
+ sc->sc_bridge_id = new_bridge_id;
+
+ bstp_configuration_update(sc);
+ bstp_port_state_selection(sc);
+
+ if (bstp_root_bridge(sc) && (!root)) {
+ sc->sc_max_age = sc->sc_bridge_max_age;
+ sc->sc_hello_time = sc->sc_bridge_hello_time;
+ sc->sc_forward_delay = sc->sc_bridge_forward_delay;
+
+ bstp_topology_change_detection(sc);
+ bstp_timer_stop(&sc->sc_tcn_timer);
+ bstp_config_bpdu_generation(sc);
+ bstp_timer_start(&sc->sc_hello_timer, 0);
+ }
+}
+
+void
+bstp_set_port_priority(sc, bif, new_port_id)
+ struct bridge_softc *sc;
+ struct bridge_iflist *bif;
+ u_int16_t new_port_id;
+{
+ if (bstp_designated_port(sc, bif))
+ bif->bif_designated_port = new_port_id;
+
+ bif->bif_port_id = new_port_id;
+
+ if ((sc->sc_bridge_id == bif->bif_designated_bridge) &&
+ (bif->bif_port_id < bif->bif_designated_port)) {
+ bstp_become_designated_port(sc, bif);
+ bstp_port_state_selection(sc);
+ }
+}
+
+void
+bstp_set_path_cost(sc, bif, path_cost)
+ struct bridge_softc *sc;
+ struct bridge_iflist *bif;
+ u_int32_t path_cost;
+{
+ bif->bif_path_cost = path_cost;
+ bstp_configuration_update(sc);
+ bstp_port_state_selection(sc);
+}
+
+void
+bstp_enable_change_detection(bif)
+ struct bridge_iflist *bif;
+{
+ bif->bif_change_detection_enabled = 1;
+}
+
+void
+bstp_disable_change_detection(bif)
+ struct bridge_iflist *bif;
+{
+ bif->bif_change_detection_enabled = 0;
+}
+
+void
+bstp_ifupdstatus(sc, bif)
+ struct bridge_softc *sc;
+ struct bridge_iflist *bif;
+{
+ struct ifnet *ifp = bif->ifp;
+ struct ifmediareq ifmr;
+ int err;
+
+ if (ifp->if_flags & IFF_UP) {
+ ifmr.ifm_count = 0;
+ err = (*ifp->if_ioctl)(ifp, SIOCGIFMEDIA, (caddr_t)&ifmr);
+ if (err) {
+ if (bif->bif_state == BSTP_IFSTATE_DISABLED)
+ bstp_enable_port(sc, bif);
+ return;
+ }
+
+ if (!(ifmr.ifm_status & IFM_AVALID)) {
+ if (bif->bif_state == BSTP_IFSTATE_DISABLED)
+ bstp_enable_port(sc, bif);
+ return;
+ }
+
+ if (ifmr.ifm_status & IFM_ACTIVE) {
+ if (bif->bif_state == BSTP_IFSTATE_DISABLED)
+ bstp_enable_port(sc, bif);
+ return;
+ }
+
+ if (bif->bif_state != BSTP_IFSTATE_DISABLED)
+ bstp_disable_port(sc, bif);
+
+ return;
+ }
+
+ if (bif->bif_state != BSTP_IFSTATE_DISABLED)
+ bstp_disable_port(sc, bif);
+}
+
+void
+bstp_tick(vsc)
+ void *vsc;
+{
+ struct bridge_softc *sc = vsc;
+ struct bridge_iflist *bif;
+ int s;
+
+ s = splnet();
+
+ LIST_FOREACH(bif, &sc->sc_iflist, next) {
+ if (!(bif->bif_flags & IFBIF_STP))
+ continue;
+ bstp_ifupdstatus(sc, bif);
+ }
+
+ if (bstp_timer_expired(&sc->sc_hello_timer, sc->sc_hello_time))
+ bstp_hello_timer_expiry(sc);
+
+ if (bstp_timer_expired(&sc->sc_tcn_timer, sc->sc_bridge_hello_time))
+ bstp_tcn_timer_expiry(sc);
+
+ if (bstp_timer_expired(&sc->sc_topology_change_timer,
+ sc->sc_topology_change_time))
+ bstp_topology_change_timer_expiry(sc);
+
+ LIST_FOREACH(bif, &sc->sc_iflist, next) {
+ if (!(bif->bif_flags & IFBIF_STP))
+ continue;
+ if (bstp_timer_expired(&bif->bif_message_age_timer,
+ sc->sc_max_age))
+ bstp_message_age_timer_expiry(sc, bif);
+ }
+
+ LIST_FOREACH(bif, &sc->sc_iflist, next) {
+ if (!(bif->bif_flags & IFBIF_STP))
+ continue;
+ if (bstp_timer_expired(&bif->bif_forward_delay_timer,
+ sc->sc_forward_delay))
+ bstp_forward_delay_timer_expiry(sc, bif);
+
+ if (bstp_timer_expired(&bif->bif_hold_timer,
+ sc->sc_hold_time))
+ bstp_hold_timer_expiry(sc, bif);
+ }
+
+ if (sc->sc_if.if_flags & IFF_RUNNING)
+ timeout_add(&sc->sc_bstptimeout, hz);
+
+ splx(s);
+}
+
+void
+bstp_timer_start(t, v)
+ struct bridge_timer *t;
+ u_int16_t v;
+{
+ t->value = v;
+ t->active = 1;
+}
+
+void
+bstp_timer_stop(t)
+ struct bridge_timer *t;
+{
+ t->value = 0;
+ t->active = 0;
+}
+
+int
+bstp_timer_expired(t, v)
+ struct bridge_timer *t;
+ u_int16_t v;
+{
+ if (!t->active)
+ return (0);
+ t->value += BSTP_TICK_VAL;
+ if (t->value >= v) {
+ bstp_timer_stop(t);
+ return (1);
+ }
+ return (0);
+
+}
+
+int
+bstp_ioctl(ifp, cmd, data)
+ struct ifnet *ifp;
+ u_long cmd;
+ caddr_t data;
+{
+ struct bridge_softc *sc = (struct bridge_softc *)ifp;
+ struct ifbrparam *bp = (struct ifbrparam *)data;
+ int r = 0, err = 0;
+
+ switch (cmd) {
+ case SIOCBRDGGPRI:
+ bp->ifbrp_prio = sc->sc_bridge_priority;
+ break;
+ case SIOCBRDGGMA:
+ bp->ifbrp_maxage = sc->sc_bridge_max_age >> 8;
+ break;
+ case SIOCBRDGGHT:
+ bp->ifbrp_hellotime = sc->sc_bridge_hello_time >> 8;
+ break;
+ case SIOCBRDGGFD:
+ bp->ifbrp_fwddelay = sc->sc_bridge_forward_delay >> 8;
+ break;
+ case SIOCBRDGSPRI:
+ sc->sc_bridge_priority = bp->ifbrp_prio;
+ r = 1;
+ break;
+ case SIOCBRDGSMA:
+ if (bp->ifbrp_maxage == 0) {
+ err = EINVAL;
+ break;
+ }
+ sc->sc_bridge_max_age = bp->ifbrp_maxage << 8;
+ r = 1;
+ break;
+ case SIOCBRDGSHT:
+ if (bp->ifbrp_hellotime == 0) {
+ err = EINVAL;
+ break;
+ }
+ sc->sc_bridge_hello_time = bp->ifbrp_hellotime << 8;
+ r = 1;
+ break;
+ case SIOCBRDGSFD:
+ if (bp->ifbrp_fwddelay == 0) {
+ err = EINVAL;
+ break;
+ }
+ sc->sc_bridge_forward_delay = bp->ifbrp_fwddelay << 8;
+ r = 1;
+ break;
+ case SIOCBRDGADD:
+ case SIOCBRDGDEL:
+ case SIOCBRDGSIFFLGS:
+ case SIOCBRDGSIFPRIO:
+ r = 1;
+ break;
+ default:
+ break;
+ }
+
+ if (r)
+ bstp_initialization(sc);
+
+ return (err);
+}
+
+#endif /* NBRIDGE */
diff --git a/sys/net/if_bridge.c b/sys/net/if_bridge.c
index 54c9e275ff4..383fee5c449 100644
--- a/sys/net/if_bridge.c
+++ b/sys/net/if_bridge.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_bridge.c,v 1.42 2000/11/10 05:24:58 jason Exp $ */
+/* $OpenBSD: if_bridge.c,v 1.43 2000/12/12 03:41:22 jason Exp $ */
/*
* Copyright (c) 1999, 2000 Jason L. Wright (jason@thought.net)
@@ -83,68 +83,28 @@
/*
* Maximum number of addresses to cache
*/
-#ifndef BRIDGE_RTABLE_MAX
-#define BRIDGE_RTABLE_MAX 100
+#ifndef BRIDGE_RTABLE_MAX
+#define BRIDGE_RTABLE_MAX 100
#endif
+/* spanning tree defaults */
+#define BSTP_DEFAULT_MAX_AGE (20 * 256)
+#define BSTP_DEFAULT_HELLO_TIME (2 * 256)
+#define BSTP_DEFAULT_FORWARD_DELAY (15 * 256)
+#define BSTP_DEFAULT_HOLD_TIME (1 * 256)
+#define BSTP_DEFAULT_BRIDGE_PRIORITY 0x8000
+#define BSTP_DEFAULT_PORT_PRIORITY 0x80
+#define BSTP_DEFAULT_PATH_COST 55
+
/*
* Timeout (in seconds) for entries learned dynamically
*/
-#ifndef BRIDGE_RTABLE_TIMEOUT
-#define BRIDGE_RTABLE_TIMEOUT 240
+#ifndef BRIDGE_RTABLE_TIMEOUT
+#define BRIDGE_RTABLE_TIMEOUT 240
#endif
extern int ifqmaxlen;
-/*
- * Bridge filtering rules
- */
-SIMPLEQ_HEAD(brl_head, brl_node);
-
-struct brl_node {
- SIMPLEQ_ENTRY(brl_node) brl_next; /* next rule */
- struct ether_addr brl_src; /* source mac address */
- struct ether_addr brl_dst; /* destination mac address */
- u_int8_t brl_action; /* what to do with match */
- u_int8_t brl_flags; /* comparision flags */
-};
-
-/*
- * Bridge interface list
- */
-struct bridge_iflist {
- LIST_ENTRY(bridge_iflist) next; /* next in list */
- struct brl_head bif_brlin; /* input rules */
- struct brl_head bif_brlout; /* output rules */
- struct ifnet *ifp; /* member interface */
- u_int32_t bif_flags; /* member flags */
-};
-
-/*
- * Bridge route node
- */
-struct bridge_rtnode {
- LIST_ENTRY(bridge_rtnode) brt_next; /* next in list */
- struct ifnet *brt_if; /* destination ifs */
- u_int8_t brt_flags; /* address flags */
- u_int8_t brt_age; /* age counter */
- struct ether_addr brt_addr; /* dst addr */
-};
-
-/*
- * Software state for each bridge
- */
-struct bridge_softc {
- struct ifnet sc_if; /* the interface */
- u_int32_t sc_brtmax; /* max # addresses */
- u_int32_t sc_brtcnt; /* current # addrs */
- u_int32_t sc_brttimeout; /* timeout ticks */
- u_int32_t sc_hashkey; /* hash key */
- struct timeout sc_brtimeout; /* timeout state */
- LIST_HEAD(, bridge_iflist) sc_iflist; /* interface list */
- LIST_HEAD(bridge_rthead, bridge_rtnode) *sc_rts;/* hash table */
-};
-
struct bridge_softc bridgectl[NBRIDGE];
void bridgeattach __P((int));
@@ -205,6 +165,11 @@ bridgeattach(unused)
sc->sc_brtmax = BRIDGE_RTABLE_MAX;
sc->sc_brttimeout = BRIDGE_RTABLE_TIMEOUT;
+ sc->sc_bridge_max_age = BSTP_DEFAULT_MAX_AGE;
+ sc->sc_bridge_hello_time = BSTP_DEFAULT_HELLO_TIME;
+ sc->sc_bridge_forward_delay= BSTP_DEFAULT_FORWARD_DELAY;
+ sc->sc_bridge_priority = BSTP_DEFAULT_BRIDGE_PRIORITY;
+ sc->sc_hold_time = BSTP_DEFAULT_HOLD_TIME;
timeout_set(&sc->sc_brtimeout, bridge_timer, sc);
LIST_INIT(&sc->sc_iflist);
ifp = &sc->sc_if;
@@ -237,16 +202,15 @@ bridge_ioctl(ifp, cmd, data)
struct ifbreq *req = (struct ifbreq *)data;
struct ifbaconf *baconf = (struct ifbaconf *)data;
struct ifbareq *bareq = (struct ifbareq *)data;
- struct ifbcachereq *bcachereq = (struct ifbcachereq *)data;
+ struct ifbrparam *bparam = (struct ifbrparam *)data;
struct ifbifconf *bifconf = (struct ifbifconf *)data;
- struct ifbcachetoreq *bcacheto = (struct ifbcachetoreq *)data;
struct ifbrlreq *brlreq = (struct ifbrlreq *)data;
struct ifbrlconf *brlconf = (struct ifbrlconf *)data;
struct ifreq ifreq;
int error = 0, s;
struct bridge_iflist *p;
- s = splsoftnet();
+ s = splnet();
switch (cmd) {
case SIOCBRDGADD:
if ((error = suser(prc->p_ucred, &prc->p_acflag)) != 0)
@@ -325,9 +289,12 @@ bridge_ioctl(ifp, cmd, data)
error = ENOMEM;
break;
}
+ bzero(p, sizeof(struct bridge_iflist));
p->ifp = ifs;
p->bif_flags = IFBIF_LEARNING | IFBIF_DISCOVER;
+ p->bif_priority = BSTP_DEFAULT_PORT_PRIORITY;
+ p->bif_path_cost = BSTP_DEFAULT_PATH_COST;
SIMPLEQ_INIT(&p->bif_brlin);
SIMPLEQ_INIT(&p->bif_brlout);
LIST_INSERT_HEAD(&sc->sc_iflist, p, next);
@@ -378,6 +345,9 @@ bridge_ioctl(ifp, cmd, data)
break;
}
req->ifbr_ifsflags = p->bif_flags;
+ req->ifbr_state = p->bif_state;
+ req->ifbr_priority = p->bif_priority;
+ req->ifbr_portno = p->ifp->if_index & 0xff;
break;
case SIOCBRDGSIFFLGS:
if ((error = suser(prc->p_ucred, &prc->p_acflag)) != 0)
@@ -399,8 +369,35 @@ bridge_ioctl(ifp, cmd, data)
error = ESRCH;
break;
}
+ if ((req->ifbr_ifsflags & IFBIF_STP) &&
+ (ifs->if_type != IFT_ETHER)) {
+ error = EINVAL;
+ break;
+ }
p->bif_flags = req->ifbr_ifsflags;
break;
+ case SIOCBRDGSIFPRIO:
+ if ((error = suser(prc->p_ucred, &prc->p_acflag)) != 0)
+ break;
+ ifs = ifunit(req->ifbr_ifsname);
+ if (ifs == NULL) {
+ error = ENOENT;
+ break;
+ }
+ if ((caddr_t)sc != ifs->if_bridge) {
+ error = ESRCH;
+ break;
+ }
+ LIST_FOREACH(p, &sc->sc_iflist, next) {
+ if (p->ifp == ifs)
+ break;
+ }
+ if (p == LIST_END(&sc->sc_iflist)) {
+ error = ESRCH;
+ break;
+ }
+ p->bif_priority = req->ifbr_priority;
+ break;
case SIOCBRDGRTS:
error = bridge_rtfind(sc, baconf);
break;
@@ -437,24 +434,24 @@ bridge_ioctl(ifp, cmd, data)
error = bridge_rtdaddr(sc, &bareq->ifba_dst);
break;
case SIOCBRDGGCACHE:
- bcachereq->ifbc_size = sc->sc_brtmax;
+ bparam->ifbrp_csize = sc->sc_brtmax;
break;
case SIOCBRDGSCACHE:
if ((error = suser(prc->p_ucred, &prc->p_acflag)) != 0)
break;
- sc->sc_brtmax = bcachereq->ifbc_size;
+ sc->sc_brtmax = bparam->ifbrp_csize;
bridge_rttrim(sc);
break;
case SIOCBRDGSTO:
if ((error = suser(prc->p_ucred, &prc->p_acflag)) != 0)
break;
- sc->sc_brttimeout = bcacheto->ifbct_time;
+ sc->sc_brttimeout = bparam->ifbrp_ctime;
timeout_del(&sc->sc_brtimeout);
- if (bcacheto->ifbct_time != 0)
+ if (bparam->ifbrp_ctime != 0)
timeout_add(&sc->sc_brtimeout, sc->sc_brttimeout * hz);
break;
case SIOCBRDGGTO:
- bcacheto->ifbct_time = sc->sc_brttimeout;
+ bparam->ifbrp_ctime = sc->sc_brttimeout;
break;
case SIOCSIFFLAGS:
if ((ifp->if_flags & IFF_UP) == IFF_UP)
@@ -528,9 +525,24 @@ bridge_ioctl(ifp, cmd, data)
case SIOCBRDGGRL:
error = bridge_brlconf(sc, brlconf);
break;
+ case SIOCBRDGGPRI:
+ case SIOCBRDGGMA:
+ case SIOCBRDGGHT:
+ case SIOCBRDGGFD:
+ break;
+ case SIOCBRDGSPRI:
+ case SIOCBRDGSFD:
+ case SIOCBRDGSMA:
+ case SIOCBRDGSHT:
+ error = suser(prc->p_ucred, &prc->p_acflag);
+ break;
default:
error = EINVAL;
}
+
+ if (!error)
+ error = bstp_ioctl(ifp, cmd, data);
+
splx(s);
return (error);
}
@@ -583,6 +595,9 @@ bridge_bifconf(sc, bifc)
sizeof(breq.ifbr_ifsname)-1);
breq.ifbr_ifsname[sizeof(breq.ifbr_ifsname) - 1] = '\0';
breq.ifbr_ifsflags = p->bif_flags;
+ breq.ifbr_state = p->bif_state;
+ breq.ifbr_priority = p->bif_priority;
+ breq.ifbr_portno = p->ifp->if_index & 0xff;
error = copyout((caddr_t)&breq,
(caddr_t)(bifc->ifbic_req + i), sizeof(breq));
if (error)
@@ -849,6 +864,9 @@ bridge_start(ifp)
{
}
+/*
+ * Loop through each bridge interface and process their input queues.
+ */
void
bridgeintr(void)
{
@@ -870,7 +888,7 @@ bridgeintr(void)
}
/*
- * Loop through each bridge interface and process their input queues.
+ * Process a single frame. Frame must be freed or queued before returning.
*/
void
bridgeintr_frame(sc, m)
@@ -908,6 +926,14 @@ bridgeintr_frame(sc, m)
return;
}
+ if ((ifl->bif_flags & IFBIF_STP) &&
+ ((ifl->bif_state == BSTP_IFSTATE_BLOCKING) ||
+ (ifl->bif_state == BSTP_IFSTATE_LISTENING) ||
+ (ifl->bif_state == BSTP_IFSTATE_DISABLED))) {
+ m_freem(m);
+ return;
+ }
+
if (m->m_pkthdr.len < sizeof(eh)) {
m_freem(m);
return;
@@ -930,6 +956,17 @@ bridgeintr_frame(sc, m)
eh.ether_shost[5] == 0))
bridge_rtupdate(sc, src, src_if, 0, IFBAF_DYNAMIC);
+ if ((ifl->bif_flags & IFBIF_STP) &&
+ (ifl->bif_state == BSTP_IFSTATE_LEARNING)) {
+ m_freem(m);
+ return;
+ }
+
+ /*
+ * At this point, the port either doesn't participate in stp or
+ * it's in the forwarding state
+ */
+
/*
* If packet is unicast, destined for someone on "this"
* side of the bridge, drop it.
@@ -1017,6 +1054,12 @@ bridgeintr_frame(sc, m)
m_freem(m);
return;
}
+ if ((ifl->bif_flags & IFBIF_STP) &&
+ (ifl->bif_state == BSTP_IFSTATE_DISABLED ||
+ ifl->bif_state == BSTP_IFSTATE_BLOCKING)) {
+ m_free(m);
+ return;
+ }
if (bridge_filterrule(&ifl->bif_brlout, &eh) == BRL_ACTION_BLOCK) {
m_freem(m);
return;
@@ -1070,7 +1113,31 @@ bridge_input(ifp, eh, m)
if ((sc->sc_if.if_flags & IFF_RUNNING) == 0)
return (m);
+ LIST_FOREACH(ifl, &sc->sc_iflist, next) {
+ if (ifl->ifp == ifp)
+ break;
+ }
+ if (ifl == LIST_END(&sc->sc_iflist))
+ return (m);
+
if (m->m_flags & (M_BCAST | M_MCAST)) {
+ /* Tap off 802.1D packets, they do not get forwarded */
+ if (bcmp(eh->ether_dhost, bstp_etheraddr, ETHER_ADDR_LEN) == 0) {
+ m = bstp_input(sc, ifp, eh, m);
+ if (m == NULL)
+ return (NULL);
+ }
+
+ /*
+ * No need to queue frames for ifs in the blocking, disabled,
+ * or listening state
+ */
+ if ((ifl->bif_flags & IFBIF_STP) &&
+ ((ifl->bif_state == BSTP_IFSTATE_BLOCKING) ||
+ (ifl->bif_state == BSTP_IFSTATE_LISTENING) ||
+ (ifl->bif_state == BSTP_IFSTATE_DISABLED)))
+ return (m);
+
/*
* make a copy of 'm' with 'eh' tacked on to the
* beginning. Return 'm' for local processing
@@ -1096,6 +1163,17 @@ bridge_input(ifp, eh, m)
}
/*
+ * No need to queue frames for ifs in the blocking, disabled, or
+ * listening state
+ */
+ if ((ifl->bif_flags & IFBIF_STP) &&
+ ((ifl->bif_state == BSTP_IFSTATE_BLOCKING) ||
+ (ifl->bif_state == BSTP_IFSTATE_LISTENING) ||
+ (ifl->bif_state == BSTP_IFSTATE_DISABLED)))
+ return (m);
+
+
+ /*
* Unicast, make sure it's not for us.
*/
LIST_FOREACH(ifl, &sc->sc_iflist, next) {
@@ -1157,6 +1235,11 @@ bridge_broadcast(sc, ifp, eh, m)
if (dst_if->if_index == ifp->if_index)
continue;
+ if ((p->bif_flags & IFBIF_STP) &&
+ (p->bif_state == BSTP_IFSTATE_BLOCKING ||
+ p->bif_state == BSTP_IFSTATE_DISABLED))
+ continue;
+
if ((p->bif_flags & IFBIF_DISCOVER) == 0 &&
(m->m_flags & (M_BCAST | M_MCAST)) == 0)
continue;
diff --git a/sys/net/if_bridge.h b/sys/net/if_bridge.h
index 209c6113752..8ed3a5462ea 100644
--- a/sys/net/if_bridge.h
+++ b/sys/net/if_bridge.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_bridge.h,v 1.12 2000/01/25 22:06:27 jason Exp $ */
+/* $OpenBSD: if_bridge.h,v 1.13 2000/12/12 03:41:22 jason Exp $ */
/*
* Copyright (c) 1999, 2000 Jason L. Wright (jason@thought.net)
@@ -38,15 +38,26 @@ struct ifbreq {
char ifbr_name[IFNAMSIZ]; /* bridge ifs name */
char ifbr_ifsname[IFNAMSIZ]; /* member ifs name */
u_int32_t ifbr_ifsflags; /* member ifs flags */
+ u_int8_t ifbr_state; /* member stp state */
+ u_int8_t ifbr_priority; /* member stp priority */
+ u_int8_t ifbr_portno; /* member port number */
};
/* SIOCBRDGIFFLGS, SIOCBRDGIFFLGS */
-#define IFBIF_LEARNING 0x1 /* ifs can learn */
-#define IFBIF_DISCOVER 0x2 /* ifs sends packets w/unknown dest */
-#define IFBIF_BLOCKNONIP 0x04 /* ifs blocks non-IP/ARP traffic in/out */
+#define IFBIF_LEARNING 0x01 /* ifs can learn */
+#define IFBIF_DISCOVER 0x02 /* ifs sends packets w/unknown dest */
+#define IFBIF_BLOCKNONIP 0x04 /* ifs blocks non-IP/ARP in/out */
+#define IFBIF_STP 0x08 /* ifs participates in spanning tree */
/* SIOCBRDGFLUSH */
#define IFBF_FLUSHDYN 0x0 /* flush dynamic addresses only */
#define IFBF_FLUSHALL 0x1 /* flush all addresses from cache */
+/* port states */
+#define BSTP_IFSTATE_DISABLED 0
+#define BSTP_IFSTATE_LISTENING 1
+#define BSTP_IFSTATE_LEARNING 2
+#define BSTP_IFSTATE_FORWARDING 3
+#define BSTP_IFSTATE_BLOCKING 4
+
/*
* Interface list structure
*/
@@ -87,21 +98,23 @@ struct ifbaconf {
#define ifbac_req ifbac_ifbacu.ifbacu_req
};
-/*
- * Bridge cache size get/set
- */
-struct ifbcachereq {
- char ifbc_name[IFNAMSIZ]; /* bridge ifs name */
- u_int32_t ifbc_size; /* cache size */
-};
-
-/*
- * Bridge cache timeout get/set
- */
-struct ifbcachetoreq {
- char ifbct_name[IFNAMSIZ]; /* bridge ifs name */
- u_int32_t ifbct_time; /* cache time (sec) */
+struct ifbrparam {
+ char ifbrp_name[IFNAMSIZ];
+ union {
+ u_int32_t ifbrpu_csize; /* cache size */
+ u_int32_t ifbrpu_ctime; /* cache time (sec) */
+ u_int16_t ifbrpu_prio; /* bridge priority */
+ u_int8_t ifbrpu_hellotime; /* hello time (sec) */
+ u_int8_t ifbrpu_fwddelay; /* fwd delay (sec) */
+ u_int8_t ifbrpu_maxage; /* max age (sec) */
+ } ifbrp_ifbrpu;
};
+#define ifbrp_csize ifbrp_ifbrpu.ifbrpu_csize
+#define ifbrp_ctime ifbrp_ifbrpu.ifbrpu_ctime
+#define ifbrp_prio ifbrp_ifbrpu.ifbrpu_prio
+#define ifbrp_hellotime ifbrp_ifbrpu.ifbrpu_hellotime
+#define ifbrp_fwddelay ifbrp_ifbrpu.ifbrpu_fwddelay
+#define ifbrp_maxage ifbrp_ifbrpu.ifbrpu_maxage
/*
* Bridge mac rules
@@ -134,9 +147,122 @@ struct ifbrlconf {
};
#ifdef _KERNEL
+/*
+ * Bridge filtering rules
+ */
+SIMPLEQ_HEAD(brl_head, brl_node);
+
+struct brl_node {
+ SIMPLEQ_ENTRY(brl_node) brl_next; /* next rule */
+ struct ether_addr brl_src; /* source mac address */
+ struct ether_addr brl_dst; /* destination mac address */
+ u_int8_t brl_action; /* what to do with match */
+ u_int8_t brl_flags; /* comparision flags */
+};
+
+struct bridge_timer {
+ u_int16_t active;
+ u_int16_t value;
+};
+
+struct bstp_config_unit {
+ u_int64_t cu_rootid;
+ u_int64_t cu_bridge_id;
+ u_int32_t cu_root_path_cost;
+ u_int16_t cu_message_age;
+ u_int16_t cu_max_age;
+ u_int16_t cu_hello_time;
+ u_int16_t cu_forward_delay;
+ u_int16_t cu_port_id;
+ u_int8_t cu_message_type;
+ u_int8_t cu_topology_change_acknowledgment;
+ u_int8_t cu_topology_change;
+};
+
+struct bstp_tcn_unit {
+ u_int8_t tu_message_type;
+};
+
+/*
+ * Bridge interface list
+ */
+struct bridge_iflist {
+ LIST_ENTRY(bridge_iflist) next; /* next in list */
+ u_int64_t bif_designated_root;
+ u_int64_t bif_designated_bridge;
+ u_int32_t bif_path_cost;
+ u_int32_t bif_designated_cost;
+ struct bridge_timer bif_hold_timer;
+ struct bridge_timer bif_message_age_timer;
+ struct bridge_timer bif_forward_delay_timer;
+ struct bstp_config_unit bif_config_bpdu;
+ struct bstp_tcn_unit bif_tcn_bpdu;
+ u_int16_t bif_port_id;
+ u_int16_t bif_designated_port;
+ u_int8_t bif_state;
+ u_int8_t bif_topology_change_acknowledge;
+ u_int8_t bif_config_pending;
+ u_int8_t bif_change_detection_enabled;
+ u_int8_t bif_priority;
+ struct brl_head bif_brlin; /* input rules */
+ struct brl_head bif_brlout; /* output rules */
+ struct ifnet *ifp; /* member interface */
+ u_int32_t bif_flags; /* member flags */
+};
+
+/*
+ * Bridge route node
+ */
+struct bridge_rtnode {
+ LIST_ENTRY(bridge_rtnode) brt_next; /* next in list */
+ struct ifnet *brt_if; /* destination ifs */
+ u_int8_t brt_flags; /* address flags */
+ u_int8_t brt_age; /* age counter */
+ struct ether_addr brt_addr; /* dst addr */
+};
+
+/*
+ * Software state for each bridge
+ */
+struct bridge_softc {
+ struct ifnet sc_if; /* the interface */
+ u_int64_t sc_designated_root;
+ u_int64_t sc_bridge_id;
+ struct bridge_iflist *sc_root_port;
+ u_int32_t sc_root_path_cost;
+ u_int16_t sc_max_age;
+ u_int16_t sc_hello_time;
+ u_int16_t sc_forward_delay;
+ u_int16_t sc_bridge_max_age;
+ u_int16_t sc_bridge_hello_time;
+ u_int16_t sc_bridge_forward_delay;
+ u_int16_t sc_topology_change_time;
+ u_int16_t sc_hold_time;
+ u_int16_t sc_bridge_priority;
+ u_int8_t sc_topology_change_detected;
+ u_int8_t sc_topology_change;
+ struct bridge_timer sc_hello_timer;
+ struct bridge_timer sc_topology_change_timer;
+ struct bridge_timer sc_tcn_timer;
+ u_int32_t sc_brtmax; /* max # addresses */
+ u_int32_t sc_brtcnt; /* current # addrs */
+ u_int32_t sc_brttimeout; /* timeout ticks */
+ u_int32_t sc_hashkey; /* hash key */
+ struct timeout sc_brtimeout; /* timeout state */
+ struct timeout sc_bstptimeout; /* stp timeout */
+ LIST_HEAD(, bridge_iflist) sc_iflist; /* interface list */
+ LIST_HEAD(bridge_rthead, bridge_rtnode) *sc_rts;/* hash table */
+};
+
+extern u_int8_t bstp_etheraddr[];
+
void bridge_ifdetach __P((struct ifnet *));
struct mbuf *bridge_input __P((struct ifnet *, struct ether_header *,
struct mbuf *));
int bridge_output __P((struct ifnet *, struct mbuf *, struct sockaddr *,
struct rtentry *rt));
+struct mbuf *bstp_input __P((struct bridge_softc *, struct ifnet *,
+ struct ether_header *, struct mbuf *));
+void bstp_initialization __P((struct bridge_softc *));
+int bstp_ioctl __P((struct ifnet *, u_long, caddr_t));
#endif /* _KERNEL */
diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c
index 8e6de698d74..39cf70baeb0 100644
--- a/sys/net/if_ethersubr.c
+++ b/sys/net/if_ethersubr.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_ethersubr.c,v 1.39 2000/10/18 16:16:33 jason Exp $ */
+/* $OpenBSD: if_ethersubr.c,v 1.40 2000/12/12 03:41:22 jason Exp $ */
/* $NetBSD: if_ethersubr.c,v 1.19 1996/05/07 02:40:30 thorpej Exp $ */
/*
@@ -87,6 +87,7 @@ didn't get a copy, you may request one from <license@ipv6.nrl.navy.mil>.
#include <sys/ioctl.h>
#include <sys/errno.h>
#include <sys/syslog.h>
+#include <sys/timeout.h>
#include <machine/cpu.h>
diff --git a/sys/sys/sockio.h b/sys/sys/sockio.h
index a5b269608a2..165665a3cae 100644
--- a/sys/sys/sockio.h
+++ b/sys/sys/sockio.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: sockio.h,v 1.16 2000/04/26 18:37:37 chris Exp $ */
+/* $OpenBSD: sockio.h,v 1.17 2000/12/12 03:41:23 jason Exp $ */
/* $NetBSD: sockio.h,v 1.5 1995/08/23 00:40:47 thorpej Exp $ */
/*-
@@ -96,34 +96,44 @@
#define SIOCGIFPSRCADDR _IOWR('i', 71, struct ifreq) /* get gif psrc addr */
#define SIOCGIFPDSTADDR _IOWR('i', 72, struct ifreq) /* get gif pdst addr */
-#define SIOCBRDGADD _IOWR('i', 60, struct ifbreq) /* add bridge ifs */
-#define SIOCBRDGDEL _IOWR('i', 61, struct ifbreq) /* del bridge ifs */
+#define SIOCBRDGADD _IOW('i', 60, struct ifbreq) /* add bridge ifs */
+#define SIOCBRDGDEL _IOW('i', 61, struct ifbreq) /* del bridge ifs */
#define SIOCBRDGGIFFLGS _IOWR('i', 62, struct ifbreq) /* get brdg if flags */
-#define SIOCBRDGSIFFLGS _IOWR('i', 63, struct ifbreq) /* set brdg if flags */
-#define SIOCBRDGSCACHE _IOWR('i', 64, struct ifbcachereq) /* set cache size */
-#define SIOCBRDGGCACHE _IOWR('i', 65, struct ifbcachereq) /* get cache size */
+#define SIOCBRDGSIFFLGS _IOW('i', 63, struct ifbreq) /* set brdg if flags */
+#define SIOCBRDGSCACHE _IOW('i', 64, struct ifbrparam)/* set cache size */
+#define SIOCBRDGGCACHE _IOWR('i', 65, struct ifbrparam)/* get cache size */
#define SIOCBRDGIFS _IOWR('i', 66, struct ifbreq) /* get member ifs */
#define SIOCBRDGRTS _IOWR('i', 67, struct ifbaconf) /* get addresses */
#define SIOCBRDGSADDR _IOWR('i', 68, struct ifbareq) /* set addr flags */
-#define SIOCBRDGSTO _IOWR('i', 69, struct ifbcachetoreq) /* cache timeout */
-#define SIOCBRDGGTO _IOWR('i', 70, struct ifbcachetoreq) /* cache timeout */
-#define SIOCBRDGDADDR _IOWR('i', 71, struct ifbareq) /* delete addr */
-#define SIOCBRDGFLUSH _IOWR('i', 72, struct ifbreq) /* flush addr cache */
+#define SIOCBRDGSTO _IOW('i', 69, struct ifbrparam)/* cache timeout */
+#define SIOCBRDGGTO _IOWR('i', 70, struct ifbrparam)/* cache timeout */
+#define SIOCBRDGDADDR _IOW('i', 71, struct ifbareq) /* delete addr */
+#define SIOCBRDGFLUSH _IOW('i', 72, struct ifbreq) /* flush addr cache */
#define SIOCGENCSA _IOWR('i', 73, struct ifsa) /* get enc sa */
-#define SIOCSENCDSTSA _IOW('i', 74, struct ifsa) /* set enc sa */
-#define SIOCSENCSRCSA _IOW('i', 75, struct ifsa) /* set enc sa */
-#define SIOCSENCCLEARSA _IOW('i', 76, struct ifsa) /* set enc sa */
+#define SIOCSENCDSTSA _IOW('i', 74, struct ifsa) /* set enc sa */
+#define SIOCSENCSRCSA _IOW('i', 75, struct ifsa) /* set enc sa */
+#define SIOCSENCCLEARSA _IOW('i', 76, struct ifsa) /* set enc sa */
-#define SIOCBRDGARL _IOWR('i', 77, struct ifbrlreq) /* add bridge rule */
-#define SIOCBRDGFRL _IOWR('i', 78, struct ifbrlreq) /* flush brdg rules */
+#define SIOCBRDGARL _IOW('i', 77, struct ifbrlreq) /* add bridge rule */
+#define SIOCBRDGFRL _IOW('i', 78, struct ifbrlreq) /* flush brdg rules */
#define SIOCBRDGGRL _IOWR('i', 79, struct ifbrlconf)/* get bridge rules */
-
-#define GRESADDRS _IOW('i', 101, struct ifreq)
-#define GRESADDRD _IOW('i', 102, struct ifreq)
+#define SIOCBRDGGPRI _IOWR('i', 80, struct ifbrparam)/* get priority */
+#define SIOCBRDGSPRI _IOW('i', 80, struct ifbrparam)/* set priority */
+#define SIOCBRDGGHT _IOWR('i', 81, struct ifbrparam)/* get hello time */
+#define SIOCBRDGSHT _IOW('i', 81, struct ifbrparam)/* set hello time */
+#define SIOCBRDGGFD _IOWR('i', 82, struct ifbrparam)/* get forward delay */
+#define SIOCBRDGSFD _IOW('i', 82, struct ifbrparam)/* set forward delay */
+#define SIOCBRDGGMA _IOWR('i', 83, struct ifbrparam)/* get max age */
+#define SIOCBRDGSMA _IOW('i', 83, struct ifbrparam)/* set max age */
+#define SIOCBRDGSIFPRIO _IOW('i', 84, struct ifbreq) /* set if priority */
+
+#define SIOCBRDGS
+#define GRESADDRS _IOW('i', 101, struct ifreq)
+#define GRESADDRD _IOW('i', 102, struct ifreq)
#define GREGADDRS _IOWR('i', 103, struct ifreq)
#define GREGADDRD _IOWR('i', 104, struct ifreq)
-#define GRESPROTO _IOW('i' , 105, struct ifreq)
+#define GRESPROTO _IOW('i', 105, struct ifreq)
#define GREGPROTO _IOWR('i', 106, struct ifreq)
#define SIOCSIFMTU _IOW('i', 127, struct ifreq) /* set ifnet mtu */