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/netinet6/ip6_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  * Copyright (c) 2014, 2018 Andrey V. Elsukov <ae@FreeBSD.org>
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  *
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   25  */
   26 
   27 #include <sys/cdefs.h>
   28 __FBSDID("$FreeBSD$");
   29 
   30 #include "opt_inet.h"
   31 #include "opt_inet6.h"
   32 
   33 #include <sys/param.h>
   34 #include <sys/jail.h>
   35 #include <sys/systm.h>
   36 #include <sys/socket.h>
   37 #include <sys/socketvar.h>
   38 #include <sys/sockio.h>
   39 #include <sys/mbuf.h>
   40 #include <sys/errno.h>
   41 #include <sys/kernel.h>
   42 #include <sys/sysctl.h>
   43 #include <sys/malloc.h>
   44 #include <sys/proc.h>
   45 
   46 #include <net/if.h>
   47 #include <net/if_var.h>
   48 #include <net/vnet.h>
   49 
   50 #include <netinet/in.h>
   51 #ifdef INET
   52 #include <net/ethernet.h>
   53 #include <netinet/ip.h>
   54 #endif
   55 #include <netinet/in_pcb.h>
   56 #include <netinet/ip_encap.h>
   57 #include <netinet/ip_var.h>
   58 #include <netinet/ip6.h>
   59 #include <netinet/udp.h>
   60 #include <netinet/udp_var.h>
   61 #include <netinet6/ip6_var.h>
   62 #include <netinet6/in6_var.h>
   63 #include <netinet6/scope6_var.h>
   64 #include <net/if_gre.h>
   65 
   66 VNET_DEFINE(int, ip6_gre_hlim) = IPV6_DEFHLIM;
   67 #define V_ip6_gre_hlim          VNET(ip6_gre_hlim)
   68 
   69 SYSCTL_DECL(_net_inet6_ip6);
   70 SYSCTL_INT(_net_inet6_ip6, OID_AUTO, grehlim, CTLFLAG_VNET | CTLFLAG_RW,
   71     &VNET_NAME(ip6_gre_hlim), 0, "Default hop limit for encapsulated packets");
   72 
   73 struct in6_gre_socket {
   74         struct gre_socket       base;
   75         struct in6_addr         addr; /* scope zone id is embedded */
   76 };
   77 VNET_DEFINE_STATIC(struct gre_sockets *, ipv6_sockets) = NULL;
   78 VNET_DEFINE_STATIC(struct gre_list *, ipv6_hashtbl) = NULL;
   79 VNET_DEFINE_STATIC(struct gre_list *, ipv6_srchashtbl) = NULL;
   80 #define V_ipv6_sockets          VNET(ipv6_sockets)
   81 #define V_ipv6_hashtbl          VNET(ipv6_hashtbl)
   82 #define V_ipv6_srchashtbl       VNET(ipv6_srchashtbl)
   83 #define GRE_HASH(src, dst)      (V_ipv6_hashtbl[\
   84     in6_gre_hashval((src), (dst)) & (GRE_HASH_SIZE - 1)])
   85 #define GRE_SRCHASH(src)        (V_ipv6_srchashtbl[\
   86     fnv_32_buf((src), sizeof(*src), FNV1_32_INIT) & (GRE_HASH_SIZE - 1)])
   87 #define GRE_SOCKHASH(src)       (V_ipv6_sockets[\
   88     fnv_32_buf((src), sizeof(*src), FNV1_32_INIT) & (GRE_HASH_SIZE - 1)])
   89 #define GRE_HASH_SC(sc)         GRE_HASH(&(sc)->gre_oip6.ip6_src,\
   90     &(sc)->gre_oip6.ip6_dst)
   91 
   92 static uint32_t
   93 in6_gre_hashval(const struct in6_addr *src, const struct in6_addr *dst)
   94 {
   95         uint32_t ret;
   96 
   97         ret = fnv_32_buf(src, sizeof(*src), FNV1_32_INIT);
   98         return (fnv_32_buf(dst, sizeof(*dst), ret));
   99 }
  100 
  101 static struct gre_socket*
  102 in6_gre_lookup_socket(const struct in6_addr *addr)
  103 {
  104         struct gre_socket *gs;
  105         struct in6_gre_socket *s;
  106 
  107         CK_LIST_FOREACH(gs, &GRE_SOCKHASH(addr), chain) {
  108                 s = __containerof(gs, struct in6_gre_socket, base);
  109                 if (IN6_ARE_ADDR_EQUAL(&s->addr, addr))
  110                         break;
  111         }
  112         return (gs);
  113 }
  114 
  115 static int
  116 in6_gre_checkdup(const struct gre_softc *sc, const struct in6_addr *src,
  117     const struct in6_addr *dst, uint32_t opts)
  118 {
  119         struct gre_list *head;
  120         struct gre_softc *tmp;
  121         struct gre_socket *gs;
  122 
  123         if (sc->gre_family == AF_INET6 &&
  124             IN6_ARE_ADDR_EQUAL(&sc->gre_oip6.ip6_src, src) &&
  125             IN6_ARE_ADDR_EQUAL(&sc->gre_oip6.ip6_dst, dst) &&
  126             (sc->gre_options & GRE_UDPENCAP) == (opts & GRE_UDPENCAP))
  127                 return (EEXIST);
  128 
  129         if (opts & GRE_UDPENCAP) {
  130                 gs = in6_gre_lookup_socket(src);
  131                 if (gs == NULL)
  132                         return (0);
  133                 head = &gs->list;
  134         } else
  135                 head = &GRE_HASH(src, dst);
  136 
  137         CK_LIST_FOREACH(tmp, head, chain) {
  138                 if (tmp == sc)
  139                         continue;
  140                 if (IN6_ARE_ADDR_EQUAL(&tmp->gre_oip6.ip6_src, src) &&
  141                     IN6_ARE_ADDR_EQUAL(&tmp->gre_oip6.ip6_dst, dst))
  142                         return (EADDRNOTAVAIL);
  143         }
  144         return (0);
  145 }
  146 
  147 static int
  148 in6_gre_lookup(const struct mbuf *m, int off, int proto, void **arg)
  149 {
  150         const struct ip6_hdr *ip6;
  151         struct gre_softc *sc;
  152 
  153         if (V_ipv6_hashtbl == NULL)
  154                 return (0);
  155 
  156         NET_EPOCH_ASSERT();
  157         ip6 = mtod(m, const struct ip6_hdr *);
  158         CK_LIST_FOREACH(sc, &GRE_HASH(&ip6->ip6_dst, &ip6->ip6_src), chain) {
  159                 /*
  160                  * This is an inbound packet, its ip6_dst is source address
  161                  * in softc.
  162                  */
  163                 if (IN6_ARE_ADDR_EQUAL(&sc->gre_oip6.ip6_src,
  164                     &ip6->ip6_dst) &&
  165                     IN6_ARE_ADDR_EQUAL(&sc->gre_oip6.ip6_dst,
  166                     &ip6->ip6_src)) {
  167                         if ((GRE2IFP(sc)->if_flags & IFF_UP) == 0)
  168                                 return (0);
  169                         *arg = sc;
  170                         return (ENCAP_DRV_LOOKUP);
  171                 }
  172         }
  173         return (0);
  174 }
  175 
  176 /*
  177  * Check that ingress address belongs to local host.
  178  */
  179 static void
  180 in6_gre_set_running(struct gre_softc *sc)
  181 {
  182 
  183         if (in6_localip(&sc->gre_oip6.ip6_src))
  184                 GRE2IFP(sc)->if_drv_flags |= IFF_DRV_RUNNING;
  185         else
  186                 GRE2IFP(sc)->if_drv_flags &= ~IFF_DRV_RUNNING;
  187 }
  188 
  189 /*
  190  * ifaddr_event handler.
  191  * Clear IFF_DRV_RUNNING flag when ingress address disappears to prevent
  192  * source address spoofing.
  193  */
  194 static void
  195 in6_gre_srcaddr(void *arg __unused, const struct sockaddr *sa,
  196     int event __unused)
  197 {
  198         const struct sockaddr_in6 *sin;
  199         struct gre_softc *sc;
  200 
  201         /* Check that VNET is ready */
  202         if (V_ipv6_hashtbl == NULL)
  203                 return;
  204 
  205         NET_EPOCH_ASSERT();
  206         sin = (const struct sockaddr_in6 *)sa;
  207         CK_LIST_FOREACH(sc, &GRE_SRCHASH(&sin->sin6_addr), srchash) {
  208                 if (IN6_ARE_ADDR_EQUAL(&sc->gre_oip6.ip6_src,
  209                     &sin->sin6_addr) == 0)
  210                         continue;
  211                 in6_gre_set_running(sc);
  212         }
  213 }
  214 
  215 static bool
  216 in6_gre_udp_input(struct mbuf *m, int off, struct inpcb *inp,
  217     const struct sockaddr *sa, void *ctx)
  218 {
  219         struct gre_socket *gs;
  220         struct gre_softc *sc;
  221         struct sockaddr_in6 dst;
  222 
  223         NET_EPOCH_ASSERT();
  224 
  225         gs = (struct gre_socket *)ctx;
  226         dst = *(const struct sockaddr_in6 *)sa;
  227         if (sa6_embedscope(&dst, 0)) {
  228                 m_freem(m);
  229                 return (true);
  230         }
  231         CK_LIST_FOREACH(sc, &gs->list, chain) {
  232                 if (IN6_ARE_ADDR_EQUAL(&sc->gre_oip6.ip6_dst, &dst.sin6_addr))
  233                         break;
  234         }
  235         if (sc != NULL && (GRE2IFP(sc)->if_flags & IFF_UP) != 0){
  236                 gre_input(m, off + sizeof(struct udphdr), IPPROTO_UDP, sc);
  237                 return (true);
  238         }
  239         m_freem(m);
  240 
  241         return (true);
  242 }
  243 
  244 static int
  245 in6_gre_setup_socket(struct gre_softc *sc)
  246 {
  247         struct sockopt sopt;
  248         struct sockaddr_in6 sin6;
  249         struct in6_gre_socket *s;
  250         struct gre_socket *gs;
  251         int error, value;
  252 
  253         /*
  254          * NOTE: we are protected with gre_ioctl_sx lock.
  255          *
  256          * First check that socket is already configured.
  257          * If so, check that source address was not changed.
  258          * If address is different, check that there are no other tunnels
  259          * and close socket.
  260          */
  261         gs = sc->gre_so;
  262         if (gs != NULL) {
  263                 s = __containerof(gs, struct in6_gre_socket, base);
  264                 if (!IN6_ARE_ADDR_EQUAL(&s->addr, &sc->gre_oip6.ip6_src)) {
  265                         if (CK_LIST_EMPTY(&gs->list)) {
  266                                 CK_LIST_REMOVE(gs, chain);
  267                                 soclose(gs->so);
  268                                 NET_EPOCH_CALL(gre_sofree, &gs->epoch_ctx);
  269                         }
  270                         gs = sc->gre_so = NULL;
  271                 }
  272         }
  273 
  274         if (gs == NULL) {
  275                 /*
  276                  * Check that socket for given address is already
  277                  * configured.
  278                  */
  279                 gs = in6_gre_lookup_socket(&sc->gre_oip6.ip6_src);
  280                 if (gs == NULL) {
  281                         s = malloc(sizeof(*s), M_GRE, M_WAITOK | M_ZERO);
  282                         s->addr = sc->gre_oip6.ip6_src;
  283                         gs = &s->base;
  284 
  285                         error = socreate(sc->gre_family, &gs->so,
  286                             SOCK_DGRAM, IPPROTO_UDP, curthread->td_ucred,
  287                             curthread);
  288                         if (error != 0) {
  289                                 if_printf(GRE2IFP(sc),
  290                                     "cannot create socket: %d\n", error);
  291                                 free(s, M_GRE);
  292                                 return (error);
  293                         }
  294 
  295                         error = udp_set_kernel_tunneling(gs->so,
  296                             in6_gre_udp_input, NULL, gs);
  297                         if (error != 0) {
  298                                 if_printf(GRE2IFP(sc),
  299                                     "cannot set UDP tunneling: %d\n", error);
  300                                 goto fail;
  301                         }
  302 
  303                         memset(&sopt, 0, sizeof(sopt));
  304                         sopt.sopt_dir = SOPT_SET;
  305                         sopt.sopt_level = IPPROTO_IPV6;
  306                         sopt.sopt_name = IPV6_BINDANY;
  307                         sopt.sopt_val = &value;
  308                         sopt.sopt_valsize = sizeof(value);
  309                         value = 1;
  310                         error = sosetopt(gs->so, &sopt);
  311                         if (error != 0) {
  312                                 if_printf(GRE2IFP(sc),
  313                                     "cannot set IPV6_BINDANY opt: %d\n",
  314                                     error);
  315                                 goto fail;
  316                         }
  317 
  318                         memset(&sin6, 0, sizeof(sin6));
  319                         sin6.sin6_family = AF_INET6;
  320                         sin6.sin6_len = sizeof(sin6);
  321                         sin6.sin6_addr = sc->gre_oip6.ip6_src;
  322                         sin6.sin6_port = htons(GRE_UDPPORT);
  323                         error = sa6_recoverscope(&sin6);
  324                         if (error != 0) {
  325                                 if_printf(GRE2IFP(sc),
  326                                     "cannot determine scope zone id: %d\n",
  327                                     error);
  328                                 goto fail;
  329                         }
  330                         error = sobind(gs->so, (struct sockaddr *)&sin6,
  331                             curthread);
  332                         if (error != 0) {
  333                                 if_printf(GRE2IFP(sc),
  334                                     "cannot bind socket: %d\n", error);
  335                                 goto fail;
  336                         }
  337                         /* Add socket to the chain */
  338                         CK_LIST_INSERT_HEAD(
  339                             &GRE_SOCKHASH(&sc->gre_oip6.ip6_src), gs, chain);
  340                 }
  341         }
  342 
  343         /* Add softc to the socket's list */
  344         CK_LIST_INSERT_HEAD(&gs->list, sc, chain);
  345         sc->gre_so = gs;
  346         return (0);
  347 fail:
  348         soclose(gs->so);
  349         free(s, M_GRE);
  350         return (error);
  351 }
  352 
  353 static int
  354 in6_gre_attach(struct gre_softc *sc)
  355 {
  356         struct grehdr *gh;
  357         int error;
  358 
  359         if (sc->gre_options & GRE_UDPENCAP) {
  360                 sc->gre_csumflags = CSUM_UDP_IPV6;
  361                 sc->gre_hlen = sizeof(struct greudp6);
  362                 sc->gre_oip6.ip6_nxt = IPPROTO_UDP;
  363                 gh = &sc->gre_udp6hdr->gi6_gre;
  364                 gre_update_udphdr(sc, &sc->gre_udp6,
  365                     in6_cksum_pseudo(&sc->gre_oip6, 0, 0, 0));
  366         } else {
  367                 sc->gre_hlen = sizeof(struct greip6);
  368                 sc->gre_oip6.ip6_nxt = IPPROTO_GRE;
  369                 gh = &sc->gre_ip6hdr->gi6_gre;
  370         }
  371         sc->gre_oip6.ip6_vfc = IPV6_VERSION;
  372         gre_update_hdr(sc, gh);
  373 
  374         /*
  375          * If we return error, this means that sc is not linked,
  376          * and caller should reset gre_family and free(sc->gre_hdr).
  377          */
  378         if (sc->gre_options & GRE_UDPENCAP) {
  379                 error = in6_gre_setup_socket(sc);
  380                 if (error != 0)
  381                         return (error);
  382         } else
  383                 CK_LIST_INSERT_HEAD(&GRE_HASH_SC(sc), sc, chain);
  384         CK_LIST_INSERT_HEAD(&GRE_SRCHASH(&sc->gre_oip6.ip6_src), sc, srchash);
  385 
  386         /* Set IFF_DRV_RUNNING if interface is ready */
  387         in6_gre_set_running(sc);
  388         return (0);
  389 }
  390 
  391 int
  392 in6_gre_setopts(struct gre_softc *sc, u_long cmd, uint32_t value)
  393 {
  394         int error;
  395 
  396         /* NOTE: we are protected with gre_ioctl_sx lock */
  397         MPASS(cmd == GRESKEY || cmd == GRESOPTS || cmd == GRESPORT);
  398         MPASS(sc->gre_family == AF_INET6);
  399 
  400         /*
  401          * If we are going to change encapsulation protocol, do check
  402          * for duplicate tunnels. Return EEXIST here to do not confuse
  403          * user.
  404          */
  405         if (cmd == GRESOPTS &&
  406             (sc->gre_options & GRE_UDPENCAP) != (value & GRE_UDPENCAP) &&
  407             in6_gre_checkdup(sc, &sc->gre_oip6.ip6_src,
  408                 &sc->gre_oip6.ip6_dst, value) == EADDRNOTAVAIL)
  409                 return (EEXIST);
  410 
  411         CK_LIST_REMOVE(sc, chain);
  412         CK_LIST_REMOVE(sc, srchash);
  413         GRE_WAIT();
  414         switch (cmd) {
  415         case GRESKEY:
  416                 sc->gre_key = value;
  417                 break;
  418         case GRESOPTS:
  419                 sc->gre_options = value;
  420                 break;
  421         case GRESPORT:
  422                 sc->gre_port = value;
  423                 break;
  424         }
  425         error = in6_gre_attach(sc);
  426         if (error != 0) {
  427                 sc->gre_family = 0;
  428                 free(sc->gre_hdr, M_GRE);
  429         }
  430         return (error);
  431 }
  432 
  433 int
  434 in6_gre_ioctl(struct gre_softc *sc, u_long cmd, caddr_t data)
  435 {
  436         struct in6_ifreq *ifr = (struct in6_ifreq *)data;
  437         struct sockaddr_in6 *dst, *src;
  438         struct ip6_hdr *ip6;
  439         int error;
  440 
  441         /* NOTE: we are protected with gre_ioctl_sx lock */
  442         error = EINVAL;
  443         switch (cmd) {
  444         case SIOCSIFPHYADDR_IN6:
  445                 src = &((struct in6_aliasreq *)data)->ifra_addr;
  446                 dst = &((struct in6_aliasreq *)data)->ifra_dstaddr;
  447 
  448                 /* sanity checks */
  449                 if (src->sin6_family != dst->sin6_family ||
  450                     src->sin6_family != AF_INET6 ||
  451                     src->sin6_len != dst->sin6_len ||
  452                     src->sin6_len != sizeof(*src))
  453                         break;
  454                 if (IN6_IS_ADDR_UNSPECIFIED(&src->sin6_addr) ||
  455                     IN6_IS_ADDR_UNSPECIFIED(&dst->sin6_addr)) {
  456                         error = EADDRNOTAVAIL;
  457                         break;
  458                 }
  459                 /*
  460                  * Check validity of the scope zone ID of the
  461                  * addresses, and convert it into the kernel
  462                  * internal form if necessary.
  463                  */
  464                 if ((error = sa6_embedscope(src, 0)) != 0 ||
  465                     (error = sa6_embedscope(dst, 0)) != 0)
  466                         break;
  467 
  468                 if (V_ipv6_hashtbl == NULL) {
  469                         V_ipv6_hashtbl = gre_hashinit();
  470                         V_ipv6_srchashtbl = gre_hashinit();
  471                         V_ipv6_sockets = (struct gre_sockets *)gre_hashinit();
  472                 }
  473                 error = in6_gre_checkdup(sc, &src->sin6_addr,
  474                     &dst->sin6_addr, sc->gre_options);
  475                 if (error == EADDRNOTAVAIL)
  476                         break;
  477                 if (error == EEXIST) {
  478                         /* Addresses are the same. Just return. */
  479                         error = 0;
  480                         break;
  481                 }
  482                 ip6 = malloc(sizeof(struct greudp6) + 3 * sizeof(uint32_t),
  483                     M_GRE, M_WAITOK | M_ZERO);
  484                 ip6->ip6_src = src->sin6_addr;
  485                 ip6->ip6_dst = dst->sin6_addr;
  486                 if (sc->gre_family != 0) {
  487                         /* Detach existing tunnel first */
  488                         CK_LIST_REMOVE(sc, chain);
  489                         CK_LIST_REMOVE(sc, srchash);
  490                         GRE_WAIT();
  491                         free(sc->gre_hdr, M_GRE);
  492                         /* XXX: should we notify about link state change? */
  493                 }
  494                 sc->gre_family = AF_INET6;
  495                 sc->gre_hdr = ip6;
  496                 sc->gre_oseq = 0;
  497                 sc->gre_iseq = UINT32_MAX;
  498                 error = in6_gre_attach(sc);
  499                 if (error != 0) {
  500                         sc->gre_family = 0;
  501                         free(sc->gre_hdr, M_GRE);
  502                 }
  503                 break;
  504         case SIOCGIFPSRCADDR_IN6:
  505         case SIOCGIFPDSTADDR_IN6:
  506                 if (sc->gre_family != AF_INET6) {
  507                         error = EADDRNOTAVAIL;
  508                         break;
  509                 }
  510                 src = (struct sockaddr_in6 *)&ifr->ifr_addr;
  511                 memset(src, 0, sizeof(*src));
  512                 src->sin6_family = AF_INET6;
  513                 src->sin6_len = sizeof(*src);
  514                 src->sin6_addr = (cmd == SIOCGIFPSRCADDR_IN6) ?
  515                     sc->gre_oip6.ip6_src: sc->gre_oip6.ip6_dst;
  516                 error = prison_if(curthread->td_ucred, (struct sockaddr *)src);
  517                 if (error == 0)
  518                         error = sa6_recoverscope(src);
  519                 if (error != 0)
  520                         memset(src, 0, sizeof(*src));
  521                 break;
  522         }
  523         return (error);
  524 }
  525 
  526 int
  527 in6_gre_output(struct mbuf *m, int af __unused, int hlen __unused,
  528     uint32_t flowid)
  529 {
  530         struct greip6 *gi6;
  531 
  532         gi6 = mtod(m, struct greip6 *);
  533         gi6->gi6_ip6.ip6_hlim = V_ip6_gre_hlim;
  534         gi6->gi6_ip6.ip6_flow |= flowid & IPV6_FLOWLABEL_MASK;
  535         return (ip6_output(m, NULL, NULL, IPV6_MINMTU, NULL, NULL, NULL));
  536 }
  537 
  538 static const struct srcaddrtab *ipv6_srcaddrtab = NULL;
  539 static const struct encaptab *ecookie = NULL;
  540 static const struct encap_config ipv6_encap_cfg = {
  541         .proto = IPPROTO_GRE,
  542         .min_length = sizeof(struct greip6) +
  543 #ifdef INET
  544             sizeof(struct ip),
  545 #else
  546             sizeof(struct ip6_hdr),
  547 #endif
  548         .exact_match = ENCAP_DRV_LOOKUP,
  549         .lookup = in6_gre_lookup,
  550         .input = gre_input
  551 };
  552 
  553 void
  554 in6_gre_init(void)
  555 {
  556 
  557         if (!IS_DEFAULT_VNET(curvnet))
  558                 return;
  559         ipv6_srcaddrtab = ip6_encap_register_srcaddr(in6_gre_srcaddr,
  560             NULL, M_WAITOK);
  561         ecookie = ip6_encap_attach(&ipv6_encap_cfg, NULL, M_WAITOK);
  562 }
  563 
  564 void
  565 in6_gre_uninit(void)
  566 {
  567 
  568         if (IS_DEFAULT_VNET(curvnet)) {
  569                 ip6_encap_detach(ecookie);
  570                 ip6_encap_unregister_srcaddr(ipv6_srcaddrtab);
  571         }
  572         if (V_ipv6_hashtbl != NULL) {
  573                 gre_hashdestroy(V_ipv6_hashtbl);
  574                 V_ipv6_hashtbl = NULL;
  575                 GRE_WAIT();
  576                 gre_hashdestroy(V_ipv6_srchashtbl);
  577                 gre_hashdestroy((struct gre_list *)V_ipv6_sockets);
  578         }
  579 }

Cache object: 69a567c3b3b1d13d205ab4df80d77aae


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