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/netinet/ip_encap.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 /*      $KAME: ip_encap.c,v 1.73 2001/10/02 08:30:58 itojun Exp $       */
    2 
    3 /*
    4  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  * 3. Neither the name of the project nor the names of its contributors
   16  *    may be used to endorse or promote products derived from this software
   17  *    without specific prior written permission.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
   20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
   23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   29  * SUCH DAMAGE.
   30  */
   31 /*
   32  * My grandfather said that there's a devil inside tunnelling technology...
   33  *
   34  * We have surprisingly many protocols that want packets with IP protocol
   35  * #4 or #41.  Here's a list of protocols that want protocol #41:
   36  *      RFC1933 configured tunnel
   37  *      RFC1933 automatic tunnel
   38  *      RFC2401 IPsec tunnel
   39  *      RFC2473 IPv6 generic packet tunnelling
   40  *      RFC2529 6over4 tunnel
   41  *      RFC3056 6to4 tunnel
   42  *      isatap tunnel
   43  *      mobile-ip6 (uses RFC2473)
   44  * Here's a list of protocol that want protocol #4:
   45  *      RFC1853 IPv4-in-IPv4 tunnelling
   46  *      RFC2003 IPv4 encapsulation within IPv4
   47  *      RFC2344 reverse tunnelling for mobile-ip4
   48  *      RFC2401 IPsec tunnel
   49  * Well, what can I say.  They impose different en/decapsulation mechanism
   50  * from each other, so they need separate protocol handler.  The only one
   51  * we can easily determine by protocol # is IPsec, which always has
   52  * AH/ESP/IPComp header right after outer IP header.
   53  *
   54  * So, clearly good old protosw does not work for protocol #4 and #41.
   55  * The code will let you match protocol via src/dst address pair.
   56  */
   57 /* XXX is M_NETADDR correct? */
   58 
   59 /*
   60  * With USE_RADIX the code will use radix table for tunnel lookup, for
   61  * tunnels registered with encap_attach() with a addr/mask pair.
   62  * Faster on machines with thousands of tunnel registerations (= interfaces).
   63  *
   64  * The code assumes that radix table code can handle non-continuous netmask,
   65  * as it will pass radix table memory region with (src + dst) sockaddr pair.
   66  *
   67  * FreeBSD is excluded here as they make max_keylen a static variable, and
   68  * thus forbid definition of radix table other than proper domains.
   69  */
   70 #define USE_RADIX
   71 
   72 #include <sys/cdefs.h>
   73 __KERNEL_RCSID(0, "$NetBSD: ip_encap.c,v 1.28 2006/05/28 11:07:04 liamjfoy Exp $");
   74 
   75 #include "opt_mrouting.h"
   76 #include "opt_inet.h"
   77 
   78 #include <sys/param.h>
   79 #include <sys/systm.h>
   80 #include <sys/socket.h>
   81 #include <sys/sockio.h>
   82 #include <sys/mbuf.h>
   83 #include <sys/errno.h>
   84 #include <sys/protosw.h>
   85 #include <sys/queue.h>
   86 
   87 #include <net/if.h>
   88 #include <net/route.h>
   89 
   90 #include <netinet/in.h>
   91 #include <netinet/in_systm.h>
   92 #include <netinet/ip.h>
   93 #include <netinet/ip_var.h>
   94 #include <netinet/ip_encap.h>
   95 #ifdef MROUTING
   96 #include <netinet/ip_mroute.h>
   97 #endif /* MROUTING */
   98 
   99 #ifdef INET6
  100 #include <netinet/ip6.h>
  101 #include <netinet6/ip6_var.h>
  102 #include <netinet6/ip6protosw.h>
  103 #include <netinet6/in6_var.h>
  104 #include <netinet6/in6_pcb.h>
  105 #include <netinet/icmp6.h>
  106 #endif
  107 
  108 #include <machine/stdarg.h>
  109 
  110 #include <net/net_osdep.h>
  111 
  112 /* to lookup a pair of address using radix tree */
  113 struct sockaddr_pack {
  114         u_int8_t sp_len;
  115         u_int8_t sp_family;     /* not really used */
  116         /* followed by variable-length data */
  117 };
  118 
  119 struct pack4 {
  120         struct sockaddr_pack p;
  121         struct sockaddr_in mine;
  122         struct sockaddr_in yours;
  123 };
  124 struct pack6 {
  125         struct sockaddr_pack p;
  126         struct sockaddr_in6 mine;
  127         struct sockaddr_in6 yours;
  128 };
  129 
  130 enum direction { INBOUND, OUTBOUND };
  131 
  132 #ifdef INET
  133 static struct encaptab *encap4_lookup(struct mbuf *, int, int, enum direction);
  134 #endif
  135 #ifdef INET6
  136 static struct encaptab *encap6_lookup(struct mbuf *, int, int, enum direction);
  137 #endif
  138 static int encap_add(struct encaptab *);
  139 static int encap_remove(struct encaptab *);
  140 static int encap_afcheck(int, const struct sockaddr *, const struct sockaddr *);
  141 #ifdef USE_RADIX
  142 static struct radix_node_head *encap_rnh(int);
  143 static int mask_matchlen(const struct sockaddr *);
  144 #endif
  145 #ifndef USE_RADIX
  146 static int mask_match(const struct encaptab *, const struct sockaddr *,
  147                 const struct sockaddr *);
  148 #endif
  149 static void encap_fillarg(struct mbuf *, const struct encaptab *);
  150 
  151 LIST_HEAD(, encaptab) encaptab = LIST_HEAD_INITIALIZER(&encaptab);
  152 
  153 #ifdef USE_RADIX
  154 extern int max_keylen;  /* radix.c */
  155 struct radix_node_head *encap_head[2];  /* 0 for AF_INET, 1 for AF_INET6 */
  156 #endif
  157 
  158 void
  159 encap_setkeylen(void)
  160 {
  161 #ifdef USE_RADIX
  162         if (sizeof(struct pack4) > max_keylen)
  163                 max_keylen = sizeof(struct pack4);
  164 #ifdef INET6
  165         if (sizeof(struct pack6) > max_keylen)
  166                 max_keylen = sizeof(struct pack6);
  167 #endif
  168 #endif
  169 }
  170 
  171 void
  172 encap_init(void)
  173 {
  174         static int initialized = 0;
  175 
  176         if (initialized)
  177                 return;
  178         initialized++;
  179 #if 0
  180         /*
  181          * we cannot use LIST_INIT() here, since drivers may want to call
  182          * encap_attach(), on driver attach.  encap_init() will be called
  183          * on AF_INET{,6} initialization, which happens after driver
  184          * initialization - using LIST_INIT() here can nuke encap_attach()
  185          * from drivers.
  186          */
  187         LIST_INIT(&encaptab);
  188 #endif
  189 
  190 #ifdef USE_RADIX
  191         /*
  192          * initialize radix lookup table.
  193          * max_keylen initialization happen in the rn_init().
  194          */
  195         rn_init();
  196         rn_inithead((void *)&encap_head[0], sizeof(struct sockaddr_pack) << 3);
  197 #ifdef INET6
  198         rn_inithead((void *)&encap_head[1], sizeof(struct sockaddr_pack) << 3);
  199 #endif
  200 #endif
  201 }
  202 
  203 #ifdef INET
  204 static struct encaptab *
  205 encap4_lookup(struct mbuf *m, int off, int proto, enum direction dir)
  206 {
  207         struct ip *ip;
  208         struct pack4 pack;
  209         struct encaptab *ep, *match;
  210         int prio, matchprio;
  211 #ifdef USE_RADIX
  212         struct radix_node_head *rnh = encap_rnh(AF_INET);
  213         struct radix_node *rn;
  214 #endif
  215 
  216 #ifdef DIAGNOSTIC
  217         if (m->m_len < sizeof(*ip))
  218                 panic("encap4_lookup");
  219 #endif
  220         ip = mtod(m, struct ip *);
  221 
  222         bzero(&pack, sizeof(pack));
  223         pack.p.sp_len = sizeof(pack);
  224         pack.mine.sin_family = pack.yours.sin_family = AF_INET;
  225         pack.mine.sin_len = pack.yours.sin_len = sizeof(struct sockaddr_in);
  226         if (dir == INBOUND) {
  227                 pack.mine.sin_addr = ip->ip_dst;
  228                 pack.yours.sin_addr = ip->ip_src;
  229         } else {
  230                 pack.mine.sin_addr = ip->ip_src;
  231                 pack.yours.sin_addr = ip->ip_dst;
  232         }
  233 
  234         match = NULL;
  235         matchprio = 0;
  236 
  237 #ifdef USE_RADIX
  238         rn = rnh->rnh_matchaddr((caddr_t)&pack, rnh);
  239         if (rn && (rn->rn_flags & RNF_ROOT) == 0) {
  240                 match = (struct encaptab *)rn;
  241                 matchprio = mask_matchlen(match->srcmask) +
  242                     mask_matchlen(match->dstmask);
  243         }
  244 #endif
  245 
  246         for (ep = LIST_FIRST(&encaptab); ep; ep = LIST_NEXT(ep, chain)) {
  247                 if (ep->af != AF_INET)
  248                         continue;
  249                 if (ep->proto >= 0 && ep->proto != proto)
  250                         continue;
  251                 if (ep->func)
  252                         prio = (*ep->func)(m, off, proto, ep->arg);
  253                 else {
  254 #ifdef USE_RADIX
  255                         continue;
  256 #else
  257                         prio = mask_match(ep, (struct sockaddr *)&pack.mine,
  258                             (struct sockaddr *)&pack.yours);
  259 #endif
  260                 }
  261 
  262                 /*
  263                  * We prioritize the matches by using bit length of the
  264                  * matches.  mask_match() and user-supplied matching function
  265                  * should return the bit length of the matches (for example,
  266                  * if both src/dst are matched for IPv4, 64 should be returned).
  267                  * 0 or negative return value means "it did not match".
  268                  *
  269                  * The question is, since we have two "mask" portion, we
  270                  * cannot really define total order between entries.
  271                  * For example, which of these should be preferred?
  272                  * mask_match() returns 48 (32 + 16) for both of them.
  273                  *      src=3ffe::/16, dst=3ffe:501::/32
  274                  *      src=3ffe:501::/32, dst=3ffe::/16
  275                  *
  276                  * We need to loop through all the possible candidates
  277                  * to get the best match - the search takes O(n) for
  278                  * n attachments (i.e. interfaces).
  279                  *
  280                  * For radix-based lookup, I guess source takes precedence.
  281                  * See rn_{refines,lexobetter} for the correct answer.
  282                  */
  283                 if (prio <= 0)
  284                         continue;
  285                 if (prio > matchprio) {
  286                         matchprio = prio;
  287                         match = ep;
  288                 }
  289         }
  290 
  291         return match;
  292 #undef s
  293 #undef d
  294 }
  295 
  296 void
  297 encap4_input(struct mbuf *m, ...)
  298 {
  299         int off, proto;
  300         va_list ap;
  301         const struct protosw *psw;
  302         struct encaptab *match;
  303 
  304         va_start(ap, m);
  305         off = va_arg(ap, int);
  306         proto = va_arg(ap, int);
  307         va_end(ap);
  308 
  309         match = encap4_lookup(m, off, proto, INBOUND);
  310 
  311         if (match) {
  312                 /* found a match, "match" has the best one */
  313                 psw = match->psw;
  314                 if (psw && psw->pr_input) {
  315                         encap_fillarg(m, match);
  316                         (*psw->pr_input)(m, off, proto);
  317                 } else
  318                         m_freem(m);
  319                 return;
  320         }
  321 
  322         /* last resort: inject to raw socket */
  323         rip_input(m, off, proto);
  324 }
  325 #endif
  326 
  327 #ifdef INET6
  328 static struct encaptab *
  329 encap6_lookup(struct mbuf *m, int off, int proto, enum direction dir)
  330 {
  331         struct ip6_hdr *ip6;
  332         struct pack6 pack;
  333         int prio, matchprio;
  334         struct encaptab *ep, *match;
  335 #ifdef USE_RADIX
  336         struct radix_node_head *rnh = encap_rnh(AF_INET6);
  337         struct radix_node *rn;
  338 #endif
  339 
  340 #ifdef DIAGNOSTIC
  341         if (m->m_len < sizeof(*ip6))
  342                 panic("encap6_lookup");
  343 #endif
  344         ip6 = mtod(m, struct ip6_hdr *);
  345 
  346         bzero(&pack, sizeof(pack));
  347         pack.p.sp_len = sizeof(pack);
  348         pack.mine.sin6_family = pack.yours.sin6_family = AF_INET6;
  349         pack.mine.sin6_len = pack.yours.sin6_len = sizeof(struct sockaddr_in6);
  350         if (dir == INBOUND) {
  351                 pack.mine.sin6_addr = ip6->ip6_dst;
  352                 pack.yours.sin6_addr = ip6->ip6_src;
  353         } else {
  354                 pack.mine.sin6_addr = ip6->ip6_src;
  355                 pack.yours.sin6_addr = ip6->ip6_dst;
  356         }
  357 
  358         match = NULL;
  359         matchprio = 0;
  360 
  361 #ifdef USE_RADIX
  362         rn = rnh->rnh_matchaddr((caddr_t)&pack, rnh);
  363         if (rn && (rn->rn_flags & RNF_ROOT) == 0) {
  364                 match = (struct encaptab *)rn;
  365                 matchprio = mask_matchlen(match->srcmask) +
  366                     mask_matchlen(match->dstmask);
  367         }
  368 #endif
  369 
  370         for (ep = LIST_FIRST(&encaptab); ep; ep = LIST_NEXT(ep, chain)) {
  371                 if (ep->af != AF_INET6)
  372                         continue;
  373                 if (ep->proto >= 0 && ep->proto != proto)
  374                         continue;
  375                 if (ep->func)
  376                         prio = (*ep->func)(m, off, proto, ep->arg);
  377                 else {
  378 #ifdef USE_RADIX
  379                         continue;
  380 #else
  381                         prio = mask_match(ep, (struct sockaddr *)&pack.mine,
  382                             (struct sockaddr *)&pack.yours);
  383 #endif
  384                 }
  385 
  386                 /* see encap4_lookup() for issues here */
  387                 if (prio <= 0)
  388                         continue;
  389                 if (prio > matchprio) {
  390                         matchprio = prio;
  391                         match = ep;
  392                 }
  393         }
  394 
  395         return match;
  396 #undef s
  397 #undef d
  398 }
  399 
  400 int
  401 encap6_input(struct mbuf **mp, int *offp, int proto)
  402 {
  403         struct mbuf *m = *mp;
  404         const struct ip6protosw *psw;
  405         struct encaptab *match;
  406 
  407         match = encap6_lookup(m, *offp, proto, INBOUND);
  408 
  409         if (match) {
  410                 /* found a match */
  411                 psw = (const struct ip6protosw *)match->psw;
  412                 if (psw && psw->pr_input) {
  413                         encap_fillarg(m, match);
  414                         return (*psw->pr_input)(mp, offp, proto);
  415                 } else {
  416                         m_freem(m);
  417                         return IPPROTO_DONE;
  418                 }
  419         }
  420 
  421         /* last resort: inject to raw socket */
  422         return rip6_input(mp, offp, proto);
  423 }
  424 #endif
  425 
  426 static int
  427 encap_add(struct encaptab *ep)
  428 {
  429 #ifdef USE_RADIX
  430         struct radix_node_head *rnh = encap_rnh(ep->af);
  431 #endif
  432         int error = 0;
  433 
  434         LIST_INSERT_HEAD(&encaptab, ep, chain);
  435 #ifdef USE_RADIX
  436         if (!ep->func && rnh) {
  437                 if (!rnh->rnh_addaddr((caddr_t)ep->addrpack,
  438                     (caddr_t)ep->maskpack, rnh, ep->nodes)) {
  439                         error = EEXIST;
  440                         goto fail;
  441                 }
  442         }
  443 #endif
  444         return error;
  445 
  446  fail:
  447         LIST_REMOVE(ep, chain);
  448         return error;
  449 }
  450 
  451 static int
  452 encap_remove(struct encaptab *ep)
  453 {
  454 #ifdef USE_RADIX
  455         struct radix_node_head *rnh = encap_rnh(ep->af);
  456 #endif
  457         int error = 0;
  458 
  459         LIST_REMOVE(ep, chain);
  460 #ifdef USE_RADIX
  461         if (!ep->func && rnh) {
  462                 if (!rnh->rnh_deladdr((caddr_t)ep->addrpack,
  463                     (caddr_t)ep->maskpack, rnh))
  464                         error = ESRCH;
  465         }
  466 #endif
  467         return error;
  468 }
  469 
  470 static int
  471 encap_afcheck(int af, const struct sockaddr *sp, const struct sockaddr *dp)
  472 {
  473         if (sp && dp) {
  474                 if (sp->sa_len != dp->sa_len)
  475                         return EINVAL;
  476                 if (af != sp->sa_family || af != dp->sa_family)
  477                         return EINVAL;
  478         } else if (!sp && !dp)
  479                 ;
  480         else
  481                 return EINVAL;
  482 
  483         switch (af) {
  484         case AF_INET:
  485                 if (sp && sp->sa_len != sizeof(struct sockaddr_in))
  486                         return EINVAL;
  487                 if (dp && dp->sa_len != sizeof(struct sockaddr_in))
  488                         return EINVAL;
  489                 break;
  490 #ifdef INET6
  491         case AF_INET6:
  492                 if (sp && sp->sa_len != sizeof(struct sockaddr_in6))
  493                         return EINVAL;
  494                 if (dp && dp->sa_len != sizeof(struct sockaddr_in6))
  495                         return EINVAL;
  496                 break;
  497 #endif
  498         default:
  499                 return EAFNOSUPPORT;
  500         }
  501 
  502         return 0;
  503 }
  504 
  505 /*
  506  * sp (src ptr) is always my side, and dp (dst ptr) is always remote side.
  507  * length of mask (sm and dm) is assumed to be same as sp/dp.
  508  * Return value will be necessary as input (cookie) for encap_detach().
  509  */
  510 const struct encaptab *
  511 encap_attach(int af, int proto,
  512     const struct sockaddr *sp, const struct sockaddr *sm,
  513     const struct sockaddr *dp, const struct sockaddr *dm,
  514     const struct protosw *psw, void *arg)
  515 {
  516         struct encaptab *ep;
  517         int error;
  518         int s;
  519         size_t l;
  520         struct pack4 *pack4;
  521 #ifdef INET6
  522         struct pack6 *pack6;
  523 #endif
  524 
  525         s = splsoftnet();
  526         /* sanity check on args */
  527         error = encap_afcheck(af, sp, dp);
  528         if (error)
  529                 goto fail;
  530 
  531         /* check if anyone have already attached with exactly same config */
  532         for (ep = LIST_FIRST(&encaptab); ep; ep = LIST_NEXT(ep, chain)) {
  533                 if (ep->af != af)
  534                         continue;
  535                 if (ep->proto != proto)
  536                         continue;
  537                 if (ep->func)
  538                         continue;
  539 #ifdef DIAGNOSTIC
  540                 if (!ep->src || !ep->dst || !ep->srcmask || !ep->dstmask)
  541                         panic("null pointers in encaptab");
  542 #endif
  543                 if (ep->src->sa_len != sp->sa_len ||
  544                     bcmp(ep->src, sp, sp->sa_len) != 0 ||
  545                     bcmp(ep->srcmask, sm, sp->sa_len) != 0)
  546                         continue;
  547                 if (ep->dst->sa_len != dp->sa_len ||
  548                     bcmp(ep->dst, dp, dp->sa_len) != 0 ||
  549                     bcmp(ep->dstmask, dm, dp->sa_len) != 0)
  550                         continue;
  551 
  552                 error = EEXIST;
  553                 goto fail;
  554         }
  555 
  556         switch (af) {
  557         case AF_INET:
  558                 l = sizeof(*pack4);
  559                 break;
  560 #ifdef INET6
  561         case AF_INET6:
  562                 l = sizeof(*pack6);
  563                 break;
  564 #endif
  565         default:
  566                 goto fail;
  567         }
  568 
  569         /* M_NETADDR ok? */
  570         ep = malloc(sizeof(*ep), M_NETADDR, M_NOWAIT|M_ZERO);
  571         if (ep == NULL) {
  572                 error = ENOBUFS;
  573                 goto fail;
  574         }
  575         ep->addrpack = malloc(l, M_NETADDR, M_NOWAIT|M_ZERO);
  576         if (ep->addrpack == NULL) {
  577                 error = ENOBUFS;
  578                 goto gc;
  579         }
  580         ep->maskpack = malloc(l, M_NETADDR, M_NOWAIT|M_ZERO);
  581         if (ep->maskpack == NULL) {
  582                 error = ENOBUFS;
  583                 goto gc;
  584         }
  585 
  586         ep->af = af;
  587         ep->proto = proto;
  588         ep->addrpack->sa_len = l & 0xff;
  589         ep->maskpack->sa_len = l & 0xff;
  590         switch (af) {
  591         case AF_INET:
  592                 pack4 = (struct pack4 *)ep->addrpack;
  593                 ep->src = (struct sockaddr *)&pack4->mine;
  594                 ep->dst = (struct sockaddr *)&pack4->yours;
  595                 pack4 = (struct pack4 *)ep->maskpack;
  596                 ep->srcmask = (struct sockaddr *)&pack4->mine;
  597                 ep->dstmask = (struct sockaddr *)&pack4->yours;
  598                 break;
  599 #ifdef INET6
  600         case AF_INET6:
  601                 pack6 = (struct pack6 *)ep->addrpack;
  602                 ep->src = (struct sockaddr *)&pack6->mine;
  603                 ep->dst = (struct sockaddr *)&pack6->yours;
  604                 pack6 = (struct pack6 *)ep->maskpack;
  605                 ep->srcmask = (struct sockaddr *)&pack6->mine;
  606                 ep->dstmask = (struct sockaddr *)&pack6->yours;
  607                 break;
  608 #endif
  609         }
  610 
  611         bcopy(sp, ep->src, sp->sa_len);
  612         bcopy(sm, ep->srcmask, sp->sa_len);
  613         bcopy(dp, ep->dst, dp->sa_len);
  614         bcopy(dm, ep->dstmask, dp->sa_len);
  615         ep->psw = psw;
  616         ep->arg = arg;
  617 
  618         error = encap_add(ep);
  619         if (error)
  620                 goto gc;
  621 
  622         error = 0;
  623         splx(s);
  624         return ep;
  625 
  626 gc:
  627         if (ep->addrpack)
  628                 free(ep->addrpack, M_NETADDR);
  629         if (ep->maskpack)
  630                 free(ep->maskpack, M_NETADDR);
  631         if (ep)
  632                 free(ep, M_NETADDR);
  633 fail:
  634         splx(s);
  635         return NULL;
  636 }
  637 
  638 const struct encaptab *
  639 encap_attach_func(int af, int proto,
  640     int (*func)(struct mbuf *, int, int, void *),
  641     const struct protosw *psw, void *arg)
  642 {
  643         struct encaptab *ep;
  644         int error;
  645         int s;
  646 
  647         s = splsoftnet();
  648         /* sanity check on args */
  649         if (!func) {
  650                 error = EINVAL;
  651                 goto fail;
  652         }
  653 
  654         error = encap_afcheck(af, NULL, NULL);
  655         if (error)
  656                 goto fail;
  657 
  658         ep = malloc(sizeof(*ep), M_NETADDR, M_NOWAIT);  /*XXX*/
  659         if (ep == NULL) {
  660                 error = ENOBUFS;
  661                 goto fail;
  662         }
  663         bzero(ep, sizeof(*ep));
  664 
  665         ep->af = af;
  666         ep->proto = proto;
  667         ep->func = func;
  668         ep->psw = psw;
  669         ep->arg = arg;
  670 
  671         error = encap_add(ep);
  672         if (error)
  673                 goto fail;
  674 
  675         error = 0;
  676         splx(s);
  677         return ep;
  678 
  679 fail:
  680         splx(s);
  681         return NULL;
  682 }
  683 
  684 /* XXX encap4_ctlinput() is necessary if we set DF=1 on outer IPv4 header */
  685 
  686 #ifdef INET6
  687 void
  688 encap6_ctlinput(int cmd, struct sockaddr *sa, void *d0)
  689 {
  690         void *d = d0;
  691         struct ip6_hdr *ip6;
  692         struct mbuf *m;
  693         int off;
  694         struct ip6ctlparam *ip6cp = NULL;
  695         int nxt;
  696         struct encaptab *ep;
  697         const struct ip6protosw *psw;
  698 
  699         if (sa->sa_family != AF_INET6 ||
  700             sa->sa_len != sizeof(struct sockaddr_in6))
  701                 return;
  702 
  703         if ((unsigned)cmd >= PRC_NCMDS)
  704                 return;
  705         if (cmd == PRC_HOSTDEAD)
  706                 d = NULL;
  707         else if (cmd == PRC_MSGSIZE)
  708                 ; /* special code is present, see below */
  709         else if (inet6ctlerrmap[cmd] == 0)
  710                 return;
  711 
  712         /* if the parameter is from icmp6, decode it. */
  713         if (d != NULL) {
  714                 ip6cp = (struct ip6ctlparam *)d;
  715                 m = ip6cp->ip6c_m;
  716                 ip6 = ip6cp->ip6c_ip6;
  717                 off = ip6cp->ip6c_off;
  718                 nxt = ip6cp->ip6c_nxt;
  719 
  720                 if (ip6 && cmd == PRC_MSGSIZE) {
  721                         int valid = 0;
  722                         struct encaptab *match;
  723 
  724                         /*
  725                         * Check to see if we have a valid encap configuration.
  726                         */
  727                         match = encap6_lookup(m, off, nxt, OUTBOUND);
  728                         if (match)
  729                                 valid++;
  730 
  731                         /*
  732                         * Depending on the value of "valid" and routing table
  733                         * size (mtudisc_{hi,lo}wat), we will:
  734                         * - recalcurate the new MTU and create the
  735                         *   corresponding routing entry, or
  736                         * - ignore the MTU change notification.
  737                         */
  738                         icmp6_mtudisc_update((struct ip6ctlparam *)d, valid);
  739                 }
  740         } else {
  741                 m = NULL;
  742                 ip6 = NULL;
  743                 nxt = -1;
  744         }
  745 
  746         /* inform all listeners */
  747         for (ep = LIST_FIRST(&encaptab); ep; ep = LIST_NEXT(ep, chain)) {
  748                 if (ep->af != AF_INET6)
  749                         continue;
  750                 if (ep->proto >= 0 && ep->proto != nxt)
  751                         continue;
  752 
  753                 /* should optimize by looking at address pairs */
  754 
  755                 /* XXX need to pass ep->arg or ep itself to listeners */
  756                 psw = (const struct ip6protosw *)ep->psw;
  757                 if (psw && psw->pr_ctlinput)
  758                         (*psw->pr_ctlinput)(cmd, sa, d);
  759         }
  760 
  761         rip6_ctlinput(cmd, sa, d0);
  762 }
  763 #endif
  764 
  765 int
  766 encap_detach(const struct encaptab *cookie)
  767 {
  768         const struct encaptab *ep = cookie;
  769         struct encaptab *p;
  770         int error;
  771 
  772         for (p = LIST_FIRST(&encaptab); p; p = LIST_NEXT(p, chain)) {
  773                 if (p == ep) {
  774                         error = encap_remove(p);
  775                         if (error)
  776                                 return error;
  777                         if (!ep->func) {
  778                                 free(p->addrpack, M_NETADDR);
  779                                 free(p->maskpack, M_NETADDR);
  780                         }
  781                         free(p, M_NETADDR);     /*XXX*/
  782                         return 0;
  783                 }
  784         }
  785 
  786         return ENOENT;
  787 }
  788 
  789 #ifdef USE_RADIX
  790 static struct radix_node_head *
  791 encap_rnh(int af)
  792 {
  793 
  794         switch (af) {
  795         case AF_INET:
  796                 return encap_head[0];
  797 #ifdef INET6
  798         case AF_INET6:
  799                 return encap_head[1];
  800 #endif
  801         default:
  802                 return NULL;
  803         }
  804 }
  805 
  806 static int
  807 mask_matchlen(const struct sockaddr *sa)
  808 {
  809         const char *p, *ep;
  810         int l;
  811 
  812         p = (const char *)sa;
  813         ep = p + sa->sa_len;
  814         p += 2; /* sa_len + sa_family */
  815 
  816         l = 0;
  817         while (p < ep) {
  818                 l += (*p ? 8 : 0);      /* estimate */
  819                 p++;
  820         }
  821         return l;
  822 }
  823 #endif
  824 
  825 #ifndef USE_RADIX
  826 static int
  827 mask_match(const struct encaptab *ep,
  828            const struct sockaddr *sp,
  829            const struct sockaddr *dp)
  830 {
  831         struct sockaddr_storage s;
  832         struct sockaddr_storage d;
  833         int i;
  834         const u_int8_t *p, *q;
  835         u_int8_t *r;
  836         int matchlen;
  837 
  838 #ifdef DIAGNOSTIC
  839         if (ep->func)
  840                 panic("wrong encaptab passed to mask_match");
  841 #endif
  842         if (sp->sa_len > sizeof(s) || dp->sa_len > sizeof(d))
  843                 return 0;
  844         if (sp->sa_family != ep->af || dp->sa_family != ep->af)
  845                 return 0;
  846         if (sp->sa_len != ep->src->sa_len || dp->sa_len != ep->dst->sa_len)
  847                 return 0;
  848 
  849         matchlen = 0;
  850 
  851         p = (const u_int8_t *)sp;
  852         q = (const u_int8_t *)ep->srcmask;
  853         r = (u_int8_t *)&s;
  854         for (i = 0 ; i < sp->sa_len; i++) {
  855                 r[i] = p[i] & q[i];
  856                 /* XXX estimate */
  857                 matchlen += (q[i] ? 8 : 0);
  858         }
  859 
  860         p = (const u_int8_t *)dp;
  861         q = (const u_int8_t *)ep->dstmask;
  862         r = (u_int8_t *)&d;
  863         for (i = 0 ; i < dp->sa_len; i++) {
  864                 r[i] = p[i] & q[i];
  865                 /* XXX rough estimate */
  866                 matchlen += (q[i] ? 8 : 0);
  867         }
  868 
  869         /* need to overwrite len/family portion as we don't compare them */
  870         s.ss_len = sp->sa_len;
  871         s.ss_family = sp->sa_family;
  872         d.ss_len = dp->sa_len;
  873         d.ss_family = dp->sa_family;
  874 
  875         if (bcmp(&s, ep->src, ep->src->sa_len) == 0 &&
  876             bcmp(&d, ep->dst, ep->dst->sa_len) == 0) {
  877                 return matchlen;
  878         } else
  879                 return 0;
  880 }
  881 #endif
  882 
  883 static void
  884 encap_fillarg(struct mbuf *m, const struct encaptab *ep)
  885 {
  886         struct m_tag *mtag;
  887 
  888         mtag = m_tag_get(PACKET_TAG_ENCAP, sizeof(void *), M_NOWAIT);
  889         if (mtag) {
  890                 *(void **)(mtag + 1) = ep->arg;
  891                 m_tag_prepend(m, mtag);
  892         }
  893 }
  894 
  895 void *
  896 encap_getarg(struct mbuf *m)
  897 {
  898         void *p;
  899         struct m_tag *mtag;
  900 
  901         p = NULL;
  902         mtag = m_tag_find(m, PACKET_TAG_ENCAP, NULL);
  903         if (mtag != NULL) {
  904                 p = *(void **)(mtag + 1);
  905                 m_tag_delete(m, mtag);
  906         }
  907         return p;
  908 }

Cache object: b1e71ef5b3ab11e727201a8cfaf4f0a7


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