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.17 2004/03/04 15:15:06 wiz 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 __P((struct mbuf *, int, int,
  134         enum direction));
  135 #endif
  136 #ifdef INET6
  137 static struct encaptab *encap6_lookup __P((struct mbuf *, int, int,
  138         enum direction));
  139 #endif
  140 static int encap_add __P((struct encaptab *));
  141 static int encap_remove __P((struct encaptab *));
  142 static int encap_afcheck __P((int, const struct sockaddr *, const struct sockaddr *));
  143 #ifdef USE_RADIX
  144 static struct radix_node_head *encap_rnh __P((int));
  145 static int mask_matchlen __P((const struct sockaddr *));
  146 #endif
  147 #ifndef USE_RADIX
  148 static int mask_match __P((const struct encaptab *, const struct sockaddr *,
  149                 const struct sockaddr *));
  150 #endif
  151 static void encap_fillarg __P((struct mbuf *, const struct encaptab *));
  152 
  153 LIST_HEAD(, encaptab) encaptab = LIST_HEAD_INITIALIZER(&encaptab);
  154 
  155 #ifdef USE_RADIX
  156 extern int max_keylen;  /* radix.c */
  157 struct radix_node_head *encap_head[2];  /* 0 for AF_INET, 1 for AF_INET6 */
  158 #endif
  159 
  160 void
  161 encap_init()
  162 {
  163         static int initialized = 0;
  164 
  165         if (initialized)
  166                 return;
  167         initialized++;
  168 #if 0
  169         /*
  170          * we cannot use LIST_INIT() here, since drivers may want to call
  171          * encap_attach(), on driver attach.  encap_init() will be called
  172          * on AF_INET{,6} initialization, which happens after driver
  173          * initialization - using LIST_INIT() here can nuke encap_attach()
  174          * from drivers.
  175          */
  176         LIST_INIT(&encaptab);
  177 #endif
  178 
  179 #ifdef USE_RADIX
  180         /*
  181          * initialize radix lookup table.
  182          * max_keylen initialization should happen before the call to rn_init().
  183          */
  184         rn_inithead((void *)&encap_head[0], sizeof(struct sockaddr_pack) << 3);
  185         if (sizeof(struct pack4) > max_keylen)
  186                 max_keylen = sizeof(struct pack4);
  187 #ifdef INET6
  188         rn_inithead((void *)&encap_head[1], sizeof(struct sockaddr_pack) << 3);
  189         if (sizeof(struct pack6) > max_keylen)
  190                 max_keylen = sizeof(struct pack6);
  191 #endif
  192 #endif
  193 }
  194 
  195 #ifdef INET
  196 static struct encaptab *
  197 encap4_lookup(m, off, proto, dir)
  198         struct mbuf *m;
  199         int off;
  200         int proto;
  201         enum direction dir;
  202 {
  203         struct ip *ip;
  204         struct pack4 pack;
  205         struct encaptab *ep, *match;
  206         int prio, matchprio;
  207 #ifdef USE_RADIX
  208         struct radix_node_head *rnh = encap_rnh(AF_INET);
  209         struct radix_node *rn;
  210 #endif
  211 
  212 #ifdef DIAGNOSTIC
  213         if (m->m_len < sizeof(*ip))
  214                 panic("encap4_lookup");
  215 #endif
  216         ip = mtod(m, struct ip *);
  217 
  218         bzero(&pack, sizeof(pack));
  219         pack.p.sp_len = sizeof(pack);
  220         pack.mine.sin_family = pack.yours.sin_family = AF_INET;
  221         pack.mine.sin_len = pack.yours.sin_len = sizeof(struct sockaddr_in);
  222         if (dir == INBOUND) {
  223                 pack.mine.sin_addr = ip->ip_dst;
  224                 pack.yours.sin_addr = ip->ip_src;
  225         } else {
  226                 pack.mine.sin_addr = ip->ip_src;
  227                 pack.yours.sin_addr = ip->ip_dst;
  228         }
  229 
  230         match = NULL;
  231         matchprio = 0;
  232 
  233 #ifdef USE_RADIX
  234         rn = rnh->rnh_matchaddr((caddr_t)&pack, rnh);
  235         if (rn && (rn->rn_flags & RNF_ROOT) == 0) {
  236                 match = (struct encaptab *)rn;
  237                 matchprio = mask_matchlen(match->srcmask) +
  238                     mask_matchlen(match->dstmask);
  239         }
  240 #endif
  241 
  242         for (ep = LIST_FIRST(&encaptab); ep; ep = LIST_NEXT(ep, chain)) {
  243                 if (ep->af != AF_INET)
  244                         continue;
  245                 if (ep->proto >= 0 && ep->proto != proto)
  246                         continue;
  247                 if (ep->func)
  248                         prio = (*ep->func)(m, off, proto, ep->arg);
  249                 else {
  250 #ifdef USE_RADIX
  251                         continue;
  252 #else
  253                         prio = mask_match(ep, (struct sockaddr *)&pack.mine,
  254                             (struct sockaddr *)&pack.yours);
  255 #endif
  256                 }
  257 
  258                 /*
  259                  * We prioritize the matches by using bit length of the
  260                  * matches.  mask_match() and user-supplied matching function
  261                  * should return the bit length of the matches (for example,
  262                  * if both src/dst are matched for IPv4, 64 should be returned).
  263                  * 0 or negative return value means "it did not match".
  264                  *
  265                  * The question is, since we have two "mask" portion, we
  266                  * cannot really define total order between entries.
  267                  * For example, which of these should be preferred?
  268                  * mask_match() returns 48 (32 + 16) for both of them.
  269                  *      src=3ffe::/16, dst=3ffe:501::/32
  270                  *      src=3ffe:501::/32, dst=3ffe::/16
  271                  *
  272                  * We need to loop through all the possible candidates
  273                  * to get the best match - the search takes O(n) for
  274                  * n attachments (i.e. interfaces).
  275                  *
  276                  * For radix-based lookup, I guess source takes precedence.
  277                  * See rn_{refines,lexobetter} for the correct answer.
  278                  */
  279                 if (prio <= 0)
  280                         continue;
  281                 if (prio > matchprio) {
  282                         matchprio = prio;
  283                         match = ep;
  284                 }
  285         }
  286 
  287         return match;
  288 #undef s
  289 #undef d
  290 }
  291 
  292 void
  293 #if __STDC__
  294 encap4_input(struct mbuf *m, ...)
  295 #else
  296 encap4_input(m, va_alist)
  297         struct mbuf *m;
  298         va_dcl
  299 #endif
  300 {
  301         int off, proto;
  302         va_list ap;
  303         const struct protosw *psw;
  304         struct encaptab *match;
  305 
  306         va_start(ap, m);
  307         off = va_arg(ap, int);
  308         proto = va_arg(ap, int);
  309         va_end(ap);
  310 
  311         match = encap4_lookup(m, off, proto, INBOUND);
  312 
  313         if (match) {
  314                 /* found a match, "match" has the best one */
  315                 psw = match->psw;
  316                 if (psw && psw->pr_input) {
  317                         encap_fillarg(m, match);
  318                         (*psw->pr_input)(m, off, proto);
  319                 } else
  320                         m_freem(m);
  321                 return;
  322         }
  323 
  324         /* last resort: inject to raw socket */
  325         rip_input(m, off, proto);
  326 }
  327 #endif
  328 
  329 #ifdef INET6
  330 static struct encaptab *
  331 encap6_lookup(m, off, proto, dir)
  332         struct mbuf *m;
  333         int off;
  334         int proto;
  335         enum direction dir;
  336 {
  337         struct ip6_hdr *ip6;
  338         struct pack6 pack;
  339         int prio, matchprio;
  340         struct encaptab *ep, *match;
  341 #ifdef USE_RADIX
  342         struct radix_node_head *rnh = encap_rnh(AF_INET6);
  343         struct radix_node *rn;
  344 #endif
  345 
  346 #ifdef DIAGNOSTIC
  347         if (m->m_len < sizeof(*ip6))
  348                 panic("encap6_lookup");
  349 #endif
  350         ip6 = mtod(m, struct ip6_hdr *);
  351 
  352         bzero(&pack, sizeof(pack));
  353         pack.p.sp_len = sizeof(pack);
  354         pack.mine.sin6_family = pack.yours.sin6_family = AF_INET6;
  355         pack.mine.sin6_len = pack.yours.sin6_len = sizeof(struct sockaddr_in6);
  356         if (dir == INBOUND) {
  357                 pack.mine.sin6_addr = ip6->ip6_dst;
  358                 pack.yours.sin6_addr = ip6->ip6_src;
  359         } else {
  360                 pack.mine.sin6_addr = ip6->ip6_src;
  361                 pack.yours.sin6_addr = ip6->ip6_dst;
  362         }
  363 
  364         match = NULL;
  365         matchprio = 0;
  366 
  367 #ifdef USE_RADIX
  368         rn = rnh->rnh_matchaddr((caddr_t)&pack, rnh);
  369         if (rn && (rn->rn_flags & RNF_ROOT) == 0) {
  370                 match = (struct encaptab *)rn;
  371                 matchprio = mask_matchlen(match->srcmask) +
  372                     mask_matchlen(match->dstmask);
  373         }
  374 #endif
  375 
  376         for (ep = LIST_FIRST(&encaptab); ep; ep = LIST_NEXT(ep, chain)) {
  377                 if (ep->af != AF_INET6)
  378                         continue;
  379                 if (ep->proto >= 0 && ep->proto != proto)
  380                         continue;
  381                 if (ep->func)
  382                         prio = (*ep->func)(m, off, proto, ep->arg);
  383                 else {
  384 #ifdef USE_RADIX
  385                         continue;
  386 #else
  387                         prio = mask_match(ep, (struct sockaddr *)&pack.mine,
  388                             (struct sockaddr *)&pack.yours);
  389 #endif
  390                 }
  391 
  392                 /* see encap4_lookup() for issues here */
  393                 if (prio <= 0)
  394                         continue;
  395                 if (prio > matchprio) {
  396                         matchprio = prio;
  397                         match = ep;
  398                 }
  399         }
  400 
  401         return match;
  402 #undef s
  403 #undef d
  404 }
  405 
  406 int
  407 encap6_input(mp, offp, proto)
  408         struct mbuf **mp;
  409         int *offp;
  410         int proto;
  411 {
  412         struct mbuf *m = *mp;
  413         const struct ip6protosw *psw;
  414         struct encaptab *match;
  415 
  416         match = encap6_lookup(m, *offp, proto, INBOUND);
  417 
  418         if (match) {
  419                 /* found a match */
  420                 psw = (const struct ip6protosw *)match->psw;
  421                 if (psw && psw->pr_input) {
  422                         encap_fillarg(m, match);
  423                         return (*psw->pr_input)(mp, offp, proto);
  424                 } else {
  425                         m_freem(m);
  426                         return IPPROTO_DONE;
  427                 }
  428         }
  429 
  430         /* last resort: inject to raw socket */
  431         return rip6_input(mp, offp, proto);
  432 }
  433 #endif
  434 
  435 static int
  436 encap_add(ep)
  437         struct encaptab *ep;
  438 {
  439 #ifdef USE_RADIX
  440         struct radix_node_head *rnh = encap_rnh(ep->af);
  441 #endif
  442         int error = 0;
  443 
  444         LIST_INSERT_HEAD(&encaptab, ep, chain);
  445 #ifdef USE_RADIX
  446         if (!ep->func && rnh) {
  447                 if (!rnh->rnh_addaddr((caddr_t)ep->addrpack,
  448                     (caddr_t)ep->maskpack, rnh, ep->nodes)) {
  449                         error = EEXIST;
  450                         goto fail;
  451                 }
  452         }
  453 #endif
  454         return error;
  455 
  456  fail:
  457         LIST_REMOVE(ep, chain);
  458         return error;
  459 }
  460 
  461 static int
  462 encap_remove(ep)
  463         struct encaptab *ep;
  464 {
  465 #ifdef USE_RADIX
  466         struct radix_node_head *rnh = encap_rnh(ep->af);
  467 #endif
  468         int error = 0;
  469 
  470         LIST_REMOVE(ep, chain);
  471 #ifdef USE_RADIX
  472         if (!ep->func && rnh) {
  473                 if (!rnh->rnh_deladdr((caddr_t)ep->addrpack,
  474                     (caddr_t)ep->maskpack, rnh))
  475                         error = ESRCH;
  476         }
  477 #endif
  478         return error;
  479 }
  480 
  481 static int
  482 encap_afcheck(af, sp, dp)
  483         int af;
  484         const struct sockaddr *sp;
  485         const struct sockaddr *dp;
  486 {
  487         if (sp && dp) {
  488                 if (sp->sa_len != dp->sa_len)
  489                         return EINVAL;
  490                 if (af != sp->sa_family || af != dp->sa_family)
  491                         return EINVAL;
  492         } else if (!sp && !dp)
  493                 ;
  494         else
  495                 return EINVAL;
  496 
  497         switch (af) {
  498         case AF_INET:
  499                 if (sp && sp->sa_len != sizeof(struct sockaddr_in))
  500                         return EINVAL;
  501                 if (dp && dp->sa_len != sizeof(struct sockaddr_in))
  502                         return EINVAL;
  503                 break;
  504 #ifdef INET6
  505         case AF_INET6:
  506                 if (sp && sp->sa_len != sizeof(struct sockaddr_in6))
  507                         return EINVAL;
  508                 if (dp && dp->sa_len != sizeof(struct sockaddr_in6))
  509                         return EINVAL;
  510                 break;
  511 #endif
  512         default:
  513                 return EAFNOSUPPORT;
  514         }
  515 
  516         return 0;
  517 }
  518 
  519 /*
  520  * sp (src ptr) is always my side, and dp (dst ptr) is always remote side.
  521  * length of mask (sm and dm) is assumed to be same as sp/dp.
  522  * Return value will be necessary as input (cookie) for encap_detach().
  523  */
  524 const struct encaptab *
  525 encap_attach(af, proto, sp, sm, dp, dm, psw, arg)
  526         int af;
  527         int proto;
  528         const struct sockaddr *sp, *sm;
  529         const struct sockaddr *dp, *dm;
  530         const struct protosw *psw;
  531         void *arg;
  532 {
  533         struct encaptab *ep;
  534         int error;
  535         int s;
  536         size_t l;
  537         struct pack4 *pack4;
  538 #ifdef INET6
  539         struct pack6 *pack6;
  540 #endif
  541 
  542         s = splsoftnet();
  543         /* sanity check on args */
  544         error = encap_afcheck(af, sp, dp);
  545         if (error)
  546                 goto fail;
  547 
  548         /* check if anyone have already attached with exactly same config */
  549         for (ep = LIST_FIRST(&encaptab); ep; ep = LIST_NEXT(ep, chain)) {
  550                 if (ep->af != af)
  551                         continue;
  552                 if (ep->proto != proto)
  553                         continue;
  554                 if (ep->func)
  555                         continue;
  556 #ifdef DIAGNOSTIC
  557                 if (!ep->src || !ep->dst || !ep->srcmask || !ep->dstmask)
  558                         panic("null pointers in encaptab");
  559 #endif
  560                 if (ep->src->sa_len != sp->sa_len ||
  561                     bcmp(ep->src, sp, sp->sa_len) != 0 ||
  562                     bcmp(ep->srcmask, sm, sp->sa_len) != 0)
  563                         continue;
  564                 if (ep->dst->sa_len != dp->sa_len ||
  565                     bcmp(ep->dst, dp, dp->sa_len) != 0 ||
  566                     bcmp(ep->dstmask, dm, dp->sa_len) != 0)
  567                         continue;
  568 
  569                 error = EEXIST;
  570                 goto fail;
  571         }
  572 
  573         switch (af) {
  574         case AF_INET:
  575                 l = sizeof(*pack4);
  576                 break;
  577 #ifdef INET6
  578         case AF_INET6:
  579                 l = sizeof(*pack6);
  580                 break;
  581 #endif
  582         default:
  583                 goto fail;
  584         }
  585 
  586 #ifdef DIAGNOSTIC
  587         /* if l exceeds the value sa_len can possibly express, it's wrong. */
  588         if (l > (1 << (8 * sizeof(ep->addrpack->sa_len)))) {
  589                 error = EINVAL;
  590                 goto fail;
  591         }
  592 #endif
  593 
  594         ep = malloc(sizeof(*ep), M_NETADDR, M_NOWAIT);  /* M_NETADDR ok? */
  595         if (ep == NULL) {
  596                 error = ENOBUFS;
  597                 goto fail;
  598         }
  599         bzero(ep, sizeof(*ep));
  600         ep->addrpack = malloc(l, M_NETADDR, M_NOWAIT);
  601         if (ep->addrpack == NULL) {
  602                 error = ENOBUFS;
  603                 goto gc;
  604         }
  605         ep->maskpack = malloc(l, M_NETADDR, M_NOWAIT);
  606         if (ep->maskpack == NULL) {
  607                 error = ENOBUFS;
  608                 goto gc;
  609         }
  610 
  611         ep->af = af;
  612         ep->proto = proto;
  613         ep->addrpack->sa_len = l & 0xff;
  614         ep->maskpack->sa_len = l & 0xff;
  615         switch (af) {
  616         case AF_INET:
  617                 pack4 = (struct pack4 *)ep->addrpack;
  618                 ep->src = (struct sockaddr *)&pack4->mine;
  619                 ep->dst = (struct sockaddr *)&pack4->yours;
  620                 pack4 = (struct pack4 *)ep->maskpack;
  621                 ep->srcmask = (struct sockaddr *)&pack4->mine;
  622                 ep->dstmask = (struct sockaddr *)&pack4->yours;
  623                 break;
  624 #ifdef INET6
  625         case AF_INET6:
  626                 pack6 = (struct pack6 *)ep->addrpack;
  627                 ep->src = (struct sockaddr *)&pack6->mine;
  628                 ep->dst = (struct sockaddr *)&pack6->yours;
  629                 pack6 = (struct pack6 *)ep->maskpack;
  630                 ep->srcmask = (struct sockaddr *)&pack6->mine;
  631                 ep->dstmask = (struct sockaddr *)&pack6->yours;
  632                 break;
  633 #endif
  634         }
  635 
  636         bcopy(sp, ep->src, sp->sa_len);
  637         bcopy(sm, ep->srcmask, sp->sa_len);
  638         bcopy(dp, ep->dst, dp->sa_len);
  639         bcopy(dm, ep->dstmask, dp->sa_len);
  640         ep->psw = psw;
  641         ep->arg = arg;
  642 
  643         error = encap_add(ep);
  644         if (error)
  645                 goto gc;
  646 
  647         error = 0;
  648         splx(s);
  649         return ep;
  650 
  651 gc:
  652         if (ep->addrpack)
  653                 free(ep->addrpack, M_NETADDR);
  654         if (ep->maskpack)
  655                 free(ep->maskpack, M_NETADDR);
  656         if (ep)
  657                 free(ep, M_NETADDR);
  658 fail:
  659         splx(s);
  660         return NULL;
  661 }
  662 
  663 const struct encaptab *
  664 encap_attach_func(af, proto, func, psw, arg)
  665         int af;
  666         int proto;
  667         int (*func) __P((const struct mbuf *, int, int, void *));
  668         const struct protosw *psw;
  669         void *arg;
  670 {
  671         struct encaptab *ep;
  672         int error;
  673         int s;
  674 
  675         s = splsoftnet();
  676         /* sanity check on args */
  677         if (!func) {
  678                 error = EINVAL;
  679                 goto fail;
  680         }
  681 
  682         error = encap_afcheck(af, NULL, NULL);
  683         if (error)
  684                 goto fail;
  685 
  686         ep = malloc(sizeof(*ep), M_NETADDR, M_NOWAIT);  /*XXX*/
  687         if (ep == NULL) {
  688                 error = ENOBUFS;
  689                 goto fail;
  690         }
  691         bzero(ep, sizeof(*ep));
  692 
  693         ep->af = af;
  694         ep->proto = proto;
  695         ep->func = func;
  696         ep->psw = psw;
  697         ep->arg = arg;
  698 
  699         error = encap_add(ep);
  700         if (error)
  701                 goto fail;
  702 
  703         error = 0;
  704         splx(s);
  705         return ep;
  706 
  707 fail:
  708         splx(s);
  709         return NULL;
  710 }
  711 
  712 /* XXX encap4_ctlinput() is necessary if we set DF=1 on outer IPv4 header */
  713 
  714 #ifdef INET6
  715 void
  716 encap6_ctlinput(cmd, sa, d0)
  717         int cmd;
  718         struct sockaddr *sa;
  719         void *d0;
  720 {
  721         void *d = d0;
  722         struct ip6_hdr *ip6;
  723         struct mbuf *m;
  724         int off;
  725         struct ip6ctlparam *ip6cp = NULL;
  726         int nxt;
  727         struct encaptab *ep;
  728         const struct ip6protosw *psw;
  729 
  730         if (sa->sa_family != AF_INET6 ||
  731             sa->sa_len != sizeof(struct sockaddr_in6))
  732                 return;
  733 
  734         if ((unsigned)cmd >= PRC_NCMDS)
  735                 return;
  736         if (cmd == PRC_HOSTDEAD)
  737                 d = NULL;
  738         else if (cmd == PRC_MSGSIZE)
  739                 ; /* special code is present, see below */
  740         else if (inet6ctlerrmap[cmd] == 0)
  741                 return;
  742 
  743         /* if the parameter is from icmp6, decode it. */
  744         if (d != NULL) {
  745                 ip6cp = (struct ip6ctlparam *)d;
  746                 m = ip6cp->ip6c_m;
  747                 ip6 = ip6cp->ip6c_ip6;
  748                 off = ip6cp->ip6c_off;
  749                 nxt = ip6cp->ip6c_nxt;
  750 
  751                 if (ip6 && cmd == PRC_MSGSIZE) {
  752                         int valid = 0;
  753                         struct encaptab *match;
  754 
  755                         /*
  756                         * Check to see if we have a valid encap configuration.
  757                         */
  758                         match = encap6_lookup(m, off, nxt, OUTBOUND);
  759                         if (match)
  760                                 valid++;
  761 
  762                         /*
  763                         * Depending on the value of "valid" and routing table
  764                         * size (mtudisc_{hi,lo}wat), we will:
  765                         * - recalcurate the new MTU and create the
  766                         *   corresponding routing entry, or
  767                         * - ignore the MTU change notification.
  768                         */
  769                         icmp6_mtudisc_update((struct ip6ctlparam *)d, valid);
  770                 }
  771         } else {
  772                 m = NULL;
  773                 ip6 = NULL;
  774                 nxt = -1;
  775         }
  776 
  777         /* inform all listeners */
  778         for (ep = LIST_FIRST(&encaptab); ep; ep = LIST_NEXT(ep, chain)) {
  779                 if (ep->af != AF_INET6)
  780                         continue;
  781                 if (ep->proto >= 0 && ep->proto != nxt)
  782                         continue;
  783 
  784                 /* should optimize by looking at address pairs */
  785 
  786                 /* XXX need to pass ep->arg or ep itself to listeners */
  787                 psw = (const struct ip6protosw *)ep->psw;
  788                 if (psw && psw->pr_ctlinput)
  789                         (*psw->pr_ctlinput)(cmd, sa, d);
  790         }
  791 
  792         rip6_ctlinput(cmd, sa, d0);
  793 }
  794 #endif
  795 
  796 int
  797 encap_detach(cookie)
  798         const struct encaptab *cookie;
  799 {
  800         const struct encaptab *ep = cookie;
  801         struct encaptab *p;
  802         int error;
  803 
  804         for (p = LIST_FIRST(&encaptab); p; p = LIST_NEXT(p, chain)) {
  805                 if (p == ep) {
  806                         error = encap_remove(p);
  807                         if (error)
  808                                 return error;
  809                         if (!ep->func) {
  810                                 free(p->addrpack, M_NETADDR);
  811                                 free(p->maskpack, M_NETADDR);
  812                         }
  813                         free(p, M_NETADDR);     /*XXX*/
  814                         return 0;
  815                 }
  816         }
  817 
  818         return ENOENT;
  819 }
  820 
  821 #ifdef USE_RADIX
  822 static struct radix_node_head *
  823 encap_rnh(af)
  824         int af;
  825 {
  826 
  827         switch (af) {
  828         case AF_INET:
  829                 return encap_head[0];
  830 #ifdef INET6
  831         case AF_INET6:
  832                 return encap_head[1];
  833 #endif
  834         default:
  835                 return NULL;
  836         }
  837 }
  838 
  839 static int
  840 mask_matchlen(sa)
  841         const struct sockaddr *sa;
  842 {
  843         const char *p, *ep;
  844         int l;
  845 
  846         p = (const char *)sa;
  847         ep = p + sa->sa_len;
  848         p += 2; /* sa_len + sa_family */
  849 
  850         l = 0;
  851         while (p < ep) {
  852                 l += (*p ? 8 : 0);      /* estimate */
  853                 p++;
  854         }
  855         return l;
  856 }
  857 #endif
  858 
  859 #ifndef USE_RADIX
  860 static int
  861 mask_match(ep, sp, dp)
  862         const struct encaptab *ep;
  863         const struct sockaddr *sp;
  864         const struct sockaddr *dp;
  865 {
  866         struct sockaddr_storage s;
  867         struct sockaddr_storage d;
  868         int i;
  869         const u_int8_t *p, *q;
  870         u_int8_t *r;
  871         int matchlen;
  872 
  873 #ifdef DIAGNOSTIC
  874         if (ep->func)
  875                 panic("wrong encaptab passed to mask_match");
  876 #endif
  877         if (sp->sa_len > sizeof(s) || dp->sa_len > sizeof(d))
  878                 return 0;
  879         if (sp->sa_family != ep->af || dp->sa_family != ep->af)
  880                 return 0;
  881         if (sp->sa_len != ep->src->sa_len || dp->sa_len != ep->dst->sa_len)
  882                 return 0;
  883 
  884         matchlen = 0;
  885 
  886         p = (const u_int8_t *)sp;
  887         q = (const u_int8_t *)ep->srcmask;
  888         r = (u_int8_t *)&s;
  889         for (i = 0 ; i < sp->sa_len; i++) {
  890                 r[i] = p[i] & q[i];
  891                 /* XXX estimate */
  892                 matchlen += (q[i] ? 8 : 0);
  893         }
  894 
  895         p = (const u_int8_t *)dp;
  896         q = (const u_int8_t *)ep->dstmask;
  897         r = (u_int8_t *)&d;
  898         for (i = 0 ; i < dp->sa_len; i++) {
  899                 r[i] = p[i] & q[i];
  900                 /* XXX rough estimate */
  901                 matchlen += (q[i] ? 8 : 0);
  902         }
  903 
  904         /* need to overwrite len/family portion as we don't compare them */
  905         s.ss_len = sp->sa_len;
  906         s.ss_family = sp->sa_family;
  907         d.ss_len = dp->sa_len;
  908         d.ss_family = dp->sa_family;
  909 
  910         if (bcmp(&s, ep->src, ep->src->sa_len) == 0 &&
  911             bcmp(&d, ep->dst, ep->dst->sa_len) == 0) {
  912                 return matchlen;
  913         } else
  914                 return 0;
  915 }
  916 #endif
  917 
  918 static void
  919 encap_fillarg(m, ep)
  920         struct mbuf *m;
  921         const struct encaptab *ep;
  922 {
  923         struct m_tag *mtag;
  924 
  925         mtag = m_tag_get(PACKET_TAG_ENCAP, sizeof(void *), M_NOWAIT);
  926         if (mtag) {
  927                 *(void **)(mtag + 1) = ep->arg;
  928                 m_tag_prepend(m, mtag);
  929         }
  930 }
  931 
  932 void *
  933 encap_getarg(m)
  934         struct mbuf *m;
  935 {
  936         void *p;
  937         struct m_tag *mtag;
  938 
  939         p = NULL;
  940         mtag = m_tag_find(m, PACKET_TAG_ENCAP, NULL);
  941         if (mtag != NULL) {
  942                 p = *(void **)(mtag + 1);
  943                 m_tag_delete(m, mtag);
  944         }
  945         return p;
  946 }

Cache object: 146344f0d266231d936abb9c48557239


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