summaryrefslogtreecommitdiff
path: root/sys/net
diff options
context:
space:
mode:
Diffstat (limited to 'sys/net')
-rw-r--r--sys/net/bridgectl.c737
-rw-r--r--sys/net/if_bridge.c690
-rw-r--r--sys/net/if_bridge.h19
3 files changed, 770 insertions, 676 deletions
diff --git a/sys/net/bridgectl.c b/sys/net/bridgectl.c
new file mode 100644
index 00000000000..06569b7f42c
--- /dev/null
+++ b/sys/net/bridgectl.c
@@ -0,0 +1,737 @@
+/* $OpenBSD: bridgectl.c,v 1.1 2015/12/01 18:28:29 goda Exp $ */
+
+/*
+ * Copyright (c) 1999, 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.
+ *
+ * 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.
+ *
+ * Effort sponsored in part by the Defense Advanced Research Projects
+ * Agency (DARPA) and Air Force Research Laboratory, Air Force
+ * Materiel Command, USAF, under agreement number F30602-01-2-0537.
+ *
+ */
+
+#include "bpfilter.h"
+#include "gif.h"
+#include "pf.h"
+#include "mpw.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/timeout.h>
+#include <sys/errno.h>
+#include <sys/kernel.h>
+#include <sys/filio.h>
+
+#include <crypto/siphash.h>
+
+#include <net/if.h>
+#include <net/if_types.h>
+#include <net/if_llc.h>
+
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+#include <netinet/if_ether.h>
+#include <netinet/ip_icmp.h>
+
+#ifdef INET6
+#include <netinet6/in6_var.h>
+#include <netinet/ip6.h>
+#include <netinet6/ip6_var.h>
+#endif
+
+#if NBPFILTER > 0
+#include <net/bpf.h>
+#endif
+
+#include <net/if_bridge.h>
+
+
+int bridge_rtfind(struct bridge_softc *, struct ifbaconf *);
+void bridge_rtage(struct bridge_softc *);
+int bridge_rtdaddr(struct bridge_softc *, struct ether_addr *);
+u_int32_t bridge_hash(struct bridge_softc *, struct ether_addr *);
+
+int bridge_brlconf(struct bridge_softc *, struct ifbrlconf *);
+int bridge_addrule(struct bridge_iflist *, struct ifbrlreq *, int out);
+
+int
+bridgectl_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
+{
+ struct bridge_softc *sc = (struct bridge_softc *)ifp->if_softc;
+ struct ifbreq *req = (struct ifbreq *)data;
+ struct ifbrlreq *brlreq = (struct ifbrlreq *)data;
+ struct ifbareq *bareq = (struct ifbareq *)data;
+ struct ifbrparam *bparam = (struct ifbrparam *)data;
+ struct bridge_iflist *p;
+ struct ifnet *ifs;
+ int error = 0;
+
+ switch (cmd) {
+ case SIOCBRDGRTS:
+ error = bridge_rtfind(sc, (struct ifbaconf *)data);
+ break;
+ case SIOCBRDGFLUSH:
+ bridge_rtflush(sc, req->ifbr_ifsflags);
+ break;
+ case SIOCBRDGSADDR:
+ ifs = ifunit(bareq->ifba_ifsname);
+ if (ifs == NULL) { /* no such interface */
+ error = ENOENT;
+ break;
+ }
+ p = (struct bridge_iflist *)ifs->if_bridgeport;
+ if (p == NULL || p->bridge_sc != sc) {
+ error = ESRCH;
+ break;
+ }
+
+ ifs = bridge_rtupdate(sc, &bareq->ifba_dst, ifs, 1,
+ bareq->ifba_flags, NULL);
+ if (ifs == NULL)
+ error = ENOMEM;
+ break;
+ case SIOCBRDGDADDR:
+ error = bridge_rtdaddr(sc, &bareq->ifba_dst);
+ break;
+ case SIOCBRDGGCACHE:
+ bparam->ifbrp_csize = sc->sc_brtmax;
+ break;
+ case SIOCBRDGSCACHE:
+ sc->sc_brtmax = bparam->ifbrp_csize;
+ break;
+ case SIOCBRDGSTO:
+ if (bparam->ifbrp_ctime < 0 ||
+ bparam->ifbrp_ctime > INT_MAX / hz) {
+ error = EINVAL;
+ break;
+ }
+ sc->sc_brttimeout = bparam->ifbrp_ctime;
+ if (bparam->ifbrp_ctime != 0)
+ timeout_add_sec(&sc->sc_brtimeout, sc->sc_brttimeout);
+ else
+ timeout_del(&sc->sc_brtimeout);
+ break;
+ case SIOCBRDGGTO:
+ bparam->ifbrp_ctime = sc->sc_brttimeout;
+ break;
+ case SIOCBRDGARL:
+ ifs = ifunit(brlreq->ifbr_ifsname);
+ if (ifs == NULL) {
+ error = ENOENT;
+ break;
+ }
+ p = (struct bridge_iflist *)ifs->if_bridgeport;
+ if (p == NULL || p->bridge_sc != sc) {
+ 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:
+ ifs = ifunit(brlreq->ifbr_ifsname);
+ if (ifs == NULL) {
+ error = ENOENT;
+ break;
+ }
+ p = (struct bridge_iflist *)ifs->if_bridgeport;
+ if (p == NULL || p->bridge_sc != sc) {
+ error = ESRCH;
+ break;
+ }
+ bridge_flushrule(p);
+ break;
+ case SIOCBRDGGRL:
+ error = bridge_brlconf(sc, (struct ifbrlconf *)data);
+ break;
+ default:
+ break;
+ }
+
+ return (error);
+}
+
+struct ifnet *
+bridge_rtupdate(struct bridge_softc *sc, struct ether_addr *ea,
+ struct ifnet *ifp, int setflags, u_int8_t flags, struct mbuf *m)
+{
+ struct bridge_rtnode *p, *q;
+ struct sockaddr *sa = NULL;
+ u_int32_t h;
+ int dir;
+
+ if (m != NULL) {
+ /* Check if the mbuf was tagged with a tunnel endpoint addr */
+ sa = bridge_tunnel(m);
+ }
+
+ h = bridge_hash(sc, ea);
+ p = LIST_FIRST(&sc->sc_rts[h]);
+ if (p == NULL) {
+ if (sc->sc_brtcnt >= sc->sc_brtmax)
+ goto done;
+ p = malloc(sizeof(*p), M_DEVBUF, M_NOWAIT);
+ if (p == NULL)
+ goto done;
+
+ bcopy(ea, &p->brt_addr, sizeof(p->brt_addr));
+ p->brt_if = ifp;
+ p->brt_age = 1;
+ bridge_copyaddr(sa, (struct sockaddr *)&p->brt_tunnel);
+
+ if (setflags)
+ p->brt_flags = flags;
+ else
+ p->brt_flags = IFBAF_DYNAMIC;
+
+ LIST_INSERT_HEAD(&sc->sc_rts[h], p, brt_next);
+ sc->sc_brtcnt++;
+ goto want;
+ }
+
+ do {
+ q = p;
+ p = LIST_NEXT(p, brt_next);
+
+ dir = memcmp(ea, &q->brt_addr, sizeof(q->brt_addr));
+ if (dir == 0) {
+ if (setflags) {
+ q->brt_if = ifp;
+ q->brt_flags = flags;
+ } else if (!(q->brt_flags & IFBAF_STATIC))
+ q->brt_if = ifp;
+
+ if (q->brt_if == ifp)
+ q->brt_age = 1;
+ ifp = q->brt_if;
+ bridge_copyaddr(sa,
+ (struct sockaddr *)&q->brt_tunnel);
+
+ goto want;
+ }
+
+ if (dir > 0) {
+ if (sc->sc_brtcnt >= sc->sc_brtmax)
+ goto done;
+ p = malloc(sizeof(*p), M_DEVBUF, M_NOWAIT);
+ if (p == NULL)
+ goto done;
+
+ bcopy(ea, &p->brt_addr, sizeof(p->brt_addr));
+ p->brt_if = ifp;
+ p->brt_age = 1;
+ bridge_copyaddr(sa,
+ (struct sockaddr *)&p->brt_tunnel);
+
+ if (setflags)
+ p->brt_flags = flags;
+ else
+ p->brt_flags = IFBAF_DYNAMIC;
+
+ LIST_INSERT_BEFORE(q, p, brt_next);
+ sc->sc_brtcnt++;
+ goto want;
+ }
+
+ if (p == NULL) {
+ if (sc->sc_brtcnt >= sc->sc_brtmax)
+ goto done;
+ p = malloc(sizeof(*p), M_DEVBUF, M_NOWAIT);
+ if (p == NULL)
+ goto done;
+
+ bcopy(ea, &p->brt_addr, sizeof(p->brt_addr));
+ p->brt_if = ifp;
+ p->brt_age = 1;
+ bridge_copyaddr(sa,
+ (struct sockaddr *)&p->brt_tunnel);
+
+ if (setflags)
+ p->brt_flags = flags;
+ else
+ p->brt_flags = IFBAF_DYNAMIC;
+ LIST_INSERT_AFTER(q, p, brt_next);
+ sc->sc_brtcnt++;
+ goto want;
+ }
+ } while (p != NULL);
+
+done:
+ ifp = NULL;
+want:
+ return (ifp);
+}
+
+struct bridge_rtnode *
+bridge_rtlookup(struct bridge_softc *sc, struct ether_addr *ea)
+{
+ struct bridge_rtnode *p;
+ u_int32_t h;
+ int dir;
+
+ h = bridge_hash(sc, ea);
+ LIST_FOREACH(p, &sc->sc_rts[h], brt_next) {
+ dir = memcmp(ea, &p->brt_addr, sizeof(p->brt_addr));
+ if (dir == 0)
+ return (p);
+ if (dir > 0)
+ goto fail;
+ }
+fail:
+ return (NULL);
+}
+
+u_int32_t
+bridge_hash(struct bridge_softc *sc, struct ether_addr *addr)
+{
+ return SipHash24((SIPHASH_KEY *)sc->sc_hashkey, addr, ETHER_ADDR_LEN) &
+ BRIDGE_RTABLE_MASK;
+}
+
+void
+bridge_timer(void *vsc)
+{
+ struct bridge_softc *sc = vsc;
+ int s;
+
+ s = splsoftnet();
+ bridge_rtage(sc);
+ splx(s);
+}
+
+/*
+ * Perform an aging cycle
+ */
+void
+bridge_rtage(struct bridge_softc *sc)
+{
+ struct bridge_rtnode *n, *p;
+ int i;
+
+ for (i = 0; i < BRIDGE_RTABLE_SIZE; i++) {
+ n = LIST_FIRST(&sc->sc_rts[i]);
+ while (n != NULL) {
+ if ((n->brt_flags & IFBAF_TYPEMASK) == IFBAF_STATIC) {
+ n->brt_age = !n->brt_age;
+ if (n->brt_age)
+ n->brt_age = 0;
+ n = LIST_NEXT(n, brt_next);
+ } else if (n->brt_age) {
+ n->brt_age = 0;
+ n = LIST_NEXT(n, brt_next);
+ } else {
+ p = LIST_NEXT(n, brt_next);
+ LIST_REMOVE(n, brt_next);
+ sc->sc_brtcnt--;
+ free(n, M_DEVBUF, sizeof *n);
+ n = p;
+ }
+ }
+ }
+
+ if (sc->sc_brttimeout != 0)
+ timeout_add_sec(&sc->sc_brtimeout, sc->sc_brttimeout);
+}
+
+void
+bridge_rtagenode(struct ifnet *ifp, int age)
+{
+ struct bridge_softc *sc;
+ struct bridge_rtnode *n;
+ int i;
+
+ sc = ((struct bridge_iflist *)ifp->if_bridgeport)->bridge_sc;
+ if (sc == NULL)
+ return;
+
+ /*
+ * If the age is zero then flush, otherwise set all the expiry times to
+ * age for the interface
+ */
+ if (age == 0)
+ bridge_rtdelete(sc, ifp, 1);
+ else {
+ for (i = 0; i < BRIDGE_RTABLE_SIZE; i++) {
+ LIST_FOREACH(n, &sc->sc_rts[i], brt_next) {
+ /* Cap the expiry time to 'age' */
+ if (n->brt_if == ifp &&
+ n->brt_age > time_uptime + age &&
+ (n->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC)
+ n->brt_age = time_uptime + age;
+ }
+ }
+ }
+}
+
+/*
+ * Remove all dynamic addresses from the cache
+ */
+void
+bridge_rtflush(struct bridge_softc *sc, int full)
+{
+ int i;
+ struct bridge_rtnode *p, *n;
+
+ for (i = 0; i < BRIDGE_RTABLE_SIZE; i++) {
+ n = LIST_FIRST(&sc->sc_rts[i]);
+ while (n != NULL) {
+ if (full ||
+ (n->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) {
+ p = LIST_NEXT(n, brt_next);
+ LIST_REMOVE(n, brt_next);
+ sc->sc_brtcnt--;
+ free(n, M_DEVBUF, sizeof *n);
+ n = p;
+ } else
+ n = LIST_NEXT(n, brt_next);
+ }
+ }
+}
+
+/*
+ * Remove an address from the cache
+ */
+int
+bridge_rtdaddr(struct bridge_softc *sc, struct ether_addr *ea)
+{
+ int h;
+ struct bridge_rtnode *p;
+
+ h = bridge_hash(sc, ea);
+ LIST_FOREACH(p, &sc->sc_rts[h], brt_next) {
+ if (bcmp(ea, &p->brt_addr, sizeof(p->brt_addr)) == 0) {
+ LIST_REMOVE(p, brt_next);
+ sc->sc_brtcnt--;
+ free(p, M_DEVBUF, sizeof *p);
+ return (0);
+ }
+ }
+
+ return (ENOENT);
+}
+
+/*
+ * Delete routes to a specific interface member.
+ */
+void
+bridge_rtdelete(struct bridge_softc *sc, struct ifnet *ifp, int dynonly)
+{
+ int i;
+ struct bridge_rtnode *n, *p;
+
+ /*
+ * Loop through all of the hash buckets and traverse each
+ * chain looking for routes to this interface.
+ */
+ for (i = 0; i < BRIDGE_RTABLE_SIZE; i++) {
+ n = LIST_FIRST(&sc->sc_rts[i]);
+ while (n != NULL) {
+ if (n->brt_if != ifp) {
+ /* Not ours */
+ n = LIST_NEXT(n, brt_next);
+ continue;
+ }
+ if (dynonly &&
+ (n->brt_flags & IFBAF_TYPEMASK) != IFBAF_DYNAMIC) {
+ /* only deleting dynamics */
+ n = LIST_NEXT(n, brt_next);
+ continue;
+ }
+ p = LIST_NEXT(n, brt_next);
+ LIST_REMOVE(n, brt_next);
+ sc->sc_brtcnt--;
+ free(n, M_DEVBUF, sizeof *n);
+ n = p;
+ }
+ }
+}
+
+/*
+ * Gather all of the routes for this interface.
+ */
+int
+bridge_rtfind(struct bridge_softc *sc, struct ifbaconf *baconf)
+{
+ int i, error = 0, onlycnt = 0;
+ u_int32_t cnt = 0;
+ struct bridge_rtnode *n;
+ struct ifbareq bareq;
+
+ if (baconf->ifbac_len == 0)
+ onlycnt = 1;
+
+ for (i = 0, cnt = 0; i < BRIDGE_RTABLE_SIZE; i++) {
+ LIST_FOREACH(n, &sc->sc_rts[i], brt_next) {
+ if (!onlycnt) {
+ if (baconf->ifbac_len < sizeof(struct ifbareq))
+ goto done;
+ bcopy(sc->sc_if.if_xname, bareq.ifba_name,
+ sizeof(bareq.ifba_name));
+ bcopy(n->brt_if->if_xname, bareq.ifba_ifsname,
+ sizeof(bareq.ifba_ifsname));
+ bcopy(&n->brt_addr, &bareq.ifba_dst,
+ sizeof(bareq.ifba_dst));
+ bridge_copyaddr(&n->brt_tunnel.sa,
+ (struct sockaddr *)&bareq.ifba_dstsa);
+ bareq.ifba_age = n->brt_age;
+ bareq.ifba_flags = n->brt_flags;
+ error = copyout((caddr_t)&bareq,
+ (caddr_t)(baconf->ifbac_req + cnt), sizeof(bareq));
+ if (error)
+ goto done;
+ baconf->ifbac_len -= sizeof(struct ifbareq);
+ }
+ cnt++;
+ }
+ }
+done:
+ baconf->ifbac_len = cnt * sizeof(struct ifbareq);
+ return (error);
+}
+
+void
+bridge_update(struct ifnet *ifp, struct ether_addr *ea, int delete)
+{
+ struct bridge_softc *sc;
+ struct bridge_iflist *bif;
+ u_int8_t *addr;
+
+ addr = (u_int8_t *)ea;
+
+ bif = (struct bridge_iflist *)ifp->if_bridgeport;
+ sc = bif->bridge_sc;
+
+ /*
+ * Update the bridge interface if it is in
+ * the learning state.
+ */
+ if ((bif->bif_flags & IFBIF_LEARNING) &&
+ (ETHER_IS_MULTICAST(addr) == 0) &&
+ !(addr[0] == 0 && addr[1] == 0 && addr[2] == 0 &&
+ addr[3] == 0 && addr[4] == 0 && addr[5] == 0)) {
+ /* Care must be taken with spanning tree */
+ if ((bif->bif_flags & IFBIF_STP) &&
+ (bif->bif_state == BSTP_IFSTATE_DISCARDING))
+ return;
+
+ /* Delete the address from the bridge */
+ bridge_rtdaddr(sc, ea);
+
+ if (!delete) {
+ /* Update the bridge table */
+ bridge_rtupdate(sc, ea, ifp, 0, IFBAF_DYNAMIC, NULL);
+ }
+ }
+}
+
+/*
+ * bridge filter/matching rules
+ */
+int
+bridge_brlconf(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 = 0, total = 0;
+
+ ifp = ifunit(bc->ifbrl_ifsname);
+ if (ifp == NULL)
+ return (ENOENT);
+ ifl = (struct bridge_iflist *)ifp->if_bridgeport;
+ if (ifl == NULL || ifl->bridge_sc != sc)
+ return (ESRCH);
+
+ SIMPLEQ_FOREACH(n, &ifl->bif_brlin, brl_next) {
+ total++;
+ }
+ SIMPLEQ_FOREACH(n, &ifl->bif_brlout, brl_next) {
+ total++;
+ }
+
+ if (bc->ifbrl_len == 0) {
+ i = total;
+ goto done;
+ }
+
+ SIMPLEQ_FOREACH(n, &ifl->bif_brlin, brl_next) {
+ bzero(&req, sizeof req);
+ if (bc->ifbrl_len < sizeof(req))
+ goto done;
+ strlcpy(req.ifbr_name, sc->sc_if.if_xname, IFNAMSIZ);
+ strlcpy(req.ifbr_ifsname, ifl->ifp->if_xname, IFNAMSIZ);
+ req.ifbr_action = n->brl_action;
+ req.ifbr_flags = n->brl_flags;
+ req.ifbr_src = n->brl_src;
+ req.ifbr_dst = n->brl_dst;
+#if NPF > 0
+ req.ifbr_tagname[0] = '\0';
+ if (n->brl_tag)
+ pf_tag2tagname(n->brl_tag, req.ifbr_tagname);
+#endif
+ error = copyout((caddr_t)&req,
+ (caddr_t)(bc->ifbrl_buf + (i * sizeof(req))), sizeof(req));
+ if (error)
+ goto done;
+ i++;
+ bc->ifbrl_len -= sizeof(req);
+ }
+
+ SIMPLEQ_FOREACH(n, &ifl->bif_brlout, brl_next) {
+ bzero(&req, sizeof req);
+ if (bc->ifbrl_len < sizeof(req))
+ goto done;
+ strlcpy(req.ifbr_name, sc->sc_if.if_xname, IFNAMSIZ);
+ strlcpy(req.ifbr_ifsname, ifl->ifp->if_xname, IFNAMSIZ);
+ req.ifbr_action = n->brl_action;
+ req.ifbr_flags = n->brl_flags;
+ req.ifbr_src = n->brl_src;
+ req.ifbr_dst = n->brl_dst;
+#if NPF > 0
+ req.ifbr_tagname[0] = '\0';
+ if (n->brl_tag)
+ pf_tag2tagname(n->brl_tag, req.ifbr_tagname);
+#endif
+ error = copyout((caddr_t)&req,
+ (caddr_t)(bc->ifbrl_buf + (i * sizeof(req))), sizeof(req));
+ if (error)
+ goto done;
+ i++;
+ bc->ifbrl_len -= sizeof(req);
+ }
+
+done:
+ bc->ifbrl_len = i * sizeof(req);
+ return (error);
+}
+
+u_int8_t
+bridge_filterrule(struct brl_head *h, struct ether_header *eh, struct mbuf *m)
+{
+ struct brl_node *n;
+ u_int8_t flags;
+
+ SIMPLEQ_FOREACH(n, h, brl_next) {
+ flags = n->brl_flags & (BRL_FLAG_SRCVALID|BRL_FLAG_DSTVALID);
+ if (flags == 0)
+ goto return_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_dst, ETHER_ADDR_LEN))
+ continue;
+ goto return_action;
+ }
+ if (flags == BRL_FLAG_SRCVALID) {
+ if (bcmp(eh->ether_shost, &n->brl_src, ETHER_ADDR_LEN))
+ continue;
+ goto return_action;
+ }
+ if (flags == BRL_FLAG_DSTVALID) {
+ if (bcmp(eh->ether_dhost, &n->brl_dst, ETHER_ADDR_LEN))
+ continue;
+ goto return_action;
+ }
+ }
+ return (BRL_ACTION_PASS);
+
+return_action:
+#if NPF > 0
+ pf_tag_packet(m, n->brl_tag, -1);
+#endif
+ return (n->brl_action);
+}
+
+int
+bridge_addrule(struct bridge_iflist *bif, struct ifbrlreq *req, int out)
+{
+ struct brl_node *n;
+
+ n = malloc(sizeof(*n), 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 NPF > 0
+ if (req->ifbr_tagname[0])
+ n->brl_tag = pf_tagname2tag(req->ifbr_tagname, 1);
+ else
+ n->brl_tag = 0;
+#endif
+ 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);
+}
+
+void
+bridge_flushrule(struct bridge_iflist *bif)
+{
+ struct brl_node *p;
+
+ while (!SIMPLEQ_EMPTY(&bif->bif_brlin)) {
+ p = SIMPLEQ_FIRST(&bif->bif_brlin);
+ SIMPLEQ_REMOVE_HEAD(&bif->bif_brlin, brl_next);
+#if NPF > 0
+ pf_tag_unref(p->brl_tag);
+#endif
+ free(p, M_DEVBUF, sizeof *p);
+ }
+ while (!SIMPLEQ_EMPTY(&bif->bif_brlout)) {
+ p = SIMPLEQ_FIRST(&bif->bif_brlout);
+ SIMPLEQ_REMOVE_HEAD(&bif->bif_brlout, brl_next);
+#if NPF > 0
+ pf_tag_unref(p->brl_tag);
+#endif
+ free(p, M_DEVBUF, sizeof *p);
+ }
+}
diff --git a/sys/net/if_bridge.c b/sys/net/if_bridge.c
index dabac1e97aa..e9a62e3b785 100644
--- a/sys/net/if_bridge.c
+++ b/sys/net/if_bridge.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_bridge.c,v 1.271 2015/12/01 14:49:04 goda Exp $ */
+/* $OpenBSD: if_bridge.c,v 1.272 2015/12/01 18:28:29 goda Exp $ */
/*
* Copyright (c) 1999, 2000 Jason L. Wright (jason@thought.net)
@@ -42,7 +42,6 @@
#include <sys/systm.h>
#include <sys/mbuf.h>
#include <sys/socket.h>
-#include <sys/timeout.h>
#include <sys/ioctl.h>
#include <sys/errno.h>
#include <sys/kernel.h>
@@ -127,31 +126,13 @@ void bridge_stop(struct bridge_softc *);
void bridge_init(struct bridge_softc *);
int bridge_bifconf(struct bridge_softc *, struct ifbifconf *);
-void bridge_timer(void *);
-int bridge_rtfind(struct bridge_softc *, struct ifbaconf *);
-void bridge_rtage(struct bridge_softc *);
-int bridge_rtdaddr(struct bridge_softc *, struct ether_addr *);
-void bridge_rtflush(struct bridge_softc *, int);
-struct ifnet *bridge_rtupdate(struct bridge_softc *,
- struct ether_addr *, struct ifnet *ifp, int, u_int8_t, struct mbuf *);
-struct bridge_rtnode *bridge_rtlookup(struct bridge_softc *,
- struct ether_addr *);
-u_int32_t bridge_hash(struct bridge_softc *, struct ether_addr *);
int bridge_blocknonip(struct ether_header *, struct mbuf *);
-int bridge_addrule(struct bridge_iflist *,
- struct ifbrlreq *, int out);
-void bridge_flushrule(struct bridge_iflist *);
-int bridge_brlconf(struct bridge_softc *, struct ifbrlconf *);
-u_int8_t bridge_filterrule(struct brl_head *, struct ether_header *,
- struct mbuf *);
struct mbuf *bridge_ip(struct bridge_softc *, int, struct ifnet *,
struct ether_header *, struct mbuf *m);
int bridge_ifenqueue(struct bridge_softc *, struct ifnet *, struct mbuf *);
void bridge_ifinput(struct ifnet *, struct mbuf *);
void bridge_fragment(struct bridge_softc *, struct ifnet *,
struct ether_header *, struct mbuf *);
-void bridge_send_icmp_err(struct bridge_softc *, struct ifnet *,
- struct ether_header *, struct mbuf *, int, struct llc *, int, int, int);
#ifdef IPSEC
int bridge_ipsec(struct bridge_softc *, struct ifnet *,
struct ether_header *, int, struct llc *,
@@ -160,7 +141,6 @@ int bridge_ipsec(struct bridge_softc *, struct ifnet *,
int bridge_clone_create(struct if_clone *, int);
int bridge_clone_destroy(struct ifnet *ifp);
int bridge_delete(struct bridge_softc *, struct bridge_iflist *);
-void bridge_copyaddr(struct sockaddr *, struct sockaddr *);
struct mbuf *bridge_m_dup(struct mbuf *);
#define ETHERADDR_IS_IP_MCAST(a) \
@@ -285,9 +265,6 @@ bridge_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
{
struct bridge_softc *sc = (struct bridge_softc *)ifp->if_softc;
struct ifbreq *req = (struct ifbreq *)data;
- struct ifbareq *bareq = (struct ifbareq *)data;
- struct ifbrparam *bparam = (struct ifbrparam *)data;
- struct ifbrlreq *brlreq = (struct ifbrlreq *)data;
struct ifbropreq *brop = (struct ifbropreq *)data;
struct ifnet *ifs;
struct bridge_iflist *p;
@@ -532,64 +509,6 @@ bridge_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
}
p->bif_flags = req->ifbr_ifsflags;
break;
- case SIOCBRDGRTS:
- error = bridge_rtfind(sc, (struct ifbaconf *)data);
- break;
- case SIOCBRDGFLUSH:
- if ((error = suser(curproc, 0)) != 0)
- break;
-
- bridge_rtflush(sc, req->ifbr_ifsflags);
- break;
- case SIOCBRDGSADDR:
- if ((error = suser(curproc, 0)) != 0)
- break;
- ifs = ifunit(bareq->ifba_ifsname);
- if (ifs == NULL) { /* no such interface */
- error = ENOENT;
- break;
- }
- p = (struct bridge_iflist *)ifs->if_bridgeport;
- if (p == NULL || p->bridge_sc != sc) {
- error = ESRCH;
- break;
- }
-
- ifs = bridge_rtupdate(sc, &bareq->ifba_dst, ifs, 1,
- bareq->ifba_flags, NULL);
- if (ifs == NULL)
- error = ENOMEM;
- break;
- case SIOCBRDGDADDR:
- if ((error = suser(curproc, 0)) != 0)
- break;
- error = bridge_rtdaddr(sc, &bareq->ifba_dst);
- break;
- case SIOCBRDGGCACHE:
- bparam->ifbrp_csize = sc->sc_brtmax;
- break;
- case SIOCBRDGSCACHE:
- if ((error = suser(curproc, 0)) != 0)
- break;
- sc->sc_brtmax = bparam->ifbrp_csize;
- break;
- case SIOCBRDGSTO:
- if ((error = suser(curproc, 0)) != 0)
- break;
- if (bparam->ifbrp_ctime < 0 ||
- bparam->ifbrp_ctime > INT_MAX / hz) {
- error = EINVAL;
- break;
- }
- sc->sc_brttimeout = bparam->ifbrp_ctime;
- if (bparam->ifbrp_ctime != 0)
- timeout_add_sec(&sc->sc_brtimeout, sc->sc_brttimeout);
- else
- timeout_del(&sc->sc_brtimeout);
- break;
- case SIOCBRDGGTO:
- bparam->ifbrp_ctime = sc->sc_brttimeout;
- break;
case SIOCSIFFLAGS:
if ((ifp->if_flags & IFF_UP) == IFF_UP)
bridge_init(sc);
@@ -598,54 +517,6 @@ bridge_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
bridge_stop(sc);
break;
- case SIOCBRDGARL:
- if ((error = suser(curproc, 0)) != 0)
- break;
- ifs = ifunit(brlreq->ifbr_ifsname);
- if (ifs == NULL) {
- error = ENOENT;
- break;
- }
- p = (struct bridge_iflist *)ifs->if_bridgeport;
- if (p == NULL || p->bridge_sc != sc) {
- 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(curproc, 0)) != 0)
- break;
- ifs = ifunit(brlreq->ifbr_ifsname);
- if (ifs == NULL) {
- error = ENOENT;
- break;
- }
- p = (struct bridge_iflist *)ifs->if_bridgeport;
- if (p == NULL || p->bridge_sc != sc) {
- error = ESRCH;
- break;
- }
- bridge_flushrule(p);
- break;
- case SIOCBRDGGRL:
- error = bridge_brlconf(sc, (struct ifbrlconf *)data);
- break;
case SIOCBRDGGPARAM:
if ((bp = bs->bs_root_port) == NULL)
brop->ifbop_root_port = 0;
@@ -664,11 +535,22 @@ bridge_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
brop->ifbop_last_tc_time.tv_sec = bs->bs_last_tc_time.tv_sec;
brop->ifbop_last_tc_time.tv_usec = bs->bs_last_tc_time.tv_usec;
break;
+ case SIOCBRDGRTS:
+ case SIOCBRDGGCACHE:
case SIOCBRDGGPRI:
case SIOCBRDGGMA:
case SIOCBRDGGHT:
case SIOCBRDGGFD:
+ case SIOCBRDGGTO:
+ case SIOCBRDGGRL:
break;
+ case SIOCBRDGFLUSH:
+ case SIOCBRDGSADDR:
+ case SIOCBRDGDADDR:
+ case SIOCBRDGSCACHE:
+ case SIOCBRDGSTO:
+ case SIOCBRDGARL:
+ case SIOCBRDGFRL:
case SIOCBRDGSPRI:
case SIOCBRDGSFD:
case SIOCBRDGSMA:
@@ -685,6 +567,9 @@ bridge_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
}
if (!error)
+ error = bridgectl_ioctl(ifp, cmd, data);
+
+ if (!error)
error = bstp_ioctl(ifp, cmd, data);
splx(s);
@@ -704,41 +589,6 @@ bridge_ifdetach(struct ifnet *ifp)
bridge_delete(sc, bif);
}
-void
-bridge_update(struct ifnet *ifp, struct ether_addr *ea, int delete)
-{
- struct bridge_softc *sc;
- struct bridge_iflist *bif;
- u_int8_t *addr;
-
- addr = (u_int8_t *)ea;
-
- bif = (struct bridge_iflist *)ifp->if_bridgeport;
- sc = bif->bridge_sc;
-
- /*
- * Update the bridge interface if it is in
- * the learning state.
- */
- if ((bif->bif_flags & IFBIF_LEARNING) &&
- (ETHER_IS_MULTICAST(addr) == 0) &&
- !(addr[0] == 0 && addr[1] == 0 && addr[2] == 0 &&
- addr[3] == 0 && addr[4] == 0 && addr[5] == 0)) {
- /* Care must be taken with spanning tree */
- if ((bif->bif_flags & IFBIF_STP) &&
- (bif->bif_state == BSTP_IFSTATE_DISCARDING))
- return;
-
- /* Delete the address from the bridge */
- bridge_rtdaddr(sc, ea);
-
- if (!delete) {
- /* Update the bridge table */
- bridge_rtupdate(sc, ea, ifp, 0, IFBAF_DYNAMIC, NULL);
- }
- }
-}
-
int
bridge_bifconf(struct bridge_softc *sc, struct ifbifconf *bifc)
{
@@ -827,86 +677,6 @@ done:
return (error);
}
-int
-bridge_brlconf(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 = 0, total = 0;
-
- ifp = ifunit(bc->ifbrl_ifsname);
- if (ifp == NULL)
- return (ENOENT);
- ifl = (struct bridge_iflist *)ifp->if_bridgeport;
- if (ifl == NULL || ifl->bridge_sc != sc)
- return (ESRCH);
-
- SIMPLEQ_FOREACH(n, &ifl->bif_brlin, brl_next) {
- total++;
- }
- SIMPLEQ_FOREACH(n, &ifl->bif_brlout, brl_next) {
- total++;
- }
-
- if (bc->ifbrl_len == 0) {
- i = total;
- goto done;
- }
-
- SIMPLEQ_FOREACH(n, &ifl->bif_brlin, brl_next) {
- bzero(&req, sizeof req);
- if (bc->ifbrl_len < sizeof(req))
- goto done;
- strlcpy(req.ifbr_name, sc->sc_if.if_xname, IFNAMSIZ);
- strlcpy(req.ifbr_ifsname, ifl->ifp->if_xname, IFNAMSIZ);
- req.ifbr_action = n->brl_action;
- req.ifbr_flags = n->brl_flags;
- req.ifbr_src = n->brl_src;
- req.ifbr_dst = n->brl_dst;
-#if NPF > 0
- req.ifbr_tagname[0] = '\0';
- if (n->brl_tag)
- pf_tag2tagname(n->brl_tag, req.ifbr_tagname);
-#endif
- error = copyout((caddr_t)&req,
- (caddr_t)(bc->ifbrl_buf + (i * sizeof(req))), sizeof(req));
- if (error)
- goto done;
- i++;
- bc->ifbrl_len -= sizeof(req);
- }
-
- SIMPLEQ_FOREACH(n, &ifl->bif_brlout, brl_next) {
- bzero(&req, sizeof req);
- if (bc->ifbrl_len < sizeof(req))
- goto done;
- strlcpy(req.ifbr_name, sc->sc_if.if_xname, IFNAMSIZ);
- strlcpy(req.ifbr_ifsname, ifl->ifp->if_xname, IFNAMSIZ);
- req.ifbr_action = n->brl_action;
- req.ifbr_flags = n->brl_flags;
- req.ifbr_src = n->brl_src;
- req.ifbr_dst = n->brl_dst;
-#if NPF > 0
- req.ifbr_tagname[0] = '\0';
- if (n->brl_tag)
- pf_tag2tagname(n->brl_tag, req.ifbr_tagname);
-#endif
- error = copyout((caddr_t)&req,
- (caddr_t)(bc->ifbrl_buf + (i * sizeof(req))), sizeof(req));
- if (error)
- goto done;
- i++;
- bc->ifbrl_len -= sizeof(req);
- }
-
-done:
- bc->ifbrl_len = i * sizeof(req);
- return (error);
-}
-
void
bridge_init(struct bridge_softc *sc)
{
@@ -1555,345 +1325,6 @@ bridge_span(struct bridge_softc *sc, struct mbuf *m)
}
}
-struct ifnet *
-bridge_rtupdate(struct bridge_softc *sc, struct ether_addr *ea,
- struct ifnet *ifp, int setflags, u_int8_t flags, struct mbuf *m)
-{
- struct bridge_rtnode *p, *q;
- struct sockaddr *sa = NULL;
- u_int32_t h;
- int dir;
-
- if (m != NULL) {
- /* Check if the mbuf was tagged with a tunnel endpoint addr */
- sa = bridge_tunnel(m);
- }
-
- h = bridge_hash(sc, ea);
- p = LIST_FIRST(&sc->sc_rts[h]);
- if (p == NULL) {
- if (sc->sc_brtcnt >= sc->sc_brtmax)
- goto done;
- p = malloc(sizeof(*p), M_DEVBUF, M_NOWAIT);
- if (p == NULL)
- goto done;
-
- bcopy(ea, &p->brt_addr, sizeof(p->brt_addr));
- p->brt_if = ifp;
- p->brt_age = 1;
- bridge_copyaddr(sa, (struct sockaddr *)&p->brt_tunnel);
-
- if (setflags)
- p->brt_flags = flags;
- else
- p->brt_flags = IFBAF_DYNAMIC;
-
- LIST_INSERT_HEAD(&sc->sc_rts[h], p, brt_next);
- sc->sc_brtcnt++;
- goto want;
- }
-
- do {
- q = p;
- p = LIST_NEXT(p, brt_next);
-
- dir = memcmp(ea, &q->brt_addr, sizeof(q->brt_addr));
- if (dir == 0) {
- if (setflags) {
- q->brt_if = ifp;
- q->brt_flags = flags;
- } else if (!(q->brt_flags & IFBAF_STATIC))
- q->brt_if = ifp;
-
- if (q->brt_if == ifp)
- q->brt_age = 1;
- ifp = q->brt_if;
- bridge_copyaddr(sa,
- (struct sockaddr *)&q->brt_tunnel);
-
- goto want;
- }
-
- if (dir > 0) {
- if (sc->sc_brtcnt >= sc->sc_brtmax)
- goto done;
- p = malloc(sizeof(*p), M_DEVBUF, M_NOWAIT);
- if (p == NULL)
- goto done;
-
- bcopy(ea, &p->brt_addr, sizeof(p->brt_addr));
- p->brt_if = ifp;
- p->brt_age = 1;
- bridge_copyaddr(sa,
- (struct sockaddr *)&p->brt_tunnel);
-
- if (setflags)
- p->brt_flags = flags;
- else
- p->brt_flags = IFBAF_DYNAMIC;
-
- LIST_INSERT_BEFORE(q, p, brt_next);
- sc->sc_brtcnt++;
- goto want;
- }
-
- if (p == NULL) {
- if (sc->sc_brtcnt >= sc->sc_brtmax)
- goto done;
- p = malloc(sizeof(*p), M_DEVBUF, M_NOWAIT);
- if (p == NULL)
- goto done;
-
- bcopy(ea, &p->brt_addr, sizeof(p->brt_addr));
- p->brt_if = ifp;
- p->brt_age = 1;
- bridge_copyaddr(sa,
- (struct sockaddr *)&p->brt_tunnel);
-
- if (setflags)
- p->brt_flags = flags;
- else
- p->brt_flags = IFBAF_DYNAMIC;
- LIST_INSERT_AFTER(q, p, brt_next);
- sc->sc_brtcnt++;
- goto want;
- }
- } while (p != NULL);
-
-done:
- ifp = NULL;
-want:
- return (ifp);
-}
-
-struct bridge_rtnode *
-bridge_rtlookup(struct bridge_softc *sc, struct ether_addr *ea)
-{
- struct bridge_rtnode *p;
- u_int32_t h;
- int dir;
-
- h = bridge_hash(sc, ea);
- LIST_FOREACH(p, &sc->sc_rts[h], brt_next) {
- dir = memcmp(ea, &p->brt_addr, sizeof(p->brt_addr));
- if (dir == 0)
- return (p);
- if (dir > 0)
- goto fail;
- }
-fail:
- return (NULL);
-}
-
-u_int32_t
-bridge_hash(struct bridge_softc *sc, struct ether_addr *addr)
-{
- return SipHash24((SIPHASH_KEY *)sc->sc_hashkey, addr, ETHER_ADDR_LEN) &
- BRIDGE_RTABLE_MASK;
-}
-
-void
-bridge_timer(void *vsc)
-{
- struct bridge_softc *sc = vsc;
- int s;
-
- s = splsoftnet();
- bridge_rtage(sc);
- splx(s);
-}
-
-/*
- * Perform an aging cycle
- */
-void
-bridge_rtage(struct bridge_softc *sc)
-{
- struct bridge_rtnode *n, *p;
- int i;
-
- for (i = 0; i < BRIDGE_RTABLE_SIZE; i++) {
- n = LIST_FIRST(&sc->sc_rts[i]);
- while (n != NULL) {
- if ((n->brt_flags & IFBAF_TYPEMASK) == IFBAF_STATIC) {
- n->brt_age = !n->brt_age;
- if (n->brt_age)
- n->brt_age = 0;
- n = LIST_NEXT(n, brt_next);
- } else if (n->brt_age) {
- n->brt_age = 0;
- n = LIST_NEXT(n, brt_next);
- } else {
- p = LIST_NEXT(n, brt_next);
- LIST_REMOVE(n, brt_next);
- sc->sc_brtcnt--;
- free(n, M_DEVBUF, sizeof *n);
- n = p;
- }
- }
- }
-
- if (sc->sc_brttimeout != 0)
- timeout_add_sec(&sc->sc_brtimeout, sc->sc_brttimeout);
-}
-
-void
-bridge_rtagenode(struct ifnet *ifp, int age)
-{
- struct bridge_softc *sc;
- struct bridge_rtnode *n;
- int i;
-
- sc = ((struct bridge_iflist *)ifp->if_bridgeport)->bridge_sc;
- if (sc == NULL)
- return;
-
- /*
- * If the age is zero then flush, otherwise set all the expiry times to
- * age for the interface
- */
- if (age == 0)
- bridge_rtdelete(sc, ifp, 1);
- else {
- for (i = 0; i < BRIDGE_RTABLE_SIZE; i++) {
- LIST_FOREACH(n, &sc->sc_rts[i], brt_next) {
- /* Cap the expiry time to 'age' */
- if (n->brt_if == ifp &&
- n->brt_age > time_uptime + age &&
- (n->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC)
- n->brt_age = time_uptime + age;
- }
- }
- }
-}
-
-
-
-/*
- * Remove all dynamic addresses from the cache
- */
-void
-bridge_rtflush(struct bridge_softc *sc, int full)
-{
- int i;
- struct bridge_rtnode *p, *n;
-
- for (i = 0; i < BRIDGE_RTABLE_SIZE; i++) {
- n = LIST_FIRST(&sc->sc_rts[i]);
- while (n != NULL) {
- if (full ||
- (n->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) {
- p = LIST_NEXT(n, brt_next);
- LIST_REMOVE(n, brt_next);
- sc->sc_brtcnt--;
- free(n, M_DEVBUF, sizeof *n);
- n = p;
- } else
- n = LIST_NEXT(n, brt_next);
- }
- }
-}
-
-/*
- * Remove an address from the cache
- */
-int
-bridge_rtdaddr(struct bridge_softc *sc, struct ether_addr *ea)
-{
- int h;
- struct bridge_rtnode *p;
-
- h = bridge_hash(sc, ea);
- LIST_FOREACH(p, &sc->sc_rts[h], brt_next) {
- if (bcmp(ea, &p->brt_addr, sizeof(p->brt_addr)) == 0) {
- LIST_REMOVE(p, brt_next);
- sc->sc_brtcnt--;
- free(p, M_DEVBUF, sizeof *p);
- return (0);
- }
- }
-
- return (ENOENT);
-}
-/*
- * Delete routes to a specific interface member.
- */
-void
-bridge_rtdelete(struct bridge_softc *sc, struct ifnet *ifp, int dynonly)
-{
- int i;
- struct bridge_rtnode *n, *p;
-
- /*
- * Loop through all of the hash buckets and traverse each
- * chain looking for routes to this interface.
- */
- for (i = 0; i < BRIDGE_RTABLE_SIZE; i++) {
- n = LIST_FIRST(&sc->sc_rts[i]);
- while (n != NULL) {
- if (n->brt_if != ifp) {
- /* Not ours */
- n = LIST_NEXT(n, brt_next);
- continue;
- }
- if (dynonly &&
- (n->brt_flags & IFBAF_TYPEMASK) != IFBAF_DYNAMIC) {
- /* only deleting dynamics */
- n = LIST_NEXT(n, brt_next);
- continue;
- }
- p = LIST_NEXT(n, brt_next);
- LIST_REMOVE(n, brt_next);
- sc->sc_brtcnt--;
- free(n, M_DEVBUF, sizeof *n);
- n = p;
- }
- }
-}
-
-/*
- * Gather all of the routes for this interface.
- */
-int
-bridge_rtfind(struct bridge_softc *sc, struct ifbaconf *baconf)
-{
- int i, error = 0, onlycnt = 0;
- u_int32_t cnt = 0;
- struct bridge_rtnode *n;
- struct ifbareq bareq;
-
- if (baconf->ifbac_len == 0)
- onlycnt = 1;
-
- for (i = 0, cnt = 0; i < BRIDGE_RTABLE_SIZE; i++) {
- LIST_FOREACH(n, &sc->sc_rts[i], brt_next) {
- if (!onlycnt) {
- if (baconf->ifbac_len < sizeof(struct ifbareq))
- goto done;
- bcopy(sc->sc_if.if_xname, bareq.ifba_name,
- sizeof(bareq.ifba_name));
- bcopy(n->brt_if->if_xname, bareq.ifba_ifsname,
- sizeof(bareq.ifba_ifsname));
- bcopy(&n->brt_addr, &bareq.ifba_dst,
- sizeof(bareq.ifba_dst));
- bridge_copyaddr(&n->brt_tunnel.sa,
- (struct sockaddr *)&bareq.ifba_dstsa);
- bareq.ifba_age = n->brt_age;
- bareq.ifba_flags = n->brt_flags;
- error = copyout((caddr_t)&bareq,
- (caddr_t)(baconf->ifbac_req + cnt), sizeof(bareq));
- if (error)
- goto done;
- baconf->ifbac_len -= sizeof(struct ifbareq);
- }
- cnt++;
- }
- }
-done:
- baconf->ifbac_len = cnt * sizeof(struct ifbareq);
- return (error);
-}
-
/*
* Block non-ip frames:
* Returns 0 if frame is ip, and 1 if it should be dropped.
@@ -1946,96 +1377,6 @@ bridge_blocknonip(struct ether_header *eh, struct mbuf *m)
return (1);
}
-u_int8_t
-bridge_filterrule(struct brl_head *h, struct ether_header *eh, struct mbuf *m)
-{
- struct brl_node *n;
- u_int8_t flags;
-
- SIMPLEQ_FOREACH(n, h, brl_next) {
- flags = n->brl_flags & (BRL_FLAG_SRCVALID|BRL_FLAG_DSTVALID);
- if (flags == 0)
- goto return_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_dst, ETHER_ADDR_LEN))
- continue;
- goto return_action;
- }
- if (flags == BRL_FLAG_SRCVALID) {
- if (bcmp(eh->ether_shost, &n->brl_src, ETHER_ADDR_LEN))
- continue;
- goto return_action;
- }
- if (flags == BRL_FLAG_DSTVALID) {
- if (bcmp(eh->ether_dhost, &n->brl_dst, ETHER_ADDR_LEN))
- continue;
- goto return_action;
- }
- }
- return (BRL_ACTION_PASS);
-
-return_action:
-#if NPF > 0
- pf_tag_packet(m, n->brl_tag, -1);
-#endif
- return (n->brl_action);
-}
-
-int
-bridge_addrule(struct bridge_iflist *bif, struct ifbrlreq *req, int out)
-{
- struct brl_node *n;
-
- n = malloc(sizeof(*n), 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 NPF > 0
- if (req->ifbr_tagname[0])
- n->brl_tag = pf_tagname2tag(req->ifbr_tagname, 1);
- else
- n->brl_tag = 0;
-#endif
- 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);
-}
-
-void
-bridge_flushrule(struct bridge_iflist *bif)
-{
- struct brl_node *p;
-
- while (!SIMPLEQ_EMPTY(&bif->bif_brlin)) {
- p = SIMPLEQ_FIRST(&bif->bif_brlin);
- SIMPLEQ_REMOVE_HEAD(&bif->bif_brlin, brl_next);
-#if NPF > 0
- pf_tag_unref(p->brl_tag);
-#endif
- free(p, M_DEVBUF, sizeof *p);
- }
- while (!SIMPLEQ_EMPTY(&bif->bif_brlout)) {
- p = SIMPLEQ_FIRST(&bif->bif_brlout);
- SIMPLEQ_REMOVE_HEAD(&bif->bif_brlout, brl_next);
-#if NPF > 0
- pf_tag_unref(p->brl_tag);
-#endif
- free(p, M_DEVBUF, sizeof *p);
- }
-}
-
#ifdef IPSEC
int
bridge_ipsec(struct bridge_softc *sc, struct ifnet *ifp,
@@ -2723,4 +2064,3 @@ bridge_m_dup(struct mbuf *m)
return (m1);
}
-
diff --git a/sys/net/if_bridge.h b/sys/net/if_bridge.h
index ac4bdfc3e80..b165ecd1103 100644
--- a/sys/net/if_bridge.h
+++ b/sys/net/if_bridge.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_bridge.h,v 1.47 2015/11/28 15:21:45 yasuoka Exp $ */
+/* $OpenBSD: if_bridge.h,v 1.48 2015/12/01 18:28:29 goda Exp $ */
/*
* Copyright (c) 1999, 2000 Jason L. Wright (jason@thought.net)
@@ -433,6 +433,7 @@ struct bridge_softc {
};
extern const u_int8_t bstp_etheraddr[];
+struct llc;
void bridge_ifdetach(struct ifnet *);
int bridge_output(struct ifnet *, struct mbuf *, struct sockaddr *,
@@ -443,6 +444,7 @@ void bridge_rtagenode(struct ifnet *, int);
struct sockaddr *bridge_tunnel(struct mbuf *);
struct sockaddr *bridge_tunneltag(struct mbuf *, int);
void bridge_tunneluntag(struct mbuf *);
+void bridge_copyaddr(struct sockaddr *, struct sockaddr *);
struct bstp_state *bstp_create(struct ifnet *);
void bstp_destroy(struct bstp_state *);
@@ -456,5 +458,20 @@ struct mbuf *bstp_input(struct bstp_state *, struct bstp_port *,
void bstp_ifstate(void *);
u_int8_t bstp_getstate(struct bstp_state *, struct bstp_port *);
void bstp_ifsflags(struct bstp_port *, u_int);
+void bridge_send_icmp_err(struct bridge_softc *, struct ifnet *,
+ struct ether_header *, struct mbuf *, int, struct llc *, int, int, int);
+
+int bridgectl_ioctl(struct ifnet *, u_long, caddr_t);
+struct ifnet *bridge_rtupdate(struct bridge_softc *,
+ struct ether_addr *, struct ifnet *ifp, int, u_int8_t, struct mbuf *);
+struct bridge_rtnode *bridge_rtlookup(struct bridge_softc *,
+ struct ether_addr *);
+void bridge_rtflush(struct bridge_softc *, int);
+void bridge_timer(void *);
+
+u_int8_t bridge_filterrule(struct brl_head *, struct ether_header *,
+ struct mbuf *);
+void bridge_flushrule(struct bridge_iflist *);
+
#endif /* _KERNEL */
#endif /* _NET_IF_BRIDGE_H_ */