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

Cache object: 50a0e7d04b027eeff4434fc6c6fd2f2f


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