From c40e45b75eb76d79a05c7fa85c1fa9b5c728a12f Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Fri, 7 Oct 2016 15:10:20 +0200 Subject: Update to FreeBSD head 2016-08-23 Git mirror commit 9fe7c416e6abb28b1398fd3e5687099846800cfd. --- freebsd/sys/netinet/in_gif.c | 421 +++++++++---------------------------------- 1 file changed, 84 insertions(+), 337 deletions(-) (limited to 'freebsd/sys/netinet/in_gif.c') diff --git a/freebsd/sys/netinet/in_gif.c b/freebsd/sys/netinet/in_gif.c index 332d7ff4..02e2efd8 100644 --- a/freebsd/sys/netinet/in_gif.c +++ b/freebsd/sys/netinet/in_gif.c @@ -1,7 +1,5 @@ #include -/* $KAME: in_gif.c,v 1.54 2001/05/14 14:02:16 itojun Exp $ */ - /*- * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. * All rights reserved. @@ -29,16 +27,19 @@ * 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. + * + * $KAME: in_gif.c,v 1.54 2001/05/14 14:02:16 itojun Exp $ */ #include __FBSDID("$FreeBSD$"); -#include #include #include #include +#include +#include #include #include #include @@ -50,6 +51,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include @@ -57,162 +59,56 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include #include #include #include +#include #ifdef INET6 #include #endif -#ifdef MROUTING -#include -#endif /* MROUTING */ - -#include +#include -static int gif_validate4(const struct ip *, struct gif_softc *, - struct ifnet *); +static int in_gif_input(struct mbuf **, int *, int); extern struct domain inetdomain; -struct protosw in_gif_protosw = { +static struct protosw in_gif_protosw = { .pr_type = SOCK_RAW, .pr_domain = &inetdomain, .pr_protocol = 0/* IPPROTO_IPV[46] */, .pr_flags = PR_ATOMIC|PR_ADDR, .pr_input = in_gif_input, - .pr_output = (pr_output_t*)rip_output, + .pr_output = rip_output, .pr_ctloutput = rip_ctloutput, .pr_usrreqs = &rip_usrreqs }; -VNET_DEFINE(int, ip_gif_ttl) = GIF_TTL; +#define GIF_TTL 30 +static VNET_DEFINE(int, ip_gif_ttl) = GIF_TTL; #define V_ip_gif_ttl VNET(ip_gif_ttl) -SYSCTL_VNET_INT(_net_inet_ip, IPCTL_GIF_TTL, gifttl, CTLFLAG_RW, +SYSCTL_INT(_net_inet_ip, IPCTL_GIF_TTL, gifttl, CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip_gif_ttl), 0, ""); int -in_gif_output(struct ifnet *ifp, int family, struct mbuf *m) +in_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_in *dst = (struct sockaddr_in *)&sc->gif_ro.ro_dst; - struct sockaddr_in *sin_src = (struct sockaddr_in *)sc->gif_psrc; - struct sockaddr_in *sin_dst = (struct sockaddr_in *)sc->gif_pdst; - struct ip iphdr; /* capsule IP header, host byte ordered */ - struct etherip_header eiphdr; - int error, len, proto; - u_int8_t tos; - - GIF_LOCK_ASSERT(sc); - - if (sin_src == NULL || sin_dst == NULL || - sin_src->sin_family != AF_INET || - sin_dst->sin_family != AF_INET) { - 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 *); - tos = ip->ip_tos; - break; - } -#endif /* INET */ -#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 *); - tos = (ntohl(ip6->ip6_flow) >> 20) & 0xff; - break; - } -#endif /* INET6 */ - 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("in_gif_output: warning: unknown family %d passed\n", - family); -#endif - m_freem(m); - return EAFNOSUPPORT; - } - - bzero(&iphdr, sizeof(iphdr)); - iphdr.ip_src = sin_src->sin_addr; - /* bidirectional configured tunnel mode */ - if (sin_dst->sin_addr.s_addr != INADDR_ANY) - iphdr.ip_dst = sin_dst->sin_addr; - else { - m_freem(m); - return ENETUNREACH; - } - iphdr.ip_p = proto; - /* version will be set in ip_output() */ - iphdr.ip_ttl = V_ip_gif_ttl; - iphdr.ip_len = m->m_pkthdr.len + sizeof(struct ip); - ip_ecn_ingress((ifp->if_flags & IFF_LINK1) ? ECN_ALLOWED : ECN_NOCARE, - &iphdr.ip_tos, &tos); + struct ip *ip; + int len; /* prepend new IP header */ len = sizeof(struct ip); #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 in_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, ("in_gif_output: unexpected misalignment")); @@ -220,212 +116,51 @@ in_gif_output(struct ifnet *ifp, int family, struct mbuf *m) m->m_len -= ETHERIP_ALIGN; } #endif - bcopy(&iphdr, mtod(m, struct ip *), sizeof(struct ip)); - - M_SETFIB(m, sc->gif_fibnum); - - if (dst->sin_family != sin_dst->sin_family || - dst->sin_addr.s_addr != sin_dst->sin_addr.s_addr) { - /* cache route doesn't match */ - bzero(dst, sizeof(*dst)); - dst->sin_family = sin_dst->sin_family; - dst->sin_len = sizeof(struct sockaddr_in); - dst->sin_addr = sin_dst->sin_addr; - if (sc->gif_ro.ro_rt) { - RTFREE(sc->gif_ro.ro_rt); - sc->gif_ro.ro_rt = NULL; - } -#if 0 - GIF2IFP(sc)->if_mtu = GIF_MTU; -#endif - } - - if (sc->gif_ro.ro_rt == NULL) { - in_rtalloc_ign(&sc->gif_ro, 0, sc->gif_fibnum); - if (sc->gif_ro.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_ro.ro_rt->rt_ifp->if_mtu - - sizeof(struct ip); -#endif + ip = mtod(m, struct ip *); + GIF_RLOCK(sc); + if (sc->gif_family != AF_INET) { + m_freem(m); + GIF_RUNLOCK(sc); + return (ENETDOWN); } + bcopy(sc->gif_iphdr, ip, sizeof(struct ip)); + GIF_RUNLOCK(sc); - m_addr_changed(m); - - error = ip_output(m, NULL, &sc->gif_ro, 0, NULL, NULL); - - if (!(GIF2IFP(sc)->if_flags & IFF_LINK0) && - sc->gif_ro.ro_rt != NULL) { - RTFREE(sc->gif_ro.ro_rt); - sc->gif_ro.ro_rt = NULL; - } + ip->ip_p = proto; + /* version will be set in ip_output() */ + ip->ip_ttl = V_ip_gif_ttl; + ip->ip_len = htons(m->m_pkthdr.len); + ip->ip_tos = ecn; - return (error); + return (ip_output(m, NULL, NULL, 0, NULL, NULL)); } -void -in_gif_input(struct mbuf *m, int off) +static int +in_gif_input(struct mbuf **mp, int *offp, int proto) { - struct ifnet *gifp = NULL; + struct mbuf *m = *mp; struct gif_softc *sc; + struct ifnet *gifp; struct ip *ip; - int af; - u_int8_t otos; - int proto; + uint8_t ecn; - ip = mtod(m, struct ip *); - proto = ip->ip_p; - - sc = (struct gif_softc *)encap_getarg(m); + sc = encap_getarg(m); if (sc == NULL) { m_freem(m); KMOD_IPSTAT_INC(ips_nogif); - return; + return (IPPROTO_DONE); } - gifp = GIF2IFP(sc); - if (gifp == NULL || (gifp->if_flags & IFF_UP) == 0) { - m_freem(m); - KMOD_IPSTAT_INC(ips_nogif); - return; - } - - otos = ip->ip_tos; - m_adj(m, off); - - switch (proto) { -#ifdef INET - case IPPROTO_IPV4: - { - struct ip *ip; - af = AF_INET; - if (m->m_len < sizeof(*ip)) { - m = m_pullup(m, sizeof(*ip)); - if (!m) - return; - } + if ((gifp->if_flags & IFF_UP) != 0) { ip = mtod(m, struct ip *); - if (ip_ecn_egress((gifp->if_flags & IFF_LINK1) ? - ECN_ALLOWED : ECN_NOCARE, - &otos, &ip->ip_tos) == 0) { - m_freem(m); - return; - } - break; - } -#endif -#ifdef INET6 - case IPPROTO_IPV6: - { - struct ip6_hdr *ip6; - u_int8_t itos, oitos; - - af = AF_INET6; - if (m->m_len < sizeof(*ip6)) { - m = m_pullup(m, sizeof(*ip6)); - if (!m) - return; - } - ip6 = mtod(m, struct ip6_hdr *); - itos = oitos = (ntohl(ip6->ip6_flow) >> 20) & 0xff; - if (ip_ecn_egress((gifp->if_flags & IFF_LINK1) ? - ECN_ALLOWED : ECN_NOCARE, - &otos, &itos) == 0) { - m_freem(m); - return; - } - if (itos != oitos) { - ip6->ip6_flow &= ~htonl(0xff << 20); - ip6->ip6_flow |= htonl((u_int32_t)itos << 20); - } - break; - } -#endif /* INET6 */ - case IPPROTO_ETHERIP: - af = AF_LINK; - break; - - default: - KMOD_IPSTAT_INC(ips_nogif); + ecn = ip->ip_tos; + m_adj(m, *offp); + gif_input(m, gifp, proto, ecn); + } else { m_freem(m); - return; - } - gif_input(m, af, gifp); - return; -} - -/* - * validate outer address. - */ -static int -gif_validate4(const struct ip *ip, struct gif_softc *sc, struct ifnet *ifp) -{ - struct sockaddr_in *src, *dst; - struct in_ifaddr *ia4; - - src = (struct sockaddr_in *)sc->gif_psrc; - dst = (struct sockaddr_in *)sc->gif_pdst; - - /* check for address match */ - if (src->sin_addr.s_addr != ip->ip_dst.s_addr || - dst->sin_addr.s_addr != ip->ip_src.s_addr) - return 0; - - /* martian filters on outer source - NOT done in ip_input! */ - if (IN_MULTICAST(ntohl(ip->ip_src.s_addr))) - return 0; - switch ((ntohl(ip->ip_src.s_addr) & 0xff000000) >> 24) { - case 0: case 127: case 255: - return 0; - } - - /* reject packets with broadcast on source */ - /* XXXRW: should use hash lists? */ - IN_IFADDR_RLOCK(); - TAILQ_FOREACH(ia4, &V_in_ifaddrhead, ia_link) { - if ((ia4->ia_ifa.ifa_ifp->if_flags & IFF_BROADCAST) == 0) - continue; - if (ip->ip_src.s_addr == ia4->ia_broadaddr.sin_addr.s_addr) { - IN_IFADDR_RUNLOCK(); - return 0; - } - } - IN_IFADDR_RUNLOCK(); - - /* ingress filters on outer source */ - if ((GIF2IFP(sc)->if_flags & IFF_LINK2) == 0 && ifp) { - struct sockaddr_in sin; - struct rtentry *rt; - - bzero(&sin, sizeof(sin)); - sin.sin_family = AF_INET; - sin.sin_len = sizeof(struct sockaddr_in); - sin.sin_addr = ip->ip_src; - /* XXX MRT check for the interface we would use on output */ - rt = in_rtalloc1((struct sockaddr *)&sin, 0, - 0UL, sc->gif_fibnum); - if (!rt || rt->rt_ifp != ifp) { -#if 0 - log(LOG_WARNING, "%s: packet from 0x%x dropped " - "due to ingress filter\n", if_name(GIF2IFP(sc)), - (u_int32_t)ntohl(sin.sin_addr.s_addr)); -#endif - if (rt) - RTFREE_LOCKED(rt); - return 0; - } - RTFREE_LOCKED(rt); + KMOD_IPSTAT_INC(ips_nogif); } - - return 32 * 2; + return (IPPROTO_DONE); } /* @@ -433,39 +168,51 @@ gif_validate4(const struct ip *ip, struct gif_softc *sc, struct ifnet *ifp) * matched the physical addr family. see gif_encapcheck(). */ int -gif_encapcheck4(const struct mbuf *m, int off, int proto, void *arg) +in_gif_encapcheck(const struct mbuf *m, int off, int proto, void *arg) { - struct ip ip; + const struct ip *ip; struct gif_softc *sc; - struct ifnet *ifp; + int ret; /* sanity check done in caller */ sc = (struct gif_softc *)arg; + GIF_RLOCK_ASSERT(sc); - /* LINTED const cast */ - m_copydata(m, 0, sizeof(ip), (caddr_t)&ip); - ifp = ((m->m_flags & M_PKTHDR) != 0) ? m->m_pkthdr.rcvif : NULL; + /* check for address match */ + ip = mtod(m, const struct ip *); + if (sc->gif_iphdr->ip_src.s_addr != ip->ip_dst.s_addr) + return (0); + ret = 32; + if (sc->gif_iphdr->ip_dst.s_addr != ip->ip_src.s_addr) { + if ((sc->gif_options & GIF_IGNORE_SOURCE) == 0) + return (0); + } else + ret += 32; - return gif_validate4(&ip, sc, ifp); -} + /* ingress filters on outer source */ + if ((GIF2IFP(sc)->if_flags & IFF_LINK2) == 0) { + struct nhop4_basic nh4; + struct in_addr dst; -int -in_gif_attach(struct gif_softc *sc) -{ - sc->encap_cookie4 = encap_attach_func(AF_INET, -1, gif_encapcheck, - &in_gif_protosw, sc); - if (sc->encap_cookie4 == NULL) - return EEXIST; - return 0; + dst = ip->ip_src; + + if (fib4_lookup_nh_basic(sc->gif_fibnum, dst, 0, 0, &nh4) != 0) + return (0); + + if (nh4.nh_ifp != m->m_pkthdr.rcvif) + return (0); + } + return (ret); } int -in_gif_detach(struct gif_softc *sc) +in_gif_attach(struct gif_softc *sc) { - int error; - error = encap_detach(sc->encap_cookie4); - if (error == 0) - sc->encap_cookie4 = NULL; - return error; + KASSERT(sc->gif_ecookie == NULL, ("gif_ecookie isn't NULL")); + sc->gif_ecookie = encap_attach_func(AF_INET, -1, gif_encapcheck, + &in_gif_protosw, sc); + if (sc->gif_ecookie == NULL) + return (EEXIST); + return (0); } -- cgit v1.2.3