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-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 /*      $NetBSD: ipcomp_output.c,v 1.18.14.1 2007/09/23 18:54:13 bouyer Exp $   */
    2 /*      $KAME: ipcomp_output.c,v 1.24 2001/07/26 06:53:18 jinmei 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 <sys/cdefs.h>
   38 __KERNEL_RCSID(0, "$NetBSD: ipcomp_output.c,v 1.18.14.1 2007/09/23 18:54:13 bouyer Exp $");
   39 
   40 #include "opt_inet.h"
   41 
   42 #include <sys/param.h>
   43 #include <sys/systm.h>
   44 #include <sys/malloc.h>
   45 #include <sys/mbuf.h>
   46 #include <sys/domain.h>
   47 #include <sys/protosw.h>
   48 #include <sys/socket.h>
   49 #include <sys/errno.h>
   50 #include <sys/time.h>
   51 #include <sys/kernel.h>
   52 #include <sys/syslog.h>
   53 
   54 #include <net/if.h>
   55 #include <net/route.h>
   56 #include <net/netisr.h>
   57 #include <net/zlib.h>
   58 #include <machine/cpu.h>
   59 
   60 #include <netinet/in.h>
   61 #include <netinet/in_systm.h>
   62 #include <netinet/in_var.h>
   63 #include <netinet/ip.h>
   64 #include <netinet/ip_var.h>
   65 #include <netinet/ip_ecn.h>
   66 
   67 #ifdef INET6
   68 #include <netinet/ip6.h>
   69 #include <netinet6/ip6_var.h>
   70 #endif
   71 #include <netinet6/ipcomp.h>
   72 
   73 #include <netinet6/ipsec.h>
   74 #include <netkey/key.h>
   75 #include <netkey/keydb.h>
   76 
   77 #include <machine/stdarg.h>
   78 
   79 #include <net/net_osdep.h>
   80 
   81 static int ipcomp_output __P((struct mbuf *, u_char *, struct mbuf *,
   82         struct ipsecrequest *, int));
   83 
   84 /*
   85  * Modify the packet so that the payload is compressed.
   86  * The mbuf (m) must start with IPv4 or IPv6 header.
   87  * On failure, free the given mbuf and return non-zero.
   88  *
   89  * on invocation:
   90  *      m   nexthdrp md
   91  *      v   v        v
   92  *      IP ......... payload
   93  * during the encryption:
   94  *      m   nexthdrp mprev md
   95  *      v   v        v     v
   96  *      IP ............... ipcomp payload
   97  *                         <-----><----->
   98  *                         complen  plen
   99  *      <-> hlen
  100  *      <-----------------> compoff
  101  */
  102 static int
  103 ipcomp_output(m, nexthdrp, md, isr, af)
  104         struct mbuf *m;
  105         u_char *nexthdrp;
  106         struct mbuf *md;
  107         struct ipsecrequest *isr;
  108         int af;
  109 {
  110         struct mbuf *n;
  111         struct mbuf *md0;
  112         struct mbuf *mcopy;
  113         struct mbuf *mprev;
  114         struct ipcomp *ipcomp;
  115         struct secasvar *sav = isr->sav;
  116         const struct ipcomp_algorithm *algo;
  117         u_int16_t cpi;          /* host order */
  118         size_t plen0, plen;     /* payload length to be compressed */
  119         size_t compoff;
  120         int afnumber;
  121         int error = 0;
  122         struct ipsecstat *stat;
  123 
  124         switch (af) {
  125 #ifdef INET
  126         case AF_INET:
  127                 afnumber = 4;
  128                 stat = &ipsecstat;
  129                 break;
  130 #endif
  131 #ifdef INET6
  132         case AF_INET6:
  133                 afnumber = 6;
  134                 stat = &ipsec6stat;
  135                 break;
  136 #endif
  137         default:
  138                 ipseclog((LOG_ERR, "ipcomp_output: unsupported af %d\n", af));
  139                 return 0;       /* no change at all */
  140         }
  141 
  142         /* grab parameters */
  143         algo = ipcomp_algorithm_lookup(sav->alg_enc);
  144         if ((ntohl(sav->spi) & ~0xffff) != 0 || !algo) {
  145                 stat->out_inval++;
  146                 error = EINVAL;
  147                 goto fail1;
  148         }
  149         if ((sav->flags & SADB_X_EXT_RAWCPI) == 0)
  150                 cpi = sav->alg_enc;
  151         else
  152                 cpi = ntohl(sav->spi) & 0xffff;
  153 
  154         /* compute original payload length */
  155         plen = 0;
  156         for (n = md; n; n = n->m_next)
  157                 plen += n->m_len;
  158 
  159         /* if the payload is short enough, we don't need to compress */
  160         if (plen < algo->minplen)
  161                 return 0;
  162 
  163         /*
  164          * retain the original packet for two purposes:
  165          * (1) we need to backout our changes when compression is not necessary.
  166          * (2) byte lifetime computation should use the original packet.
  167          *     see RFC2401 page 23.
  168          * compromise two m_copym().  we will be going through every byte of
  169          * the payload during compression process anyways.
  170          */
  171         mcopy = m_copym(m, 0, M_COPYALL, M_NOWAIT);
  172         if (mcopy == NULL) {
  173                 error = ENOBUFS;
  174                 goto fail1;
  175         }
  176         md0 = m_copym(md, 0, M_COPYALL, M_NOWAIT);
  177         if (md0 == NULL) {
  178                 error = ENOBUFS;
  179                 goto fail2;
  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                 error = EINVAL;
  191                 goto fail3;
  192         }
  193         mprev->m_next = NULL;
  194         if ((md = ipsec_copypkt(md)) == NULL) {
  195                 error = ENOBUFS;
  196                 goto fail3;
  197         }
  198         mprev->m_next = md;
  199 
  200         /* compress data part */
  201         if ((*algo->compress)(m, md, &plen) || mprev->m_next == NULL) {
  202                 ipseclog((LOG_ERR, "packet compression failure\n"));
  203                 m = NULL;
  204                 stat->out_inval++;
  205                 error = EINVAL;
  206                 goto fail3;
  207         }
  208         stat->out_comphist[sav->alg_enc]++;
  209         md = mprev->m_next;
  210 
  211         /*
  212          * if the packet became bigger, meaningless to use IPComp.
  213          * we've only wasted our CPU time.
  214          */
  215         if (plen0 < plen) {
  216                 m_freem(md);
  217                 m_freem(mcopy);
  218                 mprev->m_next = md0;
  219                 return 0;
  220         }
  221 
  222         /*
  223          * no need to backout change beyond here.
  224          */
  225         m_freem(md0);
  226         md0 = NULL;
  227 
  228         m->m_pkthdr.len -= plen0;
  229         m->m_pkthdr.len += plen;
  230 
  231     {
  232         /*
  233          * insert IPComp header.
  234          */
  235 #ifdef INET
  236         struct ip *ip = NULL;
  237 #endif
  238 #ifdef INET6
  239         struct ip6_hdr *ip6 = NULL;
  240 #endif
  241         size_t hlen = 0;        /* ip header len */
  242         size_t complen = sizeof(struct ipcomp);
  243 
  244         switch (af) {
  245 #ifdef INET
  246         case AF_INET:
  247                 ip = mtod(m, struct ip *);
  248 #ifdef _IP_VHL
  249                 hlen = IP_VHL_HL(ip->ip_vhl) << 2;
  250 #else
  251                 hlen = ip->ip_hl << 2;
  252 #endif
  253                 break;
  254 #endif
  255 #ifdef INET6
  256         case AF_INET6:
  257                 ip6 = mtod(m, struct ip6_hdr *);
  258                 hlen = sizeof(*ip6);
  259                 break;
  260 #endif
  261         }
  262 
  263         compoff = m->m_pkthdr.len - plen;
  264 
  265         /*
  266          * grow the mbuf to accomodate ipcomp header.
  267          * before: IP ... payload
  268          * after:  IP ... ipcomp payload
  269          */
  270         if (M_LEADINGSPACE(md) < complen) {
  271                 MGET(n, M_DONTWAIT, MT_DATA);
  272                 if (!n) {
  273                         error = ENOBUFS;
  274                         goto fail2;
  275                 }
  276                 n->m_len = complen;
  277                 mprev->m_next = n;
  278                 n->m_next = md;
  279                 m->m_pkthdr.len += complen;
  280                 ipcomp = mtod(n, struct ipcomp *);
  281         } else {
  282                 md->m_len += complen;
  283                 md->m_data -= complen;
  284                 m->m_pkthdr.len += complen;
  285                 ipcomp = mtod(md, struct ipcomp *);
  286         }
  287 
  288         bzero(ipcomp, sizeof(*ipcomp));
  289         ipcomp->comp_nxt = *nexthdrp;
  290         *nexthdrp = IPPROTO_IPCOMP;
  291         ipcomp->comp_cpi = htons(cpi);
  292         switch (af) {
  293 #ifdef INET
  294         case AF_INET:
  295                 if (compoff + complen + plen < IP_MAXPACKET)
  296                         ip->ip_len = htons(compoff + complen + plen);
  297                 else {
  298                         ipseclog((LOG_ERR,
  299                             "IPv4 ESP output: size exceeds limit\n"));
  300                         ipsecstat.out_inval++;
  301                         error = EMSGSIZE;
  302                         goto fail2;
  303                 }
  304                 break;
  305 #endif
  306 #ifdef INET6
  307         case AF_INET6:
  308                 /* total packet length will be computed in ip6_output() */
  309                 break;
  310 #endif
  311         }
  312     }
  313 
  314         if (!m) {
  315                 ipseclog((LOG_DEBUG,
  316                     "NULL mbuf after compression in ipcomp%d_output",
  317                     afnumber));
  318                 stat->out_inval++;
  319         }
  320                 stat->out_success++;
  321 
  322         /* compute byte lifetime against original packet */
  323         key_sa_recordxfer(sav, mcopy);
  324         m_freem(mcopy);
  325 
  326         return 0;
  327 
  328 fail3:
  329         m_freem(md0);
  330 fail2:
  331         m_freem(mcopy);
  332 fail1:
  333         m_freem(m);
  334 #if 1
  335         return error;
  336 #else
  337         panic("something bad in ipcomp_output");
  338 #endif
  339 }
  340 
  341 #ifdef INET
  342 int
  343 ipcomp4_output(m, isr)
  344         struct mbuf *m;
  345         struct ipsecrequest *isr;
  346 {
  347         struct ip *ip;
  348         if (m->m_len < sizeof(struct ip)) {
  349                 ipseclog((LOG_DEBUG, "ipcomp4_output: first mbuf too short\n"));
  350                 ipsecstat.out_inval++;
  351                 m_freem(m);
  352                 return EINVAL;
  353         }
  354         ip = mtod(m, struct ip *);
  355         /* XXX assumes that m->m_next points to payload */
  356         return ipcomp_output(m, &ip->ip_p, m->m_next, isr, AF_INET);
  357 }
  358 #endif /* INET */
  359 
  360 #ifdef INET6
  361 int
  362 ipcomp6_output(m, nexthdrp, md, isr)
  363         struct mbuf *m;
  364         u_char *nexthdrp;
  365         struct mbuf *md;
  366         struct ipsecrequest *isr;
  367 {
  368         if (m->m_len < sizeof(struct ip6_hdr)) {
  369                 ipseclog((LOG_DEBUG, "ipcomp6_output: first mbuf too short\n"));
  370                 ipsec6stat.out_inval++;
  371                 m_freem(m);
  372                 return EINVAL;
  373         }
  374         return ipcomp_output(m, nexthdrp, md, isr, AF_INET6);
  375 }
  376 #endif /* INET6 */

Cache object: 7936ae58195d5f2eacf42bf5f823b88b


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