The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/net/if_gif.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 2849a750286f557a2d2e713a3b8be044


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.