diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2013-11-06 16:20:21 +0100 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2013-11-11 10:08:08 +0100 |
commit | 66659ff1ad6831b0ea7425fa6ecd8a8687523658 (patch) | |
tree | 48e22b475fa8854128e0861a33fed6f78c8094b5 /freebsd/sys/net/if_bridge.c | |
parent | Define __GLOBL1() and __GLOBL() (diff) | |
download | rtems-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.c | 104 |
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); } |