LCOV - code coverage report
Current view: top level - net - if_gif.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 381 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 18 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*      $OpenBSD: if_gif.c,v 1.116 2018/04/18 13:24:07 bluhm Exp $      */
       2             : /*      $KAME: if_gif.c,v 1.43 2001/02/20 08:51:07 itojun Exp $ */
       3             : 
       4             : /*
       5             :  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
       6             :  * All rights reserved.
       7             :  *
       8             :  * Redistribution and use in source and binary forms, with or without
       9             :  * modification, are permitted provided that the following conditions
      10             :  * are met:
      11             :  * 1. Redistributions of source code must retain the above copyright
      12             :  *    notice, this list of conditions and the following disclaimer.
      13             :  * 2. Redistributions in binary form must reproduce the above copyright
      14             :  *    notice, this list of conditions and the following disclaimer in the
      15             :  *    documentation and/or other materials provided with the distribution.
      16             :  * 3. Neither the name of the project nor the names of its contributors
      17             :  *    may be used to endorse or promote products derived from this software
      18             :  *    without specific prior written permission.
      19             :  *
      20             :  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
      21             :  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      22             :  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      23             :  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
      24             :  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
      25             :  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
      26             :  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      27             :  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
      28             :  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
      29             :  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      30             :  * SUCH DAMAGE.
      31             :  */
      32             : 
      33             : #include <sys/param.h>
      34             : #include <sys/systm.h>
      35             : #include <sys/mbuf.h>
      36             : #include <sys/socket.h>
      37             : #include <sys/sockio.h>
      38             : #include <sys/syslog.h>
      39             : #include <sys/queue.h>
      40             : 
      41             : #include <net/if.h>
      42             : #include <net/if_var.h>
      43             : #include <net/if_types.h>
      44             : #include <net/route.h>
      45             : 
      46             : #include <netinet/in.h>
      47             : #include <netinet/in_var.h>
      48             : #include <netinet/ip.h>
      49             : #include <netinet/ip_ether.h>
      50             : #include <netinet/ip_var.h>
      51             : #include <netinet/ip_ipip.h>
      52             : #include <netinet/ip_ecn.h>
      53             : 
      54             : #ifdef INET6
      55             : #include <netinet6/in6_var.h>
      56             : #include <netinet/ip6.h>
      57             : #include <netinet6/ip6_var.h>
      58             : #endif /* INET6 */
      59             : 
      60             : #include <net/if_gif.h>
      61             : 
      62             : #include "bpfilter.h"
      63             : #if NBPFILTER > 0
      64             : #include <net/bpf.h>
      65             : #endif
      66             : 
      67             : #ifdef MPLS
      68             : #include <netmpls/mpls.h>
      69             : #endif
      70             : 
      71             : #include "pf.h"
      72             : #if NPF > 0
      73             : #include <net/pfvar.h>
      74             : #endif
      75             : 
      76             : #define GIF_MTU         (1280)  /* Default MTU */
      77             : #define GIF_MTU_MIN     (1280)  /* Minimum MTU */
      78             : #define GIF_MTU_MAX     (8192)  /* Maximum MTU */
      79             : 
      80             : union gif_addr {
      81             :         struct in6_addr         in6;
      82             :         struct in_addr          in4;
      83             : };
      84             : 
      85             : struct gif_tunnel {
      86             :         TAILQ_ENTRY(gif_tunnel) t_entry;
      87             : 
      88             :         union gif_addr          t_src;
      89             : #define t_src4          t_src.in4
      90             : #define t_src6          t_src.in6
      91             :         union gif_addr          t_dst;
      92             : #define t_dst4          t_dst.in4
      93             : #define t_dst6          t_dst.in6
      94             :         u_int                   t_rtableid;
      95             : 
      96             :         sa_family_t             t_af;
      97             : };
      98             : 
      99             : TAILQ_HEAD(gif_list, gif_tunnel);
     100             : 
     101             : static inline int       gif_cmp(const struct gif_tunnel *,
     102             :                             const struct gif_tunnel *);
     103             : 
     104             : struct gif_softc {
     105             :         struct gif_tunnel       sc_tunnel; /* must be first */
     106             :         struct ifnet            sc_if;
     107             :         uint16_t                sc_df;
     108             :         int                     sc_ttl;
     109             : };
     110             : 
     111             : struct gif_list gif_list = TAILQ_HEAD_INITIALIZER(gif_list);
     112             : 
     113             : void    gifattach(int);
     114             : int     gif_clone_create(struct if_clone *, int);
     115             : int     gif_clone_destroy(struct ifnet *);
     116             : 
     117             : void    gif_start(struct ifnet *);
     118             : int     gif_ioctl(struct ifnet *, u_long, caddr_t);
     119             : int     gif_output(struct ifnet *, struct mbuf *, struct sockaddr *,
     120             :             struct rtentry *);
     121             : int     gif_send(struct gif_softc *, struct mbuf *, uint8_t, uint8_t, uint8_t);
     122             : 
     123             : int     gif_up(struct gif_softc *);
     124             : int     gif_down(struct gif_softc *);
     125             : int     gif_set_tunnel(struct gif_softc *, struct if_laddrreq *);
     126             : int     gif_get_tunnel(struct gif_softc *, struct if_laddrreq *);
     127             : int     gif_del_tunnel(struct gif_softc *);
     128             : int     in_gif_output(struct ifnet *, int, struct mbuf **);
     129             : int     in6_gif_output(struct ifnet *, int, struct mbuf **);
     130             : int     gif_input(struct gif_tunnel *, struct mbuf **, int *, int, int,
     131             :             uint8_t, uint8_t);
     132             : 
     133             : /*
     134             :  * gif global variable definitions
     135             :  */
     136             : struct if_clone gif_cloner =
     137             :     IF_CLONE_INITIALIZER("gif", gif_clone_create, gif_clone_destroy);
     138             : 
     139             : void
     140           0 : gifattach(int count)
     141             : {
     142           0 :         if_clone_attach(&gif_cloner);
     143           0 : }
     144             : 
     145             : int
     146           0 : gif_clone_create(struct if_clone *ifc, int unit)
     147             : {
     148             :         struct gif_softc *sc;
     149             :         struct ifnet *ifp;
     150             : 
     151           0 :         sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK|M_ZERO);
     152           0 :         ifp = &sc->sc_if;
     153             : 
     154           0 :         sc->sc_df = htons(0);
     155           0 :         sc->sc_ttl = ip_defttl;
     156             : 
     157           0 :         snprintf(ifp->if_xname, sizeof(ifp->if_xname),
     158           0 :             "%s%d", ifc->ifc_name, unit);
     159             : 
     160           0 :         ifp->if_mtu    = GIF_MTU;
     161           0 :         ifp->if_flags  = IFF_POINTOPOINT | IFF_MULTICAST;
     162           0 :         ifp->if_xflags = IFXF_CLONED;
     163           0 :         ifp->if_ioctl  = gif_ioctl;
     164           0 :         ifp->if_start  = gif_start;
     165           0 :         ifp->if_output = gif_output;
     166           0 :         ifp->if_rtrequest = p2p_rtrequest;
     167           0 :         ifp->if_type   = IFT_GIF;
     168           0 :         IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
     169           0 :         ifp->if_softc = sc;
     170             : 
     171           0 :         if_attach(ifp);
     172           0 :         if_alloc_sadl(ifp);
     173             : 
     174             : #if NBPFILTER > 0
     175           0 :         bpfattach(&ifp->if_bpf, ifp, DLT_LOOP, sizeof(uint32_t));
     176             : #endif
     177             : 
     178           0 :         NET_LOCK();
     179           0 :         TAILQ_INSERT_TAIL(&gif_list, &sc->sc_tunnel, t_entry);
     180           0 :         NET_UNLOCK();
     181             : 
     182           0 :         return (0);
     183             : }
     184             : 
     185             : int
     186           0 : gif_clone_destroy(struct ifnet *ifp)
     187             : {
     188           0 :         struct gif_softc *sc = ifp->if_softc;
     189             : 
     190           0 :         NET_LOCK();
     191           0 :         if (ISSET(ifp->if_flags, IFF_RUNNING))
     192           0 :                 gif_down(sc);
     193             : 
     194           0 :         TAILQ_REMOVE(&gif_list, &sc->sc_tunnel, t_entry);
     195           0 :         NET_UNLOCK();
     196             : 
     197           0 :         if_detach(ifp);
     198             : 
     199           0 :         free(sc, M_DEVBUF, sizeof(*sc));
     200             : 
     201           0 :         return (0);
     202             : }
     203             : 
     204             : void
     205           0 : gif_start(struct ifnet *ifp)
     206             : {
     207           0 :         struct gif_softc *sc = ifp->if_softc;
     208             :         struct mbuf *m;
     209             : #if NBPFILTER > 0
     210             :         caddr_t if_bpf;
     211             : #endif
     212             :         uint8_t proto, ttl, tos;
     213             :         int ttloff, tttl;
     214             : 
     215           0 :         tttl = sc->sc_ttl;
     216             : 
     217           0 :         while ((m = ifq_dequeue(&ifp->if_snd)) != NULL) {
     218             : #if NBPFILTER > 0
     219           0 :                 if_bpf = ifp->if_bpf;
     220           0 :                 if (if_bpf) {
     221           0 :                         bpf_mtap_af(if_bpf, m->m_pkthdr.ph_family, m,
     222             :                             BPF_DIRECTION_OUT);
     223           0 :                 }
     224             : #endif
     225             : 
     226           0 :                 switch (m->m_pkthdr.ph_family) {
     227             :                 case AF_INET: {
     228             :                         struct ip *ip;
     229             : 
     230           0 :                         m = m_pullup(m, sizeof(*ip));
     231           0 :                         if (m == NULL)
     232           0 :                                 continue;
     233             : 
     234           0 :                         ip = mtod(m, struct ip *);
     235           0 :                         tos = ip->ip_tos;
     236             : 
     237             :                         ttloff = offsetof(struct ip, ip_ttl);
     238             :                         proto = IPPROTO_IPV4;
     239           0 :                         break;
     240             :                 }
     241             : #ifdef INET6
     242             :                 case AF_INET6: {
     243             :                         struct ip6_hdr *ip6;
     244             : 
     245           0 :                         m = m_pullup(m, sizeof(*ip6));
     246           0 :                         if (m == NULL)
     247           0 :                                 continue;
     248             : 
     249           0 :                         ip6 = mtod(m, struct ip6_hdr *);
     250           0 :                         tos = ntohl(ip6->ip6_flow >> 20);
     251             : 
     252             :                         ttloff = offsetof(struct ip6_hdr, ip6_hlim);
     253             :                         proto = IPPROTO_IPV6;
     254           0 :                         break;
     255             :                 }
     256             : #endif
     257             : #ifdef MPLS
     258             :                 case AF_MPLS:
     259             :                         ttloff = 3;
     260             :                         tos = 0;
     261             : 
     262             :                         proto = IPPROTO_MPLS;
     263           0 :                         break;
     264             : #endif
     265             :                 default:
     266           0 :                         unhandled_af(m->m_pkthdr.ph_family);
     267             :                 }
     268             : 
     269           0 :                 if (tttl == -1) {
     270           0 :                         m = m_pullup(m, ttloff + 1);
     271           0 :                         if (m == NULL)
     272           0 :                                 continue;
     273             : 
     274           0 :                         ttl = *(m->m_data + ttloff);
     275           0 :                 } else
     276           0 :                         ttl = tttl;
     277             : 
     278           0 :                 gif_send(sc, m, proto, ttl, tos);
     279             :         }
     280           0 : }
     281             : 
     282             : int
     283           0 : gif_send(struct gif_softc *sc, struct mbuf *m,
     284             :     uint8_t proto, uint8_t ttl, uint8_t otos)
     285             : {
     286           0 :         uint8_t itos = 0;
     287             : 
     288           0 :         m->m_flags &= ~(M_BCAST|M_MCAST);
     289           0 :         m->m_pkthdr.ph_rtableid = sc->sc_tunnel.t_rtableid;
     290             : 
     291             : #if NPF > 0
     292           0 :         pf_pkt_addr_changed(m);
     293             : #endif
     294             : 
     295           0 :         ip_ecn_ingress(ECN_ALLOWED, &otos, &itos);
     296             : 
     297           0 :         switch (sc->sc_tunnel.t_af) {
     298             :         case AF_INET: {
     299             :                 struct ip *ip;
     300             : 
     301           0 :                 if (in_nullhost(sc->sc_tunnel.t_dst4))
     302           0 :                         goto drop;
     303             : 
     304           0 :                 m = m_prepend(m, sizeof(*ip), M_DONTWAIT);
     305           0 :                 if (m == NULL)
     306           0 :                         return (-1);
     307             : 
     308           0 :                 ip = mtod(m, struct ip *);
     309           0 :                 ip->ip_off = sc->sc_df;
     310           0 :                 ip->ip_tos = otos;
     311           0 :                 ip->ip_len = htons(m->m_pkthdr.len);
     312           0 :                 ip->ip_ttl = ttl;
     313           0 :                 ip->ip_p = proto;
     314           0 :                 ip->ip_src = sc->sc_tunnel.t_src4;
     315           0 :                 ip->ip_dst = sc->sc_tunnel.t_dst4;
     316             : 
     317           0 :                 ip_send(m);
     318           0 :                 break;
     319             :         }
     320             : #ifdef INET6
     321             :         case AF_INET6: {
     322             :                 struct ip6_hdr *ip6;
     323           0 :                 int len = m->m_pkthdr.len;
     324             :                 uint32_t flow;
     325             : 
     326           0 :                 if (IN6_IS_ADDR_UNSPECIFIED(&sc->sc_tunnel.t_dst6))
     327           0 :                         goto drop;
     328             : 
     329           0 :                 m = m_prepend(m, sizeof(*ip6), M_DONTWAIT);
     330           0 :                 if (m == NULL)
     331           0 :                         return (-1);
     332             : 
     333           0 :                 flow = otos << 20;
     334           0 :                 if (ISSET(m->m_pkthdr.ph_flowid, M_FLOWID_VALID))
     335           0 :                         flow |= m->m_pkthdr.ph_flowid & M_FLOWID_MASK;
     336             : 
     337           0 :                 ip6 = mtod(m, struct ip6_hdr *);
     338           0 :                 ip6->ip6_flow = htonl(flow);
     339           0 :                 ip6->ip6_vfc |= IPV6_VERSION;
     340           0 :                 ip6->ip6_plen = htons(len);
     341           0 :                 ip6->ip6_nxt = proto;
     342           0 :                 ip6->ip6_hlim = ttl;
     343           0 :                 ip6->ip6_src = sc->sc_tunnel.t_src6;
     344           0 :                 ip6->ip6_dst = sc->sc_tunnel.t_dst6;
     345             : 
     346           0 :                 if (sc->sc_df)
     347           0 :                         SET(m->m_pkthdr.csum_flags, M_IPV6_DF_OUT);
     348             : 
     349           0 :                 ip6_send(m);
     350           0 :                 break;
     351             :         }
     352             : #endif
     353             :         default:
     354           0 :                 m_freem(m);
     355           0 :                 break;
     356             :         }
     357             : 
     358           0 :         return (0);
     359             : 
     360             : drop:
     361           0 :         m_freem(m);
     362           0 :         return (0);
     363           0 : }
     364             : 
     365             : int
     366           0 : gif_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
     367             :     struct rtentry *rt)
     368             : {
     369             :         struct m_tag *mtag;
     370             :         int error = 0;
     371             : 
     372           0 :         if (!ISSET(ifp->if_flags, IFF_RUNNING)) {
     373             :                 error = ENETDOWN;
     374           0 :                 goto drop;
     375             :         }
     376             : 
     377           0 :         switch (dst->sa_family) {
     378             :         case AF_INET:
     379             : #ifdef INET6
     380             :         case AF_INET6:
     381             : #endif
     382             : #ifdef MPLS
     383             :         case AF_MPLS:
     384             : #endif
     385             :                 break;
     386             :         default:
     387             :                 error = EAFNOSUPPORT;
     388           0 :                 goto drop;
     389             :         }
     390             : 
     391             :         /* Try to limit infinite recursion through misconfiguration. */
     392           0 :         for (mtag = m_tag_find(m, PACKET_TAG_GRE, NULL); mtag;
     393           0 :              mtag = m_tag_find(m, PACKET_TAG_GRE, mtag)) {
     394           0 :                 if (memcmp((caddr_t)(mtag + 1), &ifp->if_index,
     395           0 :                     sizeof(ifp->if_index)) == 0) {
     396             :                         error = EIO;
     397           0 :                         goto drop;
     398             :                 }
     399             :         }
     400             : 
     401           0 :         mtag = m_tag_get(PACKET_TAG_GRE, sizeof(ifp->if_index), M_NOWAIT);
     402           0 :         if (mtag == NULL) {
     403             :                 error = ENOBUFS;
     404           0 :                 goto drop;
     405             :         }
     406           0 :         memcpy((caddr_t)(mtag + 1), &ifp->if_index, sizeof(ifp->if_index));
     407           0 :         m_tag_prepend(m, mtag);
     408             : 
     409           0 :         m->m_pkthdr.ph_family = dst->sa_family;
     410             : 
     411           0 :         error = if_enqueue(ifp, m);
     412             : 
     413           0 :         if (error)
     414           0 :                 ifp->if_oerrors++;
     415           0 :         return (error);
     416             : 
     417             : drop:
     418           0 :         m_freem(m);
     419           0 :         return (error);
     420           0 : }
     421             : 
     422             : int
     423           0 : gif_up(struct gif_softc *sc)
     424             : {
     425           0 :         NET_ASSERT_LOCKED();
     426             : 
     427           0 :         SET(sc->sc_if.if_flags, IFF_RUNNING);
     428             : 
     429           0 :         return (0);
     430             : }
     431             : 
     432             : int
     433           0 : gif_down(struct gif_softc *sc)
     434             : {
     435           0 :         NET_ASSERT_LOCKED();
     436             : 
     437           0 :         CLR(sc->sc_if.if_flags, IFF_RUNNING);
     438             : 
     439             :         /* barrier? */
     440             : 
     441           0 :         return (0);
     442             : }
     443             : 
     444             : int
     445           0 : gif_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
     446             : {
     447           0 :         struct gif_softc *sc = ifp->if_softc;
     448           0 :         struct ifreq *ifr = (struct ifreq *)data;
     449             :         int error = 0;
     450             : 
     451           0 :         switch (cmd) {
     452             :         case SIOCSIFADDR:
     453           0 :                 SET(ifp->if_flags, IFF_UP);
     454             :                 /* FALLTHROUGH */
     455             :         case SIOCSIFFLAGS:
     456           0 :                 if (ISSET(ifp->if_flags, IFF_UP)) {
     457           0 :                         if (!ISSET(ifp->if_flags, IFF_RUNNING))
     458           0 :                                 error = gif_up(sc);
     459             :                         else
     460             :                                 error = 0;
     461             :                 } else {
     462           0 :                         if (ISSET(ifp->if_flags, IFF_RUNNING))
     463           0 :                                 error = gif_down(sc);
     464             :                 }
     465             :                 break;
     466             : 
     467             :         case SIOCADDMULTI:
     468             :         case SIOCDELMULTI:
     469             :                 break;
     470             : 
     471             :         case SIOCSLIFPHYADDR:
     472           0 :                 error = gif_set_tunnel(sc, (struct if_laddrreq *)data);
     473           0 :                 break;
     474             :         case SIOCGLIFPHYADDR:
     475           0 :                 error = gif_get_tunnel(sc, (struct if_laddrreq *)data);
     476           0 :                 break;
     477             :         case SIOCDIFPHYADDR:
     478           0 :                 error = gif_del_tunnel(sc);
     479           0 :                 break;
     480             : 
     481             :         case SIOCSIFMTU:
     482           0 :                 if (ifr->ifr_mtu < GIF_MTU_MIN || ifr->ifr_mtu > GIF_MTU_MAX) {
     483             :                         error = EINVAL;
     484           0 :                         break;
     485             :                 }
     486             : 
     487           0 :                 ifp->if_mtu = ifr->ifr_mtu;
     488           0 :                 break;
     489             : 
     490             :         case SIOCSLIFPHYRTABLE:
     491           0 :                 if (ifr->ifr_rdomainid < 0 ||
     492           0 :                     ifr->ifr_rdomainid > RT_TABLEID_MAX ||
     493           0 :                     !rtable_exists(ifr->ifr_rdomainid)) {
     494             :                         error = EINVAL;
     495           0 :                         break;
     496             :                 }
     497           0 :                 sc->sc_tunnel.t_rtableid = ifr->ifr_rdomainid;
     498           0 :                 break;
     499             :         case SIOCGLIFPHYRTABLE:
     500           0 :                 ifr->ifr_rdomainid = sc->sc_tunnel.t_rtableid;
     501           0 :                 break;
     502             : 
     503             :         case SIOCSLIFPHYTTL:
     504           0 :                 if (ifr->ifr_ttl != -1 &&
     505           0 :                     (ifr->ifr_ttl < 1 || ifr->ifr_ttl > 0xff)) {
     506             :                         error = EINVAL;
     507           0 :                         break;
     508             :                 }
     509             : 
     510             :                 /* commit */
     511           0 :                 sc->sc_ttl = ifr->ifr_ttl;
     512           0 :                 break;
     513             :         case SIOCGLIFPHYTTL:
     514           0 :                 ifr->ifr_ttl = sc->sc_ttl;
     515           0 :                 break;
     516             : 
     517             :         case SIOCSLIFPHYDF:
     518             :                 /* commit */
     519           0 :                 sc->sc_df = ifr->ifr_df ? htons(IP_DF) : htons(0);
     520           0 :                 break;
     521             :         case SIOCGLIFPHYDF:
     522           0 :                 ifr->ifr_df = sc->sc_df ? 1 : 0;
     523           0 :                 break;
     524             : 
     525             :         default:
     526             :                 error = ENOTTY;
     527           0 :                 break;
     528             :         }
     529             : 
     530           0 :         return (error);
     531             : }
     532             : 
     533             : int
     534           0 : gif_get_tunnel(struct gif_softc *sc, struct if_laddrreq *req)
     535             : {
     536           0 :         struct gif_tunnel *tunnel = &sc->sc_tunnel;
     537           0 :         struct sockaddr *src = (struct sockaddr *)&req->addr;
     538           0 :         struct sockaddr *dst = (struct sockaddr *)&req->dstaddr;
     539             :         struct sockaddr_in *sin;
     540             : #ifdef INET6 /* ifconfig already embeds the scopeid */
     541             :         struct sockaddr_in6 *sin6;
     542             : #endif
     543             : 
     544           0 :         switch (tunnel->t_af) {
     545             :         case AF_UNSPEC:
     546           0 :                 return (EADDRNOTAVAIL);
     547             :         case AF_INET:
     548           0 :                 sin = (struct sockaddr_in *)src;
     549           0 :                 memset(sin, 0, sizeof(*sin));
     550           0 :                 sin->sin_family = AF_INET;
     551           0 :                 sin->sin_len = sizeof(*sin);
     552           0 :                 sin->sin_addr = tunnel->t_src4;
     553             : 
     554           0 :                 sin = (struct sockaddr_in *)dst;
     555           0 :                 memset(sin, 0, sizeof(*sin));
     556           0 :                 sin->sin_family = AF_INET;
     557           0 :                 sin->sin_len = sizeof(*sin);
     558           0 :                 sin->sin_addr = tunnel->t_dst4;
     559             : 
     560           0 :                 break;
     561             : 
     562             : #ifdef INET6
     563             :         case AF_INET6:
     564           0 :                 sin6 = (struct sockaddr_in6 *)src;
     565           0 :                 memset(sin6, 0, sizeof(*sin6));
     566           0 :                 sin6->sin6_family = AF_INET6;
     567           0 :                 sin6->sin6_len = sizeof(*sin6);
     568           0 :                 in6_recoverscope(sin6, &tunnel->t_src6);
     569             : 
     570           0 :                 sin6 = (struct sockaddr_in6 *)dst;
     571           0 :                 memset(sin6, 0, sizeof(*sin6));
     572           0 :                 sin6->sin6_family = AF_INET6;
     573           0 :                 sin6->sin6_len = sizeof(*sin6);
     574           0 :                 in6_recoverscope(sin6, &tunnel->t_dst6);
     575             : 
     576           0 :                 break;
     577             : #endif
     578             :         default:
     579           0 :                 return (EAFNOSUPPORT);
     580             :         }
     581             : 
     582           0 :         return (0);
     583           0 : }
     584             : 
     585             : int
     586           0 : gif_set_tunnel(struct gif_softc *sc, struct if_laddrreq *req)
     587             : {
     588           0 :         struct gif_tunnel *tunnel = &sc->sc_tunnel;
     589           0 :         struct sockaddr *src = (struct sockaddr *)&req->addr;
     590           0 :         struct sockaddr *dst = (struct sockaddr *)&req->dstaddr;
     591             :         struct sockaddr_in *src4, *dst4;
     592             : #ifdef INET6
     593             :         struct sockaddr_in6 *src6, *dst6;
     594             :         int error;
     595             : #endif
     596             : 
     597             :         /* sa_family and sa_len must be equal */
     598           0 :         if (src->sa_family != dst->sa_family || src->sa_len != dst->sa_len)
     599           0 :                 return (EINVAL);
     600             : 
     601             :         /* validate */
     602           0 :         switch (dst->sa_family) {
     603             :         case AF_INET:
     604           0 :                 if (dst->sa_len != sizeof(*dst4))
     605           0 :                         return (EINVAL);
     606             : 
     607           0 :                 src4 = (struct sockaddr_in *)src;
     608           0 :                 if (in_nullhost(src4->sin_addr) ||
     609           0 :                     IN_MULTICAST(src4->sin_addr.s_addr))
     610           0 :                         return (EINVAL);
     611             : 
     612           0 :                 dst4 = (struct sockaddr_in *)dst;
     613             :                 /* dst4 can be 0.0.0.0 */
     614           0 :                 if (IN_MULTICAST(dst4->sin_addr.s_addr))
     615           0 :                         return (EINVAL);
     616             : 
     617           0 :                 tunnel->t_src4 = src4->sin_addr;
     618           0 :                 tunnel->t_dst4 = dst4->sin_addr;
     619             : 
     620           0 :                 break;
     621             : #ifdef INET6
     622             :         case AF_INET6:
     623           0 :                 if (dst->sa_len != sizeof(*dst6))
     624           0 :                         return (EINVAL);
     625             : 
     626           0 :                 src6 = (struct sockaddr_in6 *)src;
     627           0 :                 if (IN6_IS_ADDR_UNSPECIFIED(&src6->sin6_addr) ||
     628           0 :                     IN6_IS_ADDR_MULTICAST(&src6->sin6_addr))
     629           0 :                         return (EINVAL);
     630             : 
     631           0 :                 dst6 = (struct sockaddr_in6 *)dst;
     632           0 :                 if (IN6_IS_ADDR_MULTICAST(&dst6->sin6_addr))
     633           0 :                         return (EINVAL);
     634             : 
     635           0 :                 error = in6_embedscope(&tunnel->t_src6, src6, NULL);
     636           0 :                 if (error != 0)
     637           0 :                         return (error);
     638             : 
     639           0 :                 error = in6_embedscope(&tunnel->t_dst6, dst6, NULL);
     640           0 :                 if (error != 0)
     641           0 :                         return (error);
     642             : 
     643             :                 break;
     644             : #endif
     645             :         default:
     646           0 :                 return (EAFNOSUPPORT);
     647             :         }
     648             : 
     649             :         /* commit */
     650           0 :         tunnel->t_af = dst->sa_family;
     651             : 
     652           0 :         return (0);
     653           0 : }
     654             : 
     655             : int
     656           0 : gif_del_tunnel(struct gif_softc *sc)
     657             : {
     658             :         /* commit */
     659           0 :         sc->sc_tunnel.t_af = AF_UNSPEC;
     660             : 
     661           0 :         return (0);
     662             : }
     663             : 
     664             : int
     665           0 : in_gif_input(struct mbuf **mp, int *offp, int proto, int af)
     666             : {
     667           0 :         struct mbuf *m = *mp;
     668           0 :         struct gif_tunnel key;
     669             :         struct ip *ip;
     670             :         int rv;
     671             : 
     672           0 :         ip = mtod(m, struct ip *);
     673             : 
     674           0 :         key.t_af = AF_INET;
     675           0 :         key.t_src4 = ip->ip_dst;
     676           0 :         key.t_dst4 = ip->ip_src;
     677             : 
     678           0 :         rv = gif_input(&key, mp, offp, proto, af, ip->ip_ttl, ip->ip_tos);
     679           0 :         if (rv == -1)
     680           0 :                 rv = ipip_input(mp, offp, proto, af);
     681             : 
     682           0 :         return (rv);
     683           0 : }
     684             : 
     685             : #ifdef INET6
     686             : int
     687           0 : in6_gif_input(struct mbuf **mp, int *offp, int proto, int af)
     688             : {
     689           0 :         struct mbuf *m = *mp;
     690           0 :         struct gif_tunnel key;
     691             :         struct ip6_hdr *ip6;
     692             :         uint32_t flow;
     693             :         int rv;
     694             : 
     695           0 :         ip6 = mtod(m, struct ip6_hdr *);
     696             : 
     697           0 :         key.t_af = AF_INET6;
     698           0 :         key.t_src6 = ip6->ip6_dst;
     699           0 :         key.t_dst6 = ip6->ip6_src;
     700             : 
     701           0 :         flow = ntohl(ip6->ip6_flow);
     702             : 
     703           0 :         rv = gif_input(&key, mp, offp, proto, af, ip6->ip6_hlim,
     704           0 :             flow >> 20);
     705           0 :         if (rv == -1)
     706           0 :                 rv = ipip_input(mp, offp, proto, af);
     707             : 
     708           0 :         return (rv);
     709           0 : }
     710             : #endif /* INET6 */
     711             : 
     712             : struct gif_softc *
     713           0 : gif_find(const struct gif_tunnel *key)
     714             : {
     715             :         struct gif_tunnel *t;
     716             :         struct gif_softc *sc;
     717             : 
     718           0 :         TAILQ_FOREACH(t, &gif_list, t_entry) {
     719           0 :                 if (gif_cmp(key, t) != 0)
     720             :                         continue;
     721             : 
     722           0 :                 sc = (struct gif_softc *)t;
     723           0 :                 if (!ISSET(sc->sc_if.if_flags, IFF_RUNNING))
     724             :                         continue;
     725             : 
     726           0 :                 return (sc);
     727             :         }
     728             : 
     729           0 :         return (NULL);
     730           0 : }
     731             : 
     732             : int
     733           0 : gif_input(struct gif_tunnel *key, struct mbuf **mp, int *offp, int proto,
     734             :     int af, uint8_t ttl, uint8_t otos)
     735             : {
     736           0 :         struct mbuf *m = *mp;
     737             :         struct gif_softc *sc;
     738             :         struct ifnet *ifp;
     739             :         void (*input)(struct ifnet *, struct mbuf *);
     740             :         int ttloff;
     741           0 :         uint8_t itos;
     742             : 
     743             :         /* IP-in-IP header is caused by tunnel mode, so skip gif lookup */
     744           0 :         if (m->m_flags & M_TUNNEL) {
     745           0 :                 m->m_flags &= ~M_TUNNEL;
     746           0 :                 return (-1);
     747             :         }
     748             :         
     749           0 :         key->t_rtableid = m->m_pkthdr.ph_rtableid;
     750             : 
     751           0 :         sc = gif_find(key);
     752           0 :         if (sc == NULL) {
     753           0 :                 memset(&key->t_dst, 0, sizeof(key->t_dst));
     754           0 :                 sc = gif_find(key);
     755           0 :                 if (sc == NULL)
     756           0 :                         return (-1);
     757             :         }
     758             : 
     759           0 :         switch (proto) {
     760             :         case IPPROTO_IPV4: {
     761             :                 struct ip *ip;
     762             : 
     763           0 :                 m = *mp = m_pullup(m, sizeof(*ip));
     764           0 :                 if (m == NULL)
     765           0 :                         return (IPPROTO_DONE);
     766             : 
     767           0 :                 ip = mtod(m, struct ip *);
     768             : 
     769           0 :                 itos = ip->ip_tos;
     770           0 :                 if (ip_ecn_egress(ECN_ALLOWED, &otos, &itos) == 0)
     771           0 :                         goto drop;
     772             : 
     773           0 :                 ip->ip_tos = itos;
     774             : 
     775           0 :                 m->m_pkthdr.ph_family = AF_INET;
     776             :                 input = ipv4_input;
     777             :                 ttloff = offsetof(struct ip, ip_ttl);
     778           0 :                 break;
     779             :         }
     780             : #ifdef INET6
     781             :         case IPPROTO_IPV6: {
     782             :                 struct ip6_hdr *ip6;
     783             : 
     784           0 :                 m = *mp = m_pullup(m, sizeof(*ip6));
     785           0 :                 if (m == NULL)
     786           0 :                         return (IPPROTO_DONE);
     787             : 
     788           0 :                 ip6 = mtod(m, struct ip6_hdr *);
     789             : 
     790           0 :                 itos = ntohl(ip6->ip6_flow) >> 20;
     791           0 :                 if (!ip_ecn_egress(ECN_ALLOWED, &otos, &itos))
     792           0 :                         goto drop;
     793             : 
     794           0 :                 CLR(ip6->ip6_flow, htonl(0xff << 20));
     795           0 :                 SET(ip6->ip6_flow, htonl(itos << 20));
     796             : 
     797           0 :                 m->m_pkthdr.ph_family = AF_INET6;
     798             :                 input = ipv6_input;
     799             :                 ttloff = offsetof(struct ip6_hdr, ip6_hlim);
     800           0 :                 break;
     801             :         }
     802             : #endif /* INET6 */
     803             : #ifdef MPLS
     804             :         case IPPROTO_MPLS:
     805           0 :                 m->m_pkthdr.ph_family = AF_MPLS;
     806             :                 input = mpls_input;
     807             :                 ttloff = 3;
     808           0 :                 break;
     809             : #endif /* MPLS */
     810             :         default:
     811           0 :                 return (-1);
     812             :         }
     813             : 
     814           0 :         m_adj(m, *offp);
     815             : 
     816           0 :         if (sc->sc_ttl == -1) {
     817           0 :                 m = *mp = m_pullup(m, ttloff + 1);
     818           0 :                 if (m == NULL)
     819           0 :                         return (IPPROTO_DONE);
     820             : 
     821           0 :                 *(m->m_data + ttloff) = ttl;
     822           0 :         }
     823             : 
     824           0 :         ifp = &sc->sc_if;
     825             : 
     826           0 :         m->m_flags &= ~(M_MCAST|M_BCAST);
     827           0 :         m->m_pkthdr.ph_ifidx = ifp->if_index;
     828           0 :         m->m_pkthdr.ph_rtableid = ifp->if_rdomain;
     829             : 
     830             : #if NPF > 0
     831           0 :         pf_pkt_addr_changed(m);
     832             : #endif
     833             : 
     834           0 :         ifp->if_ipackets++;
     835           0 :         ifp->if_ibytes += m->m_pkthdr.len;
     836             : 
     837             : #if NBPFILTER > 0
     838             :         {
     839           0 :                 caddr_t if_bpf = ifp->if_bpf;
     840           0 :                 if (if_bpf) {
     841           0 :                         bpf_mtap_af(ifp->if_bpf, m->m_pkthdr.ph_family,
     842             :                             m, BPF_DIRECTION_IN);
     843           0 :                 }
     844             :         }
     845             : #endif
     846             : 
     847           0 :         *mp = NULL;
     848           0 :         (*input)(ifp, m);
     849           0 :         return (IPPROTO_DONE);
     850             : 
     851             :  drop:
     852           0 :         m_freemp(mp);
     853           0 :         return (IPPROTO_DONE);
     854           0 : }
     855             : 
     856             : static inline int
     857           0 : gif_ip_cmp(int af, const union gif_addr *a, const union gif_addr *b)
     858             : {
     859           0 :         switch (af) {
     860             : #ifdef INET6
     861             :         case AF_INET6:
     862           0 :                 return (memcmp(&a->in6, &b->in6, sizeof(a->in6)));
     863             : #endif /* INET6 */
     864             :         case AF_INET:
     865           0 :                 return (memcmp(&a->in4, &b->in4, sizeof(a->in4)));
     866             :         default:
     867           0 :                 panic("%s: unsupported af %d\n", __func__, af);
     868             :         }
     869             : 
     870             :         return (0);
     871           0 : }
     872             : 
     873             : 
     874             : static inline int
     875           0 : gif_cmp(const struct gif_tunnel *a, const struct gif_tunnel *b)
     876             : {
     877             :         int rv;
     878             : 
     879             :         /* sort by routing table */
     880           0 :         if (a->t_rtableid > b->t_rtableid)
     881           0 :                 return (1);
     882           0 :         if (a->t_rtableid < b->t_rtableid)
     883           0 :                 return (-1);
     884             : 
     885             :         /* sort by address */
     886           0 :         if (a->t_af > b->t_af)
     887           0 :                 return (1);
     888           0 :         if (a->t_af < b->t_af)
     889           0 :                 return (-1);
     890             : 
     891           0 :         rv = gif_ip_cmp(a->t_af, &a->t_dst, &b->t_dst);
     892           0 :         if (rv != 0)
     893           0 :                 return (rv);
     894             : 
     895           0 :         rv = gif_ip_cmp(a->t_af, &a->t_src, &b->t_src);
     896           0 :         if (rv != 0)
     897           0 :                 return (rv);
     898             : 
     899           0 :         return (0);
     900           0 : }

Generated by: LCOV version 1.13