summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/net/if_bridge.c
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2013-11-06 16:20:21 +0100
committerSebastian Huber <sebastian.huber@embedded-brains.de>2013-11-11 10:08:08 +0100
commit66659ff1ad6831b0ea7425fa6ecd8a8687523658 (patch)
tree48e22b475fa8854128e0861a33fed6f78c8094b5 /freebsd/sys/net/if_bridge.c
parentDefine __GLOBL1() and __GLOBL() (diff)
downloadrtems-libbsd-66659ff1ad6831b0ea7425fa6ecd8a8687523658.tar.bz2
Update to FreeBSD 9.2
Diffstat (limited to 'freebsd/sys/net/if_bridge.c')
-rw-r--r--freebsd/sys/net/if_bridge.c104
1 files changed, 79 insertions, 25 deletions
diff --git a/freebsd/sys/net/if_bridge.c b/freebsd/sys/net/if_bridge.c
index 266926a5..c8533f05 100644
--- a/freebsd/sys/net/if_bridge.c
+++ b/freebsd/sys/net/if_bridge.c
@@ -121,6 +121,7 @@ __FBSDID("$FreeBSD$");
#ifdef INET6
#include <netinet/ip6.h>
#include <netinet6/ip6_var.h>
+#include <netinet6/in6_ifattach.h>
#endif
#if defined(INET) || defined(INET6)
#include <netinet/ip_carp.h>
@@ -134,7 +135,7 @@ __FBSDID("$FreeBSD$");
#include <net/route.h>
#include <netinet/ip_fw.h>
-#include <netinet/ipfw/ip_fw_private.h>
+#include <netpfil/ipfw/ip_fw_private.h>
/*
* Size of the route hash table. Must be a power of two.
@@ -350,7 +351,7 @@ static struct bstp_cb_ops bridge_ops = {
};
SYSCTL_DECL(_net_link);
-SYSCTL_NODE(_net_link, IFT_BRIDGE, bridge, CTLFLAG_RW, 0, "Bridge");
+static SYSCTL_NODE(_net_link, IFT_BRIDGE, bridge, CTLFLAG_RW, 0, "Bridge");
static int pfil_onlyip = 1; /* only pass IP[46] packets when pfil is enabled */
static int pfil_bridge = 1; /* run pfil hooks on the bridge interface */
@@ -385,6 +386,12 @@ SYSCTL_INT(_net_link_bridge, OID_AUTO, inherit_mac, CTLFLAG_RW,
&bridge_inherit_mac, 0,
"Inherit MAC address from the first bridge member");
+static VNET_DEFINE(int, allow_llz_overlap) = 0;
+#define V_allow_llz_overlap VNET(allow_llz_overlap)
+SYSCTL_VNET_INT(_net_link_bridge, OID_AUTO, allow_llz_overlap, CTLFLAG_RW,
+ &VNET_NAME(allow_llz_overlap), 0, "Allow overlap of link-local scope "
+ "zones of a bridge interface and the member interfaces");
+
struct bridge_control {
int (*bc_func)(struct bridge_softc *, void *);
int bc_argsize;
@@ -1043,14 +1050,6 @@ bridge_ioctl_add(struct bridge_softc *sc, void *arg)
if (ifs->if_bridge != NULL)
return (EBUSY);
- bif = malloc(sizeof(*bif), M_DEVBUF, M_NOWAIT|M_ZERO);
- if (bif == NULL)
- return (ENOMEM);
-
- bif->bif_ifp = ifs;
- bif->bif_flags = IFBIF_LEARNING | IFBIF_DISCOVER;
- bif->bif_savedcaps = ifs->if_capenable;
-
switch (ifs->if_type) {
case IFT_ETHER:
case IFT_L2VLAN:
@@ -1058,20 +1057,70 @@ bridge_ioctl_add(struct bridge_softc *sc, void *arg)
/* permitted interface types */
break;
default:
- error = EINVAL;
- goto out;
+ return (EINVAL);
}
+#ifdef INET6
+ /*
+ * Two valid inet6 addresses with link-local scope must not be
+ * on the parent interface and the member interfaces at the
+ * same time. This restriction is needed to prevent violation
+ * of link-local scope zone. Attempts to add a member
+ * interface which has inet6 addresses when the parent has
+ * inet6 triggers removal of all inet6 addresses on the member
+ * interface.
+ */
+
+ /* Check if the parent interface has a link-local scope addr. */
+ if (V_allow_llz_overlap == 0 &&
+ in6ifa_llaonifp(sc->sc_ifp) != NULL) {
+ /*
+ * If any, remove all inet6 addresses from the member
+ * interfaces.
+ */
+ BRIDGE_XLOCK(sc);
+ LIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
+ if (in6ifa_llaonifp(bif->bif_ifp)) {
+ BRIDGE_UNLOCK(sc);
+ in6_ifdetach(bif->bif_ifp);
+ BRIDGE_LOCK(sc);
+ if_printf(sc->sc_ifp,
+ "IPv6 addresses on %s have been removed "
+ "before adding it as a member to prevent "
+ "IPv6 address scope violation.\n",
+ bif->bif_ifp->if_xname);
+ }
+ }
+ BRIDGE_XDROP(sc);
+ if (in6ifa_llaonifp(ifs)) {
+ BRIDGE_UNLOCK(sc);
+ in6_ifdetach(ifs);
+ BRIDGE_LOCK(sc);
+ if_printf(sc->sc_ifp,
+ "IPv6 addresses on %s have been removed "
+ "before adding it as a member to prevent "
+ "IPv6 address scope violation.\n",
+ ifs->if_xname);
+ }
+ }
+#endif
/* Allow the first Ethernet member to define the MTU */
if (LIST_EMPTY(&sc->sc_iflist))
sc->sc_ifp->if_mtu = ifs->if_mtu;
else if (sc->sc_ifp->if_mtu != ifs->if_mtu) {
if_printf(sc->sc_ifp, "invalid MTU: %lu(%s) != %lu\n",
ifs->if_mtu, ifs->if_xname, sc->sc_ifp->if_mtu);
- error = EINVAL;
- goto out;
+ return (EINVAL);
}
+ bif = malloc(sizeof(*bif), M_DEVBUF, M_NOWAIT|M_ZERO);
+ if (bif == NULL)
+ return (ENOMEM);
+
+ bif->bif_ifp = ifs;
+ bif->bif_flags = IFBIF_LEARNING | IFBIF_DISCOVER;
+ bif->bif_savedcaps = ifs->if_capenable;
+
/*
* Assign the interface's MAC address to the bridge if it's the first
* member and the MAC address of the bridge has not been changed from
@@ -1106,12 +1155,10 @@ bridge_ioctl_add(struct bridge_softc *sc, void *arg)
BRIDGE_LOCK(sc);
break;
}
- if (error)
- bridge_delete_member(sc, bif, 0);
-out:
+
if (error) {
- if (bif != NULL)
- free(bif, M_DEVBUF);
+ bridge_delete_member(sc, bif, 0);
+ free(bif, M_DEVBUF);
}
return (error);
}
@@ -1702,6 +1749,9 @@ bridge_ifdetach(void *arg __unused, struct ifnet *ifp)
struct bridge_softc *sc = ifp->if_bridge;
struct bridge_iflist *bif;
+ if (ifp->if_flags & IFF_RENAMING)
+ return;
+
/* Check if the interface is a bridge member */
if (sc != NULL) {
BRIDGE_LOCK(sc);
@@ -1813,8 +1863,10 @@ bridge_enqueue(struct bridge_softc *sc, struct ifnet *dst_ifp, struct mbuf *m)
m->m_flags &= ~M_VLANTAG;
}
- if (err == 0)
- dst_ifp->if_transmit(dst_ifp, m);
+ if ((err = dst_ifp->if_transmit(dst_ifp, m))) {
+ m_freem(m0);
+ break;
+ }
}
if (err == 0) {
@@ -2315,6 +2367,7 @@ bridge_input(struct ifnet *ifp, struct mbuf *m)
BRIDGE_UNLOCK(sc); \
return (NULL); \
} \
+ eh = mtod(m, struct ether_header *); \
} \
} \
if (bif->bif_flags & IFBIF_LEARNING) { \
@@ -3111,6 +3164,7 @@ bridge_pfil(struct mbuf **mp, struct ifnet *bifp, struct ifnet *ifp, int dir)
args.m = *mp;
args.oif = ifp;
args.next_hop = NULL;
+ args.next_hop6 = NULL;
args.eh = &eh2;
args.inp = NULL; /* used by ipfw uid/gid/jail rules */
i = V_ip_fw_chk_ptr(&args);
@@ -3396,14 +3450,14 @@ bridge_ip6_checkbasic(struct mbuf **mp)
if ((m = m_copyup(m, sizeof(struct ip6_hdr),
(max_linkhdr + 3) & ~3)) == NULL) {
/* XXXJRT new stat, please */
- V_ip6stat.ip6s_toosmall++;
+ IP6STAT_INC(ip6s_toosmall);
in6_ifstat_inc(inifp, ifs6_in_hdrerr);
goto bad;
}
} else if (__predict_false(m->m_len < sizeof(struct ip6_hdr))) {
struct ifnet *inifp = m->m_pkthdr.rcvif;
if ((m = m_pullup(m, sizeof(struct ip6_hdr))) == NULL) {
- V_ip6stat.ip6s_toosmall++;
+ IP6STAT_INC(ip6s_toosmall);
in6_ifstat_inc(inifp, ifs6_in_hdrerr);
goto bad;
}
@@ -3412,7 +3466,7 @@ bridge_ip6_checkbasic(struct mbuf **mp)
ip6 = mtod(m, struct ip6_hdr *);
if ((ip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) {
- V_ip6stat.ip6s_badvers++;
+ IP6STAT_INC(ip6s_badvers);
in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_hdrerr);
goto bad;
}
@@ -3468,7 +3522,7 @@ bridge_fragment(struct ifnet *ifp, struct mbuf *m, struct ether_header *eh,
continue;
}
bcopy(eh, mtod(m0, caddr_t), ETHER_HDR_LEN);
- } else
+ } else
m_freem(m);
}