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

Cache object: 68f8c3bed9ed89520098f6a839ebb9bc


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