[ 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  -  FREEBSD10  -  FREEBSD9  -  FREEBSD92  -  FREEBSD91  -  FREEBSD90  -  FREEBSD8  -  FREEBSD82  -  FREEBSD81  -  FREEBSD80  -  FREEBSD7  -  FREEBSD74  -  FREEBSD73  -  FREEBSD72  -  FREEBSD71  -  FREEBSD70  -  FREEBSD6  -  FREEBSD64  -  FREEBSD63  -  FREEBSD62  -  FREEBSD61  -  FREEBSD60  -  FREEBSD5  -  FREEBSD55  -  FREEBSD54  -  FREEBSD53  -  FREEBSD52  -  FREEBSD51  -  FREEBSD50  -  FREEBSD4  -  FREEBSD3  -  FREEBSD22  -  cheribsd  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1  -  FREEBSD-LIBC  -  FREEBSD8-LIBC  -  FREEBSD7-LIBC  -  FREEBSD6-LIBC  -  GLIBC27 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: xform_ipcomp.c,v 1.28 2011/05/06 21:48:46 drochner Exp $       */
    2 /*      $FreeBSD: src/sys/netipsec/xform_ipcomp.c,v 1.1.4.1 2003/01/24 05:11:36 sam Exp $       */
    3 /* $OpenBSD: ip_ipcomp.c,v 1.1 2001/07/05 12:08:52 jjbg Exp $ */
    4 
    5 /*
    6  * Copyright (c) 2001 Jean-Jacques Bernard-Gundol (jj@wabbitt.org)
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  *
   12  * 1. Redistributions of source code must retain the above copyright
   13  *   notice, this list of conditions and the following disclaimer.
   14  * 2. Redistributions in binary form must reproduce the above copyright
   15  *   notice, this list of conditions and the following disclaimer in the
   16  *   documentation and/or other materials provided with the distribution.
   17  * 3. The name of the author may not be used to endorse or promote products
   18  *   derived from this software without specific prior written permission.
   19  *
   20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   21  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   22  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   23  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   25  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   29  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   30  */
   31 
   32 #include <sys/cdefs.h>
   33 __KERNEL_RCSID(0, "$NetBSD: xform_ipcomp.c,v 1.28 2011/05/06 21:48:46 drochner Exp $");
   34 
   35 /* IP payload compression protocol (IPComp), see RFC 2393 */
   36 #include "opt_inet.h"
   37 #ifdef __FreeBSD__
   38 #include "opt_inet6.h"
   39 #endif
   40 
   41 #include <sys/param.h>
   42 #include <sys/systm.h>
   43 #include <sys/mbuf.h>
   44 #include <sys/socket.h>
   45 #include <sys/kernel.h>
   46 #include <sys/protosw.h>
   47 #include <sys/sysctl.h>
   48 #include <sys/socketvar.h> /* for softnet_lock */
   49 
   50 #include <netinet/in.h>
   51 #include <netinet/in_systm.h>
   52 #include <netinet/ip.h>
   53 #include <netinet/ip_var.h>
   54 
   55 #include <net/route.h>
   56 #include <netipsec/ipsec.h>
   57 #include <netipsec/ipsec_private.h>
   58 #include <netipsec/xform.h>
   59 
   60 #ifdef INET6
   61 #include <netinet/ip6.h>
   62 #include <netipsec/ipsec6.h>
   63 #endif
   64 
   65 #include <netipsec/ipcomp.h>
   66 #include <netipsec/ipcomp_var.h>
   67 
   68 #include <netipsec/key.h>
   69 #include <netipsec/key_debug.h>
   70 
   71 #include <netipsec/ipsec_osdep.h>
   72 
   73 #include <opencrypto/cryptodev.h>
   74 #include <opencrypto/deflate.h>
   75 #include <opencrypto/xform.h>
   76 
   77 percpu_t *ipcompstat_percpu;
   78 
   79 int     ipcomp_enable = 1;
   80 
   81 #ifdef __FreeBSD__
   82 SYSCTL_DECL(_net_inet_ipcomp);
   83 SYSCTL_INT(_net_inet_ipcomp, OID_AUTO,
   84         ipcomp_enable,  CTLFLAG_RW,     &ipcomp_enable, 0, "");
   85 SYSCTL_STRUCT(_net_inet_ipcomp, IPSECCTL_STATS,
   86         stats,          CTLFLAG_RD,     &ipcompstat,    ipcompstat, "");
   87 #endif /* __FreeBSD__ */
   88 
   89 static int ipcomp_input_cb(struct cryptop *crp);
   90 static int ipcomp_output_cb(struct cryptop *crp);
   91 
   92 const struct comp_algo *
   93 ipcomp_algorithm_lookup(int alg)
   94 {
   95         if (alg >= IPCOMP_ALG_MAX)
   96                 return NULL;
   97         switch (alg) {
   98         case SADB_X_CALG_DEFLATE:
   99                 return &comp_algo_deflate_nogrow;
  100         }
  101         return NULL;
  102 }
  103 
  104 /*
  105  * ipcomp_init() is called when an CPI is being set up.
  106  */
  107 static int
  108 ipcomp_init(struct secasvar *sav, const struct xformsw *xsp)
  109 {
  110         const struct comp_algo *tcomp;
  111         struct cryptoini cric;
  112         int ses;
  113 
  114         /* NB: algorithm really comes in alg_enc and not alg_comp! */
  115         tcomp = ipcomp_algorithm_lookup(sav->alg_enc);
  116         if (tcomp == NULL) {
  117                 DPRINTF(("ipcomp_init: unsupported compression algorithm %d\n",
  118                          sav->alg_comp));
  119                 return EINVAL;
  120         }
  121         sav->alg_comp = sav->alg_enc;           /* set for doing histogram */
  122         sav->tdb_xform = xsp;
  123         sav->tdb_compalgxform = tcomp;
  124 
  125         /* Initialize crypto session */
  126         memset(&cric, 0, sizeof (cric));
  127         cric.cri_alg = sav->tdb_compalgxform->type;
  128 
  129         ses = crypto_newsession(&sav->tdb_cryptoid, &cric, crypto_support);
  130         return ses;
  131 }
  132 
  133 /*
  134  * ipcomp_zeroize() used when IPCA is deleted
  135  */
  136 static int
  137 ipcomp_zeroize(struct secasvar *sav)
  138 {
  139         int err;
  140 
  141         err = crypto_freesession(sav->tdb_cryptoid);
  142         sav->tdb_cryptoid = 0;
  143         return err;
  144 }
  145 
  146 /*
  147  * ipcomp_input() gets called to uncompress an input packet
  148  */
  149 static int
  150 ipcomp_input(struct mbuf *m, const struct secasvar *sav, int skip, int protoff)
  151 {
  152         struct tdb_crypto *tc;
  153         struct cryptodesc *crdc;
  154         struct cryptop *crp;
  155         int hlen = IPCOMP_HLENGTH;
  156 
  157         IPSEC_SPLASSERT_SOFTNET("ipcomp_input");
  158 
  159         /* Get crypto descriptors */
  160         crp = crypto_getreq(1);
  161         if (crp == NULL) {
  162                 m_freem(m);
  163                 DPRINTF(("ipcomp_input: no crypto descriptors\n"));
  164                 IPCOMP_STATINC(IPCOMP_STAT_CRYPTO);
  165                 return ENOBUFS;
  166         }
  167         /* Get IPsec-specific opaque pointer */
  168         tc = (struct tdb_crypto *) malloc(sizeof (*tc), M_XDATA, M_NOWAIT|M_ZERO);
  169         if (tc == NULL) {
  170                 m_freem(m);
  171                 crypto_freereq(crp);
  172                 DPRINTF(("ipcomp_input: cannot allocate tdb_crypto\n"));
  173                 IPCOMP_STATINC(IPCOMP_STAT_CRYPTO);
  174                 return ENOBUFS;
  175         }
  176         crdc = crp->crp_desc;
  177 
  178         crdc->crd_skip = skip + hlen;
  179         crdc->crd_len = m->m_pkthdr.len - (skip + hlen);
  180         crdc->crd_inject = skip;
  181 
  182         tc->tc_ptr = 0;
  183 
  184         /* Decompression operation */
  185         crdc->crd_alg = sav->tdb_compalgxform->type;
  186 
  187         /* Crypto operation descriptor */
  188         crp->crp_ilen = m->m_pkthdr.len - (skip + hlen);
  189         crp->crp_olen = MCLBYTES; /* hint to decompression code */
  190         crp->crp_flags = CRYPTO_F_IMBUF;
  191         crp->crp_buf = m;
  192         crp->crp_callback = ipcomp_input_cb;
  193         crp->crp_sid = sav->tdb_cryptoid;
  194         crp->crp_opaque = tc;
  195 
  196         /* These are passed as-is to the callback */
  197         tc->tc_spi = sav->spi;
  198         tc->tc_dst = sav->sah->saidx.dst;
  199         tc->tc_proto = sav->sah->saidx.proto;
  200         tc->tc_protoff = protoff;
  201         tc->tc_skip = skip;
  202 
  203         return crypto_dispatch(crp);
  204 }
  205 
  206 #ifdef INET6
  207 #define IPSEC_COMMON_INPUT_CB(m, sav, skip, protoff, mtag) do {              \
  208         if (saidx->dst.sa.sa_family == AF_INET6) {                           \
  209                 error = ipsec6_common_input_cb(m, sav, skip, protoff, mtag); \
  210         } else {                                                             \
  211                 error = ipsec4_common_input_cb(m, sav, skip, protoff, mtag); \
  212         }                                                                    \
  213 } while (0)
  214 #else
  215 #define IPSEC_COMMON_INPUT_CB(m, sav, skip, protoff, mtag)                   \
  216         (error = ipsec4_common_input_cb(m, sav, skip, protoff, mtag))
  217 #endif
  218 
  219 /*
  220  * IPComp input callback from the crypto driver.
  221  */
  222 static int
  223 ipcomp_input_cb(struct cryptop *crp)
  224 {
  225         struct cryptodesc *crd;
  226         struct tdb_crypto *tc;
  227         int skip, protoff;
  228         struct mtag *mtag;
  229         struct mbuf *m;
  230         struct secasvar *sav;
  231         struct secasindex *saidx;
  232         int s, hlen = IPCOMP_HLENGTH, error, clen;
  233         u_int8_t nproto;
  234         void *addr;
  235         u_int16_t dport = 0;
  236         u_int16_t sport = 0;
  237 #ifdef IPSEC_NAT_T
  238         struct m_tag * tag = NULL;
  239 #endif
  240 
  241         crd = crp->crp_desc;
  242 
  243         tc = (struct tdb_crypto *) crp->crp_opaque;
  244         IPSEC_ASSERT(tc != NULL, ("ipcomp_input_cb: null opaque crypto data area!"));
  245         skip = tc->tc_skip;
  246         protoff = tc->tc_protoff;
  247         mtag = (struct mtag *) tc->tc_ptr;
  248         m = (struct mbuf *) crp->crp_buf;
  249 
  250 #ifdef IPSEC_NAT_T
  251         /* find the source port for NAT-T */
  252         if ((tag = m_tag_find(m, PACKET_TAG_IPSEC_NAT_T_PORTS, NULL))) {
  253                 sport = ((u_int16_t *)(tag + 1))[0];
  254                 dport = ((u_int16_t *)(tag + 1))[1];
  255         }
  256 #endif
  257 
  258         s = splsoftnet();
  259         mutex_enter(softnet_lock);
  260 
  261         sav = KEY_ALLOCSA(&tc->tc_dst, tc->tc_proto, tc->tc_spi, sport, dport);
  262         if (sav == NULL) {
  263                 IPCOMP_STATINC(IPCOMP_STAT_NOTDB);
  264                 DPRINTF(("ipcomp_input_cb: SA expired while in crypto\n"));
  265                 error = ENOBUFS;                /*XXX*/
  266                 goto bad;
  267         }
  268 
  269         saidx = &sav->sah->saidx;
  270         IPSEC_ASSERT(saidx->dst.sa.sa_family == AF_INET ||
  271                 saidx->dst.sa.sa_family == AF_INET6,
  272                 ("ipcomp_input_cb: unexpected protocol family %u",
  273                  saidx->dst.sa.sa_family));
  274 
  275         /* Check for crypto errors */
  276         if (crp->crp_etype) {
  277                 /* Reset the session ID */
  278                 if (sav->tdb_cryptoid != 0)
  279                         sav->tdb_cryptoid = crp->crp_sid;
  280 
  281                 if (crp->crp_etype == EAGAIN) {
  282                         KEY_FREESAV(&sav);
  283                         mutex_exit(softnet_lock);
  284                         splx(s);
  285                         return crypto_dispatch(crp);
  286                 }
  287 
  288                 IPCOMP_STATINC(IPCOMP_STAT_NOXFORM);
  289                 DPRINTF(("ipcomp_input_cb: crypto error %d\n", crp->crp_etype));
  290                 error = crp->crp_etype;
  291                 goto bad;
  292         }
  293         /* Shouldn't happen... */
  294         if (m == NULL) {
  295                 IPCOMP_STATINC(IPCOMP_STAT_CRYPTO);
  296                 DPRINTF(("ipcomp_input_cb: null mbuf returned from crypto\n"));
  297                 error = EINVAL;
  298                 goto bad;
  299         }
  300         IPCOMP_STATINC(IPCOMP_STAT_HIST + sav->alg_comp);
  301 
  302         /* Update the counters */
  303         IPCOMP_STATADD(IPCOMP_STAT_IBYTES, m->m_pkthdr.len - skip - hlen);
  304 
  305 
  306         clen = crp->crp_olen;           /* Length of data after processing */
  307 
  308         /* Release the crypto descriptors */
  309         free(tc, M_XDATA), tc = NULL;
  310         crypto_freereq(crp), crp = NULL;
  311 
  312         /* In case it's not done already, adjust the size of the mbuf chain */
  313         m->m_pkthdr.len = clen + hlen + skip;
  314 
  315         if (m->m_len < skip + hlen && (m = m_pullup(m, skip + hlen)) == 0) {
  316                 IPCOMP_STATINC(IPCOMP_STAT_HDROPS);     /*XXX*/
  317                 DPRINTF(("ipcomp_input_cb: m_pullup failed\n"));
  318                 error = EINVAL;                         /*XXX*/
  319                 goto bad;
  320         }
  321 
  322         /* Keep the next protocol field */
  323         addr = (uint8_t*) mtod(m, struct ip *) + skip;
  324         nproto = ((struct ipcomp *) addr)->comp_nxt;
  325         if (nproto == IPPROTO_IPCOMP || nproto == IPPROTO_AH || nproto == IPPROTO_ESP) {
  326                 IPCOMP_STATINC(IPCOMP_STAT_HDROPS);
  327                 DPRINTF(("ipcomp_input_cb: nested ipcomp, IPCA %s/%08lx\n",
  328                          ipsec_address(&sav->sah->saidx.dst),
  329                          (u_long) ntohl(sav->spi)));
  330                 error = EINVAL;
  331                 goto bad;
  332         }
  333 
  334         /* Remove the IPCOMP header */
  335         error = m_striphdr(m, skip, hlen);
  336         if (error) {
  337                 IPCOMP_STATINC(IPCOMP_STAT_HDROPS);
  338                 DPRINTF(("ipcomp_input_cb: bad mbuf chain, IPCA %s/%08lx\n",
  339                          ipsec_address(&sav->sah->saidx.dst),
  340                          (u_long) ntohl(sav->spi)));
  341                 goto bad;
  342         }
  343 
  344         /* Restore the Next Protocol field */
  345         m_copyback(m, protoff, sizeof (u_int8_t), (u_int8_t *) &nproto);
  346 
  347         IPSEC_COMMON_INPUT_CB(m, sav, skip, protoff, NULL);
  348 
  349         KEY_FREESAV(&sav);
  350         mutex_exit(softnet_lock);
  351         splx(s);
  352         return error;
  353 bad:
  354         if (sav)
  355                 KEY_FREESAV(&sav);
  356         mutex_exit(softnet_lock);
  357         splx(s);
  358         if (m)
  359                 m_freem(m);
  360         if (tc != NULL)
  361                 free(tc, M_XDATA);
  362         if (crp)
  363                 crypto_freereq(crp);
  364         return error;
  365 }
  366 
  367 /*
  368  * IPComp output routine, called by ipsec[46]_process_packet()
  369  */
  370 static int
  371 ipcomp_output(
  372     struct mbuf *m,
  373     struct ipsecrequest *isr,
  374     struct mbuf **mp,
  375     int skip,
  376     int protoff
  377 )
  378 {
  379         const struct secasvar *sav;
  380         const struct comp_algo *ipcompx;
  381         int error, ralen, hlen, maxpacketsize;
  382         struct cryptodesc *crdc;
  383         struct cryptop *crp;
  384         struct tdb_crypto *tc;
  385 
  386         IPSEC_SPLASSERT_SOFTNET("ipcomp_output");
  387         sav = isr->sav;
  388         IPSEC_ASSERT(sav != NULL, ("ipcomp_output: null SA"));
  389         ipcompx = sav->tdb_compalgxform;
  390         IPSEC_ASSERT(ipcompx != NULL, ("ipcomp_output: null compression xform"));
  391 
  392         ralen = m->m_pkthdr.len - skip; /* Raw payload length before comp. */
  393     
  394     /* Don't process the packet if it is too short */
  395         if (ralen < ipcompx->minlen) {
  396                 IPCOMP_STATINC(IPCOMP_STAT_MINLEN);
  397                 return ipsec_process_done(m,isr);
  398         }
  399 
  400         hlen = IPCOMP_HLENGTH;
  401 
  402         IPCOMP_STATINC(IPCOMP_STAT_OUTPUT);
  403 
  404         /* Check for maximum packet size violations. */
  405         switch (sav->sah->saidx.dst.sa.sa_family) {
  406 #ifdef INET
  407         case AF_INET:
  408                 maxpacketsize =  IP_MAXPACKET;
  409                 break;
  410 #endif /* INET */
  411 #ifdef INET6
  412         case AF_INET6:
  413                 maxpacketsize =  IPV6_MAXPACKET;
  414                 break;
  415 #endif /* INET6 */
  416         default:
  417                 IPCOMP_STATINC(IPCOMP_STAT_NOPF);
  418                 DPRINTF(("ipcomp_output: unknown/unsupported protocol family %d"
  419                     ", IPCA %s/%08lx\n",
  420                     sav->sah->saidx.dst.sa.sa_family,
  421                     ipsec_address(&sav->sah->saidx.dst),
  422                     (u_long) ntohl(sav->spi)));
  423                 error = EPFNOSUPPORT;
  424                 goto bad;
  425         }
  426         if (skip + hlen + ralen > maxpacketsize) {
  427                 IPCOMP_STATINC(IPCOMP_STAT_TOOBIG);
  428                 DPRINTF(("ipcomp_output: packet in IPCA %s/%08lx got too big "
  429                     "(len %u, max len %u)\n",
  430                     ipsec_address(&sav->sah->saidx.dst),
  431                     (u_long) ntohl(sav->spi),
  432                     skip + hlen + ralen, maxpacketsize));
  433                 error = EMSGSIZE;
  434                 goto bad;
  435         }
  436 
  437         /* Update the counters */
  438         IPCOMP_STATADD(IPCOMP_STAT_OBYTES, m->m_pkthdr.len - skip);
  439 
  440         m = m_clone(m);
  441         if (m == NULL) {
  442                 IPCOMP_STATINC(IPCOMP_STAT_HDROPS);
  443                 DPRINTF(("ipcomp_output: cannot clone mbuf chain, IPCA %s/%08lx\n",
  444                     ipsec_address(&sav->sah->saidx.dst),
  445                     (u_long) ntohl(sav->spi)));
  446                 error = ENOBUFS;
  447                 goto bad;
  448         }
  449 
  450         /* Ok now, we can pass to the crypto processing */
  451 
  452         /* Get crypto descriptors */
  453         crp = crypto_getreq(1);
  454         if (crp == NULL) {
  455                 IPCOMP_STATINC(IPCOMP_STAT_CRYPTO);
  456                 DPRINTF(("ipcomp_output: failed to acquire crypto descriptor\n"));
  457                 error = ENOBUFS;
  458                 goto bad;
  459         }
  460         crdc = crp->crp_desc;
  461 
  462         /* Compression descriptor */
  463         crdc->crd_skip = skip;
  464         crdc->crd_len = m->m_pkthdr.len - skip;
  465         crdc->crd_flags = CRD_F_COMP;
  466         crdc->crd_inject = skip;
  467 
  468         /* Compression operation */
  469         crdc->crd_alg = ipcompx->type;
  470 
  471         /* IPsec-specific opaque crypto info */
  472         tc = (struct tdb_crypto *) malloc(sizeof(struct tdb_crypto),
  473                 M_XDATA, M_NOWAIT|M_ZERO);
  474         if (tc == NULL) {
  475                 IPCOMP_STATINC(IPCOMP_STAT_CRYPTO);
  476                 DPRINTF(("ipcomp_output: failed to allocate tdb_crypto\n"));
  477                 crypto_freereq(crp);
  478                 error = ENOBUFS;
  479                 goto bad;
  480         }
  481 
  482         tc->tc_isr = isr;
  483         tc->tc_spi = sav->spi;
  484         tc->tc_dst = sav->sah->saidx.dst;
  485         tc->tc_proto = sav->sah->saidx.proto;
  486         tc->tc_skip = skip;
  487         tc->tc_protoff = protoff;
  488 
  489         /* Crypto operation descriptor */
  490         crp->crp_ilen = m->m_pkthdr.len;        /* Total input length */
  491         crp->crp_flags = CRYPTO_F_IMBUF;
  492         crp->crp_buf = m;
  493         crp->crp_callback = ipcomp_output_cb;
  494         crp->crp_opaque = tc;
  495         crp->crp_sid = sav->tdb_cryptoid;
  496 
  497         return crypto_dispatch(crp);
  498 bad:
  499         if (m)
  500                 m_freem(m);
  501         return (error);
  502 }
  503 
  504 /*
  505  * IPComp output callback from the crypto driver.
  506  */
  507 static int
  508 ipcomp_output_cb(struct cryptop *crp)
  509 {
  510         struct tdb_crypto *tc;
  511         struct ipsecrequest *isr;
  512         struct secasvar *sav;
  513         struct mbuf *m, *mo;
  514         int s, error, skip, rlen, roff;
  515         u_int8_t prot;
  516         u_int16_t cpi;
  517         struct ipcomp * ipcomp;
  518 
  519 
  520         tc = (struct tdb_crypto *) crp->crp_opaque;
  521         IPSEC_ASSERT(tc != NULL, ("ipcomp_output_cb: null opaque data area!"));
  522         m = (struct mbuf *) crp->crp_buf;
  523         skip = tc->tc_skip;
  524         rlen = crp->crp_ilen - skip;
  525 
  526         s = splsoftnet();
  527         mutex_enter(softnet_lock);
  528 
  529         isr = tc->tc_isr;
  530         sav = KEY_ALLOCSA(&tc->tc_dst, tc->tc_proto, tc->tc_spi, 0, 0);
  531         if (sav == NULL) {
  532                 IPCOMP_STATINC(IPCOMP_STAT_NOTDB);
  533                 DPRINTF(("ipcomp_output_cb: SA expired while in crypto\n"));
  534                 error = ENOBUFS;                /*XXX*/
  535                 goto bad;
  536         }
  537         IPSEC_ASSERT(isr->sav == sav, ("ipcomp_output_cb: SA changed\n"));
  538 
  539         /* Check for crypto errors */
  540         if (crp->crp_etype) {
  541                 /* Reset session ID */
  542                 if (sav->tdb_cryptoid != 0)
  543                         sav->tdb_cryptoid = crp->crp_sid;
  544 
  545                 if (crp->crp_etype == EAGAIN) {
  546                         KEY_FREESAV(&sav);
  547                         mutex_exit(softnet_lock);
  548                         splx(s);
  549                         return crypto_dispatch(crp);
  550                 }
  551                 IPCOMP_STATINC(IPCOMP_STAT_NOXFORM);
  552                 DPRINTF(("ipcomp_output_cb: crypto error %d\n", crp->crp_etype));
  553                 error = crp->crp_etype;
  554                 goto bad;
  555         }
  556         /* Shouldn't happen... */
  557         if (m == NULL) {
  558                 IPCOMP_STATINC(IPCOMP_STAT_CRYPTO);
  559                 DPRINTF(("ipcomp_output_cb: bogus return buffer from crypto\n"));
  560                 error = EINVAL;
  561                 goto bad;
  562         }
  563         IPCOMP_STATINC(IPCOMP_STAT_HIST + sav->alg_comp);
  564 
  565         if (rlen > crp->crp_olen) {
  566                 /* Inject IPCOMP header */
  567                 mo = m_makespace(m, skip, IPCOMP_HLENGTH, &roff);
  568                 if (mo == NULL) {
  569                         IPCOMP_STATINC(IPCOMP_STAT_WRAP);
  570                         DPRINTF(("ipcomp_output: failed to inject IPCOMP header for "
  571                                          "IPCA %s/%08lx\n",
  572                                                 ipsec_address(&sav->sah->saidx.dst),
  573                                                 (u_long) ntohl(sav->spi)));
  574                         error = ENOBUFS;
  575                         goto bad;
  576                 }
  577                 ipcomp = (struct ipcomp *)(mtod(mo, char *) + roff);
  578 
  579                 /* Initialize the IPCOMP header */
  580                 /* XXX alignment always correct? */
  581                 switch (sav->sah->saidx.dst.sa.sa_family) {
  582 #ifdef INET
  583                 case AF_INET:
  584                         ipcomp->comp_nxt = mtod(m, struct ip *)->ip_p;
  585                          break;
  586 #endif /* INET */
  587 #ifdef INET6
  588                 case AF_INET6:
  589                         ipcomp->comp_nxt = mtod(m, struct ip6_hdr *)->ip6_nxt;
  590                 break;
  591 #endif
  592                 }
  593                 ipcomp->comp_flags = 0;
  594 
  595                 if ((sav->flags & SADB_X_EXT_RAWCPI) == 0)
  596                          cpi = sav->alg_enc;
  597                 else
  598                         cpi = ntohl(sav->spi) & 0xffff;
  599                 ipcomp->comp_cpi = htons(cpi);
  600 
  601                 /* Fix Next Protocol in IPv4/IPv6 header */
  602                 prot = IPPROTO_IPCOMP;
  603                 m_copyback(m, tc->tc_protoff, sizeof(u_int8_t), (u_char *)&prot);
  604 
  605                 /* Adjust the length in the IP header */
  606                 switch (sav->sah->saidx.dst.sa.sa_family) {
  607 #ifdef INET
  608                 case AF_INET:
  609                         mtod(m, struct ip *)->ip_len = htons(m->m_pkthdr.len);
  610                         break;
  611 #endif /* INET */
  612 #ifdef INET6
  613                 case AF_INET6:
  614                         mtod(m, struct ip6_hdr *)->ip6_plen =
  615                                 htons(m->m_pkthdr.len) - sizeof(struct ip6_hdr);
  616                         break;
  617 #endif /* INET6 */
  618                 default:
  619                         IPCOMP_STATINC(IPCOMP_STAT_NOPF);
  620                         DPRINTF(("ipcomp_output: unknown/unsupported protocol "
  621                             "family %d, IPCA %s/%08lx\n",
  622                             sav->sah->saidx.dst.sa.sa_family,
  623                             ipsec_address(&sav->sah->saidx.dst),
  624                             (u_long) ntohl(sav->spi)));
  625                         error = EPFNOSUPPORT;
  626                         goto bad;
  627                 }
  628         } else {
  629                 /* compression was useless, we have lost time */
  630                 IPCOMP_STATINC(IPCOMP_STAT_USELESS);
  631                 DPRINTF(("ipcomp_output_cb: compression was useless : initial size was %d"
  632                                         "and compressed size is %d\n", rlen, crp->crp_olen));
  633         }
  634 
  635 
  636         /* Release the crypto descriptor */
  637         free(tc, M_XDATA);
  638         crypto_freereq(crp);
  639 
  640         /* NB: m is reclaimed by ipsec_process_done. */
  641         error = ipsec_process_done(m, isr);
  642         KEY_FREESAV(&sav);
  643         mutex_exit(softnet_lock);
  644         splx(s);
  645         return error;
  646 bad:
  647         if (sav)
  648                 KEY_FREESAV(&sav);
  649         mutex_exit(softnet_lock);
  650         splx(s);
  651         if (m)
  652                 m_freem(m);
  653         free(tc, M_XDATA);
  654         crypto_freereq(crp);
  655         return error;
  656 }
  657 
  658 static struct xformsw ipcomp_xformsw = {
  659         XF_IPCOMP,              XFT_COMP,               "IPcomp",
  660         ipcomp_init,            ipcomp_zeroize,         ipcomp_input,
  661         ipcomp_output,
  662         NULL,
  663 };
  664 
  665 INITFN void
  666 ipcomp_attach(void)
  667 {
  668         ipcompstat_percpu = percpu_alloc(sizeof(uint64_t) * IPCOMP_NSTATS);
  669         xform_register(&ipcomp_xformsw);
  670 }
  671 
  672 #ifdef __FreeBSD__
  673 SYSINIT(ipcomp_xform_init, SI_SUB_DRIVERS, SI_ORDER_FIRST, ipcomp_attach, NULL)
  674 #endif /* __FreeBSD__ */

Cache object: 31ec8204a6f861354a8c6f7ef83dfdc6


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