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.1/sys/netipsec/xform_ipcomp.c 319599 2017-06-05 11:11:07Z ae $      */
    2 /* $OpenBSD: ip_ipcomp.c,v 1.1 2001/07/05 12:08:52 jjbg Exp $ */
    3 
    4 /*-
    5  * Copyright (c) 2001 Jean-Jacques Bernard-Gundol (jj@wabbitt.org)
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  *
   11  * 1. Redistributions of source code must retain the above copyright
   12  *   notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *   notice, this list of conditions and the following disclaimer in the
   15  *   documentation and/or other materials provided with the distribution.
   16  * 3. The name of the author may not be used to endorse or promote products
   17  *   derived from this software without specific prior written permission.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   21  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   22  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   24  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   28  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   29  */
   30 
   31 /* IP payload compression protocol (IPComp), see RFC 2393 */
   32 #include "opt_inet.h"
   33 #include "opt_inet6.h"
   34 
   35 #include <sys/param.h>
   36 #include <sys/systm.h>
   37 #include <sys/mbuf.h>
   38 #include <sys/lock.h>
   39 #include <sys/mutex.h>
   40 #include <sys/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 
  257         SECASVAR_LOCK(sav);
  258         crp->crp_sid = xd->cryptoid = sav->tdb_cryptoid;
  259         SECASVAR_UNLOCK(sav);
  260 
  261         return crypto_dispatch(crp);
  262 bad:
  263         m_freem(m);
  264         key_freesav(&sav);
  265         return (error);
  266 }
  267 
  268 /*
  269  * IPComp input callback from the crypto driver.
  270  */
  271 static int
  272 ipcomp_input_cb(struct cryptop *crp)
  273 {
  274         IPSEC_DEBUG_DECLARE(char buf[IPSEC_ADDRSTRLEN]);
  275         struct cryptodesc *crd;
  276         struct xform_data *xd;
  277         struct mbuf *m;
  278         struct secasvar *sav;
  279         struct secasindex *saidx;
  280         caddr_t addr;
  281         uint64_t cryptoid;
  282         int hlen = IPCOMP_HLENGTH, error, clen;
  283         int skip, protoff;
  284         uint8_t nproto;
  285 
  286         crd = crp->crp_desc;
  287 
  288         m = (struct mbuf *) crp->crp_buf;
  289         xd = (struct xform_data *) crp->crp_opaque;
  290         sav = xd->sav;
  291         skip = xd->skip;
  292         protoff = xd->protoff;
  293         cryptoid = xd->cryptoid;
  294         saidx = &sav->sah->saidx;
  295         IPSEC_ASSERT(saidx->dst.sa.sa_family == AF_INET ||
  296                 saidx->dst.sa.sa_family == AF_INET6,
  297                 ("unexpected protocol family %u", saidx->dst.sa.sa_family));
  298 
  299         /* Check for crypto errors */
  300         if (crp->crp_etype) {
  301                 if (crp->crp_etype == EAGAIN) {
  302                         /* Reset the session ID */
  303                         if (ipsec_updateid(sav, &crp->crp_sid, &cryptoid) != 0)
  304                                 crypto_freesession(cryptoid);
  305                         xd->cryptoid = crp->crp_sid;
  306                         return (crypto_dispatch(crp));
  307                 }
  308                 IPCOMPSTAT_INC(ipcomps_noxform);
  309                 DPRINTF(("%s: crypto error %d\n", __func__, crp->crp_etype));
  310                 error = crp->crp_etype;
  311                 goto bad;
  312         }
  313         /* Shouldn't happen... */
  314         if (m == NULL) {
  315                 IPCOMPSTAT_INC(ipcomps_crypto);
  316                 DPRINTF(("%s: null mbuf returned from crypto\n", __func__));
  317                 error = EINVAL;
  318                 goto bad;
  319         }
  320         IPCOMPSTAT_INC(ipcomps_hist[sav->alg_comp]);
  321 
  322         clen = crp->crp_olen;           /* Length of data after processing */
  323 
  324         /* Release the crypto descriptors */
  325         free(xd, M_XDATA), xd = NULL;
  326         crypto_freereq(crp), crp = NULL;
  327 
  328         /* In case it's not done already, adjust the size of the mbuf chain */
  329         m->m_pkthdr.len = clen + hlen + skip;
  330 
  331         if (m->m_len < skip + hlen && (m = m_pullup(m, skip + hlen)) == NULL) {
  332                 IPCOMPSTAT_INC(ipcomps_hdrops);         /*XXX*/
  333                 DPRINTF(("%s: m_pullup failed\n", __func__));
  334                 error = EINVAL;                         /*XXX*/
  335                 goto bad;
  336         }
  337 
  338         /* Keep the next protocol field */
  339         addr = (caddr_t) mtod(m, struct ip *) + skip;
  340         nproto = ((struct ipcomp *) addr)->comp_nxt;
  341 
  342         /* Remove the IPCOMP header */
  343         error = m_striphdr(m, skip, hlen);
  344         if (error) {
  345                 IPCOMPSTAT_INC(ipcomps_hdrops);
  346                 DPRINTF(("%s: bad mbuf chain, IPCA %s/%08lx\n", __func__,
  347                     ipsec_address(&sav->sah->saidx.dst, buf, sizeof(buf)),
  348                     (u_long) ntohl(sav->spi)));
  349                 goto bad;
  350         }
  351 
  352         /* Restore the Next Protocol field */
  353         m_copyback(m, protoff, sizeof (u_int8_t), (u_int8_t *) &nproto);
  354 
  355         switch (saidx->dst.sa.sa_family) {
  356 #ifdef INET6
  357         case AF_INET6:
  358                 error = ipsec6_common_input_cb(m, sav, skip, protoff);
  359                 break;
  360 #endif
  361 #ifdef INET
  362         case AF_INET:
  363                 error = ipsec4_common_input_cb(m, sav, skip, protoff);
  364                 break;
  365 #endif
  366         default:
  367                 panic("%s: Unexpected address family: %d saidx=%p", __func__,
  368                     saidx->dst.sa.sa_family, saidx);
  369         }
  370         return error;
  371 bad:
  372         if (sav != NULL)
  373                 key_freesav(&sav);
  374         if (m != NULL)
  375                 m_freem(m);
  376         if (xd != NULL)
  377                 free(xd, M_XDATA);
  378         if (crp != NULL)
  379                 crypto_freereq(crp);
  380         return error;
  381 }
  382 
  383 /*
  384  * IPComp output routine, called by ipsec[46]_perform_request()
  385  */
  386 static int
  387 ipcomp_output(struct mbuf *m, struct secpolicy *sp, struct secasvar *sav,
  388     u_int idx, int skip, int protoff)
  389 {
  390         IPSEC_DEBUG_DECLARE(char buf[IPSEC_ADDRSTRLEN]);
  391         const struct comp_algo *ipcompx;
  392         struct cryptodesc *crdc;
  393         struct cryptop *crp;
  394         struct xform_data *xd;
  395         int error, ralen, maxpacketsize;
  396 
  397         IPSEC_ASSERT(sav != NULL, ("null SA"));
  398         ipcompx = sav->tdb_compalgxform;
  399         IPSEC_ASSERT(ipcompx != NULL, ("null compression xform"));
  400 
  401         /*
  402          * Do not touch the packet in case our payload to compress
  403          * is lower than the minimal threshold of the compression
  404          * alogrithm.  We will just send out the data uncompressed.
  405          * See RFC 3173, 2.2. Non-Expansion Policy.
  406          */
  407         if (m->m_pkthdr.len <= ipcompx->minlen) {
  408                 IPCOMPSTAT_INC(ipcomps_threshold);
  409                 return ipsec_process_done(m, sp, sav, idx);
  410         }
  411 
  412         ralen = m->m_pkthdr.len - skip; /* Raw payload length before comp. */
  413         IPCOMPSTAT_INC(ipcomps_output);
  414 
  415         /* Check for maximum packet size violations. */
  416         switch (sav->sah->saidx.dst.sa.sa_family) {
  417 #ifdef INET
  418         case AF_INET:
  419                 maxpacketsize = IP_MAXPACKET;
  420                 break;
  421 #endif /* INET */
  422 #ifdef INET6
  423         case AF_INET6:
  424                 maxpacketsize = IPV6_MAXPACKET;
  425                 break;
  426 #endif /* INET6 */
  427         default:
  428                 IPCOMPSTAT_INC(ipcomps_nopf);
  429                 DPRINTF(("%s: unknown/unsupported protocol family %d, "
  430                     "IPCA %s/%08lx\n", __func__,
  431                     sav->sah->saidx.dst.sa.sa_family,
  432                     ipsec_address(&sav->sah->saidx.dst, buf, sizeof(buf)),
  433                     (u_long) ntohl(sav->spi)));
  434                 error = EPFNOSUPPORT;
  435                 goto bad;
  436         }
  437         if (ralen + skip + IPCOMP_HLENGTH > maxpacketsize) {
  438                 IPCOMPSTAT_INC(ipcomps_toobig);
  439                 DPRINTF(("%s: packet in IPCA %s/%08lx got too big "
  440                     "(len %u, max len %u)\n", __func__,
  441                     ipsec_address(&sav->sah->saidx.dst, buf, sizeof(buf)),
  442                     (u_long) ntohl(sav->spi),
  443                     ralen + skip + IPCOMP_HLENGTH, maxpacketsize));
  444                 error = EMSGSIZE;
  445                 goto bad;
  446         }
  447 
  448         /* Update the counters */
  449         IPCOMPSTAT_ADD(ipcomps_obytes, m->m_pkthdr.len - skip);
  450 
  451         m = m_unshare(m, M_NOWAIT);
  452         if (m == NULL) {
  453                 IPCOMPSTAT_INC(ipcomps_hdrops);
  454                 DPRINTF(("%s: cannot clone mbuf chain, IPCA %s/%08lx\n",
  455                     __func__, ipsec_address(&sav->sah->saidx.dst, buf,
  456                     sizeof(buf)), (u_long) ntohl(sav->spi)));
  457                 error = ENOBUFS;
  458                 goto bad;
  459         }
  460 
  461         /* Ok now, we can pass to the crypto processing. */
  462 
  463         /* Get crypto descriptors */
  464         crp = crypto_getreq(1);
  465         if (crp == NULL) {
  466                 IPCOMPSTAT_INC(ipcomps_crypto);
  467                 DPRINTF(("%s: failed to acquire crypto descriptor\n",__func__));
  468                 error = ENOBUFS;
  469                 goto bad;
  470         }
  471         crdc = crp->crp_desc;
  472 
  473         /* Compression descriptor */
  474         crdc->crd_skip = skip;
  475         crdc->crd_len = ralen;
  476         crdc->crd_flags = CRD_F_COMP;
  477         crdc->crd_inject = skip;
  478 
  479         /* Compression operation */
  480         crdc->crd_alg = ipcompx->type;
  481 
  482         /* IPsec-specific opaque crypto info */
  483         xd =  malloc(sizeof(struct xform_data), M_XDATA, M_NOWAIT | M_ZERO);
  484         if (xd == NULL) {
  485                 IPCOMPSTAT_INC(ipcomps_crypto);
  486                 DPRINTF(("%s: failed to allocate xform_data\n", __func__));
  487                 crypto_freereq(crp);
  488                 error = ENOBUFS;
  489                 goto bad;
  490         }
  491 
  492         xd->sp = sp;
  493         xd->sav = sav;
  494         xd->idx = idx;
  495         xd->skip = skip;
  496         xd->protoff = protoff;
  497 
  498         /* Crypto operation descriptor */
  499         crp->crp_ilen = m->m_pkthdr.len;        /* Total input length */
  500         crp->crp_flags = CRYPTO_F_IMBUF | CRYPTO_F_CBIFSYNC;
  501         crp->crp_buf = (caddr_t) m;
  502         crp->crp_callback = ipcomp_output_cb;
  503         crp->crp_opaque = (caddr_t) xd;
  504 
  505         SECASVAR_LOCK(sav);
  506         crp->crp_sid = xd->cryptoid = sav->tdb_cryptoid;
  507         SECASVAR_UNLOCK(sav);
  508 
  509         return crypto_dispatch(crp);
  510 bad:
  511         if (m)
  512                 m_freem(m);
  513         key_freesav(&sav);
  514         key_freesp(&sp);
  515         return (error);
  516 }
  517 
  518 /*
  519  * IPComp output callback from the crypto driver.
  520  */
  521 static int
  522 ipcomp_output_cb(struct cryptop *crp)
  523 {
  524         IPSEC_DEBUG_DECLARE(char buf[IPSEC_ADDRSTRLEN]);
  525         struct xform_data *xd;
  526         struct secpolicy *sp;
  527         struct secasvar *sav;
  528         struct mbuf *m;
  529         uint64_t cryptoid;
  530         u_int idx;
  531         int error, skip, protoff;
  532 
  533         m = (struct mbuf *) crp->crp_buf;
  534         xd = (struct xform_data *) crp->crp_opaque;
  535         idx = xd->idx;
  536         sp = xd->sp;
  537         sav = xd->sav;
  538         skip = xd->skip;
  539         protoff = xd->protoff;
  540         cryptoid = xd->cryptoid;
  541 
  542         /* Check for crypto errors */
  543         if (crp->crp_etype) {
  544                 if (crp->crp_etype == EAGAIN) {
  545                         /* Reset the session ID */
  546                         if (ipsec_updateid(sav, &crp->crp_sid, &cryptoid) != 0)
  547                                 crypto_freesession(cryptoid);
  548                         xd->cryptoid = crp->crp_sid;
  549                         return (crypto_dispatch(crp));
  550                 }
  551                 IPCOMPSTAT_INC(ipcomps_noxform);
  552                 DPRINTF(("%s: crypto error %d\n", __func__, crp->crp_etype));
  553                 error = crp->crp_etype;
  554                 goto bad;
  555         }
  556         /* Shouldn't happen... */
  557         if (m == NULL) {
  558                 IPCOMPSTAT_INC(ipcomps_crypto);
  559                 DPRINTF(("%s: bogus return buffer from crypto\n", __func__));
  560                 error = EINVAL;
  561                 goto bad;
  562         }
  563         IPCOMPSTAT_INC(ipcomps_hist[sav->alg_comp]);
  564 
  565         if (crp->crp_ilen - skip > crp->crp_olen) {
  566                 struct mbuf *mo;
  567                 struct ipcomp *ipcomp;
  568                 int roff;
  569                 uint8_t prot;
  570 
  571                 /* Compression helped, inject IPCOMP header. */
  572                 mo = m_makespace(m, skip, IPCOMP_HLENGTH, &roff);
  573                 if (mo == NULL) {
  574                         IPCOMPSTAT_INC(ipcomps_wrap);
  575                         DPRINTF(("%s: IPCOMP header inject failed "
  576                             "for IPCA %s/%08lx\n",
  577                             __func__, ipsec_address(&sav->sah->saidx.dst, buf,
  578                             sizeof(buf)), (u_long) ntohl(sav->spi)));
  579                         error = ENOBUFS;
  580                         goto bad;
  581                 }
  582                 ipcomp = (struct ipcomp *)(mtod(mo, caddr_t) + roff);
  583 
  584                 /* Initialize the IPCOMP header */
  585                 /* XXX alignment always correct? */
  586                 switch (sav->sah->saidx.dst.sa.sa_family) {
  587 #ifdef INET
  588                 case AF_INET:
  589                         ipcomp->comp_nxt = mtod(m, struct ip *)->ip_p;
  590                         break;
  591 #endif /* INET */
  592 #ifdef INET6
  593                 case AF_INET6:
  594                         ipcomp->comp_nxt = mtod(m, struct ip6_hdr *)->ip6_nxt;
  595                         break;
  596 #endif
  597                 }
  598                 ipcomp->comp_flags = 0;
  599                 ipcomp->comp_cpi = htons((u_int16_t) ntohl(sav->spi));
  600 
  601                 /* Fix Next Protocol in IPv4/IPv6 header */
  602                 prot = IPPROTO_IPCOMP;
  603                 m_copyback(m, protoff, sizeof(u_int8_t),
  604                     (u_char *)&prot);
  605 
  606                 /* Adjust the length in the IP header */
  607                 switch (sav->sah->saidx.dst.sa.sa_family) {
  608 #ifdef INET
  609                 case AF_INET:
  610                         mtod(m, struct ip *)->ip_len = htons(m->m_pkthdr.len);
  611                         break;
  612 #endif /* INET */
  613 #ifdef INET6
  614                 case AF_INET6:
  615                         mtod(m, struct ip6_hdr *)->ip6_plen =
  616                                 htons(m->m_pkthdr.len) - sizeof(struct ip6_hdr);
  617                         break;
  618 #endif /* INET6 */
  619                 default:
  620                         IPCOMPSTAT_INC(ipcomps_nopf);
  621                         DPRINTF(("%s: unknown/unsupported protocol "
  622                             "family %d, IPCA %s/%08lx\n", __func__,
  623                             sav->sah->saidx.dst.sa.sa_family,
  624                             ipsec_address(&sav->sah->saidx.dst, buf,
  625                                 sizeof(buf)), (u_long) ntohl(sav->spi)));
  626                         error = EPFNOSUPPORT;
  627                         goto bad;
  628                 }
  629         } else {
  630                 /* Compression was useless, we have lost time. */
  631                 IPCOMPSTAT_INC(ipcomps_uncompr);
  632                 DPRINTF(("%s: compressions was useless %d - %d <= %d\n",
  633                     __func__, crp->crp_ilen, skip, crp->crp_olen));
  634                 /* XXX remember state to not compress the next couple
  635                  *     of packets, RFC 3173, 2.2. Non-Expansion Policy */
  636         }
  637 
  638         /* Release the crypto descriptor */
  639         free(xd, M_XDATA);
  640         crypto_freereq(crp);
  641 
  642         /* NB: m is reclaimed by ipsec_process_done. */
  643         error = ipsec_process_done(m, sp, sav, idx);
  644         return (error);
  645 bad:
  646         if (m)
  647                 m_freem(m);
  648         free(xd, M_XDATA);
  649         crypto_freereq(crp);
  650         key_freesav(&sav);
  651         key_freesp(&sp);
  652         return (error);
  653 }
  654 
  655 #ifdef INET
  656 static const struct encaptab *ipe4_cookie = NULL;
  657 extern struct domain inetdomain;
  658 static struct protosw ipcomp4_protosw = {
  659         .pr_type =      SOCK_RAW,
  660         .pr_domain =    &inetdomain,
  661         .pr_protocol =  0 /* IPPROTO_IPV[46] */,
  662         .pr_flags =     PR_ATOMIC | PR_ADDR | PR_LASTHDR,
  663         .pr_input =     ipcomp_nonexp_input,
  664         .pr_output =    rip_output,
  665         .pr_ctloutput = rip_ctloutput,
  666         .pr_usrreqs =   &rip_usrreqs
  667 };
  668 
  669 static int
  670 ipcomp4_nonexp_encapcheck(const struct mbuf *m, int off, int proto,
  671     void *arg __unused)
  672 {
  673         union sockaddr_union src, dst;
  674         const struct ip *ip;
  675 
  676         if (V_ipcomp_enable == 0)
  677                 return (0);
  678         if (proto != IPPROTO_IPV4 && proto != IPPROTO_IPV6)
  679                 return (0);
  680         bzero(&src, sizeof(src));
  681         bzero(&dst, sizeof(dst));
  682         src.sa.sa_family = dst.sa.sa_family = AF_INET;
  683         src.sin.sin_len = dst.sin.sin_len = sizeof(struct sockaddr_in);
  684         ip = mtod(m, const struct ip *);
  685         src.sin.sin_addr = ip->ip_src;
  686         dst.sin.sin_addr = ip->ip_dst;
  687         return (ipcomp_encapcheck(&src, &dst));
  688 }
  689 #endif
  690 #ifdef INET6
  691 static const struct encaptab *ipe6_cookie = NULL;
  692 extern struct domain inet6domain;
  693 static struct protosw ipcomp6_protosw = {
  694         .pr_type =      SOCK_RAW,
  695         .pr_domain =    &inet6domain,
  696         .pr_protocol =  0 /* IPPROTO_IPV[46] */,
  697         .pr_flags =     PR_ATOMIC | PR_ADDR | PR_LASTHDR,
  698         .pr_input =     ipcomp_nonexp_input,
  699         .pr_output =    rip6_output,
  700         .pr_ctloutput = rip6_ctloutput,
  701         .pr_usrreqs =   &rip6_usrreqs
  702 };
  703 
  704 static int
  705 ipcomp6_nonexp_encapcheck(const struct mbuf *m, int off, int proto,
  706     void *arg __unused)
  707 {
  708         union sockaddr_union src, dst;
  709         const struct ip6_hdr *ip6;
  710 
  711         if (V_ipcomp_enable == 0)
  712                 return (0);
  713         if (proto != IPPROTO_IPV4 && proto != IPPROTO_IPV6)
  714                 return (0);
  715         bzero(&src, sizeof(src));
  716         bzero(&dst, sizeof(dst));
  717         src.sa.sa_family = dst.sa.sa_family = AF_INET;
  718         src.sin6.sin6_len = dst.sin6.sin6_len = sizeof(struct sockaddr_in6);
  719         ip6 = mtod(m, const struct ip6_hdr *);
  720         src.sin6.sin6_addr = ip6->ip6_src;
  721         dst.sin6.sin6_addr = ip6->ip6_dst;
  722         if (IN6_IS_SCOPE_LINKLOCAL(&src.sin6.sin6_addr)) {
  723                 /* XXX: sa6_recoverscope() */
  724                 src.sin6.sin6_scope_id =
  725                     ntohs(src.sin6.sin6_addr.s6_addr16[1]);
  726                 src.sin6.sin6_addr.s6_addr16[1] = 0;
  727         }
  728         if (IN6_IS_SCOPE_LINKLOCAL(&dst.sin6.sin6_addr)) {
  729                 /* XXX: sa6_recoverscope() */
  730                 dst.sin6.sin6_scope_id =
  731                     ntohs(dst.sin6.sin6_addr.s6_addr16[1]);
  732                 dst.sin6.sin6_addr.s6_addr16[1] = 0;
  733         }
  734         return (ipcomp_encapcheck(&src, &dst));
  735 }
  736 #endif
  737 
  738 static struct xformsw ipcomp_xformsw = {
  739         .xf_type =      XF_IPCOMP,
  740         .xf_name =      "IPcomp",
  741         .xf_init =      ipcomp_init,
  742         .xf_zeroize =   ipcomp_zeroize,
  743         .xf_input =     ipcomp_input,
  744         .xf_output =    ipcomp_output,
  745 };
  746 
  747 static void
  748 ipcomp_attach(void)
  749 {
  750 
  751 #ifdef INET
  752         ipe4_cookie = encap_attach_func(AF_INET, -1,
  753             ipcomp4_nonexp_encapcheck, &ipcomp4_protosw, NULL);
  754 #endif
  755 #ifdef INET6
  756         ipe6_cookie = encap_attach_func(AF_INET6, -1,
  757             ipcomp6_nonexp_encapcheck, &ipcomp6_protosw, NULL);
  758 #endif
  759         xform_attach(&ipcomp_xformsw);
  760 }
  761 
  762 static void
  763 ipcomp_detach(void)
  764 {
  765 
  766 #ifdef INET
  767         encap_detach(ipe4_cookie);
  768 #endif
  769 #ifdef INET6
  770         encap_detach(ipe6_cookie);
  771 #endif
  772         xform_detach(&ipcomp_xformsw);
  773 }
  774 
  775 SYSINIT(ipcomp_xform_init, SI_SUB_PROTO_DOMAIN, SI_ORDER_MIDDLE,
  776     ipcomp_attach, NULL);
  777 SYSUNINIT(ipcomp_xform_uninit, SI_SUB_PROTO_DOMAIN, SI_ORDER_MIDDLE,
  778     ipcomp_detach, NULL);

Cache object: 38ebd49760b68992a2443205238639be


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