From: dlg Date: Sat, 10 Feb 2018 08:12:01 +0000 (+0000) Subject: rework gif to be more consistent. X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=12ed6a17f20ad5bc7c4f14610feda2f03f54f318;p=openbsd rework gif to be more consistent. while here, give us support for mpls in gif on ipv6. this moves all the gif handling into if_gif, eg, the mpls handling is no longer in ip_etherip.c. ok claudio@ --- diff --git a/sys/net/if_gif.c b/sys/net/if_gif.c index f613e4da4d1..6fc91735568 100644 --- a/sys/net/if_gif.c +++ b/sys/net/if_gif.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_gif.c,v 1.108 2018/01/12 02:25:27 dlg Exp $ */ +/* $OpenBSD: if_gif.c,v 1.109 2018/02/10 08:12:01 dlg Exp $ */ /* $KAME: if_gif.c,v 1.43 2001/02/20 08:51:07 itojun Exp $ */ /* @@ -48,7 +48,7 @@ #include #include #include -#include +#include #ifdef INET6 #include @@ -64,7 +64,7 @@ #endif #ifdef MPLS -#include +#include #endif #include "pf.h" @@ -76,29 +76,69 @@ #define GIF_MTU_MIN (1280) /* Minimum MTU */ #define GIF_MTU_MAX (8192) /* Maximum MTU */ +union gif_addr { + struct in6_addr in6; + struct in_addr in4; +}; + +struct gif_tunnel { + RBT_ENTRY(gif_tunnel) t_entry; + + union gif_addr t_src; +#define t_src4 t_src.in4 +#define t_src6 t_src.in6 + union gif_addr t_dst; +#define t_dst4 t_dst.in4 +#define t_dst6 t_dst.in6 + u_int t_rtableid; + + sa_family_t t_af; +}; + +RBT_HEAD(gif_tree, gif_tunnel); + +static inline int gif_cmp(const struct gif_tunnel *, + const struct gif_tunnel *); + +RBT_PROTOTYPE(gif_tree, gif_tunnel, t_entry, gif_cmp); + +struct gif_softc { + struct gif_tunnel sc_tunnel; /* must be first */ + struct ifnet sc_if; + int sc_ttl; +}; + +struct gif_tree gif_tree = RBT_INITIALIZER(); + void gifattach(int); int gif_clone_create(struct if_clone *, int); int gif_clone_destroy(struct ifnet *); -int gif_checkloop(struct ifnet *, struct mbuf *); + void gif_start(struct ifnet *); int gif_ioctl(struct ifnet *, u_long, caddr_t); int gif_output(struct ifnet *, struct mbuf *, struct sockaddr *, struct rtentry *); +int gif_send(struct gif_softc *, struct mbuf *, uint8_t, uint8_t, uint8_t); +int gif_up(struct gif_softc *); +int gif_down(struct gif_softc *); +int gif_set_tunnel(struct gif_softc *, struct if_laddrreq *); +int gif_get_tunnel(struct gif_softc *, struct if_laddrreq *); +int gif_del_tunnel(struct gif_softc *); int in_gif_output(struct ifnet *, int, struct mbuf **); int in6_gif_output(struct ifnet *, int, struct mbuf **); +int gif_input(struct gif_tunnel *, struct mbuf **, int *, int, int, + uint8_t, uint8_t); /* * gif global variable definitions */ -struct gif_softc_head gif_softc_list; struct if_clone gif_cloner = IF_CLONE_INITIALIZER("gif", gif_clone_create, gif_clone_destroy); void gifattach(int count) { - LIST_INIT(&gif_softc_list); if_clone_attach(&gif_cloner); } @@ -106,29 +146,33 @@ int gif_clone_create(struct if_clone *ifc, int unit) { struct gif_softc *sc; + struct ifnet *ifp; sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK|M_ZERO); - snprintf(sc->gif_if.if_xname, sizeof sc->gif_if.if_xname, - "%s%d", ifc->ifc_name, unit); - sc->gif_if.if_mtu = GIF_MTU; - sc->gif_if.if_flags = IFF_POINTOPOINT | IFF_MULTICAST; - sc->gif_if.if_xflags = IFXF_CLONED; - sc->gif_if.if_ioctl = gif_ioctl; - sc->gif_if.if_start = gif_start; - sc->gif_if.if_output = gif_output; - sc->gif_if.if_rtrequest = p2p_rtrequest; - sc->gif_if.if_type = IFT_GIF; - IFQ_SET_MAXLEN(&sc->gif_if.if_snd, IFQ_MAXLEN); - sc->gif_if.if_softc = sc; - if_attach(&sc->gif_if); - if_alloc_sadl(&sc->gif_if); + ifp = &sc->sc_if; + + sc->sc_ttl = ip_defttl; + + snprintf(ifp->if_xname, sizeof(ifp->if_xname), + "%s%d", ifc->ifc_name, unit); + + ifp->if_mtu = GIF_MTU; + ifp->if_flags = IFF_POINTOPOINT | IFF_MULTICAST; + ifp->if_xflags = IFXF_CLONED; + ifp->if_ioctl = gif_ioctl; + ifp->if_start = gif_start; + ifp->if_output = gif_output; + ifp->if_rtrequest = p2p_rtrequest; + ifp->if_type = IFT_GIF; + IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN); + ifp->if_softc = sc; + + if_attach(ifp); + if_alloc_sadl(ifp); #if NBPFILTER > 0 - bpfattach(&sc->gif_if.if_bpf, &sc->gif_if, DLT_LOOP, sizeof(u_int32_t)); + bpfattach(&ifp->if_bpf, ifp, DLT_LOOP, sizeof(uint32_t)); #endif - NET_LOCK(); - LIST_INSERT_HEAD(&gif_softc_list, sc, gif_list); - NET_UNLOCK(); return (0); } @@ -138,596 +182,703 @@ gif_clone_destroy(struct ifnet *ifp) { struct gif_softc *sc = ifp->if_softc; - NET_LOCK(); - LIST_REMOVE(sc, gif_list); - NET_UNLOCK(); + if (ISSET(ifp->if_flags, IFF_RUNNING)) { + NET_LOCK(); + gif_down(sc); + NET_UNLOCK(); + } if_detach(ifp); - if (sc->gif_psrc) - free((caddr_t)sc->gif_psrc, M_IFADDR, 0); - sc->gif_psrc = NULL; - if (sc->gif_pdst) - free((caddr_t)sc->gif_pdst, M_IFADDR, 0); - sc->gif_pdst = NULL; free(sc, M_DEVBUF, sizeof(*sc)); + return (0); } void gif_start(struct ifnet *ifp) { - struct gif_softc *sc = (struct gif_softc*)ifp; + struct gif_softc *sc = ifp->if_softc; struct mbuf *m; +#if NBPFILTER > 0 + caddr_t if_bpf; +#endif + uint8_t proto, ttl, tos; + int ttloff, tttl; - for (;;) { - IFQ_DEQUEUE(&ifp->if_snd, m); - if (m == NULL) - break; - - /* is interface up and usable? */ - if (!(ifp->if_flags & IFF_UP) || - sc->gif_psrc == NULL || sc->gif_pdst == NULL || - sc->gif_psrc->sa_family != sc->gif_pdst->sa_family) { - m_freem(m); - continue; - } + tttl = sc->sc_ttl; + while ((m = ifq_dequeue(&ifp->if_snd)) != NULL) { #if NBPFILTER > 0 - if (ifp->if_bpf) { - bpf_mtap_af(ifp->if_bpf, m->m_pkthdr.ph_family, m, + if_bpf = ifp->if_bpf; + if (if_bpf) { + bpf_mtap_af(if_bpf, m->m_pkthdr.ph_family, m, BPF_DIRECTION_OUT); } #endif - if (gif_encap(ifp, &m, m->m_pkthdr.ph_family) != 0) - continue; + switch (m->m_pkthdr.ph_family) { + case AF_INET: { + struct ip *ip; + + m = m_pullup(m, sizeof(*ip)); + if (m == NULL) + continue; - /* XXX we should cache the outgoing route */ + ip = mtod(m, struct ip *); + tos = ip->ip_tos; - switch (sc->gif_psrc->sa_family) { - case AF_INET: - ip_send(m); + ttloff = offsetof(struct ip, ip_ttl); + proto = IPPROTO_IPV4; break; + } #ifdef INET6 - case AF_INET6: - ip6_send(m); + case AF_INET6: { + struct ip6_hdr *ip6; + + m = m_pullup(m, sizeof(*ip6)); + if (m == NULL) + continue; + + ip6 = mtod(m, struct ip6_hdr *); + tos = ntohl(ip6->ip6_flow >> 20); + + ttloff = offsetof(struct ip6_hdr, ip6_hlim); + proto = IPPROTO_IPV6; break; + } #endif - default: - m_freem(m); +#ifdef MPLS + case AF_MPLS: + ttloff = 3; + tos = 0; + + proto = IPPROTO_MPLS; break; +#endif + default: + unhandled_af(m->m_pkthdr.ph_family); } + + if (tttl == -1) { + m = m_pullup(m, ttloff + 1); + if (m == NULL) + continue; + + ttl = *(m->m_data + ttloff); + } else + ttl = tttl; + + gif_send(sc, m, proto, ttl, tos); } } int -gif_encap(struct ifnet *ifp, struct mbuf **mp, sa_family_t af) +gif_send(struct gif_softc *sc, struct mbuf *m, + uint8_t proto, uint8_t ttl, uint8_t otos) { - struct gif_softc *sc = (struct gif_softc*)ifp; - int error = 0; + uint8_t itos = 0; - /* - * Remove multicast and broadcast flags or encapsulated packet - * ends up as multicast or broadcast packet. - */ - (*mp)->m_flags &= ~(M_BCAST|M_MCAST); + m->m_flags &= ~(M_BCAST|M_MCAST); + m->m_pkthdr.ph_rtableid = sc->sc_tunnel.t_rtableid; - /* - * Encapsulate packet. Add IP or IP6 header depending on tunnel AF. - */ - switch (sc->gif_psrc->sa_family) { - case AF_INET: - error = in_gif_output(ifp, af, mp); +#if NPF > 0 + pf_pkt_addr_changed(m); +#endif + + ip_ecn_ingress(ECN_ALLOWED, &otos, &itos); + + switch (sc->sc_tunnel.t_af) { + case AF_INET: { + struct ip *ip; + + if (in_nullhost(sc->sc_tunnel.t_dst4)) + goto drop; + + m = m_prepend(m, sizeof(*ip), M_DONTWAIT); + if (m == NULL) + return (-1); + + ip = mtod(m, struct ip *); + ip->ip_off = 0; /* DF ? */ + ip->ip_tos = otos; + ip->ip_len = htons(m->m_pkthdr.len); + ip->ip_ttl = ttl; + ip->ip_p = proto; + ip->ip_src = sc->sc_tunnel.t_src4; + ip->ip_dst = sc->sc_tunnel.t_dst4; + + ip_send(m); break; + } #ifdef INET6 - case AF_INET6: - error = in6_gif_output(ifp, af, mp); + case AF_INET6: { + struct ip6_hdr *ip6; + int len = m->m_pkthdr.len; + uint32_t flow; + + if (IN6_IS_ADDR_UNSPECIFIED(&sc->sc_tunnel.t_dst6)) + goto drop; + + m = m_prepend(m, sizeof(*ip6), M_DONTWAIT); + if (m == NULL) + return (-1); + + flow = otos << 20; + if (ISSET(m->m_pkthdr.ph_flowid, M_FLOWID_VALID)) + flow |= m->m_pkthdr.ph_flowid & M_FLOWID_MASK; + + ip6 = mtod(m, struct ip6_hdr *); + ip6->ip6_flow = htonl(flow); + ip6->ip6_vfc |= IPV6_VERSION; + ip6->ip6_plen = htons(len); + ip6->ip6_nxt = IPPROTO_GRE; + ip6->ip6_hlim = ttl; + ip6->ip6_src = sc->sc_tunnel.t_src6; + ip6->ip6_dst = sc->sc_tunnel.t_dst6; + + ip6_send(m); break; + } #endif default: - m_freemp(mp); - error = EAFNOSUPPORT; - break; + unhandled_af(sc->sc_tunnel.t_af); } - if (error) - return (error); + return (0); - error = gif_checkloop(ifp, *mp); - return (error); +drop: + m_freem(m); + return (0); } int gif_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, struct rtentry *rt) { - struct gif_softc *sc = (struct gif_softc*)ifp; + struct m_tag *mtag; int error = 0; - if (!(ifp->if_flags & IFF_UP) || - sc->gif_psrc == NULL || sc->gif_pdst == NULL || - sc->gif_psrc->sa_family != sc->gif_pdst->sa_family) { - m_freem(m); + if (!ISSET(ifp->if_flags, IFF_RUNNING)) { error = ENETDOWN; - goto end; + goto drop; + } + + switch (dst->sa_family) { + case AF_INET: +#ifdef INET6 + case AF_INET6: +#endif +#ifdef MPLS + case AF_MPLS: +#endif + break; + default: + error = EAFNOSUPPORT; + goto drop; + } + + /* Try to limit infinite recursion through misconfiguration. */ + for (mtag = m_tag_find(m, PACKET_TAG_GRE, NULL); mtag; + mtag = m_tag_find(m, PACKET_TAG_GRE, mtag)) { + if (memcmp((caddr_t)(mtag + 1), &ifp->if_index, + sizeof(ifp->if_index)) == 0) { + error = EIO; + goto drop; + } + } + + mtag = m_tag_get(PACKET_TAG_GRE, sizeof(ifp->if_index), M_NOWAIT); + if (mtag == NULL) { + error = ENOBUFS; + goto drop; } m->m_pkthdr.ph_family = dst->sa_family; error = if_enqueue(ifp, m); -end: if (error) ifp->if_oerrors++; return (error); + +drop: + m_freem(m); + return (error); } int -gif_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) +gif_up(struct gif_softc *sc) { - struct gif_softc *sc = (struct gif_softc*)ifp; - struct ifreq *ifr = (struct ifreq *)data; - int error = 0, size; - struct sockaddr *dst, *src; - struct sockaddr *sa; - struct gif_softc *sc2; + if (sc->sc_tunnel.t_af == AF_UNSPEC) + return (EDESTADDRREQ); - switch (cmd) { - case SIOCSIFADDR: - break; + NET_ASSERT_LOCKED(); + if (RBT_INSERT(gif_tree, &gif_tree, &sc->sc_tunnel) != NULL) + return (EADDRINUSE); - case SIOCSIFDSTADDR: - break; + SET(sc->sc_if.if_flags, IFF_RUNNING); - case SIOCADDMULTI: - case SIOCDELMULTI: - break; + return (0); +} - case SIOCSLIFPHYADDR: - src = sstosa(&(((struct if_laddrreq *)data)->addr)); - dst = sstosa(&(((struct if_laddrreq *)data)->dstaddr)); +int +gif_down(struct gif_softc *sc) +{ + NET_ASSERT_LOCKED(); - /* sa_family must be equal */ - if (src->sa_family != dst->sa_family) - return (EINVAL); + RBT_REMOVE(gif_tree, &gif_tree, &sc->sc_tunnel); - /* validate sa_len */ - switch (src->sa_family) { - case AF_INET: - if (src->sa_len != sizeof(struct sockaddr_in)) - return (EINVAL); - break; -#ifdef INET6 - case AF_INET6: - if (src->sa_len != sizeof(struct sockaddr_in6)) - return (EINVAL); - break; -#endif - default: - return (EAFNOSUPPORT); - } - switch (dst->sa_family) { - case AF_INET: - if (dst->sa_len != sizeof(struct sockaddr_in)) - return (EINVAL); - break; -#ifdef INET6 - case AF_INET6: - if (dst->sa_len != sizeof(struct sockaddr_in6)) - return (EINVAL); - break; -#endif - default: - return (EAFNOSUPPORT); - } + CLR(sc->sc_if.if_flags, IFF_RUNNING); - LIST_FOREACH(sc2, &gif_softc_list, gif_list) { - if (sc2 == sc) - continue; - if (!sc2->gif_pdst || !sc2->gif_psrc) - continue; - if (sc2->gif_pdst->sa_family != dst->sa_family || - sc2->gif_pdst->sa_len != dst->sa_len || - sc2->gif_psrc->sa_family != src->sa_family || - sc2->gif_psrc->sa_len != src->sa_len) - continue; - /* can't configure same pair of address onto two gifs */ - if (bcmp(sc2->gif_pdst, dst, dst->sa_len) == 0 && - bcmp(sc2->gif_psrc, src, src->sa_len) == 0) { - error = EADDRNOTAVAIL; - goto bad; - } - - /* can't configure multiple multi-dest interfaces */ -#define multidest(x) \ - (satosin(x)->sin_addr.s_addr == INADDR_ANY) -#ifdef INET6 -#define multidest6(x) \ - (IN6_IS_ADDR_UNSPECIFIED(&satosin6(x)->sin6_addr)) -#endif - if (dst->sa_family == AF_INET && - multidest(dst) && multidest(sc2->gif_pdst)) { - error = EADDRNOTAVAIL; - goto bad; - } -#ifdef INET6 - if (dst->sa_family == AF_INET6 && - multidest6(dst) && multidest6(sc2->gif_pdst)) { - error = EADDRNOTAVAIL; - goto bad; - } -#endif - } + /* barrier? */ - if (sc->gif_psrc) - free((caddr_t)sc->gif_psrc, M_IFADDR, 0); - sa = malloc(src->sa_len, M_IFADDR, M_WAITOK); - bcopy((caddr_t)src, (caddr_t)sa, src->sa_len); - sc->gif_psrc = sa; + return (0); +} - if (sc->gif_pdst) - free((caddr_t)sc->gif_pdst, M_IFADDR, 0); - sa = malloc(dst->sa_len, M_IFADDR, M_WAITOK); - bcopy((caddr_t)dst, (caddr_t)sa, dst->sa_len); - sc->gif_pdst = sa; +int +gif_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) +{ + struct gif_softc *sc = ifp->if_softc; + struct ifreq *ifr = (struct ifreq *)data; + int error = 0; - ifp->if_flags |= IFF_RUNNING; - if_up(ifp); /* send up RTM_IFINFO */ + switch (cmd) { + case SIOCSIFADDR: + SET(ifp->if_flags, IFF_UP); + /* FALLTHROUGH */ + case SIOCSIFFLAGS: + if (ISSET(ifp->if_flags, IFF_UP)) { + if (!ISSET(ifp->if_flags, IFF_RUNNING)) + error = gif_up(sc); + else + error = 0; + } else { + if (ISSET(ifp->if_flags, IFF_RUNNING)) + error = gif_down(sc); + } + break; - error = 0; + case SIOCADDMULTI: + case SIOCDELMULTI: break; - case SIOCDIFPHYADDR: - if (sc->gif_psrc) { - free((caddr_t)sc->gif_psrc, M_IFADDR, 0); - sc->gif_psrc = NULL; - } - if (sc->gif_pdst) { - free((caddr_t)sc->gif_pdst, M_IFADDR, 0); - sc->gif_pdst = NULL; + case SIOCSLIFPHYADDR: + if (ISSET(ifp->if_flags, IFF_RUNNING)) { + error = EBUSY; + break; } - /* change the IFF_{UP, RUNNING} flag as well? */ + error = gif_set_tunnel(sc, (struct if_laddrreq *)data); break; - case SIOCGLIFPHYADDR: - if (sc->gif_psrc == NULL || sc->gif_pdst == NULL) { - error = EADDRNOTAVAIL; - goto bad; - } - - /* copy src */ - src = sc->gif_psrc; - dst = sstosa(&(((struct if_laddrreq *)data)->addr)); - size = sizeof(((struct if_laddrreq *)data)->addr); - if (src->sa_len > size) - return (EINVAL); - bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); - - /* copy dst */ - src = sc->gif_pdst; - dst = sstosa(&(((struct if_laddrreq *)data)->dstaddr)); - size = sizeof(((struct if_laddrreq *)data)->dstaddr); - if (src->sa_len > size) - return (EINVAL); - bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); + error = gif_get_tunnel(sc, (struct if_laddrreq *)data); break; - - case SIOCSIFFLAGS: + case SIOCDIFPHYADDR: + if (ISSET(ifp->if_flags, IFF_RUNNING)) { + error = EBUSY; + break; + } + error = gif_del_tunnel(sc); break; case SIOCSIFMTU: - if (ifr->ifr_mtu < GIF_MTU_MIN || ifr->ifr_mtu > GIF_MTU_MAX) + if (ifr->ifr_mtu < GIF_MTU_MIN || ifr->ifr_mtu > GIF_MTU_MAX) { error = EINVAL; - else - ifp->if_mtu = ifr->ifr_mtu; + break; + } + + ifp->if_mtu = ifr->ifr_mtu; break; case SIOCSLIFPHYRTABLE: + if (ISSET(ifp->if_flags, IFF_RUNNING)) { + error = EBUSY; + break; + } if (ifr->ifr_rdomainid < 0 || ifr->ifr_rdomainid > RT_TABLEID_MAX || !rtable_exists(ifr->ifr_rdomainid)) { error = EINVAL; break; } - sc->gif_rtableid = ifr->ifr_rdomainid; + sc->sc_tunnel.t_rtableid = ifr->ifr_rdomainid; break; case SIOCGLIFPHYRTABLE: - ifr->ifr_rdomainid = sc->gif_rtableid; + ifr->ifr_rdomainid = sc->sc_tunnel.t_rtableid; break; + + case SIOCSLIFPHYTTL: + if (ifr->ifr_ttl != -1 && + (ifr->ifr_ttl < 1 || ifr->ifr_ttl > 0xff)) { + error = EINVAL; + break; + } + + /* commit */ + sc->sc_ttl = ifr->ifr_ttl; + break; + case SIOCGLIFPHYTTL: + ifr->ifr_ttl = sc->sc_ttl; + break; + default: error = ENOTTY; break; } - bad: + return (error); } int -gif_checkloop(struct ifnet *ifp, struct mbuf *m) +gif_get_tunnel(struct gif_softc *sc, struct if_laddrreq *req) { - struct m_tag *mtag; + struct gif_tunnel *tunnel = &sc->sc_tunnel; + struct sockaddr *src = (struct sockaddr *)&req->addr; + struct sockaddr *dst = (struct sockaddr *)&req->dstaddr; + struct sockaddr_in *sin; +#ifdef INET6 /* ifconfig already embeds the scopeid */ + struct sockaddr_in6 *sin6; +#endif - /* - * gif may cause infinite recursion calls when misconfigured. - * We'll prevent this by detecting loops. - */ - for (mtag = m_tag_find(m, PACKET_TAG_GIF, NULL); mtag; - mtag = m_tag_find(m, PACKET_TAG_GIF, mtag)) { - if (*(struct ifnet **)(mtag + 1) == ifp) { - log(LOG_NOTICE, "gif_output: " - "recursively called too many times\n"); - m_freem(m); - return ENETUNREACH; - } - } + switch (tunnel->t_af) { + case AF_UNSPEC: + return (EADDRNOTAVAIL); + case AF_INET: + sin = (struct sockaddr_in *)src; + memset(sin, 0, sizeof(*sin)); + sin->sin_family = AF_INET; + sin->sin_len = sizeof(*sin); + sin->sin_addr = tunnel->t_src4; + + sin = (struct sockaddr_in *)dst; + memset(sin, 0, sizeof(*sin)); + sin->sin_family = AF_INET; + sin->sin_len = sizeof(*sin); + sin->sin_addr = tunnel->t_dst4; - mtag = m_tag_get(PACKET_TAG_GIF, sizeof(struct ifnet *), M_NOWAIT); - if (mtag == NULL) { - m_freem(m); - return ENOMEM; + break; + +#ifdef INET6 + case AF_INET6: + sin6 = (struct sockaddr_in6 *)src; + memset(sin6, 0, sizeof(*sin6)); + sin6->sin6_family = AF_INET6; + sin6->sin6_len = sizeof(*sin6); + in6_recoverscope(sin6, &tunnel->t_src6); + + sin6 = (struct sockaddr_in6 *)dst; + memset(sin6, 0, sizeof(*sin6)); + sin6->sin6_family = AF_INET6; + sin6->sin6_len = sizeof(*sin6); + in6_recoverscope(sin6, &tunnel->t_dst6); + + break; +#endif + default: + return (EAFNOSUPPORT); } - *(struct ifnet **)(mtag + 1) = ifp; - m_tag_prepend(m, mtag); - return 0; + + return (0); } int -in_gif_output(struct ifnet *ifp, int family, struct mbuf **m0) +gif_set_tunnel(struct gif_softc *sc, struct if_laddrreq *req) { - struct gif_softc *sc = (struct gif_softc*)ifp; - struct sockaddr_in *sin_src = satosin(sc->gif_psrc); - struct sockaddr_in *sin_dst = satosin(sc->gif_pdst); - struct tdb tdb; - struct xformsw xfs; + struct gif_tunnel *tunnel = &sc->sc_tunnel; + struct sockaddr *src = (struct sockaddr *)&req->addr; + struct sockaddr *dst = (struct sockaddr *)&req->dstaddr; + struct sockaddr_in *src4, *dst4; +#ifdef INET6 + struct sockaddr_in6 *src6, *dst6; int error; - struct mbuf *m = *m0; - - if (sin_src == NULL || sin_dst == NULL || - sin_src->sin_family != AF_INET || - sin_dst->sin_family != AF_INET) { - m_freem(m); - return EAFNOSUPPORT; - } - -#ifdef DIAGNOSTIC - if (ifp->if_rdomain != rtable_l2(m->m_pkthdr.ph_rtableid)) { - printf("%s: trying to send packet on wrong domain. " - "if %d vs. mbuf %d, AF %d\n", ifp->if_xname, - ifp->if_rdomain, rtable_l2(m->m_pkthdr.ph_rtableid), - family); - } #endif - /* setup dummy tdb. it highly depends on ipip_output() code. */ - bzero(&tdb, sizeof(tdb)); - bzero(&xfs, sizeof(xfs)); - tdb.tdb_src.sin.sin_family = AF_INET; - tdb.tdb_src.sin.sin_len = sizeof(struct sockaddr_in); - tdb.tdb_src.sin.sin_addr = sin_src->sin_addr; - tdb.tdb_dst.sin.sin_family = AF_INET; - tdb.tdb_dst.sin.sin_len = sizeof(struct sockaddr_in); - tdb.tdb_dst.sin.sin_addr = sin_dst->sin_addr; - tdb.tdb_xform = &xfs; - xfs.xf_type = -1; /* not XF_IP4 */ - - switch (family) { + /* sa_family and sa_len must be equal */ + if (src->sa_family != dst->sa_family || src->sa_len != dst->sa_len) + return (EINVAL); + + /* validate */ + switch (dst->sa_family) { case AF_INET: + if (dst->sa_len != sizeof(*dst4)) + return (EINVAL); + + src4 = (struct sockaddr_in *)src; + if (in_nullhost(src4->sin_addr) || + IN_MULTICAST(src4->sin_addr.s_addr)) + return (EINVAL); + + dst4 = (struct sockaddr_in *)dst; + /* dst4 can be 0.0.0.0 */ + if (IN_MULTICAST(dst4->sin_addr.s_addr)) + return (EINVAL); + + tunnel->t_src4 = src4->sin_addr; + tunnel->t_dst4 = dst4->sin_addr; + break; #ifdef INET6 case AF_INET6: - break; -#endif -#ifdef MPLS - case AF_MPLS: + if (dst->sa_len != sizeof(*dst6)) + return (EINVAL); + + src6 = (struct sockaddr_in6 *)src; + if (IN6_IS_ADDR_UNSPECIFIED(&src6->sin6_addr) || + IN6_IS_ADDR_MULTICAST(&src6->sin6_addr)) + return (EINVAL); + + dst6 = (struct sockaddr_in6 *)dst; + if (IN6_IS_ADDR_MULTICAST(&dst6->sin6_addr)) + return (EINVAL); + + error = in6_embedscope(&tunnel->t_src6, src6, NULL); + if (error != 0) + return (error); + + error = in6_embedscope(&tunnel->t_dst6, dst6, NULL); + if (error != 0) + return (error); + break; #endif default: -#ifdef DEBUG - printf("%s: warning: unknown family %d passed\n", __func__, - family); -#endif - m_freem(m); - return EAFNOSUPPORT; + return (EAFNOSUPPORT); } - /* encapsulate into IPv4 packet */ - *m0 = NULL; -#ifdef MPLS - if (family == AF_MPLS) - error = mplsip_output(m, &tdb, m0, IPPROTO_MPLS); - else -#endif - error = ipip_output(m, &tdb, m0, 0, 0); - if (error) - return error; - else if (*m0 == NULL) - return EFAULT; + /* commit */ + tunnel->t_af = dst->sa_family; + + return (0); +} - m = *m0; +int +gif_del_tunnel(struct gif_softc *sc) +{ + /* commit */ + sc->sc_tunnel.t_af = AF_UNSPEC; - m->m_pkthdr.ph_rtableid = sc->gif_rtableid; -#if NPF > 0 - pf_pkt_addr_changed(m); -#endif - return 0; + return (0); } int in_gif_input(struct mbuf **mp, int *offp, int proto, int af) { struct mbuf *m = *mp; - struct gif_softc *sc; - struct ifnet *gifp = NULL; + struct gif_tunnel key; struct ip *ip; - - /* IP-in-IP header is caused by tunnel mode, so skip gif lookup */ - if (m->m_flags & M_TUNNEL) { - m->m_flags &= ~M_TUNNEL; - goto inject; - } + int rv; ip = mtod(m, struct ip *); - NET_ASSERT_LOCKED(); - /* this code will be soon improved. */ - LIST_FOREACH(sc, &gif_softc_list, gif_list) { - if (sc->gif_psrc == NULL || sc->gif_pdst == NULL || - sc->gif_psrc->sa_family != AF_INET || - sc->gif_pdst->sa_family != AF_INET || - rtable_l2(sc->gif_rtableid) != - rtable_l2(m->m_pkthdr.ph_rtableid)) { - continue; - } + key.t_af = AF_INET; + key.t_src4 = ip->ip_dst; + key.t_dst4 = ip->ip_dst; - if ((sc->gif_if.if_flags & IFF_UP) == 0) - continue; + rv = gif_input(&key, mp, offp, proto, af, ip->ip_ttl, ip->ip_tos); + if (rv == -1) + rv = ipip_input(mp, offp, proto, af); - if (in_hosteq(satosin(sc->gif_psrc)->sin_addr, ip->ip_dst) && - in_hosteq(satosin(sc->gif_pdst)->sin_addr, ip->ip_src)) { - gifp = &sc->gif_if; - break; - } - } + return (rv); +} - if (gifp) { - m->m_pkthdr.ph_ifidx = gifp->if_index; - m->m_pkthdr.ph_rtableid = gifp->if_rdomain; - gifp->if_ipackets++; - gifp->if_ibytes += m->m_pkthdr.len; - /* We have a configured GIF */ - return ipip_input_if(mp, offp, proto, af, gifp); - } +#ifdef INET6 +int +in6_gif_input(struct mbuf **mp, int *offp, int proto, int af) +{ + struct mbuf *m = *mp; + struct gif_tunnel key; + struct ip6_hdr *ip6; + uint32_t flow; + int rv; + + ip6 = mtod(m, struct ip6_hdr *); -inject: - /* No GIF interface was configured */ - return ipip_input(mp, offp, proto, af); + key.t_af = AF_INET6; + key.t_src6 = ip6->ip6_dst; + key.t_dst6 = ip6->ip6_src; + + flow = ntohl(ip6->ip6_flow); + + rv = gif_input(&key, mp, offp, proto, af, ip6->ip6_hlim, + flow >> 20); + if (rv == -1) + rv = ipip_input(mp, offp, proto, af); + + return (rv); } +#endif /* INET6 */ -#ifdef INET6 int -in6_gif_output(struct ifnet *ifp, int family, struct mbuf **m0) +gif_input(struct gif_tunnel *key, struct mbuf **mp, int *offp, int proto, + int af, uint8_t ttl, uint8_t otos) { - struct gif_softc *sc = (struct gif_softc*)ifp; - struct sockaddr_in6 *sin6_src = satosin6(sc->gif_psrc); - struct sockaddr_in6 *sin6_dst = satosin6(sc->gif_pdst); - struct tdb tdb; - struct xformsw xfs; - int error; - struct mbuf *m = *m0; + struct mbuf *m = *mp; + struct gif_softc *sc; + struct ifnet *ifp; + void (*input)(struct ifnet *, struct mbuf *); + int ttloff; + uint8_t itos; + + /* IP-in-IP header is caused by tunnel mode, so skip gif lookup */ + if (m->m_flags & M_TUNNEL) { + m->m_flags &= ~M_TUNNEL; + return (-1); + } + + /* XXX What if we run transport-mode IPsec to protect gif tunnel ? */ + if (m->m_flags & (M_AUTH | M_CONF)) + return (-1); - if (sin6_src == NULL || sin6_dst == NULL || - sin6_src->sin6_family != AF_INET6 || - sin6_dst->sin6_family != AF_INET6) { - m_freem(m); - return EAFNOSUPPORT; + key->t_rtableid = m->m_pkthdr.ph_rtableid; + + sc = (struct gif_softc *)RBT_FIND(gif_tree, &gif_tree, key); + if (sc == NULL) { + memset(&key->t_dst, 0, sizeof(key->t_dst)); + sc = (struct gif_softc *)RBT_FIND(gif_tree, &gif_tree, key); + if (sc == NULL) + return (-1); } - /* setup dummy tdb. it highly depends on ipip_output() code. */ - bzero(&tdb, sizeof(tdb)); - bzero(&xfs, sizeof(xfs)); - tdb.tdb_src.sin6.sin6_family = AF_INET6; - tdb.tdb_src.sin6.sin6_len = sizeof(struct sockaddr_in6); - tdb.tdb_src.sin6.sin6_addr = sin6_src->sin6_addr; - tdb.tdb_src.sin6.sin6_scope_id = sin6_src->sin6_scope_id; - tdb.tdb_dst.sin6.sin6_family = AF_INET6; - tdb.tdb_dst.sin6.sin6_len = sizeof(struct sockaddr_in6); - tdb.tdb_dst.sin6.sin6_addr = sin6_dst->sin6_addr; - tdb.tdb_src.sin6.sin6_scope_id = sin6_dst->sin6_scope_id; - tdb.tdb_xform = &xfs; - xfs.xf_type = -1; /* not XF_IP4 */ - - switch (family) { - case AF_INET: + switch (proto) { + case IPPROTO_IPV4: { + struct ip *ip; + + m = m_pullup(m, sizeof(*ip)); + if (m == NULL) + return (IPPROTO_DONE); + + ip = mtod(m, struct ip *); + + itos = ip->ip_tos; + if (ip_ecn_egress(ECN_ALLOWED, &otos, &itos) == 0) + goto drop; + + ip->ip_tos = itos; + + m->m_pkthdr.ph_family = AF_INET; + input = ipv4_input; + ttloff = offsetof(struct ip, ip_ttl); break; + } #ifdef INET6 - case AF_INET6: + case IPPROTO_IPV6: { + struct ip6_hdr *ip6; + + m = m_pullup(m, sizeof(*ip6)); + if (m == NULL) + return (IPPROTO_DONE); + + ip6 = mtod(m, struct ip6_hdr *); + + itos = ntohl(ip6->ip6_flow) >> 20; + if (!ip_ecn_egress(ECN_ALLOWED, &otos, &itos)) + goto drop; + + CLR(ip6->ip6_flow, htonl(0xff << 20)); + SET(ip6->ip6_flow, htonl(itos << 20)); + + m->m_pkthdr.ph_family = AF_INET6; + input = ipv6_input; + ttloff = offsetof(struct ip6_hdr, ip6_hlim); break; -#endif + } +#endif /* INET6 */ #ifdef MPLS - case AF_MPLS: + case IPPROTO_MPLS: + m->m_pkthdr.ph_family = AF_MPLS; + input = mpls_input; + ttloff = 3; break; -#endif +#endif /* MPLS */ default: -#ifdef DEBUG - printf("%s: warning: unknown family %d passed\n", __func__, - family); -#endif - m_freem(m); - return EAFNOSUPPORT; + return (-1); } - /* encapsulate into IPv6 packet */ - *m0 = NULL; -#ifdef MPLS - if (family == AF_MPLS) - error = mplsip_output(m, &tdb, m0, IPPROTO_MPLS); - else -#endif - error = ipip_output(m, &tdb, m0, 0, 0); - if (error) - return error; - else if (*m0 == NULL) - return EFAULT; + m_adj(m, *offp); - m = *m0; + if (sc->sc_ttl == -1) { + m = m_pullup(m, ttloff + 1); + if (m == NULL) + return (IPPROTO_DONE); + + *(m->m_data + ttloff) = ttl; + } + + ifp = &sc->sc_if; + + m->m_flags &= ~(M_MCAST|M_BCAST); + m->m_pkthdr.ph_ifidx = ifp->if_index; + m->m_pkthdr.ph_rtableid = ifp->if_rdomain; #if NPF > 0 pf_pkt_addr_changed(m); #endif - return 0; + + ifp->if_ipackets++; + ifp->if_ibytes += m->m_pkthdr.len; + +#if NBPFILTER > 0 + { + caddr_t if_bpf = ifp->if_bpf; + if (if_bpf) { + bpf_mtap_af(ifp->if_bpf, m->m_pkthdr.ph_family, + m, BPF_DIRECTION_IN); + } + } +#endif + + (*input)(ifp, m); + return (IPPROTO_DONE); + + drop: + m_freem(m); + return (IPPROTO_DONE); } -int -in6_gif_input(struct mbuf **mp, int *offp, int proto, int af) +static inline int +gif_ip_cmp(int af, const union gif_addr *a, const union gif_addr *b) { - struct mbuf *m = *mp; - struct gif_softc *sc; - struct ifnet *gifp = NULL; - struct ip6_hdr *ip6; - struct sockaddr_in6 src, dst; - struct sockaddr_in6 *psrc, *pdst; + switch (af) { +#ifdef INET6 + case AF_INET6: + return (memcmp(&a->in6, &b->in6, sizeof(a->in6))); +#endif /* INET6 */ + case AF_INET: + return (memcmp(&a->in4, &b->in4, sizeof(a->in4))); + default: + panic("%s: unsupported af %d\n", __func__, af); + } - /* XXX What if we run transport-mode IPsec to protect gif tunnel ? */ - if (m->m_flags & (M_AUTH | M_CONF)) - goto inject; + return (0); +} - ip6 = mtod(m, struct ip6_hdr *); - in6_recoverscope(&src, &ip6->ip6_src); - in6_recoverscope(&dst, &ip6->ip6_dst); - NET_ASSERT_LOCKED(); - LIST_FOREACH(sc, &gif_softc_list, gif_list) { - if (sc->gif_psrc == NULL || sc->gif_pdst == NULL || - sc->gif_psrc->sa_family != AF_INET6 || - sc->gif_pdst->sa_family != AF_INET6) { - continue; - } +static inline int +gif_cmp(const struct gif_tunnel *a, const struct gif_tunnel *b) +{ + int rv; - if ((sc->gif_if.if_flags & IFF_UP) == 0) - continue; + /* sort by routing table */ + if (a->t_rtableid > b->t_rtableid) + return (1); + if (a->t_rtableid < b->t_rtableid) + return (-1); - psrc = satosin6(sc->gif_psrc); - pdst = satosin6(sc->gif_pdst); + /* sort by address */ + if (a->t_af > b->t_af) + return (1); + if (a->t_af < b->t_af) + return (-1); - if (IN6_ARE_ADDR_EQUAL(&psrc->sin6_addr, &dst.sin6_addr) && - psrc->sin6_scope_id == dst.sin6_scope_id && - IN6_ARE_ADDR_EQUAL(&pdst->sin6_addr, &src.sin6_addr) && - pdst->sin6_scope_id == src.sin6_scope_id) { - gifp = &sc->gif_if; - break; - } - } + rv = gif_ip_cmp(a->t_af, &a->t_dst, &b->t_dst); + if (rv != 0) + return (rv); - if (gifp) { - m->m_pkthdr.ph_ifidx = gifp->if_index; - gifp->if_ipackets++; - gifp->if_ibytes += m->m_pkthdr.len; - return ipip_input_if(mp, offp, proto, af, gifp); - } + rv = gif_ip_cmp(a->t_af, &a->t_src, &b->t_src); + if (rv != 0) + return (rv); -inject: - /* No GIF tunnel configured */ - return ipip_input(mp, offp, proto, af); + return (0); } -#endif /* INET6 */ + +RBT_GENERATE(gif_tree, gif_tunnel, t_entry, gif_cmp); diff --git a/sys/net/if_gif.h b/sys/net/if_gif.h index 96cd3abb428..2aaac537674 100644 --- a/sys/net/if_gif.h +++ b/sys/net/if_gif.h @@ -1,4 +1,4 @@ -/* $OpenBSD: if_gif.h,v 1.17 2017/04/14 20:46:31 bluhm Exp $ */ +/* $OpenBSD: if_gif.h,v 1.18 2018/02/10 08:12:01 dlg Exp $ */ /* $KAME: if_gif.h,v 1.17 2000/09/11 11:36:41 sumikawa Exp $ */ /* @@ -37,18 +37,6 @@ #ifndef _NET_IF_GIF_H_ #define _NET_IF_GIF_H_ -struct gif_softc { - struct ifnet gif_if; /* common area */ - struct sockaddr *gif_psrc; /* Physical src addr */ - struct sockaddr *gif_pdst; /* Physical dst addr */ - u_int gif_rtableid; - LIST_ENTRY(gif_softc) gif_list; /* list of all gifs */ -}; - -extern LIST_HEAD(gif_softc_head, gif_softc) gif_softc_list; - -int gif_encap(struct ifnet *, struct mbuf **, sa_family_t); - int in_gif_input(struct mbuf **, int *, int, int); int in6_gif_input(struct mbuf **, int *, int, int); diff --git a/sys/netinet/in_proto.c b/sys/netinet/in_proto.c index 54ad512571d..e50680e6f04 100644 --- a/sys/netinet/in_proto.c +++ b/sys/netinet/in_proto.c @@ -1,4 +1,4 @@ -/* $OpenBSD: in_proto.c,v 1.89 2018/02/07 01:09:57 dlg Exp $ */ +/* $OpenBSD: in_proto.c,v 1.90 2018/02/10 08:12:01 dlg Exp $ */ /* $NetBSD: in_proto.c,v 1.14 1996/02/18 18:58:32 christos Exp $ */ /* @@ -279,7 +279,7 @@ const struct protosw inetsw[] = { .pr_domain = &inetdomain, .pr_protocol = IPPROTO_MPLS, .pr_flags = PR_ATOMIC|PR_ADDR, - .pr_input = mplsip_input, + .pr_input = in_gif_input, .pr_usrreq = rip_usrreq, .pr_attach = rip_attach, .pr_detach = rip_detach, diff --git a/sys/netinet/ip_ether.c b/sys/netinet/ip_ether.c index f84a065984f..4cc850f499a 100644 --- a/sys/netinet/ip_ether.c +++ b/sys/netinet/ip_ether.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_ether.c,v 1.98 2018/01/09 06:24:15 dlg Exp $ */ +/* $OpenBSD: ip_ether.c,v 1.99 2018/02/10 08:12:01 dlg Exp $ */ /* * The author of this code is Angelos D. Keromytis (kermit@adk.gr) * @@ -26,286 +26,3 @@ * Ethernet-inside-IP processing (RFC3378). */ -#include "pf.h" - -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include - -#include - -#ifdef MPLS -#include -#endif -#if NPF > 0 -#include -#endif - -#include "bpfilter.h" - -#ifdef ENCDEBUG -#define DPRINTF(x) if (encdebug) printf x -#else -#define DPRINTF(x) -#endif - -#ifdef MPLS -void mplsip_decap(struct mbuf *, int); -struct gif_softc *mplsip_getgif(struct mbuf *); - -/* - * mplsip_input gets called when we receive an encapsulated packet. - */ -int -mplsip_input(struct mbuf **mp, int *offp, int proto, int af) -{ - switch (proto) { - case IPPROTO_MPLS: - mplsip_decap(*mp, *offp); - return IPPROTO_DONE; - default: - DPRINTF(("%s: dropped, unhandled protocol\n", __func__)); - m_freemp(mp); - return IPPROTO_DONE; - } -} - -void -mplsip_decap(struct mbuf *m, int iphlen) -{ - struct gif_softc *sc; - - /* - * Make sure there's at least one MPLS label worth of data after - * the outer IP header. - */ - if (m->m_pkthdr.len < iphlen + sizeof(struct shim_hdr)) { - DPRINTF(("%s: encapsulated packet too short\n", __func__)); - m_freem(m); - return; - } - - /* Make sure the mpls label at least is in the first mbuf. */ - if (m->m_len < iphlen + sizeof(struct shim_hdr)) { - if ((m = m_pullup(m, iphlen + sizeof(struct shim_hdr))) == - NULL) { - DPRINTF(("%s: m_pullup() failed\n", __func__)); - return; - } - } - - sc = mplsip_getgif(m); - if (sc == NULL) - return; - - /* Chop off the `outer' IP header and reschedule. */ - m_adj(m, iphlen); - - /* Reset the flags based */ - m->m_flags &= ~(M_BCAST|M_MCAST); - -#if NBPFILTER > 0 - if (sc->gif_if.if_bpf) - bpf_mtap_af(sc->gif_if.if_bpf, AF_MPLS, m, BPF_DIRECTION_IN); -#endif - - m->m_pkthdr.ph_ifidx = sc->gif_if.if_index; - m->m_pkthdr.ph_rtableid = sc->gif_if.if_rdomain; -#if NPF > 0 - pf_pkt_addr_changed(m); -#endif - - mpls_input(&sc->gif_if, m); -} - -struct gif_softc * -mplsip_getgif(struct mbuf *m) -{ - union sockaddr_union ssrc, sdst; - struct gif_softc *sc; - u_int8_t v; - - /* Copy the addresses for use later. */ - memset(&ssrc, 0, sizeof(ssrc)); - memset(&sdst, 0, sizeof(sdst)); - - v = *mtod(m, u_int8_t *); - switch (v >> 4) { - case 4: - ssrc.sa.sa_len = sdst.sa.sa_len = sizeof(struct sockaddr_in); - ssrc.sa.sa_family = sdst.sa.sa_family = AF_INET; - m_copydata(m, offsetof(struct ip, ip_src), - sizeof(struct in_addr), - (caddr_t) &ssrc.sin.sin_addr); - m_copydata(m, offsetof(struct ip, ip_dst), - sizeof(struct in_addr), - (caddr_t) &sdst.sin.sin_addr); - break; -#ifdef INET6 - case 6: - ssrc.sa.sa_len = sdst.sa.sa_len = sizeof(struct sockaddr_in6); - ssrc.sa.sa_family = sdst.sa.sa_family = AF_INET6; - m_copydata(m, offsetof(struct ip6_hdr, ip6_src), - sizeof(struct in6_addr), - (caddr_t) &ssrc.sin6.sin6_addr); - m_copydata(m, offsetof(struct ip6_hdr, ip6_dst), - sizeof(struct in6_addr), - (caddr_t) &sdst.sin6.sin6_addr); - break; -#endif /* INET6 */ - default: - DPRINTF(("%s: invalid protocol %d\n", __func__, v)); - m_freem(m); - return NULL; - } - - NET_ASSERT_LOCKED(); - /* Find appropriate gif(4) interface */ - LIST_FOREACH(sc, &gif_softc_list, gif_list) { - if ((sc->gif_psrc == NULL) || - (sc->gif_pdst == NULL) || - !(sc->gif_if.if_flags & (IFF_UP|IFF_RUNNING))) - continue; - - if (!memcmp(sc->gif_psrc, &sdst, sc->gif_psrc->sa_len) && - !memcmp(sc->gif_pdst, &ssrc, sc->gif_pdst->sa_len)) - break; - } - - /* None found. */ - if (sc == NULL) { - DPRINTF(("%s: no interface found\n", __func__)); - m_freem(m); - return NULL; - } - - return sc; -} - -int -mplsip_output(struct mbuf *m, struct tdb *tdb, struct mbuf **mp, int proto) -{ - struct ip *ipo; -#ifdef INET6 - struct ip6_hdr *ip6; -#endif /* INET6 */ - ushort hlen; - - /* Some address family sanity checks. */ - if ((tdb->tdb_src.sa.sa_family != 0) && - (tdb->tdb_src.sa.sa_family != AF_INET) && - (tdb->tdb_src.sa.sa_family != AF_INET6)) { - DPRINTF(("%s: IP in protocol-family <%d> attempted, aborting", - __func__, tdb->tdb_src.sa.sa_family)); - m_freem(m); - return EINVAL; - } - - if ((tdb->tdb_dst.sa.sa_family != AF_INET) && - (tdb->tdb_dst.sa.sa_family != AF_INET6)) { - DPRINTF(("%s: IP in protocol-family <%d> attempted, aborting", - __func__, tdb->tdb_dst.sa.sa_family)); - m_freem(m); - return EINVAL; - } - - if (tdb->tdb_dst.sa.sa_family != tdb->tdb_src.sa.sa_family) { - DPRINTF(("%s: mismatch in tunnel source and destination address" - " protocol families (%d/%d), aborting", __func__, - tdb->tdb_src.sa.sa_family, tdb->tdb_dst.sa.sa_family)); - m_freem(m); - return EINVAL; - } - - switch (tdb->tdb_dst.sa.sa_family) { - case AF_INET: - hlen = sizeof(struct ip); - break; -#ifdef INET6 - case AF_INET6: - hlen = sizeof(struct ip6_hdr); - break; -#endif /* INET6 */ - default: - DPRINTF(("%s: unsupported tunnel protocol family <%d>, " - "aborting", __func__, tdb->tdb_dst.sa.sa_family)); - m_freem(m); - return EINVAL; - } - - M_PREPEND(m, hlen, M_DONTWAIT); - if (m == NULL) { - DPRINTF(("%s: M_PREPEND failed\n", __func__)); - return ENOBUFS; - } - - /* - * Normalize mbuf so that it can be reinjected into higherlevel - * output functions (alignment also required in this function). - */ - if ((long)mtod(m, caddr_t) & 0x03) { - int off = (long)mtod(m, caddr_t) & 0x03; - if (M_LEADINGSPACE(m) < off) - panic("mplsip_output: no space for align fixup"); - m->m_data -= off; - memmove(mtod(m, caddr_t), mtod(m, caddr_t) + off, m->m_len); - } - - switch (tdb->tdb_dst.sa.sa_family) { - case AF_INET: - ipo = mtod(m, struct ip *); - - ipo->ip_v = IPVERSION; - ipo->ip_hl = 5; - ipo->ip_len = htons(m->m_pkthdr.len); - ipo->ip_ttl = ip_defttl; - ipo->ip_p = proto; - ipo->ip_tos = 0; - ipo->ip_off = 0; - ipo->ip_sum = 0; - ipo->ip_id = htons(ip_randomid()); - - /* - * We should be keeping tunnel soft-state and send back - * ICMPs as needed. - */ - - ipo->ip_src = tdb->tdb_src.sin.sin_addr; - ipo->ip_dst = tdb->tdb_dst.sin.sin_addr; - break; -#ifdef INET6 - case AF_INET6: - ip6 = mtod(m, struct ip6_hdr *); - - ip6->ip6_flow = 0; - ip6->ip6_nxt = proto; - ip6->ip6_vfc &= ~IPV6_VERSION_MASK; - ip6->ip6_vfc |= IPV6_VERSION; - ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(*ip6)); - ip6->ip6_hlim = ip_defttl; - ip6->ip6_dst = tdb->tdb_dst.sin6.sin6_addr; - ip6->ip6_src = tdb->tdb_src.sin6.sin6_addr; - break; -#endif /* INET6 */ - } - - *mp = m; - - return 0; -} -#endif /* MPLS */ diff --git a/sys/netinet6/in6_proto.c b/sys/netinet6/in6_proto.c index 1435acc15c0..3be98fd1b9a 100644 --- a/sys/netinet6/in6_proto.c +++ b/sys/netinet6/in6_proto.c @@ -1,4 +1,4 @@ -/* $OpenBSD: in6_proto.c,v 1.101 2018/02/07 22:30:59 dlg Exp $ */ +/* $OpenBSD: in6_proto.c,v 1.102 2018/02/10 08:12:01 dlg Exp $ */ /* $KAME: in6_proto.c,v 1.66 2000/10/10 15:35:47 itojun Exp $ */ /* @@ -97,7 +97,6 @@ #include "gif.h" #if NGIF > 0 -#include #include #endif @@ -277,6 +276,23 @@ const struct protosw inet6sw[] = { .pr_attach = rip6_attach, .pr_detach = rip6_detach, }, +#if defined(MPLS) && NGIF > 0 +{ + .pr_type = SOCK_RAW, + .pr_domain = &inet6domain, + .pr_protocol = IPPROTO_MPLS, + .pr_flags = PR_ATOMIC|PR_ADDR, +#if NGIF > 0 + .pr_input = in6_gif_input, +#else + .pr_input = ipip_input, +#endif + .pr_ctloutput = rip6_ctloutput, + .pr_usrreq = rip6_usrreq, /* XXX */ + .pr_attach = rip6_attach, + .pr_detach = rip6_detach, +}, +#endif /* MPLS */ #if NCARP > 0 { .pr_type = SOCK_RAW,