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

Cache object: fb8104f1e5aa974daa6ba44cfb1d3420


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