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/netipsec/xform_ipcomp.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 /*      $FreeBSD$       */
    2 /* $OpenBSD: ip_ipcomp.c,v 1.1 2001/07/05 12:08:52 jjbg Exp $ */
    3 
    4 /*-
    5  * SPDX-License-Identifier: BSD-3-Clause
    6  *
    7  * Copyright (c) 2001 Jean-Jacques Bernard-Gundol (jj@wabbitt.org)
    8  *
    9  * Redistribution and use in source and binary forms, with or without
   10  * modification, are permitted provided that the following conditions
   11  * are met:
   12  *
   13  * 1. Redistributions of source code must retain the above copyright
   14  *   notice, this list of conditions and the following disclaimer.
   15  * 2. Redistributions in binary form must reproduce the above copyright
   16  *   notice, this list of conditions and the following disclaimer in the
   17  *   documentation and/or other materials provided with the distribution.
   18  * 3. The name of the author may not be used to endorse or promote products
   19  *   derived from this software without specific prior written permission.
   20  *
   21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   31  */
   32 
   33 /* IP payload compression protocol (IPComp), see RFC 2393 */
   34 #include "opt_inet.h"
   35 #include "opt_inet6.h"
   36 #include "opt_ipsec.h"
   37 
   38 #include <sys/param.h>
   39 #include <sys/systm.h>
   40 #include <sys/mbuf.h>
   41 #include <sys/lock.h>
   42 #include <sys/mutex.h>
   43 #include <sys/socket.h>
   44 #include <sys/kernel.h>
   45 #include <sys/protosw.h>
   46 #include <sys/sysctl.h>
   47 
   48 #include <netinet/in.h>
   49 #include <netinet/in_systm.h>
   50 #include <netinet/ip.h>
   51 #include <netinet/ip_var.h>
   52 #include <netinet/ip_encap.h>
   53 
   54 #include <net/netisr.h>
   55 #include <net/vnet.h>
   56 
   57 #include <netipsec/ipsec.h>
   58 #include <netipsec/xform.h>
   59 
   60 #ifdef INET6
   61 #include <netinet/ip6.h>
   62 #include <netinet6/ip6_var.h>
   63 #include <netipsec/ipsec6.h>
   64 #endif
   65 
   66 #include <netipsec/ipcomp.h>
   67 #include <netipsec/ipcomp_var.h>
   68 
   69 #include <netipsec/key.h>
   70 #include <netipsec/key_debug.h>
   71 
   72 #include <opencrypto/cryptodev.h>
   73 #include <opencrypto/deflate.h>
   74 #include <opencrypto/xform.h>
   75 
   76 VNET_DEFINE(int, ipcomp_enable) = 1;
   77 VNET_PCPUSTAT_DEFINE(struct ipcompstat, ipcompstat);
   78 VNET_PCPUSTAT_SYSINIT(ipcompstat);
   79 
   80 #ifdef VIMAGE
   81 VNET_PCPUSTAT_SYSUNINIT(ipcompstat);
   82 #endif /* VIMAGE */
   83 
   84 SYSCTL_DECL(_net_inet_ipcomp);
   85 SYSCTL_INT(_net_inet_ipcomp, OID_AUTO, ipcomp_enable,
   86         CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ipcomp_enable), 0, "");
   87 SYSCTL_VNET_PCPUSTAT(_net_inet_ipcomp, IPSECCTL_STATS, stats,
   88     struct ipcompstat, ipcompstat,
   89     "IPCOMP statistics (struct ipcompstat, netipsec/ipcomp_var.h");
   90 
   91 static int ipcomp_input_cb(struct cryptop *crp);
   92 static int ipcomp_output_cb(struct cryptop *crp);
   93 
   94 /*
   95  * RFC 3173 p 2.2. Non-Expansion Policy:
   96  * If the total size of a compressed payload and the IPComp header, as
   97  * defined in section 3, is not smaller than the size of the original
   98  * payload, the IP datagram MUST be sent in the original non-compressed
   99  * form.
  100  *
  101  * When we use IPComp in tunnel mode, for small packets we will receive
  102  * encapsulated IP-IP datagrams without any compression and without IPComp
  103  * header.
  104  */
  105 static int
  106 ipcomp_encapcheck(union sockaddr_union *src, union sockaddr_union *dst)
  107 {
  108         struct secasvar *sav;
  109 
  110         sav = key_allocsa_tunnel(src, dst, IPPROTO_IPCOMP);
  111         if (sav == NULL)
  112                 return (0);
  113         key_freesav(&sav);
  114 
  115         if (src->sa.sa_family == AF_INET)
  116                 return (sizeof(struct in_addr) << 4);
  117         else
  118                 return (sizeof(struct in6_addr) << 4);
  119 }
  120 
  121 static int
  122 ipcomp_nonexp_input(struct mbuf *m, int off, int proto, void *arg __unused)
  123 {
  124         int isr;
  125 
  126         switch (proto) {
  127 #ifdef INET
  128         case IPPROTO_IPV4:
  129                 isr = NETISR_IP;
  130                 break;
  131 #endif
  132 #ifdef INET6
  133         case IPPROTO_IPV6:
  134                 isr = NETISR_IPV6;
  135                 break;
  136 #endif
  137         default:
  138                 IPCOMPSTAT_INC(ipcomps_nopf);
  139                 m_freem(m);
  140                 return (IPPROTO_DONE);
  141         }
  142         m_adj(m, off);
  143         IPCOMPSTAT_ADD(ipcomps_ibytes, m->m_pkthdr.len);
  144         IPCOMPSTAT_INC(ipcomps_input);
  145         netisr_dispatch(isr, m);
  146         return (IPPROTO_DONE);
  147 }
  148 
  149 /*
  150  * ipcomp_init() is called when an CPI is being set up.
  151  */
  152 static int
  153 ipcomp_init(struct secasvar *sav, struct xformsw *xsp)
  154 {
  155         const struct comp_algo *tcomp;
  156         struct cryptoini cric;
  157 
  158         /* NB: algorithm really comes in alg_enc and not alg_comp! */
  159         tcomp = comp_algorithm_lookup(sav->alg_enc);
  160         if (tcomp == NULL) {
  161                 DPRINTF(("%s: unsupported compression algorithm %d\n", __func__,
  162                          sav->alg_comp));
  163                 return EINVAL;
  164         }
  165         sav->alg_comp = sav->alg_enc;           /* set for doing histogram */
  166         sav->tdb_xform = xsp;
  167         sav->tdb_compalgxform = tcomp;
  168 
  169         /* Initialize crypto session */
  170         bzero(&cric, sizeof (cric));
  171         cric.cri_alg = sav->tdb_compalgxform->type;
  172 
  173         return crypto_newsession(&sav->tdb_cryptoid, &cric, V_crypto_support);
  174 }
  175 
  176 /*
  177  * ipcomp_zeroize() used when IPCA is deleted
  178  */
  179 static int
  180 ipcomp_zeroize(struct secasvar *sav)
  181 {
  182 
  183         crypto_freesession(sav->tdb_cryptoid);
  184         sav->tdb_cryptoid = NULL;
  185         return 0;
  186 }
  187 
  188 /*
  189  * ipcomp_input() gets called to uncompress an input packet
  190  */
  191 static int
  192 ipcomp_input(struct mbuf *m, struct secasvar *sav, int skip, int protoff)
  193 {
  194         struct xform_data *xd;
  195         struct cryptodesc *crdc;
  196         struct cryptop *crp;
  197         struct ipcomp *ipcomp;
  198         caddr_t addr;
  199         int error, hlen = IPCOMP_HLENGTH;
  200 
  201         /*
  202          * Check that the next header of the IPComp is not IPComp again, before
  203          * doing any real work.  Given it is not possible to do double
  204          * compression it means someone is playing tricks on us.
  205          */
  206         error = ENOBUFS;
  207         if (m->m_len < skip + hlen && (m = m_pullup(m, skip + hlen)) == NULL) {
  208                 IPCOMPSTAT_INC(ipcomps_hdrops);         /*XXX*/
  209                 DPRINTF(("%s: m_pullup failed\n", __func__));
  210                 key_freesav(&sav);
  211                 return (error);
  212         }
  213         addr = (caddr_t) mtod(m, struct ip *) + skip;
  214         ipcomp = (struct ipcomp *)addr;
  215         if (ipcomp->comp_nxt == IPPROTO_IPCOMP) {
  216                 IPCOMPSTAT_INC(ipcomps_pdrops); /* XXX have our own stats? */
  217                 DPRINTF(("%s: recursive compression detected\n", __func__));
  218                 error = EINVAL;
  219                 goto bad;
  220         }
  221 
  222         /* Get crypto descriptors */
  223         crp = crypto_getreq(1);
  224         if (crp == NULL) {
  225                 DPRINTF(("%s: no crypto descriptors\n", __func__));
  226                 IPCOMPSTAT_INC(ipcomps_crypto);
  227                 goto bad;
  228         }
  229         /* Get IPsec-specific opaque pointer */
  230         xd = malloc(sizeof(*xd), M_XDATA, M_NOWAIT | M_ZERO);
  231         if (xd == NULL) {
  232                 DPRINTF(("%s: cannot allocate xform_data\n", __func__));
  233                 IPCOMPSTAT_INC(ipcomps_crypto);
  234                 crypto_freereq(crp);
  235                 goto bad;
  236         }
  237         crdc = crp->crp_desc;
  238 
  239         crdc->crd_skip = skip + hlen;
  240         crdc->crd_len = m->m_pkthdr.len - (skip + hlen);
  241         crdc->crd_inject = skip;
  242 
  243         /* Decompression operation */
  244         crdc->crd_alg = sav->tdb_compalgxform->type;
  245 
  246 
  247         /* Crypto operation descriptor */
  248         crp->crp_ilen = m->m_pkthdr.len - (skip + hlen);
  249         crp->crp_flags = CRYPTO_F_IMBUF | CRYPTO_F_CBIFSYNC;
  250         crp->crp_buf = (caddr_t) m;
  251         crp->crp_callback = ipcomp_input_cb;
  252         crp->crp_opaque = (caddr_t) xd;
  253 
  254         /* These are passed as-is to the callback */
  255         xd->sav = sav;
  256         xd->protoff = protoff;
  257         xd->skip = skip;
  258         xd->vnet = curvnet;
  259 
  260         SECASVAR_LOCK(sav);
  261         crp->crp_session = xd->cryptoid = sav->tdb_cryptoid;
  262         SECASVAR_UNLOCK(sav);
  263 
  264         return crypto_dispatch(crp);
  265 bad:
  266         m_freem(m);
  267         key_freesav(&sav);
  268         return (error);
  269 }
  270 
  271 /*
  272  * IPComp input callback from the crypto driver.
  273  */
  274 static int
  275 ipcomp_input_cb(struct cryptop *crp)
  276 {
  277         IPSEC_DEBUG_DECLARE(char buf[IPSEC_ADDRSTRLEN]);
  278         struct xform_data *xd;
  279         struct mbuf *m;
  280         struct secasvar *sav;
  281         struct secasindex *saidx;
  282         caddr_t addr;
  283         crypto_session_t cryptoid;
  284         int hlen = IPCOMP_HLENGTH, error, clen;
  285         int skip, protoff;
  286         uint8_t nproto;
  287 
  288         m = (struct mbuf *) crp->crp_buf;
  289         xd = (struct xform_data *) crp->crp_opaque;
  290         CURVNET_SET(xd->vnet);
  291         sav = xd->sav;
  292         skip = xd->skip;
  293         protoff = xd->protoff;
  294         cryptoid = xd->cryptoid;
  295         saidx = &sav->sah->saidx;
  296         IPSEC_ASSERT(saidx->dst.sa.sa_family == AF_INET ||
  297                 saidx->dst.sa.sa_family == AF_INET6,
  298                 ("unexpected protocol family %u", saidx->dst.sa.sa_family));
  299 
  300         /* Check for crypto errors */
  301         if (crp->crp_etype) {
  302                 if (crp->crp_etype == EAGAIN) {
  303                         /* Reset the session ID */
  304                         if (ipsec_updateid(sav, &crp->crp_session, &cryptoid) != 0)
  305                                 crypto_freesession(cryptoid);
  306                         xd->cryptoid = crp->crp_session;
  307                         CURVNET_RESTORE();
  308                         return (crypto_dispatch(crp));
  309                 }
  310                 IPCOMPSTAT_INC(ipcomps_noxform);
  311                 DPRINTF(("%s: crypto error %d\n", __func__, crp->crp_etype));
  312                 error = crp->crp_etype;
  313                 goto bad;
  314         }
  315         /* Shouldn't happen... */
  316         if (m == NULL) {
  317                 IPCOMPSTAT_INC(ipcomps_crypto);
  318                 DPRINTF(("%s: null mbuf returned from crypto\n", __func__));
  319                 error = EINVAL;
  320                 goto bad;
  321         }
  322         IPCOMPSTAT_INC(ipcomps_hist[sav->alg_comp]);
  323 
  324         clen = crp->crp_olen;           /* Length of data after processing */
  325 
  326         /* Release the crypto descriptors */
  327         free(xd, M_XDATA), xd = NULL;
  328         crypto_freereq(crp), crp = NULL;
  329 
  330         /* In case it's not done already, adjust the size of the mbuf chain */
  331         m->m_pkthdr.len = clen + hlen + skip;
  332 
  333         if (m->m_len < skip + hlen && (m = m_pullup(m, skip + hlen)) == NULL) {
  334                 IPCOMPSTAT_INC(ipcomps_hdrops);         /*XXX*/
  335                 DPRINTF(("%s: m_pullup failed\n", __func__));
  336                 error = EINVAL;                         /*XXX*/
  337                 goto bad;
  338         }
  339 
  340         /* Keep the next protocol field */
  341         addr = (caddr_t) mtod(m, struct ip *) + skip;
  342         nproto = ((struct ipcomp *) addr)->comp_nxt;
  343 
  344         /* Remove the IPCOMP header */
  345         error = m_striphdr(m, skip, hlen);
  346         if (error) {
  347                 IPCOMPSTAT_INC(ipcomps_hdrops);
  348                 DPRINTF(("%s: bad mbuf chain, IPCA %s/%08lx\n", __func__,
  349                     ipsec_address(&sav->sah->saidx.dst, buf, sizeof(buf)),
  350                     (u_long) ntohl(sav->spi)));
  351                 goto bad;
  352         }
  353 
  354         /* Restore the Next Protocol field */
  355         m_copyback(m, protoff, sizeof (u_int8_t), (u_int8_t *) &nproto);
  356 
  357         switch (saidx->dst.sa.sa_family) {
  358 #ifdef INET6
  359         case AF_INET6:
  360                 error = ipsec6_common_input_cb(m, sav, skip, protoff);
  361                 break;
  362 #endif
  363 #ifdef INET
  364         case AF_INET:
  365                 error = ipsec4_common_input_cb(m, sav, skip, protoff);
  366                 break;
  367 #endif
  368         default:
  369                 panic("%s: Unexpected address family: %d saidx=%p", __func__,
  370                     saidx->dst.sa.sa_family, saidx);
  371         }
  372         CURVNET_RESTORE();
  373         return error;
  374 bad:
  375         CURVNET_RESTORE();
  376         if (sav != NULL)
  377                 key_freesav(&sav);
  378         if (m != NULL)
  379                 m_freem(m);
  380         if (xd != NULL)
  381                 free(xd, M_XDATA);
  382         if (crp != NULL)
  383                 crypto_freereq(crp);
  384         return error;
  385 }
  386 
  387 /*
  388  * IPComp output routine, called by ipsec[46]_perform_request()
  389  */
  390 static int
  391 ipcomp_output(struct mbuf *m, struct secpolicy *sp, struct secasvar *sav,
  392     u_int idx, int skip, int protoff)
  393 {
  394         IPSEC_DEBUG_DECLARE(char buf[IPSEC_ADDRSTRLEN]);
  395         const struct comp_algo *ipcompx;
  396         struct cryptodesc *crdc;
  397         struct cryptop *crp;
  398         struct xform_data *xd;
  399         int error, ralen, maxpacketsize;
  400 
  401         IPSEC_ASSERT(sav != NULL, ("null SA"));
  402         ipcompx = sav->tdb_compalgxform;
  403         IPSEC_ASSERT(ipcompx != NULL, ("null compression xform"));
  404 
  405         /*
  406          * Do not touch the packet in case our payload to compress
  407          * is lower than the minimal threshold of the compression
  408          * alogrithm.  We will just send out the data uncompressed.
  409          * See RFC 3173, 2.2. Non-Expansion Policy.
  410          */
  411         if (m->m_pkthdr.len <= ipcompx->minlen) {
  412                 IPCOMPSTAT_INC(ipcomps_threshold);
  413                 return ipsec_process_done(m, sp, sav, idx);
  414         }
  415 
  416         ralen = m->m_pkthdr.len - skip; /* Raw payload length before comp. */
  417         IPCOMPSTAT_INC(ipcomps_output);
  418 
  419         /* Check for maximum packet size violations. */
  420         switch (sav->sah->saidx.dst.sa.sa_family) {
  421 #ifdef INET
  422         case AF_INET:
  423                 maxpacketsize = IP_MAXPACKET;
  424                 break;
  425 #endif /* INET */
  426 #ifdef INET6
  427         case AF_INET6:
  428                 maxpacketsize = IPV6_MAXPACKET;
  429                 break;
  430 #endif /* INET6 */
  431         default:
  432                 IPCOMPSTAT_INC(ipcomps_nopf);
  433                 DPRINTF(("%s: unknown/unsupported protocol family %d, "
  434                     "IPCA %s/%08lx\n", __func__,
  435                     sav->sah->saidx.dst.sa.sa_family,
  436                     ipsec_address(&sav->sah->saidx.dst, buf, sizeof(buf)),
  437                     (u_long) ntohl(sav->spi)));
  438                 error = EPFNOSUPPORT;
  439                 goto bad;
  440         }
  441         if (ralen + skip + IPCOMP_HLENGTH > maxpacketsize) {
  442                 IPCOMPSTAT_INC(ipcomps_toobig);
  443                 DPRINTF(("%s: packet in IPCA %s/%08lx got too big "
  444                     "(len %u, max len %u)\n", __func__,
  445                     ipsec_address(&sav->sah->saidx.dst, buf, sizeof(buf)),
  446                     (u_long) ntohl(sav->spi),
  447                     ralen + skip + IPCOMP_HLENGTH, maxpacketsize));
  448                 error = EMSGSIZE;
  449                 goto bad;
  450         }
  451 
  452         /* Update the counters */
  453         IPCOMPSTAT_ADD(ipcomps_obytes, m->m_pkthdr.len - skip);
  454 
  455         m = m_unshare(m, M_NOWAIT);
  456         if (m == NULL) {
  457                 IPCOMPSTAT_INC(ipcomps_hdrops);
  458                 DPRINTF(("%s: cannot clone mbuf chain, IPCA %s/%08lx\n",
  459                     __func__, ipsec_address(&sav->sah->saidx.dst, buf,
  460                     sizeof(buf)), (u_long) ntohl(sav->spi)));
  461                 error = ENOBUFS;
  462                 goto bad;
  463         }
  464 
  465         /* Ok now, we can pass to the crypto processing. */
  466 
  467         /* Get crypto descriptors */
  468         crp = crypto_getreq(1);
  469         if (crp == NULL) {
  470                 IPCOMPSTAT_INC(ipcomps_crypto);
  471                 DPRINTF(("%s: failed to acquire crypto descriptor\n",__func__));
  472                 error = ENOBUFS;
  473                 goto bad;
  474         }
  475         crdc = crp->crp_desc;
  476 
  477         /* Compression descriptor */
  478         crdc->crd_skip = skip;
  479         crdc->crd_len = ralen;
  480         crdc->crd_flags = CRD_F_COMP;
  481         crdc->crd_inject = skip;
  482 
  483         /* Compression operation */
  484         crdc->crd_alg = ipcompx->type;
  485 
  486         /* IPsec-specific opaque crypto info */
  487         xd =  malloc(sizeof(struct xform_data), M_XDATA, M_NOWAIT | M_ZERO);
  488         if (xd == NULL) {
  489                 IPCOMPSTAT_INC(ipcomps_crypto);
  490                 DPRINTF(("%s: failed to allocate xform_data\n", __func__));
  491                 crypto_freereq(crp);
  492                 error = ENOBUFS;
  493                 goto bad;
  494         }
  495 
  496         xd->sp = sp;
  497         xd->sav = sav;
  498         xd->idx = idx;
  499         xd->skip = skip;
  500         xd->protoff = protoff;
  501         xd->vnet = curvnet;
  502 
  503         /* Crypto operation descriptor */
  504         crp->crp_ilen = m->m_pkthdr.len;        /* Total input length */
  505         crp->crp_flags = CRYPTO_F_IMBUF | CRYPTO_F_CBIFSYNC;
  506         crp->crp_buf = (caddr_t) m;
  507         crp->crp_callback = ipcomp_output_cb;
  508         crp->crp_opaque = (caddr_t) xd;
  509 
  510         SECASVAR_LOCK(sav);
  511         crp->crp_session = xd->cryptoid = sav->tdb_cryptoid;
  512         SECASVAR_UNLOCK(sav);
  513 
  514         return crypto_dispatch(crp);
  515 bad:
  516         if (m)
  517                 m_freem(m);
  518         key_freesav(&sav);
  519         key_freesp(&sp);
  520         return (error);
  521 }
  522 
  523 /*
  524  * IPComp output callback from the crypto driver.
  525  */
  526 static int
  527 ipcomp_output_cb(struct cryptop *crp)
  528 {
  529         IPSEC_DEBUG_DECLARE(char buf[IPSEC_ADDRSTRLEN]);
  530         struct xform_data *xd;
  531         struct secpolicy *sp;
  532         struct secasvar *sav;
  533         struct mbuf *m;
  534         crypto_session_t cryptoid;
  535         u_int idx;
  536         int error, skip, protoff;
  537 
  538         m = (struct mbuf *) crp->crp_buf;
  539         xd = (struct xform_data *) crp->crp_opaque;
  540         CURVNET_SET(xd->vnet);
  541         idx = xd->idx;
  542         sp = xd->sp;
  543         sav = xd->sav;
  544         skip = xd->skip;
  545         protoff = xd->protoff;
  546         cryptoid = xd->cryptoid;
  547 
  548         /* Check for crypto errors */
  549         if (crp->crp_etype) {
  550                 if (crp->crp_etype == EAGAIN) {
  551                         /* Reset the session ID */
  552                         if (ipsec_updateid(sav, &crp->crp_session, &cryptoid) != 0)
  553                                 crypto_freesession(cryptoid);
  554                         xd->cryptoid = crp->crp_session;
  555                         CURVNET_RESTORE();
  556                         return (crypto_dispatch(crp));
  557                 }
  558                 IPCOMPSTAT_INC(ipcomps_noxform);
  559                 DPRINTF(("%s: crypto error %d\n", __func__, crp->crp_etype));
  560                 error = crp->crp_etype;
  561                 goto bad;
  562         }
  563         /* Shouldn't happen... */
  564         if (m == NULL) {
  565                 IPCOMPSTAT_INC(ipcomps_crypto);
  566                 DPRINTF(("%s: bogus return buffer from crypto\n", __func__));
  567                 error = EINVAL;
  568                 goto bad;
  569         }
  570         IPCOMPSTAT_INC(ipcomps_hist[sav->alg_comp]);
  571 
  572         if (crp->crp_ilen - skip > crp->crp_olen) {
  573                 struct mbuf *mo;
  574                 struct ipcomp *ipcomp;
  575                 int roff;
  576                 uint8_t prot;
  577 
  578                 /* Compression helped, inject IPCOMP header. */
  579                 mo = m_makespace(m, skip, IPCOMP_HLENGTH, &roff);
  580                 if (mo == NULL) {
  581                         IPCOMPSTAT_INC(ipcomps_wrap);
  582                         DPRINTF(("%s: IPCOMP header inject failed "
  583                             "for IPCA %s/%08lx\n",
  584                             __func__, ipsec_address(&sav->sah->saidx.dst, buf,
  585                             sizeof(buf)), (u_long) ntohl(sav->spi)));
  586                         error = ENOBUFS;
  587                         goto bad;
  588                 }
  589                 ipcomp = (struct ipcomp *)(mtod(mo, caddr_t) + roff);
  590 
  591                 /* Initialize the IPCOMP header */
  592                 /* XXX alignment always correct? */
  593                 switch (sav->sah->saidx.dst.sa.sa_family) {
  594 #ifdef INET
  595                 case AF_INET:
  596                         ipcomp->comp_nxt = mtod(m, struct ip *)->ip_p;
  597                         break;
  598 #endif /* INET */
  599 #ifdef INET6
  600                 case AF_INET6:
  601                         ipcomp->comp_nxt = mtod(m, struct ip6_hdr *)->ip6_nxt;
  602                         break;
  603 #endif
  604                 }
  605                 ipcomp->comp_flags = 0;
  606                 ipcomp->comp_cpi = htons((u_int16_t) ntohl(sav->spi));
  607 
  608                 /* Fix Next Protocol in IPv4/IPv6 header */
  609                 prot = IPPROTO_IPCOMP;
  610                 m_copyback(m, protoff, sizeof(u_int8_t),
  611                     (u_char *)&prot);
  612 
  613                 /* Adjust the length in the IP header */
  614                 switch (sav->sah->saidx.dst.sa.sa_family) {
  615 #ifdef INET
  616                 case AF_INET:
  617                         mtod(m, struct ip *)->ip_len = htons(m->m_pkthdr.len);
  618                         break;
  619 #endif /* INET */
  620 #ifdef INET6
  621                 case AF_INET6:
  622                         mtod(m, struct ip6_hdr *)->ip6_plen =
  623                                 htons(m->m_pkthdr.len) - sizeof(struct ip6_hdr);
  624                         break;
  625 #endif /* INET6 */
  626                 default:
  627                         IPCOMPSTAT_INC(ipcomps_nopf);
  628                         DPRINTF(("%s: unknown/unsupported protocol "
  629                             "family %d, IPCA %s/%08lx\n", __func__,
  630                             sav->sah->saidx.dst.sa.sa_family,
  631                             ipsec_address(&sav->sah->saidx.dst, buf,
  632                                 sizeof(buf)), (u_long) ntohl(sav->spi)));
  633                         error = EPFNOSUPPORT;
  634                         goto bad;
  635                 }
  636         } else {
  637                 /* Compression was useless, we have lost time. */
  638                 IPCOMPSTAT_INC(ipcomps_uncompr);
  639                 DPRINTF(("%s: compressions was useless %d - %d <= %d\n",
  640                     __func__, crp->crp_ilen, skip, crp->crp_olen));
  641                 /* XXX remember state to not compress the next couple
  642                  *     of packets, RFC 3173, 2.2. Non-Expansion Policy */
  643         }
  644 
  645         /* Release the crypto descriptor */
  646         free(xd, M_XDATA);
  647         crypto_freereq(crp);
  648 
  649         /* NB: m is reclaimed by ipsec_process_done. */
  650         error = ipsec_process_done(m, sp, sav, idx);
  651         CURVNET_RESTORE();
  652         return (error);
  653 bad:
  654         if (m)
  655                 m_freem(m);
  656         CURVNET_RESTORE();
  657         free(xd, M_XDATA);
  658         crypto_freereq(crp);
  659         key_freesav(&sav);
  660         key_freesp(&sp);
  661         return (error);
  662 }
  663 
  664 #ifdef INET
  665 static int
  666 ipcomp4_nonexp_encapcheck(const struct mbuf *m, int off, int proto,
  667     void *arg __unused)
  668 {
  669         union sockaddr_union src, dst;
  670         const struct ip *ip;
  671 
  672         if (V_ipcomp_enable == 0)
  673                 return (0);
  674         if (proto != IPPROTO_IPV4 && proto != IPPROTO_IPV6)
  675                 return (0);
  676         bzero(&src, sizeof(src));
  677         bzero(&dst, sizeof(dst));
  678         src.sa.sa_family = dst.sa.sa_family = AF_INET;
  679         src.sin.sin_len = dst.sin.sin_len = sizeof(struct sockaddr_in);
  680         ip = mtod(m, const struct ip *);
  681         src.sin.sin_addr = ip->ip_src;
  682         dst.sin.sin_addr = ip->ip_dst;
  683         return (ipcomp_encapcheck(&src, &dst));
  684 }
  685 
  686 static const struct encaptab *ipe4_cookie = NULL;
  687 static const struct encap_config ipv4_encap_cfg = {
  688         .proto = -1,
  689         .min_length = sizeof(struct ip),
  690         .exact_match = sizeof(in_addr_t) << 4,
  691         .check = ipcomp4_nonexp_encapcheck,
  692         .input = ipcomp_nonexp_input
  693 };
  694 #endif
  695 #ifdef INET6
  696 static int
  697 ipcomp6_nonexp_encapcheck(const struct mbuf *m, int off, int proto,
  698     void *arg __unused)
  699 {
  700         union sockaddr_union src, dst;
  701         const struct ip6_hdr *ip6;
  702 
  703         if (V_ipcomp_enable == 0)
  704                 return (0);
  705         if (proto != IPPROTO_IPV4 && proto != IPPROTO_IPV6)
  706                 return (0);
  707         bzero(&src, sizeof(src));
  708         bzero(&dst, sizeof(dst));
  709         src.sa.sa_family = dst.sa.sa_family = AF_INET;
  710         src.sin6.sin6_len = dst.sin6.sin6_len = sizeof(struct sockaddr_in6);
  711         ip6 = mtod(m, const struct ip6_hdr *);
  712         src.sin6.sin6_addr = ip6->ip6_src;
  713         dst.sin6.sin6_addr = ip6->ip6_dst;
  714         if (IN6_IS_SCOPE_LINKLOCAL(&src.sin6.sin6_addr)) {
  715                 /* XXX: sa6_recoverscope() */
  716                 src.sin6.sin6_scope_id =
  717                     ntohs(src.sin6.sin6_addr.s6_addr16[1]);
  718                 src.sin6.sin6_addr.s6_addr16[1] = 0;
  719         }
  720         if (IN6_IS_SCOPE_LINKLOCAL(&dst.sin6.sin6_addr)) {
  721                 /* XXX: sa6_recoverscope() */
  722                 dst.sin6.sin6_scope_id =
  723                     ntohs(dst.sin6.sin6_addr.s6_addr16[1]);
  724                 dst.sin6.sin6_addr.s6_addr16[1] = 0;
  725         }
  726         return (ipcomp_encapcheck(&src, &dst));
  727 }
  728 
  729 static const struct encaptab *ipe6_cookie = NULL;
  730 static const struct encap_config ipv6_encap_cfg = {
  731         .proto = -1,
  732         .min_length = sizeof(struct ip6_hdr),
  733         .exact_match = sizeof(struct in6_addr) << 4,
  734         .check = ipcomp6_nonexp_encapcheck,
  735         .input = ipcomp_nonexp_input
  736 };
  737 #endif
  738 
  739 static struct xformsw ipcomp_xformsw = {
  740         .xf_type =      XF_IPCOMP,
  741         .xf_name =      "IPcomp",
  742         .xf_init =      ipcomp_init,
  743         .xf_zeroize =   ipcomp_zeroize,
  744         .xf_input =     ipcomp_input,
  745         .xf_output =    ipcomp_output,
  746 };
  747 
  748 static void
  749 ipcomp_attach(void)
  750 {
  751 
  752 #ifdef INET
  753         ipe4_cookie = ip_encap_attach(&ipv4_encap_cfg, NULL, M_WAITOK);
  754 #endif
  755 #ifdef INET6
  756         ipe6_cookie = ip6_encap_attach(&ipv6_encap_cfg, NULL, M_WAITOK);
  757 #endif
  758         xform_attach(&ipcomp_xformsw);
  759 }
  760 
  761 static void
  762 ipcomp_detach(void)
  763 {
  764 
  765 #ifdef INET
  766         ip_encap_detach(ipe4_cookie);
  767 #endif
  768 #ifdef INET6
  769         ip6_encap_detach(ipe6_cookie);
  770 #endif
  771         xform_detach(&ipcomp_xformsw);
  772 }
  773 
  774 SYSINIT(ipcomp_xform_init, SI_SUB_PROTO_DOMAIN, SI_ORDER_MIDDLE,
  775     ipcomp_attach, NULL);
  776 SYSUNINIT(ipcomp_xform_uninit, SI_SUB_PROTO_DOMAIN, SI_ORDER_MIDDLE,
  777     ipcomp_detach, NULL);

Cache object: 9eeaecbe4103cc5f4ea2553116d8b4f2


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