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/netinet6/ipcomp_output.c

Version: -  FREEBSD  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-2  -  FREEBSD-11-1  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-4  -  FREEBSD-10-3  -  FREEBSD-10-2  -  FREEBSD-10-1  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-3  -  FREEBSD-9-2  -  FREEBSD-9-1  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-4  -  FREEBSD-8-3  -  FREEBSD-8-2  -  FREEBSD-8-1  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-4  -  FREEBSD-7-3  -  FREEBSD-7-2  -  FREEBSD-7-1  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-4  -  FREEBSD-6-3  -  FREEBSD-6-2  -  FREEBSD-6-1  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-5  -  FREEBSD-5-4  -  FREEBSD-5-3  -  FREEBSD-5-2  -  FREEBSD-5-1  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

    1 /*      $FreeBSD: src/sys/netinet6/ipcomp_output.c,v 1.1.2.4 2003/04/29 08:33:50 suz Exp $      */
    2 /*      $KAME: ipcomp_output.c,v 1.25 2002/06/09 14:44:00 itojun Exp $  */
    3 
    4 /*
    5  * Copyright (C) 1999 WIDE Project.
    6  * All rights reserved.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 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. Neither the name of the project nor the names of its contributors
   17  *    may be used to endorse or promote products derived from this software
   18  *    without specific prior written permission.
   19  *
   20  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
   21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
   24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   30  * SUCH DAMAGE.
   31  */
   32 
   33 /*
   34  * RFC2393 IP payload compression protocol (IPComp).
   35  */
   36 
   37 #include "opt_inet.h"
   38 #include "opt_inet6.h"
   39 
   40 #include <sys/param.h>
   41 #include <sys/systm.h>
   42 #include <sys/malloc.h>
   43 #include <sys/mbuf.h>
   44 #include <sys/domain.h>
   45 #include <sys/protosw.h>
   46 #include <sys/socket.h>
   47 #include <sys/errno.h>
   48 #include <sys/time.h>
   49 #include <sys/syslog.h>
   50 
   51 #include <net/if.h>
   52 #include <net/route.h>
   53 #include <net/netisr.h>
   54 #include <net/zlib.h>
   55 #include <machine/cpu.h>
   56 
   57 #include <netinet/in.h>
   58 #include <netinet/in_systm.h>
   59 #include <netinet/in_var.h>
   60 #include <netinet/ip.h>
   61 #include <netinet/ip_var.h>
   62 #include <netinet/ip_ecn.h>
   63 
   64 #ifdef INET6
   65 #include <netinet/ip6.h>
   66 #include <netinet6/ip6_var.h>
   67 #endif
   68 #include <netinet6/ipcomp.h>
   69 #ifdef INET6
   70 #include <netinet6/ipcomp6.h>
   71 #endif
   72 
   73 #include <netinet6/ipsec.h>
   74 #ifdef INET6
   75 #include <netinet6/ipsec6.h>
   76 #endif
   77 #include <netproto/key/key.h>
   78 #include <netproto/key/keydb.h>
   79 
   80 #include <machine/stdarg.h>
   81 
   82 #include <net/net_osdep.h>
   83 
   84 static int ipcomp_output (struct mbuf *, u_char *, struct mbuf *,
   85         struct ipsecrequest *, int);
   86 
   87 /*
   88  * Modify the packet so that the payload is compressed.
   89  * The mbuf (m) must start with IPv4 or IPv6 header.
   90  * On failure, free the given mbuf and return non-zero.
   91  *
   92  * on invocation:
   93  *      m   nexthdrp md
   94  *      v   v        v
   95  *      IP ......... payload
   96  * during the encryption:
   97  *      m   nexthdrp mprev md
   98  *      v   v        v     v
   99  *      IP ............... ipcomp payload
  100  *                         <-----><----->
  101  *                         complen  plen
  102  *      <-> hlen
  103  *      <-----------------> compoff
  104  */
  105 static int
  106 ipcomp_output(struct mbuf *m, u_char *nexthdrp, struct mbuf *md,
  107               struct ipsecrequest *isr, int af)
  108 {
  109         struct mbuf *n;
  110         struct mbuf *md0;
  111         struct mbuf *mcopy;
  112         struct mbuf *mprev;
  113         struct ipcomp *ipcomp;
  114         struct secasvar *sav = isr->sav;
  115         const struct ipcomp_algorithm *algo;
  116         u_int16_t cpi;          /* host order */
  117         size_t plen0, plen;     /* payload length to be compressed */
  118         size_t compoff;
  119         int afnumber;
  120         int error = 0;
  121         struct ipsecstat *stat;
  122 
  123         switch (af) {
  124 #ifdef INET
  125         case AF_INET:
  126                 afnumber = 4;
  127                 stat = &ipsecstat;
  128                 break;
  129 #endif
  130 #ifdef INET6
  131         case AF_INET6:
  132                 afnumber = 6;
  133                 stat = &ipsec6stat;
  134                 break;
  135 #endif
  136         default:
  137                 ipseclog((LOG_ERR, "ipcomp_output: unsupported af %d\n", af));
  138                 return 0;       /* no change at all */
  139         }
  140 
  141         /* grab parameters */
  142         algo = ipcomp_algorithm_lookup(sav->alg_enc);
  143         if ((ntohl(sav->spi) & ~0xffff) != 0 || !algo) {
  144                 stat->out_inval++;
  145                 m_freem(m);
  146                 return EINVAL;
  147         }
  148         if ((sav->flags & SADB_X_EXT_RAWCPI) == 0)
  149                 cpi = sav->alg_enc;
  150         else
  151                 cpi = ntohl(sav->spi) & 0xffff;
  152 
  153         /* compute original payload length */
  154         plen = 0;
  155         for (n = md; n; n = n->m_next)
  156                 plen += n->m_len;
  157 
  158         /* if the payload is short enough, we don't need to compress */
  159         if (plen < algo->minplen)
  160                 return 0;
  161 
  162         /*
  163          * retain the original packet for two purposes:
  164          * (1) we need to backout our changes when compression is not necessary.
  165          * (2) byte lifetime computation should use the original packet.
  166          *     see RFC2401 page 23.
  167          * compromise two m_copym().  we will be going through every byte of
  168          * the payload during compression process anyways.
  169          */
  170         mcopy = m_copym(m, 0, M_COPYALL, MB_DONTWAIT);
  171         if (mcopy == NULL) {
  172                 error = ENOBUFS;
  173                 return 0;
  174         }
  175         md0 = m_copym(md, 0, M_COPYALL, MB_DONTWAIT);
  176         if (md0 == NULL) {
  177                 m_freem(mcopy);
  178                 error = ENOBUFS;
  179                 return 0;
  180         }
  181         plen0 = plen;
  182 
  183         /* make the packet over-writable */
  184         for (mprev = m; mprev && mprev->m_next != md; mprev = mprev->m_next)
  185                 ;
  186         if (mprev == NULL || mprev->m_next != md) {
  187                 ipseclog((LOG_DEBUG, "ipcomp%d_output: md is not in chain\n",
  188                     afnumber));
  189                 stat->out_inval++;
  190                 m_freem(m);
  191                 m_freem(md0);
  192                 m_freem(mcopy);
  193                 return EINVAL;
  194         }
  195         mprev->m_next = NULL;
  196         if ((md = ipsec_copypkt(md)) == NULL) {
  197                 m_freem(m);
  198                 m_freem(md0);
  199                 m_freem(mcopy);
  200                 error = ENOBUFS;
  201                 goto fail;
  202         }
  203         mprev->m_next = md;
  204 
  205         /* compress data part */
  206         if ((*algo->compress)(m, md, &plen) || mprev->m_next == NULL) {
  207                 ipseclog((LOG_ERR, "packet compression failure\n"));
  208                 m = NULL;
  209                 m_freem(md0);
  210                 m_freem(mcopy);
  211                 stat->out_inval++;
  212                 error = EINVAL;
  213                 goto fail;
  214         }
  215         stat->out_comphist[sav->alg_enc]++;
  216         md = mprev->m_next;
  217 
  218         /*
  219          * if the packet became bigger, meaningless to use IPComp.
  220          * we've only wasted our cpu time.
  221          */
  222         if (plen0 < plen) {
  223                 m_freem(md);
  224                 m_freem(mcopy);
  225                 mprev->m_next = md0;
  226                 return 0;
  227         }
  228 
  229         /*
  230          * no need to backout change beyond here.
  231          */
  232         m_freem(md0);
  233         md0 = NULL;
  234 
  235         m->m_pkthdr.len -= plen0;
  236         m->m_pkthdr.len += plen;
  237 
  238     {
  239         /*
  240          * insert IPComp header.
  241          */
  242 #ifdef INET
  243         struct ip *ip = NULL;
  244 #endif
  245         size_t complen = sizeof(struct ipcomp);
  246 
  247         switch (af) {
  248 #ifdef INET
  249         case AF_INET:
  250                 ip = mtod(m, struct ip *);
  251                 break;
  252 #endif
  253 #ifdef INET6
  254         case AF_INET6:
  255                 break;
  256 #endif
  257         }
  258 
  259         compoff = m->m_pkthdr.len - plen;
  260 
  261         /*
  262          * grow the mbuf to accomodate ipcomp header.
  263          * before: IP ... payload
  264          * after:  IP ... ipcomp payload
  265          */
  266         if (M_LEADINGSPACE(md) < complen) {
  267                 MGET(n, MB_DONTWAIT, MT_DATA);
  268                 if (!n) {
  269                         m_freem(m);
  270                         error = ENOBUFS;
  271                         goto fail;
  272                 }
  273                 n->m_len = complen;
  274                 mprev->m_next = n;
  275                 n->m_next = md;
  276                 m->m_pkthdr.len += complen;
  277                 ipcomp = mtod(n, struct ipcomp *);
  278         } else {
  279                 md->m_len += complen;
  280                 md->m_data -= complen;
  281                 m->m_pkthdr.len += complen;
  282                 ipcomp = mtod(md, struct ipcomp *);
  283         }
  284 
  285         bzero(ipcomp, sizeof(*ipcomp));
  286         ipcomp->comp_nxt = *nexthdrp;
  287         *nexthdrp = IPPROTO_IPCOMP;
  288         ipcomp->comp_cpi = htons(cpi);
  289         switch (af) {
  290 #ifdef INET
  291         case AF_INET:
  292                 if (compoff + complen + plen < IP_MAXPACKET)
  293                         ip->ip_len = htons(compoff + complen + plen);
  294                 else {
  295                         ipseclog((LOG_ERR,
  296                             "IPv4 ESP output: size exceeds limit\n"));
  297                         ipsecstat.out_inval++;
  298                         m_freem(m);
  299                         error = EMSGSIZE;
  300                         goto fail;
  301                 }
  302                 break;
  303 #endif
  304 #ifdef INET6
  305         case AF_INET6:
  306                 /* total packet length will be computed in ip6_output() */
  307                 break;
  308 #endif
  309         }
  310     }
  311 
  312         if (!m) {
  313                 ipseclog((LOG_DEBUG,
  314                     "NULL mbuf after compression in ipcomp%d_output",
  315                     afnumber));
  316                 stat->out_inval++;
  317         }
  318                 stat->out_success++;
  319 
  320         /* compute byte lifetime against original packet */
  321         key_sa_recordxfer(sav, mcopy);
  322         m_freem(mcopy);
  323 
  324         return 0;
  325 
  326 fail:
  327 #if 1
  328         return error;
  329 #else
  330         panic("something bad in ipcomp_output");
  331 #endif
  332 }
  333 
  334 #ifdef INET
  335 int
  336 ipcomp4_output(struct mbuf *m, struct ipsecrequest *isr)
  337 {
  338         struct ip *ip;
  339         if (m->m_len < sizeof(struct ip)) {
  340                 ipseclog((LOG_DEBUG, "ipcomp4_output: first mbuf too short\n"));
  341                 ipsecstat.out_inval++;
  342                 m_freem(m);
  343                 return 0;
  344         }
  345         ip = mtod(m, struct ip *);
  346         /* XXX assumes that m->m_next points to payload */
  347         return ipcomp_output(m, &ip->ip_p, m->m_next, isr, AF_INET);
  348 }
  349 #endif /* INET */
  350 
  351 #ifdef INET6
  352 int
  353 ipcomp6_output(struct mbuf *m, u_char *nexthdrp, struct mbuf *md,
  354                struct ipsecrequest *isr)
  355 {
  356         if (m->m_len < sizeof(struct ip6_hdr)) {
  357                 ipseclog((LOG_DEBUG, "ipcomp6_output: first mbuf too short\n"));
  358                 ipsec6stat.out_inval++;
  359                 m_freem(m);
  360                 return 0;
  361         }
  362         return ipcomp_output(m, nexthdrp, md, isr, AF_INET6);
  363 }
  364 #endif /* INET6 */

Cache object: 1fe9cec083c4ff44a9d7db6c0674b72d


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