diff options
Diffstat (limited to 'freebsd/sys/netinet6/in6_gif.c')
-rw-r--r-- | freebsd/sys/netinet6/in6_gif.c | 387 |
1 files changed, 74 insertions, 313 deletions
diff --git a/freebsd/sys/netinet6/in6_gif.c b/freebsd/sys/netinet6/in6_gif.c index 9e0f37f0..6e1fb8b1 100644 --- a/freebsd/sys/netinet6/in6_gif.c +++ b/freebsd/sys/netinet6/in6_gif.c @@ -38,6 +38,8 @@ __FBSDID("$FreeBSD$"); #include <rtems/bsd/local/opt_inet6.h> #include <rtems/bsd/sys/param.h> +#include <rtems/bsd/sys/lock.h> +#include <sys/rmlock.h> #include <sys/systm.h> #include <sys/socket.h> #include <sys/sockio.h> @@ -51,7 +53,9 @@ __FBSDID("$FreeBSD$"); #include <sys/malloc.h> #include <net/if.h> +#include <net/if_var.h> #include <net/route.h> +#include <net/vnet.h> #include <netinet/in.h> #include <netinet/in_systm.h> @@ -62,29 +66,28 @@ __FBSDID("$FreeBSD$"); #ifdef INET6 #include <netinet/ip6.h> #include <netinet6/ip6_var.h> -#include <netinet6/in6_gif.h> #include <netinet6/in6_var.h> #endif -#include <netinet6/ip6protosw.h> #include <netinet/ip_ecn.h> #ifdef INET6 #include <netinet6/ip6_ecn.h> +#include <netinet6/in6_fib.h> #endif #include <net/if_gif.h> -VNET_DEFINE(int, ip6_gif_hlim) = GIF_HLIM; +#define GIF_HLIM 30 +static VNET_DEFINE(int, ip6_gif_hlim) = GIF_HLIM; #define V_ip6_gif_hlim VNET(ip6_gif_hlim) SYSCTL_DECL(_net_inet6_ip6); -SYSCTL_VNET_INT(_net_inet6_ip6, IPV6CTL_GIF_HLIM, gifhlim, CTLFLAG_RW, +SYSCTL_INT(_net_inet6_ip6, IPV6CTL_GIF_HLIM, gifhlim, CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip6_gif_hlim), 0, ""); -static int gif_validate6(const struct ip6_hdr *, struct gif_softc *, - struct ifnet *); +static int in6_gif_input(struct mbuf **, int *, int); extern struct domain inet6domain; -struct ip6protosw in6_gif_protosw = { +static struct protosw in6_gif_protosw = { .pr_type = SOCK_RAW, .pr_domain = &inet6domain, .pr_protocol = 0, /* IPPROTO_IPV[46] */ @@ -96,112 +99,24 @@ struct ip6protosw in6_gif_protosw = { }; int -in6_gif_output(struct ifnet *ifp, - int family, /* family of the packet to be encapsulate */ - struct mbuf *m) +in6_gif_output(struct ifnet *ifp, struct mbuf *m, int proto, uint8_t ecn) { + GIF_RLOCK_TRACKER; struct gif_softc *sc = ifp->if_softc; - struct sockaddr_in6 *dst = (struct sockaddr_in6 *)&sc->gif_ro6.ro_dst; - struct sockaddr_in6 *sin6_src = (struct sockaddr_in6 *)sc->gif_psrc; - struct sockaddr_in6 *sin6_dst = (struct sockaddr_in6 *)sc->gif_pdst; struct ip6_hdr *ip6; - struct etherip_header eiphdr; - int error, len, proto; - u_int8_t itos, otos; - - GIF_LOCK_ASSERT(sc); - - if (sin6_src == NULL || sin6_dst == NULL || - sin6_src->sin6_family != AF_INET6 || - sin6_dst->sin6_family != AF_INET6) { - m_freem(m); - return EAFNOSUPPORT; - } - - switch (family) { -#ifdef INET - case AF_INET: - { - struct ip *ip; - - proto = IPPROTO_IPV4; - if (m->m_len < sizeof(*ip)) { - m = m_pullup(m, sizeof(*ip)); - if (!m) - return ENOBUFS; - } - ip = mtod(m, struct ip *); - itos = ip->ip_tos; - break; - } -#endif -#ifdef INET6 - case AF_INET6: - { - struct ip6_hdr *ip6; - proto = IPPROTO_IPV6; - if (m->m_len < sizeof(*ip6)) { - m = m_pullup(m, sizeof(*ip6)); - if (!m) - return ENOBUFS; - } - ip6 = mtod(m, struct ip6_hdr *); - itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff; - break; - } -#endif - case AF_LINK: - proto = IPPROTO_ETHERIP; - - /* - * GIF_SEND_REVETHIP (disabled by default) intentionally - * sends an EtherIP packet with revered version field in - * the header. This is a knob for backward compatibility - * with FreeBSD 7.2R or prior. - */ - if ((sc->gif_options & GIF_SEND_REVETHIP)) { - eiphdr.eip_ver = 0; - eiphdr.eip_resvl = ETHERIP_VERSION; - eiphdr.eip_resvh = 0; - } else { - eiphdr.eip_ver = ETHERIP_VERSION; - eiphdr.eip_resvl = 0; - eiphdr.eip_resvh = 0; - } - /* prepend Ethernet-in-IP header */ - M_PREPEND(m, sizeof(struct etherip_header), M_DONTWAIT); - if (m && m->m_len < sizeof(struct etherip_header)) - m = m_pullup(m, sizeof(struct etherip_header)); - if (m == NULL) - return ENOBUFS; - bcopy(&eiphdr, mtod(m, struct etherip_header *), - sizeof(struct etherip_header)); - break; - - default: -#ifdef DEBUG - printf("in6_gif_output: warning: unknown family %d passed\n", - family); -#endif - m_freem(m); - return EAFNOSUPPORT; - } + int len; /* prepend new IP header */ len = sizeof(struct ip6_hdr); #ifndef __NO_STRICT_ALIGNMENT - if (family == AF_LINK) + if (proto == IPPROTO_ETHERIP) len += ETHERIP_ALIGN; #endif - M_PREPEND(m, len, M_DONTWAIT); - if (m != NULL && m->m_len < len) - m = m_pullup(m, len); - if (m == NULL) { - printf("ENOBUFS in in6_gif_output %d\n", __LINE__); - return ENOBUFS; - } + M_PREPEND(m, len, M_NOWAIT); + if (m == NULL) + return (ENOBUFS); #ifndef __NO_STRICT_ALIGNMENT - if (family == AF_LINK) { + if (proto == IPPROTO_ETHERIP) { len = mtod(m, vm_offset_t) & 3; KASSERT(len == 0 || len == ETHERIP_ALIGN, ("in6_gif_output: unexpected misalignment")); @@ -211,261 +126,107 @@ in6_gif_output(struct ifnet *ifp, #endif ip6 = mtod(m, struct ip6_hdr *); - ip6->ip6_flow = 0; - ip6->ip6_vfc &= ~IPV6_VERSION_MASK; - ip6->ip6_vfc |= IPV6_VERSION; - ip6->ip6_plen = htons((u_short)m->m_pkthdr.len); - ip6->ip6_nxt = proto; - ip6->ip6_hlim = V_ip6_gif_hlim; - ip6->ip6_src = sin6_src->sin6_addr; - /* bidirectional configured tunnel mode */ - if (!IN6_IS_ADDR_UNSPECIFIED(&sin6_dst->sin6_addr)) - ip6->ip6_dst = sin6_dst->sin6_addr; - else { + GIF_RLOCK(sc); + if (sc->gif_family != AF_INET6) { m_freem(m); - return ENETUNREACH; + GIF_RUNLOCK(sc); + return (ENETDOWN); } - ip_ecn_ingress((ifp->if_flags & IFF_LINK1) ? ECN_ALLOWED : ECN_NOCARE, - &otos, &itos); - ip6->ip6_flow &= ~htonl(0xff << 20); - ip6->ip6_flow |= htonl((u_int32_t)otos << 20); + bcopy(sc->gif_ip6hdr, ip6, sizeof(struct ip6_hdr)); + GIF_RUNLOCK(sc); - M_SETFIB(m, sc->gif_fibnum); - - if (dst->sin6_family != sin6_dst->sin6_family || - !IN6_ARE_ADDR_EQUAL(&dst->sin6_addr, &sin6_dst->sin6_addr)) { - /* cache route doesn't match */ - bzero(dst, sizeof(*dst)); - dst->sin6_family = sin6_dst->sin6_family; - dst->sin6_len = sizeof(struct sockaddr_in6); - dst->sin6_addr = sin6_dst->sin6_addr; - if (sc->gif_ro6.ro_rt) { - RTFREE(sc->gif_ro6.ro_rt); - sc->gif_ro6.ro_rt = NULL; - } -#if 0 - GIF2IFP(sc)->if_mtu = GIF_MTU; -#endif - } - - if (sc->gif_ro6.ro_rt == NULL) { - in6_rtalloc(&sc->gif_ro6, sc->gif_fibnum); - if (sc->gif_ro6.ro_rt == NULL) { - m_freem(m); - return ENETUNREACH; - } - - /* if it constitutes infinite encapsulation, punt. */ - if (sc->gif_ro.ro_rt->rt_ifp == ifp) { - m_freem(m); - return ENETUNREACH; /*XXX*/ - } -#if 0 - ifp->if_mtu = sc->gif_ro6.ro_rt->rt_ifp->if_mtu - - sizeof(struct ip6_hdr); -#endif - } - - m_addr_changed(m); - -#ifdef IPV6_MINMTU + ip6->ip6_flow |= htonl((uint32_t)ecn << 20); + ip6->ip6_nxt = proto; + ip6->ip6_hlim = V_ip6_gif_hlim; /* * force fragmentation to minimum MTU, to avoid path MTU discovery. * it is too painful to ask for resend of inner packet, to achieve * path MTU discovery for encapsulated packets. */ - error = ip6_output(m, 0, &sc->gif_ro6, IPV6_MINMTU, 0, NULL, NULL); -#else - error = ip6_output(m, 0, &sc->gif_ro6, 0, 0, NULL, NULL); -#endif - - if (!(GIF2IFP(sc)->if_flags & IFF_LINK0) && - sc->gif_ro6.ro_rt != NULL) { - RTFREE(sc->gif_ro6.ro_rt); - sc->gif_ro6.ro_rt = NULL; - } - - return (error); + return (ip6_output(m, 0, NULL, IPV6_MINMTU, 0, NULL, NULL)); } -int +static int in6_gif_input(struct mbuf **mp, int *offp, int proto) { struct mbuf *m = *mp; - struct ifnet *gifp = NULL; + struct ifnet *gifp; struct gif_softc *sc; struct ip6_hdr *ip6; - int af = 0; - u_int32_t otos; + uint8_t ecn; - ip6 = mtod(m, struct ip6_hdr *); - - sc = (struct gif_softc *)encap_getarg(m); + sc = encap_getarg(m); if (sc == NULL) { m_freem(m); IP6STAT_INC(ip6s_nogif); - return IPPROTO_DONE; + return (IPPROTO_DONE); } - gifp = GIF2IFP(sc); - if (gifp == NULL || (gifp->if_flags & IFF_UP) == 0) { - m_freem(m); - IP6STAT_INC(ip6s_nogif); - return IPPROTO_DONE; - } - - otos = ip6->ip6_flow; - m_adj(m, *offp); - - switch (proto) { -#ifdef INET - case IPPROTO_IPV4: - { - struct ip *ip; - u_int8_t otos8; - af = AF_INET; - otos8 = (ntohl(otos) >> 20) & 0xff; - if (m->m_len < sizeof(*ip)) { - m = m_pullup(m, sizeof(*ip)); - if (!m) - return IPPROTO_DONE; - } - ip = mtod(m, struct ip *); - if (ip_ecn_egress((gifp->if_flags & IFF_LINK1) ? - ECN_ALLOWED : ECN_NOCARE, - &otos8, &ip->ip_tos) == 0) { - m_freem(m); - return IPPROTO_DONE; - } - break; - } -#endif /* INET */ -#ifdef INET6 - case IPPROTO_IPV6: - { - struct ip6_hdr *ip6; - af = AF_INET6; - if (m->m_len < sizeof(*ip6)) { - m = m_pullup(m, sizeof(*ip6)); - if (!m) - return IPPROTO_DONE; - } + if ((gifp->if_flags & IFF_UP) != 0) { ip6 = mtod(m, struct ip6_hdr *); - if (ip6_ecn_egress((gifp->if_flags & IFF_LINK1) ? - ECN_ALLOWED : ECN_NOCARE, - &otos, &ip6->ip6_flow) == 0) { - m_freem(m); - return IPPROTO_DONE; - } - break; - } -#endif - case IPPROTO_ETHERIP: - af = AF_LINK; - break; - - default: - IP6STAT_INC(ip6s_nogif); + ecn = (ntohl(ip6->ip6_flow) >> 20) & 0xff; + m_adj(m, *offp); + gif_input(m, gifp, proto, ecn); + } else { m_freem(m); - return IPPROTO_DONE; + IP6STAT_INC(ip6s_nogif); } - - gif_input(m, af, gifp); - return IPPROTO_DONE; + return (IPPROTO_DONE); } /* - * validate outer address. + * we know that we are in IFF_UP, outer address available, and outer family + * matched the physical addr family. see gif_encapcheck(). */ -static int -gif_validate6(const struct ip6_hdr *ip6, struct gif_softc *sc, - struct ifnet *ifp) +int +in6_gif_encapcheck(const struct mbuf *m, int off, int proto, void *arg) { - struct sockaddr_in6 *src, *dst; + const struct ip6_hdr *ip6; + struct gif_softc *sc; + int ret; - src = (struct sockaddr_in6 *)sc->gif_psrc; - dst = (struct sockaddr_in6 *)sc->gif_pdst; + /* sanity check done in caller */ + sc = (struct gif_softc *)arg; + GIF_RLOCK_ASSERT(sc); /* * Check for address match. Note that the check is for an incoming * packet. We should compare the *source* address in our configuration * and the *destination* address of the packet, and vice versa. */ - if (!IN6_ARE_ADDR_EQUAL(&src->sin6_addr, &ip6->ip6_dst) || - !IN6_ARE_ADDR_EQUAL(&dst->sin6_addr, &ip6->ip6_src)) - return 0; - - /* martian filters on outer source - done in ip6_input */ + ip6 = mtod(m, const struct ip6_hdr *); + if (!IN6_ARE_ADDR_EQUAL(&sc->gif_ip6hdr->ip6_src, &ip6->ip6_dst)) + return (0); + ret = 128; + if (!IN6_ARE_ADDR_EQUAL(&sc->gif_ip6hdr->ip6_dst, &ip6->ip6_src)) { + if ((sc->gif_options & GIF_IGNORE_SOURCE) == 0) + return (0); + } else + ret += 128; /* ingress filters on outer source */ - if ((GIF2IFP(sc)->if_flags & IFF_LINK2) == 0 && ifp) { - struct sockaddr_in6 sin6; - struct rtentry *rt; + if ((GIF2IFP(sc)->if_flags & IFF_LINK2) == 0) { + struct nhop6_basic nh6; - bzero(&sin6, sizeof(sin6)); - sin6.sin6_family = AF_INET6; - sin6.sin6_len = sizeof(struct sockaddr_in6); - sin6.sin6_addr = ip6->ip6_src; - sin6.sin6_scope_id = 0; /* XXX */ + /* XXX empty scope id */ + if (fib6_lookup_nh_basic(sc->gif_fibnum, &ip6->ip6_src, 0, 0, 0, + &nh6) != 0) + return (0); - rt = in6_rtalloc1((struct sockaddr *)&sin6, 0, 0UL, - sc->gif_fibnum); - if (!rt || rt->rt_ifp != ifp) { -#if 0 - char ip6buf[INET6_ADDRSTRLEN]; - log(LOG_WARNING, "%s: packet from %s dropped " - "due to ingress filter\n", if_name(GIF2IFP(sc)), - ip6_sprintf(ip6buf, &sin6.sin6_addr)); -#endif - if (rt) - RTFREE_LOCKED(rt); - return 0; - } - RTFREE_LOCKED(rt); + if (nh6.nh_ifp != m->m_pkthdr.rcvif) + return (0); } - - return 128 * 2; -} - -/* - * we know that we are in IFF_UP, outer address available, and outer family - * matched the physical addr family. see gif_encapcheck(). - * sanity check for arg should have been done in the caller. - */ -int -gif_encapcheck6(const struct mbuf *m, int off, int proto, void *arg) -{ - struct ip6_hdr ip6; - struct gif_softc *sc; - struct ifnet *ifp; - - /* sanity check done in caller */ - sc = (struct gif_softc *)arg; - - /* LINTED const cast */ - m_copydata(m, 0, sizeof(ip6), (caddr_t)&ip6); - ifp = ((m->m_flags & M_PKTHDR) != 0) ? m->m_pkthdr.rcvif : NULL; - - return gif_validate6(&ip6, sc, ifp); + return (ret); } int in6_gif_attach(struct gif_softc *sc) { - sc->encap_cookie6 = encap_attach_func(AF_INET6, -1, gif_encapcheck, - (void *)&in6_gif_protosw, sc); - if (sc->encap_cookie6 == NULL) - return EEXIST; - return 0; -} - -int -in6_gif_detach(struct gif_softc *sc) -{ - int error; - error = encap_detach(sc->encap_cookie6); - if (error == 0) - sc->encap_cookie6 = NULL; - return error; + KASSERT(sc->gif_ecookie == NULL, ("gif_ecookie isn't NULL")); + sc->gif_ecookie = encap_attach_func(AF_INET6, -1, gif_encapcheck, + (void *)&in6_gif_protosw, sc); + if (sc->gif_ecookie == NULL) + return (EEXIST); + return (0); } |