summaryrefslogtreecommitdiff
path: root/sys/net/if_bridge.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/net/if_bridge.c')
-rw-r--r--sys/net/if_bridge.c568
1 files changed, 429 insertions, 139 deletions
diff --git a/sys/net/if_bridge.c b/sys/net/if_bridge.c
index 961f7c2f448..51b76ba0ddc 100644
--- a/sys/net/if_bridge.c
+++ b/sys/net/if_bridge.c
@@ -1,7 +1,7 @@
-/* $OpenBSD: if_bridge.c,v 1.24 2000/01/15 20:02:36 angelos Exp $ */
+/* $OpenBSD: if_bridge.c,v 1.25 2000/01/25 22:06:27 jason Exp $ */
/*
- * Copyright (c) 1999 Jason L. Wright (jason@thought.net)
+ * Copyright (c) 1999, 2000 Jason L. Wright (jason@thought.net)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -104,10 +104,23 @@
extern int ifqmaxlen;
/*
+ * Bridge filtering rules
+ */
+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 */
+ SIMPLEQ_HEAD(, brl_node) bif_brlin; /* input rules */
+ SIMPLEQ_HEAD(, brl_node) bif_brlout; /* output rules */
struct ifnet *ifp; /* member interface */
u_int32_t bif_flags; /* member flags */
};
@@ -148,6 +161,7 @@ struct bridge_softc bridgectl[NBRIDGE];
void bridgeattach __P((int));
int bridge_ioctl __P((struct ifnet *, u_long, caddr_t));
void bridge_start __P((struct ifnet *));
+void bridgeintr_frame __P((struct bridge_softc *, struct mbuf *));
void bridge_broadcast __P((struct bridge_softc *, struct ifnet *,
struct ether_header *, struct mbuf *));
void bridge_stop __P((struct bridge_softc *));
@@ -166,6 +180,11 @@ struct ifnet * bridge_rtlookup __P((struct bridge_softc *,
struct ether_addr *));
u_int32_t bridge_hash __P((struct ether_addr *));
struct mbuf *bridge_blocknonip __P((struct mbuf *));
+int bridge_addrule __P((struct bridge_iflist *,
+ struct ifbrlreq *, int out));
+int bridge_flushrule __P((struct bridge_iflist *));
+int bridge_brlconf __P((struct bridge_softc *, struct ifbrlconf *));
+u_int8_t bridge_filterrule __P((struct brl_node *, struct ether_header *));
#define ETHERADDR_IS_IP_MCAST(a) \
/* struct etheraddr *a; */ \
@@ -173,6 +192,7 @@ struct mbuf *bridge_blocknonip __P((struct mbuf *));
(a)->ether_addr_octet[1] == 0x00 && \
(a)->ether_addr_octet[2] == 0x5e)
+
#if defined(INET) && (defined(IPFILTER) || defined(IPFILTER_LKM))
/*
* Filter hooks
@@ -227,6 +247,8 @@ bridge_ioctl(ifp, cmd, data)
struct ifbcachereq *bcachereq = (struct ifbcachereq *)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;
@@ -310,6 +332,8 @@ bridge_ioctl(ifp, cmd, data)
p->ifp = ifs;
p->bif_flags = IFBIF_LEARNING | IFBIF_DISCOVER;
+ SIMPLEQ_INIT(&p->bif_brlin);
+ SIMPLEQ_INIT(&p->bif_brlout);
LIST_INSERT_HEAD(&sc->sc_iflist, p, next);
ifs->if_bridge = (caddr_t)sc;
break;
@@ -327,6 +351,7 @@ bridge_ioctl(ifp, cmd, data)
LIST_REMOVE(p, next);
bridge_rtdelete(sc, p->ifp);
+ bridge_flushrule(p);
free(p, M_DEVBUF);
break;
}
@@ -445,6 +470,70 @@ bridge_ioctl(ifp, cmd, data)
bridge_stop(sc);
break;
+ case SIOCBRDGARL:
+ if ((error = suser(prc->p_ucred, &prc->p_acflag)) != 0)
+ break;
+ ifs = ifunit(brlreq->ifbr_ifsname);
+ if (ifs == NULL) {
+ error = ENOENT;
+ break;
+ }
+ if (ifs->if_bridge == NULL ||
+ ifs->if_bridge != (caddr_t)sc) {
+ error = ESRCH;
+ break;
+ }
+ p = LIST_FIRST(&sc->sc_iflist);
+ while (p != NULL && p->ifp != ifs) {
+ p = LIST_NEXT(p, next);
+ }
+ if (p == NULL) {
+ error = ESRCH;
+ break;
+ }
+ if ((brlreq->ifbr_action != BRL_ACTION_BLOCK &&
+ brlreq->ifbr_action != BRL_ACTION_PASS) ||
+ (brlreq->ifbr_flags & (BRL_FLAG_IN|BRL_FLAG_OUT)) == 0) {
+ error = EINVAL;
+ break;
+ }
+ if (brlreq->ifbr_flags & BRL_FLAG_IN) {
+ error = bridge_addrule(p, brlreq, 0);
+ if (error)
+ break;
+ }
+ if (brlreq->ifbr_flags & BRL_FLAG_OUT) {
+ error = bridge_addrule(p, brlreq, 1);
+ if (error)
+ break;
+ }
+ break;
+ case SIOCBRDGFRL:
+ if ((error = suser(prc->p_ucred, &prc->p_acflag)) != 0)
+ break;
+ ifs = ifunit(brlreq->ifbr_ifsname);
+ if (ifs == NULL) {
+ error = ENOENT;
+ break;
+ }
+ if (ifs->if_bridge == NULL ||
+ ifs->if_bridge != (caddr_t)sc) {
+ error = ESRCH;
+ break;
+ }
+ p = LIST_FIRST(&sc->sc_iflist);
+ while (p != NULL && p->ifp != ifs) {
+ p = LIST_NEXT(p, next);
+ }
+ if (p == NULL) {
+ error = ESRCH;
+ break;
+ }
+ error = bridge_flushrule(p);
+ break;
+ case SIOCBRDGGRL:
+ error = bridge_brlconf(sc, brlconf);
+ break;
default:
error = EINVAL;
}
@@ -465,6 +554,7 @@ bridge_ifdetach(ifp)
if (bif->ifp == ifp) {
LIST_REMOVE(bif, next);
bridge_rtdelete(bsc, ifp);
+ bridge_flushrule(bif);
free(bif, M_DEVBUF);
break;
}
@@ -514,6 +604,93 @@ done:
return (error);
}
+int
+bridge_brlconf(sc, bc)
+ struct bridge_softc *sc;
+ struct ifbrlconf *bc;
+{
+ struct ifnet *ifp;
+ struct bridge_iflist *ifl;
+ struct brl_node *n;
+ struct ifbrlreq req;
+ int error = 0;
+ u_int32_t i, total;
+
+ ifp = ifunit(bc->ifbrl_ifsname);
+ if (ifp == NULL)
+ return (ENOENT);
+ if (ifp->if_bridge == NULL || ifp->if_bridge != (caddr_t)sc)
+ return (ESRCH);
+ ifl = LIST_FIRST(&sc->sc_iflist);
+ while (ifl != NULL && ifl->ifp != ifp)
+ ifl = LIST_NEXT(ifl, next);
+ if (ifl == NULL)
+ return (ESRCH);
+
+ n = SIMPLEQ_FIRST(&ifl->bif_brlin);
+ while (n != NULL) {
+ total++;
+ n = SIMPLEQ_NEXT(n, brl_next);
+ }
+ n = SIMPLEQ_FIRST(&ifl->bif_brlout);
+ while (n != NULL) {
+ total++;
+ n = SIMPLEQ_NEXT(n, brl_next);
+ }
+
+ if (bc->ifbrl_len == 0) {
+ i = total;
+ goto done;
+ }
+
+ i = 0;
+ n = SIMPLEQ_FIRST(&ifl->bif_brlin);
+ while (n != NULL && bc->ifbrl_len > i * sizeof(req)) {
+ strncpy(req.ifbr_name, sc->sc_if.if_xname,
+ sizeof(req.ifbr_name) - 1);
+ req.ifbr_name[sizeof(req.ifbr_name) - 1] = '\0';
+ strncpy(req.ifbr_ifsname, ifl->ifp->if_xname,
+ sizeof(req.ifbr_ifsname) - 1);
+ req.ifbr_ifsname[sizeof(req.ifbr_ifsname) - 1] = '\0';
+ req.ifbr_action = n->brl_action;
+ req.ifbr_flags = n->brl_flags;
+ req.ifbr_src = n->brl_src;
+ req.ifbr_dst = n->brl_dst;
+ error = copyout((caddr_t)&req,
+ (caddr_t)(bc->ifbrl_buf + (i * sizeof(req))), sizeof(req));
+ if (error)
+ goto done;
+ n = SIMPLEQ_NEXT(n, brl_next);
+ i++;
+ bc->ifbrl_len -= sizeof(req);
+ }
+
+ n = SIMPLEQ_FIRST(&ifl->bif_brlout);
+ while (n != NULL && bc->ifbrl_len > i * sizeof(req)) {
+ strncpy(req.ifbr_name, sc->sc_if.if_xname,
+ sizeof(req.ifbr_name) - 1);
+ req.ifbr_name[sizeof(req.ifbr_name) - 1] = '\0';
+ strncpy(req.ifbr_ifsname, ifl->ifp->if_xname,
+ sizeof(req.ifbr_ifsname) - 1);
+ req.ifbr_ifsname[sizeof(req.ifbr_ifsname) - 1] = '\0';
+ req.ifbr_action = n->brl_action;
+ req.ifbr_flags = n->brl_flags;
+ req.ifbr_src = n->brl_src;
+ req.ifbr_dst = n->brl_dst;
+ error = copyout((caddr_t)&req,
+ (caddr_t)(bc->ifbrl_buf + (i * sizeof(req))), sizeof(req));
+ if (error)
+ goto done;
+ n = SIMPLEQ_NEXT(n, brl_next);
+ i++;
+ bc->ifbrl_len -= sizeof(req);
+ }
+
+done:
+ bc->ifbrl_len = i * sizeof(req);
+ return (error);
+}
+
void
bridge_init(sc)
struct bridge_softc *sc;
@@ -670,171 +847,195 @@ bridge_start(ifp)
{
}
-/*
- * Loop through each bridge interface and process their input queues.
- */
void
bridgeintr(void)
{
- int i, s;
struct bridge_softc *sc;
- struct ifnet *bifp, *src_if, *dst_if;
- struct bridge_iflist *ifl;
- struct ether_addr *dst, *src;
- struct ether_header *eh;
struct mbuf *m;
+ int i, s;
for (i = 0; i < NBRIDGE; i++) {
sc = &bridgectl[i];
- bifp = &sc->sc_if;
for (;;) {
s = splimp();
- IF_DEQUEUE(&bifp->if_snd, m);
+ IF_DEQUEUE(&sc->sc_if.if_snd, m);
splx(s);
if (m == NULL)
break;
+ bridgeintr_frame(sc, m);
+ }
+ }
+}
- src_if = m->m_pkthdr.rcvif;
- if ((sc->sc_if.if_flags & IFF_RUNNING) == 0) {
- m_freem(m);
- continue;
- }
+/*
+ * Loop through each bridge interface and process their input queues.
+ */
+void
+bridgeintr_frame(sc, m)
+ struct bridge_softc *sc;
+ struct mbuf *m;
+{
+ int s;
+ struct ifnet *src_if, *dst_if;
+ struct bridge_iflist *ifl;
+ struct ether_addr *dst, *src;
+ struct ether_header *eh;
+
+ if ((sc->sc_if.if_flags & IFF_RUNNING) == 0) {
+ m_freem(m);
+ return;
+ }
+
+ src_if = m->m_pkthdr.rcvif;
#if NBPFILTER > 0
- if (sc->sc_if.if_bpf)
- bpf_mtap(sc->sc_if.if_bpf, m);
+ if (sc->sc_if.if_bpf)
+ bpf_mtap(sc->sc_if.if_bpf, m);
#endif
- sc->sc_if.if_lastchange = time;
- sc->sc_if.if_ipackets++;
- sc->sc_if.if_ibytes += m->m_pkthdr.len;
+ sc->sc_if.if_lastchange = time;
+ sc->sc_if.if_ipackets++;
+ sc->sc_if.if_ibytes += m->m_pkthdr.len;
- ifl = LIST_FIRST(&sc->sc_iflist);
- while (ifl != NULL && ifl->ifp != src_if) {
- ifl = LIST_NEXT(ifl, next);
- }
- if (ifl == NULL) {
- m_freem(m);
- continue;
- }
+ ifl = LIST_FIRST(&sc->sc_iflist);
+ while (ifl != NULL && ifl->ifp != src_if) {
+ ifl = LIST_NEXT(ifl, next);
+ }
+ if (ifl == NULL) {
+ m_freem(m);
+ return;
+ }
- if (m->m_len < sizeof(*eh)) {
- m = m_pullup(m, sizeof(*eh));
- if (m == NULL)
- continue;
- }
- eh = mtod(m, struct ether_header *);
- dst = (struct ether_addr *)&eh->ether_dhost[0];
- src = (struct ether_addr *)&eh->ether_shost[0];
-
- /*
- * If interface is learning, and if source address
- * is not broadcast or multicast, record it's address.
- */
- if ((ifl->bif_flags & IFBIF_LEARNING) &&
- (eh->ether_shost[0] & 1) == 0 &&
- !(eh->ether_shost[0] == 0 &&
- eh->ether_shost[1] == 0 &&
- eh->ether_shost[2] == 0 &&
- eh->ether_shost[3] == 0 &&
- eh->ether_shost[4] == 0 &&
- eh->ether_shost[5] == 0))
- bridge_rtupdate(sc, src, src_if, 0, IFBAF_DYNAMIC);
-
- /*
- * If packet is unicast, destined for someone on "this"
- * side of the bridge, drop it.
- */
- dst_if = bridge_rtlookup(sc, dst);
- if ((m->m_flags & (M_BCAST | M_MCAST)) == 0 &&
- dst_if == src_if) {
- m_freem(m);
- continue;
- }
+ if (m->m_len < sizeof(*eh)) {
+ m = m_pullup(m, sizeof(*eh));
+ if (m == NULL)
+ return;
+ }
+ eh = mtod(m, struct ether_header *);
+ dst = (struct ether_addr *)&eh->ether_dhost[0];
+ src = (struct ether_addr *)&eh->ether_shost[0];
- /*
- * Multicast packets get handled a little differently:
- * If interface is:
- * -link0,-link1 (default) Forward all multicast
- * as broadcast.
- * -link0,link1 Drop non-IP multicast, forward
- * as broadcast IP multicast.
- * link0,-link1 Drop IP multicast, forward as
- * broadcast non-IP multicast.
- * link0,link1 Drop all multicast.
- */
- if (m->m_flags & M_MCAST) {
- if ((sc->sc_if.if_flags &
- (IFF_LINK0 | IFF_LINK1)) ==
- (IFF_LINK0 | IFF_LINK1)) {
- m_freem(m);
- continue;
- }
- if (sc->sc_if.if_flags & IFF_LINK0 &&
- ETHERADDR_IS_IP_MCAST(dst)) {
- m_freem(m);
- continue;
- }
- if (sc->sc_if.if_flags & IFF_LINK1 &&
- !ETHERADDR_IS_IP_MCAST(dst)) {
- m_freem(m);
- continue;
- }
- }
+ /*
+ * If interface is learning, and if source address
+ * is not broadcast or multicast, record it's address.
+ */
+ if ((ifl->bif_flags & IFBIF_LEARNING) &&
+ (eh->ether_shost[0] & 1) == 0 &&
+ !(eh->ether_shost[0] == 0 &&
+ eh->ether_shost[1] == 0 &&
+ eh->ether_shost[2] == 0 &&
+ eh->ether_shost[3] == 0 &&
+ eh->ether_shost[4] == 0 &&
+ eh->ether_shost[5] == 0))
+ bridge_rtupdate(sc, src, src_if, 0, IFBAF_DYNAMIC);
- if (ifl->bif_flags & IFBIF_BLOCKNONIP) {
- m = bridge_blocknonip(m);
- if (m == NULL)
- continue;
- eh = mtod(m, struct ether_header *);
- dst = (struct ether_addr *)&eh->ether_dhost[0];
- src = (struct ether_addr *)&eh->ether_shost[0];
- }
+ /*
+ * If packet is unicast, destined for someone on "this"
+ * side of the bridge, drop it.
+ */
+ if (m->m_flags & (M_BCAST | M_MCAST)) {
+ dst_if = bridge_rtlookup(sc, dst);
+ if (dst_if == src_if) {
+ m_freem(m);
+ return;
+ }
+ } else
+ dst_if = NULL;
+
+ /*
+ * Multicast packets get handled a little differently:
+ * If interface is:
+ * -link0,-link1 (default) Forward all multicast
+ * as broadcast.
+ * -link0,link1 Drop non-IP multicast, forward
+ * as broadcast IP multicast.
+ * link0,-link1 Drop IP multicast, forward as
+ * broadcast non-IP multicast.
+ * link0,link1 Drop all multicast.
+ */
+ if (m->m_flags & M_MCAST) {
+ if ((sc->sc_if.if_flags &
+ (IFF_LINK0 | IFF_LINK1)) ==
+ (IFF_LINK0 | IFF_LINK1)) {
+ m_freem(m);
+ return;
+ }
+ if (sc->sc_if.if_flags & IFF_LINK0 &&
+ ETHERADDR_IS_IP_MCAST(dst)) {
+ m_freem(m);
+ return;
+ }
+ if (sc->sc_if.if_flags & IFF_LINK1 &&
+ !ETHERADDR_IS_IP_MCAST(dst)) {
+ m_freem(m);
+ return;
+ }
+ }
+
+ if (ifl->bif_flags & IFBIF_BLOCKNONIP) {
+ m = bridge_blocknonip(m);
+ if (m == NULL)
+ return;
+ eh = mtod(m, struct ether_header *);
+ dst = (struct ether_addr *)&eh->ether_dhost[0];
+ src = (struct ether_addr *)&eh->ether_shost[0];
+ }
+
+ if (SIMPLEQ_FIRST(&ifl->bif_brlin) &&
+ bridge_filterrule(SIMPLEQ_FIRST(&ifl->bif_brlin), eh) ==
+ BRL_ACTION_BLOCK) {
+ m_freem(m);
+ return;
+ }
#if defined(INET) && (defined(IPFILTER) || defined(IPFILTER_LKM))
- if (bridge_filter(sc, src_if, eh, &m) ==
- BRIDGE_FILTER_DROP) {
- if (m != NULL)
- m_freem(m);
- continue;
- }
+ if (bridge_filter(sc, src_if, eh, &m) == BRIDGE_FILTER_DROP) {
+ if (m != NULL)
+ m_freem(m);
+ return;
+ }
#endif
- /*
- * If the packet is a multicast or broadcast, then
- * forward it to all interfaces.
- */
- if (m->m_flags & (M_BCAST | M_MCAST)) {
- bifp->if_imcasts++;
- bridge_broadcast(sc, src_if, eh, m);
- continue;
- }
-
- if (dst_if != NULL) {
- if ((dst_if->if_flags & IFF_RUNNING) == 0) {
- m_freem(m);
- continue;
- }
- s = splimp();
- if (IF_QFULL(&dst_if->if_snd)) {
- sc->sc_if.if_oerrors++;
- m_freem(m);
- splx(s);
- continue;
- }
- sc->sc_if.if_opackets++;
- sc->sc_if.if_obytes += m->m_pkthdr.len;
- IF_ENQUEUE(&dst_if->if_snd, m);
- if ((dst_if->if_flags & IFF_OACTIVE) == 0)
- (*dst_if->if_start)(dst_if);
- splx(s);
- continue;
- }
+ /*
+ * If the packet is a multicast or broadcast OR if we don't
+ * know any better, forward it to all interfaces.
+ */
+ if ((m->m_flags & (M_BCAST | M_MCAST)) || dst_if == NULL) {
+ sc->sc_if.if_imcasts++;
+ bridge_broadcast(sc, src_if, eh, m);
+ return;
+ }
- bridge_broadcast(sc, src_if, eh, m);
- dst_if = NULL;
- }
+ /*
+ * At this point, we're dealing with a unicast frame going to a
+ * different interface
+ */
+ if ((dst_if->if_flags & IFF_RUNNING) == 0) {
+ m_freem(m);
+ return;
+ }
+ ifl = LIST_FIRST(&sc->sc_iflist);
+ while (ifl != NULL && ifl->ifp != dst_if)
+ ifl = LIST_NEXT(ifl, next);
+ if (SIMPLEQ_FIRST(&ifl->bif_brlout) &&
+ bridge_filterrule(SIMPLEQ_FIRST(&ifl->bif_brlout), eh) ==
+ BRL_ACTION_BLOCK) {
+ m_freem(m);
+ return;
}
+ s = splimp();
+ if (IF_QFULL(&dst_if->if_snd)) {
+ sc->sc_if.if_oerrors++;
+ m_freem(m);
+ splx(s);
+ return;
+ }
+ sc->sc_if.if_opackets++;
+ sc->sc_if.if_obytes += m->m_pkthdr.len;
+ IF_ENQUEUE(&dst_if->if_snd, m);
+ if ((dst_if->if_flags & IFF_OACTIVE) == 0)
+ (*dst_if->if_start)(dst_if);
+ splx(s);
}
/*
@@ -965,6 +1166,12 @@ bridge_broadcast(sc, ifp, eh, m)
continue;
}
+ if (SIMPLEQ_FIRST(&p->bif_brlout) &&
+ bridge_filterrule(SIMPLEQ_FIRST(&p->bif_brlout), eh) ==
+ BRL_ACTION_BLOCK) {
+ continue;
+ }
+
/* If last one, reuse the passed-in mbuf */
if (LIST_NEXT(p, next) == NULL) {
mc = m;
@@ -1491,6 +1698,89 @@ notip:
return (NULL);
}
+u_int8_t
+bridge_filterrule(n, eh)
+ struct brl_node *n;
+ struct ether_header *eh;
+{
+ u_int8_t flags;
+
+ for (; n != NULL; n = SIMPLEQ_NEXT(n, brl_next)) {
+ flags = n->brl_flags & (BRL_FLAG_SRCVALID|BRL_FLAG_DSTVALID);
+ if (flags == 0)
+ return (n->brl_action);
+ if (flags == (BRL_FLAG_SRCVALID|BRL_FLAG_DSTVALID)) {
+ if (bcmp(eh->ether_shost, &n->brl_src, ETHER_ADDR_LEN))
+ continue;
+ if (bcmp(eh->ether_dhost, &n->brl_src, ETHER_ADDR_LEN))
+ continue;
+ return (n->brl_action);
+ }
+ if (flags == BRL_FLAG_SRCVALID) {
+ if (bcmp(eh->ether_shost, &n->brl_src, ETHER_ADDR_LEN))
+ continue;
+ return (n->brl_action);
+ }
+ if (flags == BRL_FLAG_DSTVALID) {
+ if (bcmp(eh->ether_dhost, &n->brl_dst, ETHER_ADDR_LEN))
+ continue;
+ return (n->brl_action);
+ }
+ }
+ return (BRL_ACTION_PASS);
+}
+
+int
+bridge_addrule(bif, req, out)
+ struct bridge_iflist *bif;
+ struct ifbrlreq *req;
+ int out;
+{
+ struct brl_node *n;
+
+ n = (struct brl_node *)malloc(sizeof(struct brl_node), M_DEVBUF, M_NOWAIT);
+ if (n == NULL)
+ return (ENOMEM);
+ bcopy(&req->ifbr_src, &n->brl_src, sizeof(struct ether_addr));
+ bcopy(&req->ifbr_dst, &n->brl_dst, sizeof(struct ether_addr));
+ n->brl_action = req->ifbr_action;
+ n->brl_flags = req->ifbr_flags;
+ if (out) {
+ n->brl_flags &= ~BRL_FLAG_IN;
+ n->brl_flags |= BRL_FLAG_OUT;
+ SIMPLEQ_INSERT_TAIL(&bif->bif_brlout, n, brl_next);
+ }
+ else {
+ n->brl_flags &= ~BRL_FLAG_OUT;
+ n->brl_flags |= BRL_FLAG_IN;
+ SIMPLEQ_INSERT_TAIL(&bif->bif_brlin, n, brl_next);
+ }
+ return (0);
+}
+
+int
+bridge_flushrule(bif)
+ struct bridge_iflist *bif;
+{
+ struct brl_node *p, *q;
+
+ p = SIMPLEQ_FIRST(&bif->bif_brlin);
+ while (p != NULL) {
+ q = SIMPLEQ_NEXT(p, brl_next);
+ SIMPLEQ_REMOVE_HEAD(&bif->bif_brlin, p, brl_next);
+ free(p, M_DEVBUF);
+ p = q;
+ }
+ p = SIMPLEQ_FIRST(&bif->bif_brlout);
+ while (p != NULL) {
+ q = SIMPLEQ_NEXT(p, brl_next);
+ SIMPLEQ_REMOVE_HEAD(&bif->bif_brlout, p, brl_next);
+ free(p, M_DEVBUF);
+ p = q;
+ }
+ return (0);
+}
+
#if defined(INET) && (defined(IPFILTER) || defined(IPFILTER_LKM))
/*