rework gif to be more consistent.
authordlg <dlg@openbsd.org>
Sat, 10 Feb 2018 08:12:01 +0000 (08:12 +0000)
committerdlg <dlg@openbsd.org>
Sat, 10 Feb 2018 08:12:01 +0000 (08:12 +0000)
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@

sys/net/if_gif.c
sys/net/if_gif.h
sys/netinet/in_proto.c
sys/netinet/ip_ether.c
sys/netinet6/in6_proto.c

index f613e4d..6fc9173 100644 (file)
@@ -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 <netinet/ip_ether.h>
 #include <netinet/ip_var.h>
 #include <netinet/ip_ipip.h>
-#include <netinet/ip_ipsp.h>
+#include <netinet/ip_ecn.h>
 
 #ifdef INET6
 #include <netinet6/in6_var.h>
@@ -64,7 +64,7 @@
 #endif
 
 #ifdef MPLS
-#include <netinet/ip_ether.h>
+#include <netmpls/mpls.h>
 #endif
 
 #include "pf.h"
 #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);
index 96cd3ab..2aaac53 100644 (file)
@@ -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 $       */
 
 /*
 #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);
 
index 54ad512..e50680e 100644 (file)
@@ -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,
index f84a065..4cc850f 100644 (file)
@@ -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)
  *
  * Ethernet-inside-IP processing (RFC3378).
  */
 
-#include "pf.h"
-
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/mbuf.h>
-#include <sys/socket.h>
-#include <sys/sysctl.h>
-
-#include <net/bpf.h>
-#include <net/if.h>
-#include <net/netisr.h>
-#include <net/route.h>
-
-#include <netinet/in.h>
-#include <netinet/ip.h>
-#include <netinet/in_pcb.h>
-#include <netinet/ip_var.h>
-
-#include <netinet/ip_ether.h>
-#include <netinet/if_ether.h>
-
-#include <net/if_gif.h>
-
-#ifdef MPLS
-#include <netmpls/mpls.h>
-#endif
-#if NPF > 0
-#include <net/pfvar.h>
-#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 */
index 1435acc..3be98fd 100644 (file)
@@ -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 <netinet/ip_ether.h>
 #include <net/if_gif.h>
 #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,