The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/netipsec/xform_ipcomp.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 87f9c29311bc76e81e7158d5393bb410


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