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         MPASS(in_epoch(net_epoch_preempt));
  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         MPASS(in_epoch(net_epoch_preempt));
  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 void
  216 in6_gre_udp_input(struct mbuf *m, int off, struct inpcb *inp,
  217     const struct sockaddr *sa, void *ctx)
  218 {
  219         struct epoch_tracker et;
  220         struct gre_socket *gs;
  221         struct gre_softc *sc;
  222         struct sockaddr_in6 dst;
  223 
  224         NET_EPOCH_ENTER_ET(et);
  225         /*
  226          * udp_append() holds reference to inp, it is safe to check
  227          * inp_flags2 without INP_RLOCK().
  228          * If socket was closed before we have entered NET_EPOCH section,
  229          * INP_FREED flag should be set. Otherwise it should be safe to
  230          * make access to ctx data, because gre_so will be freed by
  231          * gre_sofree() via epoch_call().
  232          */
  233         if (__predict_false(inp->inp_flags2 & INP_FREED)) {
  234                 NET_EPOCH_EXIT_ET(et);
  235                 m_freem(m);
  236                 return;
  237         }
  238 
  239         gs = (struct gre_socket *)ctx;
  240         dst = *(const struct sockaddr_in6 *)sa;
  241         if (sa6_embedscope(&dst, 0)) {
  242                 NET_EPOCH_EXIT_ET(et);
  243                 m_freem(m);
  244                 return;
  245         }
  246         CK_LIST_FOREACH(sc, &gs->list, chain) {
  247                 if (IN6_ARE_ADDR_EQUAL(&sc->gre_oip6.ip6_dst, &dst.sin6_addr))
  248                         break;
  249         }
  250         if (sc != NULL && (GRE2IFP(sc)->if_flags & IFF_UP) != 0){
  251                 gre_input(m, off + sizeof(struct udphdr), IPPROTO_UDP, sc);
  252                 NET_EPOCH_EXIT_ET(et);
  253                 return;
  254         }
  255         m_freem(m);
  256         NET_EPOCH_EXIT_ET(et);
  257 }
  258 
  259 static int
  260 in6_gre_setup_socket(struct gre_softc *sc)
  261 {
  262         struct sockopt sopt;
  263         struct sockaddr_in6 sin6;
  264         struct in6_gre_socket *s;
  265         struct gre_socket *gs;
  266         int error, value;
  267 
  268         /*
  269          * NOTE: we are protected with gre_ioctl_sx lock.
  270          *
  271          * First check that socket is already configured.
  272          * If so, check that source address was not changed.
  273          * If address is different, check that there are no other tunnels
  274          * and close socket.
  275          */
  276         gs = sc->gre_so;
  277         if (gs != NULL) {
  278                 s = __containerof(gs, struct in6_gre_socket, base);
  279                 if (!IN6_ARE_ADDR_EQUAL(&s->addr, &sc->gre_oip6.ip6_src)) {
  280                         if (CK_LIST_EMPTY(&gs->list)) {
  281                                 CK_LIST_REMOVE(gs, chain);
  282                                 soclose(gs->so);
  283                                 epoch_call(net_epoch_preempt, &gs->epoch_ctx,
  284                                     gre_sofree);
  285                         }
  286                         gs = sc->gre_so = NULL;
  287                 }
  288         }
  289 
  290         if (gs == NULL) {
  291                 /*
  292                  * Check that socket for given address is already
  293                  * configured.
  294                  */
  295                 gs = in6_gre_lookup_socket(&sc->gre_oip6.ip6_src);
  296                 if (gs == NULL) {
  297                         s = malloc(sizeof(*s), M_GRE, M_WAITOK | M_ZERO);
  298                         s->addr = sc->gre_oip6.ip6_src;
  299                         gs = &s->base;
  300 
  301                         error = socreate(sc->gre_family, &gs->so,
  302                             SOCK_DGRAM, IPPROTO_UDP, curthread->td_ucred,
  303                             curthread);
  304                         if (error != 0) {
  305                                 if_printf(GRE2IFP(sc),
  306                                     "cannot create socket: %d\n", error);
  307                                 free(s, M_GRE);
  308                                 return (error);
  309                         }
  310 
  311                         error = udp_set_kernel_tunneling(gs->so,
  312                             in6_gre_udp_input, NULL, gs);
  313                         if (error != 0) {
  314                                 if_printf(GRE2IFP(sc),
  315                                     "cannot set UDP tunneling: %d\n", error);
  316                                 goto fail;
  317                         }
  318 
  319                         memset(&sopt, 0, sizeof(sopt));
  320                         sopt.sopt_dir = SOPT_SET;
  321                         sopt.sopt_level = IPPROTO_IPV6;
  322                         sopt.sopt_name = IPV6_BINDANY;
  323                         sopt.sopt_val = &value;
  324                         sopt.sopt_valsize = sizeof(value);
  325                         value = 1;
  326                         error = sosetopt(gs->so, &sopt);
  327                         if (error != 0) {
  328                                 if_printf(GRE2IFP(sc),
  329                                     "cannot set IPV6_BINDANY opt: %d\n",
  330                                     error);
  331                                 goto fail;
  332                         }
  333 
  334                         memset(&sin6, 0, sizeof(sin6));
  335                         sin6.sin6_family = AF_INET6;
  336                         sin6.sin6_len = sizeof(sin6);
  337                         sin6.sin6_addr = sc->gre_oip6.ip6_src;
  338                         sin6.sin6_port = htons(GRE_UDPPORT);
  339                         error = sa6_recoverscope(&sin6);
  340                         if (error != 0) {
  341                                 if_printf(GRE2IFP(sc),
  342                                     "cannot determine scope zone id: %d\n",
  343                                     error);
  344                                 goto fail;
  345                         }
  346                         error = sobind(gs->so, (struct sockaddr *)&sin6,
  347                             curthread);
  348                         if (error != 0) {
  349                                 if_printf(GRE2IFP(sc),
  350                                     "cannot bind socket: %d\n", error);
  351                                 goto fail;
  352                         }
  353                         /* Add socket to the chain */
  354                         CK_LIST_INSERT_HEAD(
  355                             &GRE_SOCKHASH(&sc->gre_oip6.ip6_src), gs, chain);
  356                 }
  357         }
  358 
  359         /* Add softc to the socket's list */
  360         CK_LIST_INSERT_HEAD(&gs->list, sc, chain);
  361         sc->gre_so = gs;
  362         return (0);
  363 fail:
  364         soclose(gs->so);
  365         free(s, M_GRE);
  366         return (error);
  367 }
  368 
  369 static int
  370 in6_gre_attach(struct gre_softc *sc)
  371 {
  372         struct grehdr *gh;
  373         int error;
  374 
  375         if (sc->gre_options & GRE_UDPENCAP) {
  376                 sc->gre_csumflags = CSUM_UDP_IPV6;
  377                 sc->gre_hlen = sizeof(struct greudp6);
  378                 sc->gre_oip6.ip6_nxt = IPPROTO_UDP;
  379                 gh = &sc->gre_udp6hdr->gi6_gre;
  380                 gre_update_udphdr(sc, &sc->gre_udp6,
  381                     in6_cksum_pseudo(&sc->gre_oip6, 0, 0, 0));
  382         } else {
  383                 sc->gre_hlen = sizeof(struct greip6);
  384                 sc->gre_oip6.ip6_nxt = IPPROTO_GRE;
  385                 gh = &sc->gre_ip6hdr->gi6_gre;
  386         }
  387         sc->gre_oip6.ip6_vfc = IPV6_VERSION;
  388         gre_update_hdr(sc, gh);
  389 
  390         /*
  391          * If we return error, this means that sc is not linked,
  392          * and caller should reset gre_family and free(sc->gre_hdr).
  393          */
  394         if (sc->gre_options & GRE_UDPENCAP) {
  395                 error = in6_gre_setup_socket(sc);
  396                 if (error != 0)
  397                         return (error);
  398         } else
  399                 CK_LIST_INSERT_HEAD(&GRE_HASH_SC(sc), sc, chain);
  400         CK_LIST_INSERT_HEAD(&GRE_SRCHASH(&sc->gre_oip6.ip6_src), sc, srchash);
  401 
  402         /* Set IFF_DRV_RUNNING if interface is ready */
  403         in6_gre_set_running(sc);
  404         return (0);
  405 }
  406 
  407 int
  408 in6_gre_setopts(struct gre_softc *sc, u_long cmd, uint32_t value)
  409 {
  410         int error;
  411 
  412         /* NOTE: we are protected with gre_ioctl_sx lock */
  413         MPASS(cmd == GRESKEY || cmd == GRESOPTS || cmd == GRESPORT);
  414         MPASS(sc->gre_family == AF_INET6);
  415 
  416         /*
  417          * If we are going to change encapsulation protocol, do check
  418          * for duplicate tunnels. Return EEXIST here to do not confuse
  419          * user.
  420          */
  421         if (cmd == GRESOPTS &&
  422             (sc->gre_options & GRE_UDPENCAP) != (value & GRE_UDPENCAP) &&
  423             in6_gre_checkdup(sc, &sc->gre_oip6.ip6_src,
  424                 &sc->gre_oip6.ip6_dst, value) == EADDRNOTAVAIL)
  425                 return (EEXIST);
  426 
  427         CK_LIST_REMOVE(sc, chain);
  428         CK_LIST_REMOVE(sc, srchash);
  429         GRE_WAIT();
  430         switch (cmd) {
  431         case GRESKEY:
  432                 sc->gre_key = value;
  433                 break;
  434         case GRESOPTS:
  435                 sc->gre_options = value;
  436                 break;
  437         case GRESPORT:
  438                 sc->gre_port = value;
  439                 break;
  440         }
  441         error = in6_gre_attach(sc);
  442         if (error != 0) {
  443                 sc->gre_family = 0;
  444                 free(sc->gre_hdr, M_GRE);
  445         }
  446         return (error);
  447 }
  448 
  449 int
  450 in6_gre_ioctl(struct gre_softc *sc, u_long cmd, caddr_t data)
  451 {
  452         struct in6_ifreq *ifr = (struct in6_ifreq *)data;
  453         struct sockaddr_in6 *dst, *src;
  454         struct ip6_hdr *ip6;
  455         int error;
  456 
  457         /* NOTE: we are protected with gre_ioctl_sx lock */
  458         error = EINVAL;
  459         switch (cmd) {
  460         case SIOCSIFPHYADDR_IN6:
  461                 src = &((struct in6_aliasreq *)data)->ifra_addr;
  462                 dst = &((struct in6_aliasreq *)data)->ifra_dstaddr;
  463 
  464                 /* sanity checks */
  465                 if (src->sin6_family != dst->sin6_family ||
  466                     src->sin6_family != AF_INET6 ||
  467                     src->sin6_len != dst->sin6_len ||
  468                     src->sin6_len != sizeof(*src))
  469                         break;
  470                 if (IN6_IS_ADDR_UNSPECIFIED(&src->sin6_addr) ||
  471                     IN6_IS_ADDR_UNSPECIFIED(&dst->sin6_addr)) {
  472                         error = EADDRNOTAVAIL;
  473                         break;
  474                 }
  475                 /*
  476                  * Check validity of the scope zone ID of the
  477                  * addresses, and convert it into the kernel
  478                  * internal form if necessary.
  479                  */
  480                 if ((error = sa6_embedscope(src, 0)) != 0 ||
  481                     (error = sa6_embedscope(dst, 0)) != 0)
  482                         break;
  483 
  484                 if (V_ipv6_hashtbl == NULL) {
  485                         V_ipv6_hashtbl = gre_hashinit();
  486                         V_ipv6_srchashtbl = gre_hashinit();
  487                         V_ipv6_sockets = (struct gre_sockets *)gre_hashinit();
  488                 }
  489                 error = in6_gre_checkdup(sc, &src->sin6_addr,
  490                     &dst->sin6_addr, sc->gre_options);
  491                 if (error == EADDRNOTAVAIL)
  492                         break;
  493                 if (error == EEXIST) {
  494                         /* Addresses are the same. Just return. */
  495                         error = 0;
  496                         break;
  497                 }
  498                 ip6 = malloc(sizeof(struct greudp6) + 3 * sizeof(uint32_t),
  499                     M_GRE, M_WAITOK | M_ZERO);
  500                 ip6->ip6_src = src->sin6_addr;
  501                 ip6->ip6_dst = dst->sin6_addr;
  502                 if (sc->gre_family != 0) {
  503                         /* Detach existing tunnel first */
  504                         CK_LIST_REMOVE(sc, chain);
  505                         CK_LIST_REMOVE(sc, srchash);
  506                         GRE_WAIT();
  507                         free(sc->gre_hdr, M_GRE);
  508                         /* XXX: should we notify about link state change? */
  509                 }
  510                 sc->gre_family = AF_INET6;
  511                 sc->gre_hdr = ip6;
  512                 sc->gre_oseq = 0;
  513                 sc->gre_iseq = UINT32_MAX;
  514                 error = in6_gre_attach(sc);
  515                 if (error != 0) {
  516                         sc->gre_family = 0;
  517                         free(sc->gre_hdr, M_GRE);
  518                 }
  519                 break;
  520         case SIOCGIFPSRCADDR_IN6:
  521         case SIOCGIFPDSTADDR_IN6:
  522                 if (sc->gre_family != AF_INET6) {
  523                         error = EADDRNOTAVAIL;
  524                         break;
  525                 }
  526                 src = (struct sockaddr_in6 *)&ifr->ifr_addr;
  527                 memset(src, 0, sizeof(*src));
  528                 src->sin6_family = AF_INET6;
  529                 src->sin6_len = sizeof(*src);
  530                 src->sin6_addr = (cmd == SIOCGIFPSRCADDR_IN6) ?
  531                     sc->gre_oip6.ip6_src: sc->gre_oip6.ip6_dst;
  532                 error = prison_if(curthread->td_ucred, (struct sockaddr *)src);
  533                 if (error == 0)
  534                         error = sa6_recoverscope(src);
  535                 if (error != 0)
  536                         memset(src, 0, sizeof(*src));
  537                 break;
  538         }
  539         return (error);
  540 }
  541 
  542 int
  543 in6_gre_output(struct mbuf *m, int af __unused, int hlen __unused,
  544     uint32_t flowid)
  545 {
  546         struct greip6 *gi6;
  547 
  548         gi6 = mtod(m, struct greip6 *);
  549         gi6->gi6_ip6.ip6_hlim = V_ip6_gre_hlim;
  550         gi6->gi6_ip6.ip6_flow |= flowid & IPV6_FLOWLABEL_MASK;
  551         return (ip6_output(m, NULL, NULL, IPV6_MINMTU, NULL, NULL, NULL));
  552 }
  553 
  554 static const struct srcaddrtab *ipv6_srcaddrtab = NULL;
  555 static const struct encaptab *ecookie = NULL;
  556 static const struct encap_config ipv6_encap_cfg = {
  557         .proto = IPPROTO_GRE,
  558         .min_length = sizeof(struct greip6) +
  559 #ifdef INET
  560             sizeof(struct ip),
  561 #else
  562             sizeof(struct ip6_hdr),
  563 #endif
  564         .exact_match = ENCAP_DRV_LOOKUP,
  565         .lookup = in6_gre_lookup,
  566         .input = gre_input
  567 };
  568 
  569 void
  570 in6_gre_init(void)
  571 {
  572 
  573         if (!IS_DEFAULT_VNET(curvnet))
  574                 return;
  575         ipv6_srcaddrtab = ip6_encap_register_srcaddr(in6_gre_srcaddr,
  576             NULL, M_WAITOK);
  577         ecookie = ip6_encap_attach(&ipv6_encap_cfg, NULL, M_WAITOK);
  578 }
  579 
  580 void
  581 in6_gre_uninit(void)
  582 {
  583 
  584         if (IS_DEFAULT_VNET(curvnet)) {
  585                 ip6_encap_detach(ecookie);
  586                 ip6_encap_unregister_srcaddr(ipv6_srcaddrtab);
  587         }
  588         if (V_ipv6_hashtbl != NULL) {
  589                 gre_hashdestroy(V_ipv6_hashtbl);
  590                 V_ipv6_hashtbl = NULL;
  591                 GRE_WAIT();
  592                 gre_hashdestroy(V_ipv6_srchashtbl);
  593                 gre_hashdestroy((struct gre_list *)V_ipv6_sockets);
  594         }
  595 }

Cache object: b3a035e983bba54d24fa224caddd72a5


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