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_gre.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 /*-
    2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 1998 The NetBSD Foundation, Inc.
    5  * Copyright (c) 2014, 2018 Andrey V. Elsukov <ae@FreeBSD.org>
    6  * All rights reserved.
    7  *
    8  * This code is derived from software contributed to The NetBSD Foundation
    9  * by Heiko W.Rupp <hwr@pilhuhn.de>
   10  *
   11  * IPv6-over-GRE contributed by Gert Doering <gert@greenie.muc.de>
   12  *
   13  * Redistribution and use in source and binary forms, with or without
   14  * modification, are permitted provided that the following conditions
   15  * are met:
   16  * 1. Redistributions of source code must retain the above copyright
   17  *    notice, this list of conditions and the following disclaimer.
   18  * 2. Redistributions in binary form must reproduce the above copyright
   19  *    notice, this list of conditions and the following disclaimer in the
   20  *    documentation and/or other materials provided with the distribution.
   21  *
   22  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   23  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   24  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   25  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   26  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   27  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   28  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   29  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   30  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   31  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   32  * POSSIBILITY OF SUCH DAMAGE.
   33  *
   34  * $NetBSD: if_gre.c,v 1.49 2003/12/11 00:22:29 itojun Exp $
   35  */
   36 
   37 #include <sys/cdefs.h>
   38 __FBSDID("$FreeBSD$");
   39 
   40 #include "opt_inet.h"
   41 #include "opt_inet6.h"
   42 #include "opt_rss.h"
   43 
   44 #include <sys/param.h>
   45 #include <sys/kernel.h>
   46 #include <sys/lock.h>
   47 #include <sys/malloc.h>
   48 #include <sys/module.h>
   49 #include <sys/mbuf.h>
   50 #include <sys/priv.h>
   51 #include <sys/proc.h>
   52 #include <sys/socket.h>
   53 #include <sys/socketvar.h>
   54 #include <sys/sockio.h>
   55 #include <sys/sx.h>
   56 #include <sys/sysctl.h>
   57 #include <sys/syslog.h>
   58 #include <sys/systm.h>
   59 
   60 #include <net/ethernet.h>
   61 #include <net/if.h>
   62 #include <net/if_var.h>
   63 #include <net/if_private.h>
   64 #include <net/if_clone.h>
   65 #include <net/if_types.h>
   66 #include <net/netisr.h>
   67 #include <net/vnet.h>
   68 #include <net/route.h>
   69 
   70 #include <netinet/in.h>
   71 #include <netinet/in_pcb.h>
   72 #ifdef INET
   73 #include <netinet/in_var.h>
   74 #include <netinet/ip.h>
   75 #include <netinet/ip_var.h>
   76 #ifdef RSS
   77 #include <netinet/in_rss.h>
   78 #endif
   79 #endif
   80 
   81 #ifdef INET6
   82 #include <netinet/ip6.h>
   83 #include <netinet6/in6_var.h>
   84 #include <netinet6/ip6_var.h>
   85 #ifdef RSS
   86 #include <netinet6/in6_rss.h>
   87 #endif
   88 #endif
   89 
   90 #include <netinet/ip_encap.h>
   91 #include <netinet/udp.h>
   92 #include <net/bpf.h>
   93 #include <net/if_gre.h>
   94 
   95 #include <machine/in_cksum.h>
   96 #include <security/mac/mac_framework.h>
   97 
   98 #define GREMTU                  1476
   99 
  100 static const char grename[] = "gre";
  101 MALLOC_DEFINE(M_GRE, grename, "Generic Routing Encapsulation");
  102 
  103 static struct sx gre_ioctl_sx;
  104 SX_SYSINIT(gre_ioctl_sx, &gre_ioctl_sx, "gre_ioctl");
  105 
  106 static int      gre_clone_create(struct if_clone *, int, caddr_t);
  107 static void     gre_clone_destroy(struct ifnet *);
  108 VNET_DEFINE_STATIC(struct if_clone *, gre_cloner);
  109 #define V_gre_cloner    VNET(gre_cloner)
  110 
  111 #ifdef VIMAGE
  112 static void     gre_reassign(struct ifnet *, struct vnet *, char *);
  113 #endif
  114 static void     gre_qflush(struct ifnet *);
  115 static int      gre_transmit(struct ifnet *, struct mbuf *);
  116 static int      gre_ioctl(struct ifnet *, u_long, caddr_t);
  117 static int      gre_output(struct ifnet *, struct mbuf *,
  118                     const struct sockaddr *, struct route *);
  119 static void     gre_delete_tunnel(struct gre_softc *);
  120 
  121 SYSCTL_DECL(_net_link);
  122 static SYSCTL_NODE(_net_link, IFT_TUNNEL, gre, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
  123     "Generic Routing Encapsulation");
  124 #ifndef MAX_GRE_NEST
  125 /*
  126  * This macro controls the default upper limitation on nesting of gre tunnels.
  127  * Since, setting a large value to this macro with a careless configuration
  128  * may introduce system crash, we don't allow any nestings by default.
  129  * If you need to configure nested gre tunnels, you can define this macro
  130  * in your kernel configuration file.  However, if you do so, please be
  131  * careful to configure the tunnels so that it won't make a loop.
  132  */
  133 #define MAX_GRE_NEST 1
  134 #endif
  135 
  136 VNET_DEFINE_STATIC(int, max_gre_nesting) = MAX_GRE_NEST;
  137 #define V_max_gre_nesting       VNET(max_gre_nesting)
  138 SYSCTL_INT(_net_link_gre, OID_AUTO, max_nesting, CTLFLAG_RW | CTLFLAG_VNET,
  139     &VNET_NAME(max_gre_nesting), 0, "Max nested tunnels");
  140 
  141 static void
  142 vnet_gre_init(const void *unused __unused)
  143 {
  144 
  145         V_gre_cloner = if_clone_simple(grename, gre_clone_create,
  146             gre_clone_destroy, 0);
  147 #ifdef INET
  148         in_gre_init();
  149 #endif
  150 #ifdef INET6
  151         in6_gre_init();
  152 #endif
  153 }
  154 VNET_SYSINIT(vnet_gre_init, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY,
  155     vnet_gre_init, NULL);
  156 
  157 static void
  158 vnet_gre_uninit(const void *unused __unused)
  159 {
  160 
  161         if_clone_detach(V_gre_cloner);
  162 #ifdef INET
  163         in_gre_uninit();
  164 #endif
  165 #ifdef INET6
  166         in6_gre_uninit();
  167 #endif
  168         /* XXX: epoch_call drain */
  169 }
  170 VNET_SYSUNINIT(vnet_gre_uninit, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY,
  171     vnet_gre_uninit, NULL);
  172 
  173 static int
  174 gre_clone_create(struct if_clone *ifc, int unit, caddr_t params)
  175 {
  176         struct gre_softc *sc;
  177 
  178         sc = malloc(sizeof(struct gre_softc), M_GRE, M_WAITOK | M_ZERO);
  179         sc->gre_fibnum = curthread->td_proc->p_fibnum;
  180         GRE2IFP(sc) = if_alloc(IFT_TUNNEL);
  181         GRE2IFP(sc)->if_softc = sc;
  182         if_initname(GRE2IFP(sc), grename, unit);
  183 
  184         GRE2IFP(sc)->if_mtu = GREMTU;
  185         GRE2IFP(sc)->if_flags = IFF_POINTOPOINT|IFF_MULTICAST;
  186         GRE2IFP(sc)->if_output = gre_output;
  187         GRE2IFP(sc)->if_ioctl = gre_ioctl;
  188         GRE2IFP(sc)->if_transmit = gre_transmit;
  189         GRE2IFP(sc)->if_qflush = gre_qflush;
  190 #ifdef VIMAGE
  191         GRE2IFP(sc)->if_reassign = gre_reassign;
  192 #endif
  193         GRE2IFP(sc)->if_capabilities |= IFCAP_LINKSTATE;
  194         GRE2IFP(sc)->if_capenable |= IFCAP_LINKSTATE;
  195         if_attach(GRE2IFP(sc));
  196         bpfattach(GRE2IFP(sc), DLT_NULL, sizeof(u_int32_t));
  197         return (0);
  198 }
  199 
  200 #ifdef VIMAGE
  201 static void
  202 gre_reassign(struct ifnet *ifp, struct vnet *new_vnet __unused,
  203     char *unused __unused)
  204 {
  205         struct gre_softc *sc;
  206 
  207         sx_xlock(&gre_ioctl_sx);
  208         sc = ifp->if_softc;
  209         if (sc != NULL)
  210                 gre_delete_tunnel(sc);
  211         sx_xunlock(&gre_ioctl_sx);
  212 }
  213 #endif /* VIMAGE */
  214 
  215 static void
  216 gre_clone_destroy(struct ifnet *ifp)
  217 {
  218         struct gre_softc *sc;
  219 
  220         sx_xlock(&gre_ioctl_sx);
  221         sc = ifp->if_softc;
  222         gre_delete_tunnel(sc);
  223         bpfdetach(ifp);
  224         if_detach(ifp);
  225         ifp->if_softc = NULL;
  226         sx_xunlock(&gre_ioctl_sx);
  227 
  228         GRE_WAIT();
  229         if_free(ifp);
  230         free(sc, M_GRE);
  231 }
  232 
  233 static int
  234 gre_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
  235 {
  236         struct ifreq *ifr = (struct ifreq *)data;
  237         struct gre_softc *sc;
  238         uint32_t opt;
  239         int error;
  240 
  241         switch (cmd) {
  242         case SIOCSIFMTU:
  243                  /* XXX: */
  244                 if (ifr->ifr_mtu < 576)
  245                         return (EINVAL);
  246                 ifp->if_mtu = ifr->ifr_mtu;
  247                 return (0);
  248         case SIOCSIFADDR:
  249                 ifp->if_flags |= IFF_UP;
  250         case SIOCSIFFLAGS:
  251         case SIOCADDMULTI:
  252         case SIOCDELMULTI:
  253                 return (0);
  254         case GRESADDRS:
  255         case GRESADDRD:
  256         case GREGADDRS:
  257         case GREGADDRD:
  258         case GRESPROTO:
  259         case GREGPROTO:
  260                 return (EOPNOTSUPP);
  261         }
  262         sx_xlock(&gre_ioctl_sx);
  263         sc = ifp->if_softc;
  264         if (sc == NULL) {
  265                 error = ENXIO;
  266                 goto end;
  267         }
  268         error = 0;
  269         switch (cmd) {
  270         case SIOCDIFPHYADDR:
  271                 if (sc->gre_family == 0)
  272                         break;
  273                 gre_delete_tunnel(sc);
  274                 break;
  275 #ifdef INET
  276         case SIOCSIFPHYADDR:
  277         case SIOCGIFPSRCADDR:
  278         case SIOCGIFPDSTADDR:
  279                 error = in_gre_ioctl(sc, cmd, data);
  280                 break;
  281 #endif
  282 #ifdef INET6
  283         case SIOCSIFPHYADDR_IN6:
  284         case SIOCGIFPSRCADDR_IN6:
  285         case SIOCGIFPDSTADDR_IN6:
  286                 error = in6_gre_ioctl(sc, cmd, data);
  287                 break;
  288 #endif
  289         case SIOCGTUNFIB:
  290                 ifr->ifr_fib = sc->gre_fibnum;
  291                 break;
  292         case SIOCSTUNFIB:
  293                 if ((error = priv_check(curthread, PRIV_NET_GRE)) != 0)
  294                         break;
  295                 if (ifr->ifr_fib >= rt_numfibs)
  296                         error = EINVAL;
  297                 else
  298                         sc->gre_fibnum = ifr->ifr_fib;
  299                 break;
  300         case GRESKEY:
  301         case GRESOPTS:
  302         case GRESPORT:
  303                 if ((error = priv_check(curthread, PRIV_NET_GRE)) != 0)
  304                         break;
  305                 if ((error = copyin(ifr_data_get_ptr(ifr), &opt,
  306                     sizeof(opt))) != 0)
  307                         break;
  308                 if (cmd == GRESKEY) {
  309                         if (sc->gre_key == opt)
  310                                 break;
  311                 } else if (cmd == GRESOPTS) {
  312                         if (opt & ~GRE_OPTMASK) {
  313                                 error = EINVAL;
  314                                 break;
  315                         }
  316                         if (sc->gre_options == opt)
  317                                 break;
  318                 } else if (cmd == GRESPORT) {
  319                         if (opt != 0 && (opt < V_ipport_hifirstauto ||
  320                             opt > V_ipport_hilastauto)) {
  321                                 error = EINVAL;
  322                                 break;
  323                         }
  324                         if (sc->gre_port == opt)
  325                                 break;
  326                         if ((sc->gre_options & GRE_UDPENCAP) == 0) {
  327                                 /*
  328                                  * UDP encapsulation is not enabled, thus
  329                                  * there is no need to reattach softc.
  330                                  */
  331                                 sc->gre_port = opt;
  332                                 break;
  333                         }
  334                 }
  335                 switch (sc->gre_family) {
  336 #ifdef INET
  337                 case AF_INET:
  338                         error = in_gre_setopts(sc, cmd, opt);
  339                         break;
  340 #endif
  341 #ifdef INET6
  342                 case AF_INET6:
  343                         error = in6_gre_setopts(sc, cmd, opt);
  344                         break;
  345 #endif
  346                 default:
  347                         /*
  348                          * Tunnel is not yet configured.
  349                          * We can just change any parameters.
  350                          */
  351                         if (cmd == GRESKEY)
  352                                 sc->gre_key = opt;
  353                         if (cmd == GRESOPTS)
  354                                 sc->gre_options = opt;
  355                         if (cmd == GRESPORT)
  356                                 sc->gre_port = opt;
  357                         break;
  358                 }
  359                 /*
  360                  * XXX: Do we need to initiate change of interface
  361                  * state here?
  362                  */
  363                 break;
  364         case GREGKEY:
  365                 error = copyout(&sc->gre_key, ifr_data_get_ptr(ifr),
  366                     sizeof(sc->gre_key));
  367                 break;
  368         case GREGOPTS:
  369                 error = copyout(&sc->gre_options, ifr_data_get_ptr(ifr),
  370                     sizeof(sc->gre_options));
  371                 break;
  372         case GREGPORT:
  373                 error = copyout(&sc->gre_port, ifr_data_get_ptr(ifr),
  374                     sizeof(sc->gre_port));
  375                 break;
  376         default:
  377                 error = EINVAL;
  378                 break;
  379         }
  380         if (error == 0 && sc->gre_family != 0) {
  381                 if (
  382 #ifdef INET
  383                     cmd == SIOCSIFPHYADDR ||
  384 #endif
  385 #ifdef INET6
  386                     cmd == SIOCSIFPHYADDR_IN6 ||
  387 #endif
  388                     0) {
  389                         if_link_state_change(ifp, LINK_STATE_UP);
  390                 }
  391         }
  392 end:
  393         sx_xunlock(&gre_ioctl_sx);
  394         return (error);
  395 }
  396 
  397 static void
  398 gre_delete_tunnel(struct gre_softc *sc)
  399 {
  400         struct gre_socket *gs;
  401 
  402         sx_assert(&gre_ioctl_sx, SA_XLOCKED);
  403         if (sc->gre_family != 0) {
  404                 CK_LIST_REMOVE(sc, chain);
  405                 CK_LIST_REMOVE(sc, srchash);
  406                 GRE_WAIT();
  407                 free(sc->gre_hdr, M_GRE);
  408                 sc->gre_family = 0;
  409         }
  410         /*
  411          * If this Tunnel was the last one that could use UDP socket,
  412          * we should unlink socket from hash table and close it.
  413          */
  414         if ((gs = sc->gre_so) != NULL && CK_LIST_EMPTY(&gs->list)) {
  415                 CK_LIST_REMOVE(gs, chain);
  416                 soclose(gs->so);
  417                 NET_EPOCH_CALL(gre_sofree, &gs->epoch_ctx);
  418                 sc->gre_so = NULL;
  419         }
  420         GRE2IFP(sc)->if_drv_flags &= ~IFF_DRV_RUNNING;
  421         if_link_state_change(GRE2IFP(sc), LINK_STATE_DOWN);
  422 }
  423 
  424 struct gre_list *
  425 gre_hashinit(void)
  426 {
  427         struct gre_list *hash;
  428         int i;
  429 
  430         hash = malloc(sizeof(struct gre_list) * GRE_HASH_SIZE,
  431             M_GRE, M_WAITOK);
  432         for (i = 0; i < GRE_HASH_SIZE; i++)
  433                 CK_LIST_INIT(&hash[i]);
  434 
  435         return (hash);
  436 }
  437 
  438 void
  439 gre_hashdestroy(struct gre_list *hash)
  440 {
  441 
  442         free(hash, M_GRE);
  443 }
  444 
  445 void
  446 gre_sofree(epoch_context_t ctx)
  447 {
  448         struct gre_socket *gs;
  449 
  450         gs = __containerof(ctx, struct gre_socket, epoch_ctx);
  451         free(gs, M_GRE);
  452 }
  453 
  454 static __inline uint16_t
  455 gre_cksum_add(uint16_t sum, uint16_t a)
  456 {
  457         uint16_t res;
  458 
  459         res = sum + a;
  460         return (res + (res < a));
  461 }
  462 
  463 void
  464 gre_update_udphdr(struct gre_softc *sc, struct udphdr *udp, uint16_t csum)
  465 {
  466 
  467         sx_assert(&gre_ioctl_sx, SA_XLOCKED);
  468         MPASS(sc->gre_options & GRE_UDPENCAP);
  469 
  470         udp->uh_dport = htons(GRE_UDPPORT);
  471         udp->uh_sport = htons(sc->gre_port);
  472         udp->uh_sum = csum;
  473         udp->uh_ulen = 0;
  474 }
  475 
  476 void
  477 gre_update_hdr(struct gre_softc *sc, struct grehdr *gh)
  478 {
  479         uint32_t *opts;
  480         uint16_t flags;
  481 
  482         sx_assert(&gre_ioctl_sx, SA_XLOCKED);
  483 
  484         flags = 0;
  485         opts = gh->gre_opts;
  486         if (sc->gre_options & GRE_ENABLE_CSUM) {
  487                 flags |= GRE_FLAGS_CP;
  488                 sc->gre_hlen += 2 * sizeof(uint16_t);
  489                 *opts++ = 0;
  490         }
  491         if (sc->gre_key != 0) {
  492                 flags |= GRE_FLAGS_KP;
  493                 sc->gre_hlen += sizeof(uint32_t);
  494                 *opts++ = htonl(sc->gre_key);
  495         }
  496         if (sc->gre_options & GRE_ENABLE_SEQ) {
  497                 flags |= GRE_FLAGS_SP;
  498                 sc->gre_hlen += sizeof(uint32_t);
  499                 *opts++ = 0;
  500         } else
  501                 sc->gre_oseq = 0;
  502         gh->gre_flags = htons(flags);
  503 }
  504 
  505 int
  506 gre_input(struct mbuf *m, int off, int proto, void *arg)
  507 {
  508         struct gre_softc *sc = arg;
  509         struct grehdr *gh;
  510         struct ifnet *ifp;
  511         uint32_t *opts;
  512 #ifdef notyet
  513         uint32_t key;
  514 #endif
  515         uint16_t flags;
  516         int hlen, isr, af;
  517 
  518         ifp = GRE2IFP(sc);
  519         hlen = off + sizeof(struct grehdr) + 4 * sizeof(uint32_t);
  520         if (m->m_pkthdr.len < hlen)
  521                 goto drop;
  522         if (m->m_len < hlen) {
  523                 m = m_pullup(m, hlen);
  524                 if (m == NULL)
  525                         goto drop;
  526         }
  527         gh = (struct grehdr *)mtodo(m, off);
  528         flags = ntohs(gh->gre_flags);
  529         if (flags & ~GRE_FLAGS_MASK)
  530                 goto drop;
  531         opts = gh->gre_opts;
  532         hlen = 2 * sizeof(uint16_t);
  533         if (flags & GRE_FLAGS_CP) {
  534                 /* reserved1 field must be zero */
  535                 if (((uint16_t *)opts)[1] != 0)
  536                         goto drop;
  537                 if (in_cksum_skip(m, m->m_pkthdr.len, off) != 0)
  538                         goto drop;
  539                 hlen += 2 * sizeof(uint16_t);
  540                 opts++;
  541         }
  542         if (flags & GRE_FLAGS_KP) {
  543 #ifdef notyet
  544         /* 
  545          * XXX: The current implementation uses the key only for outgoing
  546          * packets. But we can check the key value here, or even in the
  547          * encapcheck function.
  548          */
  549                 key = ntohl(*opts);
  550 #endif
  551                 hlen += sizeof(uint32_t);
  552                 opts++;
  553     }
  554 #ifdef notyet
  555         } else
  556                 key = 0;
  557 
  558         if (sc->gre_key != 0 && (key != sc->gre_key || key != 0))
  559                 goto drop;
  560 #endif
  561         if (flags & GRE_FLAGS_SP) {
  562 #ifdef notyet
  563                 seq = ntohl(*opts);
  564 #endif
  565                 hlen += sizeof(uint32_t);
  566         }
  567         switch (ntohs(gh->gre_proto)) {
  568         case ETHERTYPE_WCCP:
  569                 /*
  570                  * For WCCP skip an additional 4 bytes if after GRE header
  571                  * doesn't follow an IP header.
  572                  */
  573                 if (flags == 0 && (*(uint8_t *)gh->gre_opts & 0xF0) != 0x40)
  574                         hlen += sizeof(uint32_t);
  575                 /* FALLTHROUGH */
  576         case ETHERTYPE_IP:
  577                 isr = NETISR_IP;
  578                 af = AF_INET;
  579                 break;
  580         case ETHERTYPE_IPV6:
  581                 isr = NETISR_IPV6;
  582                 af = AF_INET6;
  583                 break;
  584         default:
  585                 goto drop;
  586         }
  587         m_adj(m, off + hlen);
  588         m_clrprotoflags(m);
  589         m->m_pkthdr.rcvif = ifp;
  590         M_SETFIB(m, ifp->if_fib);
  591 #ifdef MAC
  592         mac_ifnet_create_mbuf(ifp, m);
  593 #endif
  594         BPF_MTAP2(ifp, &af, sizeof(af), m);
  595         if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
  596         if_inc_counter(ifp, IFCOUNTER_IBYTES, m->m_pkthdr.len);
  597         if ((ifp->if_flags & IFF_MONITOR) != 0)
  598                 m_freem(m);
  599         else
  600                 netisr_dispatch(isr, m);
  601         return (IPPROTO_DONE);
  602 drop:
  603         if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
  604         m_freem(m);
  605         return (IPPROTO_DONE);
  606 }
  607 
  608 static int
  609 gre_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
  610    struct route *ro)
  611 {
  612         uint32_t af;
  613 
  614         if (dst->sa_family == AF_UNSPEC)
  615                 bcopy(dst->sa_data, &af, sizeof(af));
  616         else
  617                 af = RO_GET_FAMILY(ro, dst);
  618         /*
  619          * Now save the af in the inbound pkt csum data, this is a cheat since
  620          * we are using the inbound csum_data field to carry the af over to
  621          * the gre_transmit() routine, avoiding using yet another mtag.
  622          */
  623         m->m_pkthdr.csum_data = af;
  624         return (ifp->if_transmit(ifp, m));
  625 }
  626 
  627 static void
  628 gre_setseqn(struct grehdr *gh, uint32_t seq)
  629 {
  630         uint32_t *opts;
  631         uint16_t flags;
  632 
  633         opts = gh->gre_opts;
  634         flags = ntohs(gh->gre_flags);
  635         KASSERT((flags & GRE_FLAGS_SP) != 0,
  636             ("gre_setseqn called, but GRE_FLAGS_SP isn't set "));
  637         if (flags & GRE_FLAGS_CP)
  638                 opts++;
  639         if (flags & GRE_FLAGS_KP)
  640                 opts++;
  641         *opts = htonl(seq);
  642 }
  643 
  644 static uint32_t
  645 gre_flowid(struct gre_softc *sc, struct mbuf *m, uint32_t af)
  646 {
  647         uint32_t flowid = 0;
  648 
  649         if ((sc->gre_options & GRE_UDPENCAP) == 0 || sc->gre_port != 0)
  650                 return (flowid);
  651         switch (af) {
  652 #ifdef INET
  653         case AF_INET:
  654 #ifdef RSS
  655                 flowid = rss_hash_ip4_2tuple(mtod(m, struct ip *)->ip_src,
  656                     mtod(m, struct ip *)->ip_dst);
  657                 break;
  658 #endif
  659                 flowid = mtod(m, struct ip *)->ip_src.s_addr ^
  660                     mtod(m, struct ip *)->ip_dst.s_addr;
  661                 break;
  662 #endif
  663 #ifdef INET6
  664         case AF_INET6:
  665 #ifdef RSS
  666                 flowid = rss_hash_ip6_2tuple(
  667                     &mtod(m, struct ip6_hdr *)->ip6_src,
  668                     &mtod(m, struct ip6_hdr *)->ip6_dst);
  669                 break;
  670 #endif
  671                 flowid = mtod(m, struct ip6_hdr *)->ip6_src.s6_addr32[3] ^
  672                     mtod(m, struct ip6_hdr *)->ip6_dst.s6_addr32[3];
  673                 break;
  674 #endif
  675         default:
  676                 break;
  677         }
  678         return (flowid);
  679 }
  680 
  681 #define MTAG_GRE        1307983903
  682 static int
  683 gre_transmit(struct ifnet *ifp, struct mbuf *m)
  684 {
  685         GRE_RLOCK_TRACKER;
  686         struct gre_softc *sc;
  687         struct grehdr *gh;
  688         struct udphdr *uh;
  689         uint32_t af, flowid;
  690         int error, len;
  691         uint16_t proto;
  692 
  693         len = 0;
  694         GRE_RLOCK();
  695 #ifdef MAC
  696         error = mac_ifnet_check_transmit(ifp, m);
  697         if (error) {
  698                 m_freem(m);
  699                 goto drop;
  700         }
  701 #endif
  702         error = ENETDOWN;
  703         sc = ifp->if_softc;
  704         if ((ifp->if_flags & IFF_MONITOR) != 0 ||
  705             (ifp->if_flags & IFF_UP) == 0 ||
  706             (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 ||
  707             sc->gre_family == 0 ||
  708             (error = if_tunnel_check_nesting(ifp, m, MTAG_GRE,
  709                 V_max_gre_nesting)) != 0) {
  710                 m_freem(m);
  711                 goto drop;
  712         }
  713         af = m->m_pkthdr.csum_data;
  714         BPF_MTAP2(ifp, &af, sizeof(af), m);
  715         m->m_flags &= ~(M_BCAST|M_MCAST);
  716         flowid = gre_flowid(sc, m, af);
  717         M_SETFIB(m, sc->gre_fibnum);
  718         M_PREPEND(m, sc->gre_hlen, M_NOWAIT);
  719         if (m == NULL) {
  720                 error = ENOBUFS;
  721                 goto drop;
  722         }
  723         bcopy(sc->gre_hdr, mtod(m, void *), sc->gre_hlen);
  724         /* Determine GRE proto */
  725         switch (af) {
  726 #ifdef INET
  727         case AF_INET:
  728                 proto = htons(ETHERTYPE_IP);
  729                 break;
  730 #endif
  731 #ifdef INET6
  732         case AF_INET6:
  733                 proto = htons(ETHERTYPE_IPV6);
  734                 break;
  735 #endif
  736         default:
  737                 m_freem(m);
  738                 error = ENETDOWN;
  739                 goto drop;
  740         }
  741         /* Determine offset of GRE header */
  742         switch (sc->gre_family) {
  743 #ifdef INET
  744         case AF_INET:
  745                 len = sizeof(struct ip);
  746                 break;
  747 #endif
  748 #ifdef INET6
  749         case AF_INET6:
  750                 len = sizeof(struct ip6_hdr);
  751                 break;
  752 #endif
  753         default:
  754                 m_freem(m);
  755                 error = ENETDOWN;
  756                 goto drop;
  757         }
  758         if (sc->gre_options & GRE_UDPENCAP) {
  759                 uh = (struct udphdr *)mtodo(m, len);
  760                 uh->uh_sport |= htons(V_ipport_hifirstauto) |
  761                     (flowid >> 16) | (flowid & 0xFFFF);
  762                 uh->uh_sport = htons(ntohs(uh->uh_sport) %
  763                     V_ipport_hilastauto);
  764                 uh->uh_ulen = htons(m->m_pkthdr.len - len);
  765                 uh->uh_sum = gre_cksum_add(uh->uh_sum,
  766                     htons(m->m_pkthdr.len - len + IPPROTO_UDP));
  767                 m->m_pkthdr.csum_flags = sc->gre_csumflags;
  768                 m->m_pkthdr.csum_data = offsetof(struct udphdr, uh_sum);
  769                 len += sizeof(struct udphdr);
  770         }
  771         gh = (struct grehdr *)mtodo(m, len);
  772         gh->gre_proto = proto;
  773         if (sc->gre_options & GRE_ENABLE_SEQ)
  774                 gre_setseqn(gh, sc->gre_oseq++);
  775         if (sc->gre_options & GRE_ENABLE_CSUM) {
  776                 *(uint16_t *)gh->gre_opts = in_cksum_skip(m,
  777                     m->m_pkthdr.len, len);
  778         }
  779         len = m->m_pkthdr.len - len;
  780         switch (sc->gre_family) {
  781 #ifdef INET
  782         case AF_INET:
  783                 error = in_gre_output(m, af, sc->gre_hlen);
  784                 break;
  785 #endif
  786 #ifdef INET6
  787         case AF_INET6:
  788                 error = in6_gre_output(m, af, sc->gre_hlen, flowid);
  789                 break;
  790 #endif
  791         default:
  792                 m_freem(m);
  793                 error = ENETDOWN;
  794         }
  795 drop:
  796         if (error)
  797                 if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
  798         else {
  799                 if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
  800                 if_inc_counter(ifp, IFCOUNTER_OBYTES, len);
  801         }
  802         GRE_RUNLOCK();
  803         return (error);
  804 }
  805 
  806 static void
  807 gre_qflush(struct ifnet *ifp __unused)
  808 {
  809 
  810 }
  811 
  812 static int
  813 gremodevent(module_t mod, int type, void *data)
  814 {
  815 
  816         switch (type) {
  817         case MOD_LOAD:
  818         case MOD_UNLOAD:
  819                 break;
  820         default:
  821                 return (EOPNOTSUPP);
  822         }
  823         return (0);
  824 }
  825 
  826 static moduledata_t gre_mod = {
  827         "if_gre",
  828         gremodevent,
  829         0
  830 };
  831 
  832 DECLARE_MODULE(if_gre, gre_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
  833 MODULE_VERSION(if_gre, 1);

Cache object: 873b7c2b1ed278e6a305dce8e67e537f


[ 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.