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-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-2  -  FREEBSD-11-1  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-4  -  FREEBSD-10-3  -  FREEBSD-10-2  -  FREEBSD-10-1  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-3  -  FREEBSD-9-2  -  FREEBSD-9-1  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-4  -  FREEBSD-8-3  -  FREEBSD-8-2  -  FREEBSD-8-1  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-4  -  FREEBSD-7-3  -  FREEBSD-7-2  -  FREEBSD-7-1  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-4  -  FREEBSD-6-3  -  FREEBSD-6-2  -  FREEBSD-6-1  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-5  -  FREEBSD-5-4  -  FREEBSD-5-3  -  FREEBSD-5-2  -  FREEBSD-5-1  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  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 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: xform_ipcomp.c,v 1.18.12.1 2011/04/03 06:08:35 jdc 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.18.12.1 2011/04/03 06:08:35 jdc 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 
   49 #include <netinet/in.h>
   50 #include <netinet/in_systm.h>
   51 #include <netinet/ip.h>
   52 #include <netinet/ip_var.h>
   53 
   54 #include <net/route.h>
   55 #include <netipsec/ipsec.h>
   56 #include <netipsec/ipsec_private.h>
   57 #include <netipsec/xform.h>
   58 
   59 #ifdef INET6
   60 #include <netinet/ip6.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 #include <netipsec/key_debug.h>
   69 
   70 #include <netipsec/ipsec_osdep.h>
   71 
   72 #include <opencrypto/cryptodev.h>
   73 #include <opencrypto/deflate.h>
   74 #include <opencrypto/xform.h>
   75 
   76 percpu_t *ipcompstat_percpu;
   77 
   78 int     ipcomp_enable = 1;
   79 
   80 #ifdef __FreeBSD__
   81 SYSCTL_DECL(_net_inet_ipcomp);
   82 SYSCTL_INT(_net_inet_ipcomp, OID_AUTO,
   83         ipcomp_enable,  CTLFLAG_RW,     &ipcomp_enable, 0, "");
   84 SYSCTL_STRUCT(_net_inet_ipcomp, IPSECCTL_STATS,
   85         stats,          CTLFLAG_RD,     &ipcompstat,    ipcompstat, "");
   86 #endif /* __FreeBSD__ */
   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  * ipcomp_init() is called when an CPI is being set up.
  105  */
  106 static int
  107 ipcomp_init(struct secasvar *sav, struct xformsw *xsp)
  108 {
  109         struct comp_algo *tcomp;
  110         struct cryptoini cric;
  111         int ses;
  112 
  113         /* NB: algorithm really comes in alg_enc and not alg_comp! */
  114         tcomp = ipcomp_algorithm_lookup(sav->alg_enc);
  115         if (tcomp == NULL) {
  116                 DPRINTF(("ipcomp_init: unsupported compression algorithm %d\n",
  117                          sav->alg_comp));
  118                 return EINVAL;
  119         }
  120         sav->alg_comp = sav->alg_enc;           /* set for doing histogram */
  121         sav->tdb_xform = xsp;
  122         sav->tdb_compalgxform = tcomp;
  123 
  124         /* Initialize crypto session */
  125         bzero(&cric, sizeof (cric));
  126         cric.cri_alg = sav->tdb_compalgxform->type;
  127 
  128         mutex_spin_enter(&crypto_mtx);
  129         ses = crypto_newsession(&sav->tdb_cryptoid, &cric, crypto_support);
  130         mutex_spin_exit(&crypto_mtx);
  131         return ses;
  132 }
  133 
  134 /*
  135  * ipcomp_zeroize() used when IPCA is deleted
  136  */
  137 static int
  138 ipcomp_zeroize(struct secasvar *sav)
  139 {
  140         int err;
  141 
  142         mutex_spin_enter(&crypto_mtx);
  143         err = crypto_freesession(sav->tdb_cryptoid);
  144         mutex_spin_exit(&crypto_mtx);
  145         sav->tdb_cryptoid = 0;
  146         return err;
  147 }
  148 
  149 /*
  150  * ipcomp_input() gets called to uncompress an input packet
  151  */
  152 static int
  153 ipcomp_input(struct mbuf *m, struct secasvar *sav, int skip, int protoff)
  154 {
  155         struct tdb_crypto *tc;
  156         struct cryptodesc *crdc;
  157         struct cryptop *crp;
  158         int hlen = IPCOMP_HLENGTH;
  159 
  160         IPSEC_SPLASSERT_SOFTNET("ipcomp_input");
  161 
  162         /* Get crypto descriptors */
  163         crp = crypto_getreq(1);
  164         if (crp == NULL) {
  165                 m_freem(m);
  166                 DPRINTF(("ipcomp_input: no crypto descriptors\n"));
  167                 IPCOMP_STATINC(IPCOMP_STAT_CRYPTO);
  168                 return ENOBUFS;
  169         }
  170         /* Get IPsec-specific opaque pointer */
  171         tc = (struct tdb_crypto *) malloc(sizeof (*tc), M_XDATA, M_NOWAIT|M_ZERO);
  172         if (tc == NULL) {
  173                 m_freem(m);
  174                 crypto_freereq(crp);
  175                 DPRINTF(("ipcomp_input: cannot allocate tdb_crypto\n"));
  176                 IPCOMP_STATINC(IPCOMP_STAT_CRYPTO);
  177                 return ENOBUFS;
  178         }
  179         crdc = crp->crp_desc;
  180 
  181         crdc->crd_skip = skip + hlen;
  182         crdc->crd_len = m->m_pkthdr.len - (skip + hlen);
  183         crdc->crd_inject = skip;
  184 
  185         tc->tc_ptr = 0;
  186 
  187         /* Decompression operation */
  188         crdc->crd_alg = sav->tdb_compalgxform->type;
  189 
  190         /* Crypto operation descriptor */
  191         crp->crp_ilen = m->m_pkthdr.len - (skip + hlen);
  192         crp->crp_flags = CRYPTO_F_IMBUF;
  193         crp->crp_buf = m;
  194         crp->crp_callback = ipcomp_input_cb;
  195         crp->crp_sid = sav->tdb_cryptoid;
  196         crp->crp_opaque = tc;
  197 
  198         /* These are passed as-is to the callback */
  199         tc->tc_spi = sav->spi;
  200         tc->tc_dst = sav->sah->saidx.dst;
  201         tc->tc_proto = sav->sah->saidx.proto;
  202         tc->tc_protoff = protoff;
  203         tc->tc_skip = skip;
  204 
  205         return crypto_dispatch(crp);
  206 }
  207 
  208 #ifdef INET6
  209 #define IPSEC_COMMON_INPUT_CB(m, sav, skip, protoff, mtag) do {              \
  210         if (saidx->dst.sa.sa_family == AF_INET6) {                           \
  211                 error = ipsec6_common_input_cb(m, sav, skip, protoff, mtag); \
  212         } else {                                                             \
  213                 error = ipsec4_common_input_cb(m, sav, skip, protoff, mtag); \
  214         }                                                                    \
  215 } while (0)
  216 #else
  217 #define IPSEC_COMMON_INPUT_CB(m, sav, skip, protoff, mtag)                   \
  218         (error = ipsec4_common_input_cb(m, sav, skip, protoff, mtag))
  219 #endif
  220 
  221 /*
  222  * IPComp input callback from the crypto driver.
  223  */
  224 static int
  225 ipcomp_input_cb(struct cryptop *crp)
  226 {
  227         struct cryptodesc *crd;
  228         struct tdb_crypto *tc;
  229         int skip, protoff;
  230         struct mtag *mtag;
  231         struct mbuf *m;
  232         struct secasvar *sav;
  233         struct secasindex *saidx;
  234         int s, hlen = IPCOMP_HLENGTH, error, clen;
  235         u_int8_t nproto;
  236         void *addr;
  237         u_int16_t dport = 0;
  238         u_int16_t sport = 0;
  239 #ifdef IPSEC_NAT_T
  240         struct m_tag * tag = NULL;
  241 #endif
  242 
  243         crd = crp->crp_desc;
  244 
  245         tc = (struct tdb_crypto *) crp->crp_opaque;
  246         IPSEC_ASSERT(tc != NULL, ("ipcomp_input_cb: null opaque crypto data area!"));
  247         skip = tc->tc_skip;
  248         protoff = tc->tc_protoff;
  249         mtag = (struct mtag *) tc->tc_ptr;
  250         m = (struct mbuf *) crp->crp_buf;
  251 
  252 #ifdef IPSEC_NAT_T
  253         /* find the source port for NAT-T */
  254         if ((tag = m_tag_find(m, PACKET_TAG_IPSEC_NAT_T_PORTS, NULL))) {
  255                 sport = ((u_int16_t *)(tag + 1))[0];
  256                 dport = ((u_int16_t *)(tag + 1))[1];
  257         }
  258 #endif
  259 
  260         s = splsoftnet();
  261 
  262         sav = KEY_ALLOCSA(&tc->tc_dst, tc->tc_proto, tc->tc_spi, sport, dport);
  263         if (sav == NULL) {
  264                 IPCOMP_STATINC(IPCOMP_STAT_NOTDB);
  265                 DPRINTF(("ipcomp_input_cb: SA expired while in crypto\n"));
  266                 error = ENOBUFS;                /*XXX*/
  267                 goto bad;
  268         }
  269 
  270         saidx = &sav->sah->saidx;
  271         IPSEC_ASSERT(saidx->dst.sa.sa_family == AF_INET ||
  272                 saidx->dst.sa.sa_family == AF_INET6,
  273                 ("ah_input_cb: unexpected protocol family %u",
  274                  saidx->dst.sa.sa_family));
  275 
  276         /* Check for crypto errors */
  277         if (crp->crp_etype) {
  278                 /* Reset the session ID */
  279                 if (sav->tdb_cryptoid != 0)
  280                         sav->tdb_cryptoid = crp->crp_sid;
  281 
  282                 if (crp->crp_etype == EAGAIN) {
  283                         KEY_FREESAV(&sav);
  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         clen = crp->crp_olen;           /* Length of data after processing */
  303 
  304         /* Release the crypto descriptors */
  305         free(tc, M_XDATA), tc = NULL;
  306         crypto_freereq(crp), crp = NULL;
  307 
  308         /* In case it's not done already, adjust the size of the mbuf chain */
  309         m->m_pkthdr.len = clen + hlen + skip;
  310 
  311         if (m->m_len < skip + hlen && (m = m_pullup(m, skip + hlen)) == 0) {
  312                 IPCOMP_STATINC(IPCOMP_STAT_HDROPS);     /*XXX*/
  313                 DPRINTF(("ipcomp_input_cb: m_pullup failed\n"));
  314                 error = EINVAL;                         /*XXX*/
  315                 goto bad;
  316         }
  317 
  318         /* Keep the next protocol field */
  319         addr = (uint8_t*) mtod(m, struct ip *) + skip;
  320         nproto = ((struct ipcomp *) addr)->comp_nxt;
  321         if (nproto == IPPROTO_IPCOMP || nproto == IPPROTO_AH || nproto == IPPROTO_ESP) {
  322                 IPCOMP_STATINC(IPCOMP_STAT_HDROPS);
  323                 DPRINTF(("ipcomp_input_cb: nested ipcomp, IPCA %s/%08lx\n",
  324                          ipsec_address(&sav->sah->saidx.dst),
  325                          (u_long) ntohl(sav->spi)));
  326                 error = EINVAL;
  327                 goto bad;
  328         }
  329 
  330         /* Remove the IPCOMP header */
  331         error = m_striphdr(m, skip, hlen);
  332         if (error) {
  333                 IPCOMP_STATINC(IPCOMP_STAT_HDROPS);
  334                 DPRINTF(("ipcomp_input_cb: bad mbuf chain, IPCA %s/%08lx\n",
  335                          ipsec_address(&sav->sah->saidx.dst),
  336                          (u_long) ntohl(sav->spi)));
  337                 goto bad;
  338         }
  339 
  340         /* Restore the Next Protocol field */
  341         m_copyback(m, protoff, sizeof (u_int8_t), (u_int8_t *) &nproto);
  342 
  343         IPSEC_COMMON_INPUT_CB(m, sav, skip, protoff, NULL);
  344 
  345         KEY_FREESAV(&sav);
  346         splx(s);
  347         return error;
  348 bad:
  349         if (sav)
  350                 KEY_FREESAV(&sav);
  351         splx(s);
  352         if (m)
  353                 m_freem(m);
  354         if (tc != NULL)
  355                 free(tc, M_XDATA);
  356         if (crp)
  357                 crypto_freereq(crp);
  358         return error;
  359 }
  360 
  361 /*
  362  * IPComp output routine, called by ipsec[46]_process_packet()
  363  */
  364 static int
  365 ipcomp_output(
  366     struct mbuf *m,
  367     struct ipsecrequest *isr,
  368     struct mbuf **mp,
  369     int skip,
  370     int protoff
  371 )
  372 {
  373         struct secasvar *sav;
  374         struct comp_algo *ipcompx;
  375         int error, ralen, hlen, maxpacketsize;
  376         struct cryptodesc *crdc;
  377         struct cryptop *crp;
  378         struct tdb_crypto *tc;
  379 
  380         IPSEC_SPLASSERT_SOFTNET("ipcomp_output");
  381         sav = isr->sav;
  382         IPSEC_ASSERT(sav != NULL, ("ipcomp_output: null SA"));
  383         ipcompx = sav->tdb_compalgxform;
  384         IPSEC_ASSERT(ipcompx != NULL, ("ipcomp_output: null compression xform"));
  385 
  386         ralen = m->m_pkthdr.len - skip; /* Raw payload length before comp. */
  387     
  388     /* Don't process the packet if it is too short */
  389         if (ralen < ipcompx->minlen) {
  390                 IPCOMP_STATINC(IPCOMP_STAT_MINLEN);
  391                 return ipsec_process_done(m,isr);
  392         }
  393 
  394         hlen = IPCOMP_HLENGTH;
  395 
  396         IPCOMP_STATINC(IPCOMP_STAT_OUTPUT);
  397 
  398         /* Check for maximum packet size violations. */
  399         switch (sav->sah->saidx.dst.sa.sa_family) {
  400 #ifdef INET
  401         case AF_INET:
  402                 maxpacketsize =  IP_MAXPACKET;
  403                 break;
  404 #endif /* INET */
  405 #ifdef INET6
  406         case AF_INET6:
  407                 maxpacketsize =  IPV6_MAXPACKET;
  408                 break;
  409 #endif /* INET6 */
  410         default:
  411                 IPCOMP_STATINC(IPCOMP_STAT_NOPF);
  412                 DPRINTF(("ipcomp_output: unknown/unsupported protocol family %d"
  413                     ", IPCA %s/%08lx\n",
  414                     sav->sah->saidx.dst.sa.sa_family,
  415                     ipsec_address(&sav->sah->saidx.dst),
  416                     (u_long) ntohl(sav->spi)));
  417                 error = EPFNOSUPPORT;
  418                 goto bad;
  419         }
  420         if (skip + hlen + ralen > maxpacketsize) {
  421                 IPCOMP_STATINC(IPCOMP_STAT_TOOBIG);
  422                 DPRINTF(("ipcomp_output: packet in IPCA %s/%08lx got too big "
  423                     "(len %u, max len %u)\n",
  424                     ipsec_address(&sav->sah->saidx.dst),
  425                     (u_long) ntohl(sav->spi),
  426                     skip + hlen + ralen, maxpacketsize));
  427                 error = EMSGSIZE;
  428                 goto bad;
  429         }
  430 
  431         /* Update the counters */
  432         IPCOMP_STATADD(IPCOMP_STAT_OBYTES, m->m_pkthdr.len - skip);
  433 
  434         m = m_clone(m);
  435         if (m == NULL) {
  436                 IPCOMP_STATINC(IPCOMP_STAT_HDROPS);
  437                 DPRINTF(("ipcomp_output: cannot clone mbuf chain, IPCA %s/%08lx\n",
  438                     ipsec_address(&sav->sah->saidx.dst),
  439                     (u_long) ntohl(sav->spi)));
  440                 error = ENOBUFS;
  441                 goto bad;
  442         }
  443 
  444         /* Ok now, we can pass to the crypto processing */
  445 
  446         /* Get crypto descriptors */
  447         crp = crypto_getreq(1);
  448         if (crp == NULL) {
  449                 IPCOMP_STATINC(IPCOMP_STAT_CRYPTO);
  450                 DPRINTF(("ipcomp_output: failed to acquire crypto descriptor\n"));
  451                 error = ENOBUFS;
  452                 goto bad;
  453         }
  454         crdc = crp->crp_desc;
  455 
  456         /* Compression descriptor */
  457         crdc->crd_skip = skip;
  458         crdc->crd_len = m->m_pkthdr.len - skip;
  459         crdc->crd_flags = CRD_F_COMP;
  460         crdc->crd_inject = skip;
  461 
  462         /* Compression operation */
  463         crdc->crd_alg = ipcompx->type;
  464 
  465         /* IPsec-specific opaque crypto info */
  466         tc = (struct tdb_crypto *) malloc(sizeof(struct tdb_crypto),
  467                 M_XDATA, M_NOWAIT|M_ZERO);
  468         if (tc == NULL) {
  469                 IPCOMP_STATINC(IPCOMP_STAT_CRYPTO);
  470                 DPRINTF(("ipcomp_output: failed to allocate tdb_crypto\n"));
  471                 crypto_freereq(crp);
  472                 error = ENOBUFS;
  473                 goto bad;
  474         }
  475 
  476         tc->tc_isr = isr;
  477         tc->tc_spi = sav->spi;
  478         tc->tc_dst = sav->sah->saidx.dst;
  479         tc->tc_proto = sav->sah->saidx.proto;
  480         tc->tc_skip = skip;
  481         tc->tc_protoff = protoff;
  482 
  483         /* Crypto operation descriptor */
  484         crp->crp_ilen = m->m_pkthdr.len;        /* Total input length */
  485         crp->crp_flags = CRYPTO_F_IMBUF;
  486         crp->crp_buf = m;
  487         crp->crp_callback = ipcomp_output_cb;
  488         crp->crp_opaque = tc;
  489         crp->crp_sid = sav->tdb_cryptoid;
  490 
  491         return crypto_dispatch(crp);
  492 bad:
  493         if (m)
  494                 m_freem(m);
  495         return (error);
  496 }
  497 
  498 /*
  499  * IPComp output callback from the crypto driver.
  500  */
  501 static int
  502 ipcomp_output_cb(struct cryptop *crp)
  503 {
  504         struct tdb_crypto *tc;
  505         struct ipsecrequest *isr;
  506         struct secasvar *sav;
  507         struct mbuf *m, *mo;
  508         int s, error, skip, rlen, roff;
  509         u_int8_t prot;
  510         u_int16_t cpi;
  511         struct ipcomp * ipcomp;
  512 
  513 
  514         tc = (struct tdb_crypto *) crp->crp_opaque;
  515         IPSEC_ASSERT(tc != NULL, ("ipcomp_output_cb: null opaque data area!"));
  516         m = (struct mbuf *) crp->crp_buf;
  517         skip = tc->tc_skip;
  518         rlen = crp->crp_ilen - skip;
  519 
  520         s = splsoftnet();
  521 
  522         isr = tc->tc_isr;
  523         sav = KEY_ALLOCSA(&tc->tc_dst, tc->tc_proto, tc->tc_spi, 0, 0);
  524         if (sav == NULL) {
  525                 IPCOMP_STATINC(IPCOMP_STAT_NOTDB);
  526                 DPRINTF(("ipcomp_output_cb: SA expired while in crypto\n"));
  527                 error = ENOBUFS;                /*XXX*/
  528                 goto bad;
  529         }
  530         IPSEC_ASSERT(isr->sav == sav, ("ipcomp_output_cb: SA changed\n"));
  531 
  532         /* Check for crypto errors */
  533         if (crp->crp_etype) {
  534                 /* Reset session ID */
  535                 if (sav->tdb_cryptoid != 0)
  536                         sav->tdb_cryptoid = crp->crp_sid;
  537 
  538                 if (crp->crp_etype == EAGAIN) {
  539                         KEY_FREESAV(&sav);
  540                         splx(s);
  541                         return crypto_dispatch(crp);
  542                 }
  543                 IPCOMP_STATINC(IPCOMP_STAT_NOXFORM);
  544                 DPRINTF(("ipcomp_output_cb: crypto error %d\n", crp->crp_etype));
  545                 error = crp->crp_etype;
  546                 goto bad;
  547         }
  548         /* Shouldn't happen... */
  549         if (m == NULL) {
  550                 IPCOMP_STATINC(IPCOMP_STAT_CRYPTO);
  551                 DPRINTF(("ipcomp_output_cb: bogus return buffer from crypto\n"));
  552                 error = EINVAL;
  553                 goto bad;
  554         }
  555         IPCOMP_STATINC(IPCOMP_STAT_HIST + sav->alg_comp);
  556 
  557         if (rlen > crp->crp_olen) {
  558                 /* Inject IPCOMP header */
  559                 mo = m_makespace(m, skip, IPCOMP_HLENGTH, &roff);
  560                 if (mo == NULL) {
  561                         IPCOMP_STATINC(IPCOMP_STAT_WRAP);
  562                         DPRINTF(("ipcomp_output: failed to inject IPCOMP header for "
  563                                          "IPCA %s/%08lx\n",
  564                                                 ipsec_address(&sav->sah->saidx.dst),
  565                                                 (u_long) ntohl(sav->spi)));
  566                         error = ENOBUFS;
  567                         goto bad;
  568                 }
  569                 ipcomp = (struct ipcomp *)(mtod(mo, char *) + roff);
  570 
  571                 /* Initialize the IPCOMP header */
  572                 /* XXX alignment always correct? */
  573                 switch (sav->sah->saidx.dst.sa.sa_family) {
  574 #ifdef INET
  575                 case AF_INET:
  576                         ipcomp->comp_nxt = mtod(m, struct ip *)->ip_p;
  577                          break;
  578 #endif /* INET */
  579 #ifdef INET6
  580                 case AF_INET6:
  581                         ipcomp->comp_nxt = mtod(m, struct ip6_hdr *)->ip6_nxt;
  582                 break;
  583 #endif
  584                 }
  585                 ipcomp->comp_flags = 0;
  586 
  587                 if ((sav->flags & SADB_X_EXT_RAWCPI) == 0)
  588                          cpi = sav->alg_enc;
  589                 else
  590                         cpi = ntohl(sav->spi) & 0xffff;
  591                 ipcomp->comp_cpi = htons(cpi);
  592 
  593                 /* Fix Next Protocol in IPv4/IPv6 header */
  594                 prot = IPPROTO_IPCOMP;
  595                 m_copyback(m, tc->tc_protoff, sizeof(u_int8_t), (u_char *)&prot);
  596 
  597                 /* Adjust the length in the IP header */
  598                 switch (sav->sah->saidx.dst.sa.sa_family) {
  599 #ifdef INET
  600                 case AF_INET:
  601                         mtod(m, struct ip *)->ip_len = htons(m->m_pkthdr.len);
  602                         break;
  603 #endif /* INET */
  604 #ifdef INET6
  605                 case AF_INET6:
  606                         mtod(m, struct ip6_hdr *)->ip6_plen =
  607                                 htons(m->m_pkthdr.len) - sizeof(struct ip6_hdr);
  608                         break;
  609 #endif /* INET6 */
  610                 default:
  611                         IPCOMP_STATINC(IPCOMP_STAT_NOPF);
  612                         DPRINTF(("ipcomp_output: unknown/unsupported protocol "
  613                             "family %d, IPCA %s/%08lx\n",
  614                             sav->sah->saidx.dst.sa.sa_family,
  615                             ipsec_address(&sav->sah->saidx.dst),
  616                             (u_long) ntohl(sav->spi)));
  617                         error = EPFNOSUPPORT;
  618                         goto bad;
  619                 }
  620         } else {
  621                 /* compression was useless, we have lost time */
  622                 IPCOMP_STATINC(IPCOMP_STAT_USELESS);
  623                 DPRINTF(("ipcomp_output_cb: compression was useless : initial size was %d"
  624                                         "and compressed size is %d\n", rlen, crp->crp_olen));
  625         }
  626 
  627 
  628         /* Release the crypto descriptor */
  629         free(tc, M_XDATA);
  630         crypto_freereq(crp);
  631 
  632         /* NB: m is reclaimed by ipsec_process_done. */
  633         error = ipsec_process_done(m, isr);
  634         KEY_FREESAV(&sav);
  635         splx(s);
  636         return error;
  637 bad:
  638         if (sav)
  639                 KEY_FREESAV(&sav);
  640         splx(s);
  641         if (m)
  642                 m_freem(m);
  643         free(tc, M_XDATA);
  644         crypto_freereq(crp);
  645         return error;
  646 }
  647 
  648 static struct xformsw ipcomp_xformsw = {
  649         XF_IPCOMP,              XFT_COMP,               "IPcomp",
  650         ipcomp_init,            ipcomp_zeroize,         ipcomp_input,
  651         ipcomp_output,
  652         NULL,
  653 };
  654 
  655 INITFN void
  656 ipcomp_attach(void)
  657 {
  658         ipcompstat_percpu = percpu_alloc(sizeof(uint64_t) * IPCOMP_NSTATS);
  659         xform_register(&ipcomp_xformsw);
  660 }
  661 
  662 #ifdef __FreeBSD__
  663 SYSINIT(ipcomp_xform_init, SI_SUB_DRIVERS, SI_ORDER_FIRST, ipcomp_attach, NULL)
  664 #endif /* __FreeBSD__ */

Cache object: 9f3a215cdf8051472d8214bb750219ef


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