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/esp_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: releng/5.3/sys/netinet6/esp_output.c 136588 2004-10-16 08:43:07Z cvs2svn $    */
    2 /*      $KAME: esp_output.c,v 1.44 2001/07/26 06:53:15 jinmei Exp $     */
    3 
    4 /*
    5  * Copyright (C) 1995, 1996, 1997, and 1998 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 #include "opt_inet.h"
   34 #include "opt_inet6.h"
   35 
   36 /*
   37  * RFC1827/2406 Encapsulated Security Payload.
   38  */
   39 
   40 #include <sys/param.h>
   41 #include <sys/systm.h>
   42 #include <sys/mbuf.h>
   43 #include <sys/domain.h>
   44 #include <sys/protosw.h>
   45 #include <sys/socket.h>
   46 #include <sys/socketvar.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 
   54 #include <netinet/in.h>
   55 #include <netinet/in_systm.h>
   56 #include <netinet/ip.h>
   57 #include <netinet/in_var.h>
   58 
   59 #ifdef INET6
   60 #include <netinet/ip6.h>
   61 #include <netinet6/ip6_var.h>
   62 #include <netinet/icmp6.h>
   63 #endif
   64 
   65 #include <netinet6/ipsec.h>
   66 #ifdef INET6
   67 #include <netinet6/ipsec6.h>
   68 #endif
   69 #include <netinet6/ah.h>
   70 #ifdef INET6
   71 #include <netinet6/ah6.h>
   72 #endif
   73 #include <netinet6/esp.h>
   74 #ifdef INET6
   75 #include <netinet6/esp6.h>
   76 #endif
   77 #include <netkey/key.h>
   78 #include <netkey/keydb.h>
   79 
   80 #include <net/net_osdep.h>
   81 
   82 static int esp_output __P((struct mbuf *, u_char *, struct mbuf *,
   83         struct ipsecrequest *, int));
   84 
   85 /*
   86  * compute ESP header size.
   87  */
   88 size_t
   89 esp_hdrsiz(isr)
   90         struct ipsecrequest *isr;
   91 {
   92         struct secasvar *sav;
   93         const struct esp_algorithm *algo;
   94         const struct ah_algorithm *aalgo;
   95         size_t ivlen;
   96         size_t authlen;
   97         size_t hdrsiz;
   98 
   99         /* sanity check */
  100         if (isr == NULL)
  101                 panic("esp_hdrsiz: NULL was passed.");
  102 
  103         sav = isr->sav;
  104 
  105         if (isr->saidx.proto != IPPROTO_ESP)
  106                 panic("unsupported mode passed to esp_hdrsiz");
  107 
  108         if (sav == NULL)
  109                 goto estimate;
  110         if (sav->state != SADB_SASTATE_MATURE
  111          && sav->state != SADB_SASTATE_DYING)
  112                 goto estimate;
  113 
  114         /* we need transport mode ESP. */
  115         algo = esp_algorithm_lookup(sav->alg_enc);
  116         if (!algo)
  117                 goto estimate;
  118         ivlen = sav->ivlen;
  119         if (ivlen < 0)
  120                 goto estimate;
  121 
  122         /*
  123          * XXX
  124          * right now we don't calcurate the padding size.  simply
  125          * treat the padding size as constant, for simplicity.
  126          *
  127          * XXX variable size padding support
  128          */
  129         if (sav->flags & SADB_X_EXT_OLD) {
  130                 /* RFC 1827 */
  131                 hdrsiz = sizeof(struct esp) + ivlen + 9;
  132         } else {
  133                 /* RFC 2406 */
  134                 aalgo = ah_algorithm_lookup(sav->alg_auth);
  135                 if (aalgo && sav->replay && sav->key_auth)
  136                         authlen = (aalgo->sumsiz)(sav);
  137                 else
  138                         authlen = 0;
  139                 hdrsiz = sizeof(struct newesp) + ivlen + 9 + authlen;
  140         }
  141 
  142         return hdrsiz;
  143 
  144    estimate:
  145         /*
  146          * ASSUMING:
  147          *      sizeof(struct newesp) > sizeof(struct esp).
  148          *      esp_max_ivlen() = max ivlen for CBC mode
  149          *      9 = (maximum padding length without random padding length)
  150          *         + (Pad Length field) + (Next Header field).
  151          *      16 = maximum ICV we support.
  152          */
  153         return sizeof(struct newesp) + esp_max_ivlen() + 9 + 16;
  154 }
  155 
  156 /*
  157  * Modify the packet so that the payload is encrypted.
  158  * The mbuf (m) must start with IPv4 or IPv6 header.
  159  * On failure, free the given mbuf and return NULL.
  160  *
  161  * on invocation:
  162  *      m   nexthdrp md
  163  *      v   v        v
  164  *      IP ......... payload
  165  * during the encryption:
  166  *      m   nexthdrp mprev md
  167  *      v   v        v     v
  168  *      IP ............... esp iv payload pad padlen nxthdr
  169  *                         <--><-><------><--------------->
  170  *                         esplen plen    extendsiz
  171  *                             ivlen
  172  *                         <-----> esphlen
  173  *      <-> hlen
  174  *      <-----------------> espoff
  175  */
  176 static int
  177 esp_output(m, nexthdrp, md, isr, af)
  178         struct mbuf *m;
  179         u_char *nexthdrp;
  180         struct mbuf *md;
  181         struct ipsecrequest *isr;
  182         int af;
  183 {
  184         struct mbuf *n;
  185         struct mbuf *mprev;
  186         struct esp *esp;
  187         struct esptail *esptail;
  188         struct secasvar *sav = isr->sav;
  189         const struct esp_algorithm *algo;
  190         u_int32_t spi;
  191         u_int8_t nxt = 0;
  192         size_t plen;    /* payload length to be encrypted */
  193         size_t espoff;
  194         int ivlen;
  195         int afnumber;
  196         size_t extendsiz;
  197         int error = 0;
  198         struct ipsecstat *stat;
  199 
  200         switch (af) {
  201 #ifdef INET
  202         case AF_INET:
  203                 afnumber = 4;
  204                 stat = &ipsecstat;
  205                 break;
  206 #endif
  207 #ifdef INET6
  208         case AF_INET6:
  209                 afnumber = 6;
  210                 stat = &ipsec6stat;
  211                 break;
  212 #endif
  213         default:
  214                 ipseclog((LOG_ERR, "esp_output: unsupported af %d\n", af));
  215                 return 0;       /* no change at all */
  216         }
  217 
  218         /* some sanity check */
  219         if ((sav->flags & SADB_X_EXT_OLD) == 0 && !sav->replay) {
  220                 switch (af) {
  221 #ifdef INET
  222                 case AF_INET:
  223                     {
  224                         struct ip *ip;
  225 
  226                         ip = mtod(m, struct ip *);
  227                         ipseclog((LOG_DEBUG, "esp4_output: internal error: "
  228                                 "sav->replay is null: %x->%x, SPI=%u\n",
  229                                 (u_int32_t)ntohl(ip->ip_src.s_addr),
  230                                 (u_int32_t)ntohl(ip->ip_dst.s_addr),
  231                                 (u_int32_t)ntohl(sav->spi)));
  232                         ipsecstat.out_inval++;
  233                         break;
  234                     }
  235 #endif /* INET */
  236 #ifdef INET6
  237                 case AF_INET6:
  238                         ipseclog((LOG_DEBUG, "esp6_output: internal error: "
  239                                 "sav->replay is null: SPI=%u\n",
  240                                 (u_int32_t)ntohl(sav->spi)));
  241                         ipsec6stat.out_inval++;
  242                         break;
  243 #endif /* INET6 */
  244                 default:
  245                         panic("esp_output: should not reach here");
  246                 }
  247                 m_freem(m);
  248                 return EINVAL;
  249         }
  250 
  251         algo = esp_algorithm_lookup(sav->alg_enc);
  252         if (!algo) {
  253                 ipseclog((LOG_ERR, "esp_output: unsupported algorithm: "
  254                     "SPI=%u\n", (u_int32_t)ntohl(sav->spi)));
  255                 m_freem(m);
  256                 return EINVAL;
  257         }
  258         spi = sav->spi;
  259         ivlen = sav->ivlen;
  260         /* should be okey */
  261         if (ivlen < 0) {
  262                 panic("invalid ivlen");
  263         }
  264 
  265     {
  266         /*
  267          * insert ESP header.
  268          * XXX inserts ESP header right after IPv4 header.  should
  269          * chase the header chain.
  270          * XXX sequential number
  271          */
  272 #ifdef INET
  273         struct ip *ip = NULL;
  274 #endif
  275 #ifdef INET6
  276         struct ip6_hdr *ip6 = NULL;
  277 #endif
  278         size_t esplen;  /* sizeof(struct esp/newesp) */
  279         size_t esphlen; /* sizeof(struct esp/newesp) + ivlen */
  280         size_t hlen = 0;        /* ip header len */
  281 
  282         if (sav->flags & SADB_X_EXT_OLD) {
  283                 /* RFC 1827 */
  284                 esplen = sizeof(struct esp);
  285         } else {
  286                 /* RFC 2406 */
  287                 if (sav->flags & SADB_X_EXT_DERIV)
  288                         esplen = sizeof(struct esp);
  289                 else
  290                         esplen = sizeof(struct newesp);
  291         }
  292         esphlen = esplen + ivlen;
  293 
  294         for (mprev = m; mprev && mprev->m_next != md; mprev = mprev->m_next)
  295                 ;
  296         if (mprev == NULL || mprev->m_next != md) {
  297                 ipseclog((LOG_DEBUG, "esp%d_output: md is not in chain\n",
  298                     afnumber));
  299                 m_freem(m);
  300                 return EINVAL;
  301         }
  302 
  303         plen = 0;
  304         for (n = md; n; n = n->m_next)
  305                 plen += n->m_len;
  306 
  307         switch (af) {
  308 #ifdef INET
  309         case AF_INET:
  310                 ip = mtod(m, struct ip *);
  311 #ifdef _IP_VHL
  312                 hlen = IP_VHL_HL(ip->ip_vhl) << 2;
  313 #else
  314                 hlen = ip->ip_hl << 2;
  315 #endif
  316                 break;
  317 #endif
  318 #ifdef INET6
  319         case AF_INET6:
  320                 ip6 = mtod(m, struct ip6_hdr *);
  321                 hlen = sizeof(*ip6);
  322                 break;
  323 #endif
  324         }
  325 
  326         /* make the packet over-writable */
  327         mprev->m_next = NULL;
  328         if ((md = ipsec_copypkt(md)) == NULL) {
  329                 m_freem(m);
  330                 error = ENOBUFS;
  331                 goto fail;
  332         }
  333         mprev->m_next = md;
  334 
  335         espoff = m->m_pkthdr.len - plen;
  336 
  337         /*
  338          * grow the mbuf to accomodate ESP header.
  339          * before: IP ... payload
  340          * after:  IP ... ESP IV payload
  341          */
  342         if (M_LEADINGSPACE(md) < esphlen || (md->m_flags & M_EXT) != 0) {
  343                 MGET(n, M_DONTWAIT, MT_DATA);
  344                 if (!n) {
  345                         m_freem(m);
  346                         error = ENOBUFS;
  347                         goto fail;
  348                 }
  349                 n->m_len = esphlen;
  350                 mprev->m_next = n;
  351                 n->m_next = md;
  352                 m->m_pkthdr.len += esphlen;
  353                 esp = mtod(n, struct esp *);
  354         } else {
  355                 md->m_len += esphlen;
  356                 md->m_data -= esphlen;
  357                 m->m_pkthdr.len += esphlen;
  358                 esp = mtod(md, struct esp *);
  359         }
  360 
  361         nxt = *nexthdrp;
  362         *nexthdrp = IPPROTO_ESP;
  363         switch (af) {
  364 #ifdef INET
  365         case AF_INET:
  366                 if (esphlen < (IP_MAXPACKET - ntohs(ip->ip_len)))
  367                         ip->ip_len = htons(ntohs(ip->ip_len) + esphlen);
  368                 else {
  369                         ipseclog((LOG_ERR,
  370                             "IPv4 ESP output: size exceeds limit\n"));
  371                         ipsecstat.out_inval++;
  372                         m_freem(m);
  373                         error = EMSGSIZE;
  374                         goto fail;
  375                 }
  376                 break;
  377 #endif
  378 #ifdef INET6
  379         case AF_INET6:
  380                 /* total packet length will be computed in ip6_output() */
  381                 break;
  382 #endif
  383         }
  384     }
  385 
  386         /* initialize esp header. */
  387         esp->esp_spi = spi;
  388         if ((sav->flags & SADB_X_EXT_OLD) == 0) {
  389                 struct newesp *nesp;
  390                 nesp = (struct newesp *)esp;
  391                 if (sav->replay->count == ~0) {
  392                         if ((sav->flags & SADB_X_EXT_CYCSEQ) == 0) {
  393                                 /* XXX Is it noisy ? */
  394                                 ipseclog((LOG_WARNING,
  395                                     "replay counter overflowed. %s\n",
  396                                     ipsec_logsastr(sav)));
  397                                 stat->out_inval++;
  398                                 m_freem(m);
  399                                 return EINVAL;
  400                         }
  401                 }
  402                 sav->replay->count++;
  403                 /*
  404                  * XXX sequence number must not be cycled, if the SA is
  405                  * installed by IKE daemon.
  406                  */
  407                 nesp->esp_seq = htonl(sav->replay->count & 0xffffffff);
  408         }
  409 
  410     {
  411         /*
  412          * find the last mbuf. make some room for ESP trailer.
  413          */
  414 #ifdef INET
  415         struct ip *ip = NULL;
  416 #endif
  417         size_t padbound;
  418         u_char *extend;
  419         int i;
  420         int randpadmax;
  421 
  422         if (algo->padbound)
  423                 padbound = algo->padbound;
  424         else
  425                 padbound = 4;
  426         /* ESP packet, including nxthdr field, must be length of 4n */
  427         if (padbound < 4)
  428                 padbound = 4;
  429 
  430         extendsiz = padbound - (plen % padbound);
  431         if (extendsiz == 1)
  432                 extendsiz = padbound + 1;
  433 
  434         /* random padding */
  435         switch (af) {
  436 #ifdef INET
  437         case AF_INET:
  438                 randpadmax = ip4_esp_randpad;
  439                 break;
  440 #endif
  441 #ifdef INET6
  442         case AF_INET6:
  443                 randpadmax = ip6_esp_randpad;
  444                 break;
  445 #endif
  446         default:
  447                 randpadmax = -1;
  448                 break;
  449         }
  450         if (randpadmax < 0 || plen + extendsiz >= randpadmax)
  451                 ;
  452         else {
  453                 int n;
  454 
  455                 /* round */
  456                 randpadmax = (randpadmax / padbound) * padbound;
  457                 n = (randpadmax - plen + extendsiz) / padbound;
  458 
  459                 if (n > 0)
  460                         n = (random() % n) * padbound;
  461                 else
  462                         n = 0;
  463 
  464                 /*
  465                  * make sure we do not pad too much.
  466                  * MLEN limitation comes from the trailer attachment
  467                  * code below.
  468                  * 256 limitation comes from sequential padding.
  469                  * also, the 1-octet length field in ESP trailer imposes
  470                  * limitation (but is less strict than sequential padding
  471                  * as length field do not count the last 2 octets).
  472                  */
  473                 if (extendsiz + n <= MLEN && extendsiz + n < 256)
  474                         extendsiz += n;
  475         }
  476 
  477 #ifdef DIAGNOSTIC
  478         if (extendsiz > MLEN || extendsiz >= 256)
  479                 panic("extendsiz too big in esp_output");
  480 #endif
  481 
  482         n = m;
  483         while (n->m_next)
  484                 n = n->m_next;
  485 
  486         /*
  487          * if M_EXT, the external mbuf data may be shared among
  488          * two consequtive TCP packets, and it may be unsafe to use the
  489          * trailing space.
  490          */
  491         if (!(n->m_flags & M_EXT) && extendsiz < M_TRAILINGSPACE(n)) {
  492                 extend = mtod(n, u_char *) + n->m_len;
  493                 n->m_len += extendsiz;
  494                 m->m_pkthdr.len += extendsiz;
  495         } else {
  496                 struct mbuf *nn;
  497 
  498                 MGET(nn, M_DONTWAIT, MT_DATA);
  499                 if (!nn) {
  500                         ipseclog((LOG_DEBUG, "esp%d_output: can't alloc mbuf",
  501                             afnumber));
  502                         m_freem(m);
  503                         error = ENOBUFS;
  504                         goto fail;
  505                 }
  506                 extend = mtod(nn, u_char *);
  507                 nn->m_len = extendsiz;
  508                 nn->m_next = NULL;
  509                 n->m_next = nn;
  510                 n = nn;
  511                 m->m_pkthdr.len += extendsiz;
  512         }
  513         switch (sav->flags & SADB_X_EXT_PMASK) {
  514         case SADB_X_EXT_PRAND:
  515                 key_randomfill(extend, extendsiz);
  516                 break;
  517         case SADB_X_EXT_PZERO:
  518                 bzero(extend, extendsiz);
  519                 break;
  520         case SADB_X_EXT_PSEQ:
  521                 for (i = 0; i < extendsiz; i++)
  522                         extend[i] = (i + 1) & 0xff;
  523                 break;
  524         }
  525 
  526         /* initialize esp trailer. */
  527         esptail = (struct esptail *)
  528                 (mtod(n, u_int8_t *) + n->m_len - sizeof(struct esptail));
  529         esptail->esp_nxt = nxt;
  530         esptail->esp_padlen = extendsiz - 2;
  531 
  532         /* modify IP header (for ESP header part only) */
  533         switch (af) {
  534 #ifdef INET
  535         case AF_INET:
  536                 ip = mtod(m, struct ip *);
  537                 if (extendsiz < (IP_MAXPACKET - ntohs(ip->ip_len)))
  538                         ip->ip_len = htons(ntohs(ip->ip_len) + extendsiz);
  539                 else {
  540                         ipseclog((LOG_ERR,
  541                             "IPv4 ESP output: size exceeds limit\n"));
  542                         ipsecstat.out_inval++;
  543                         m_freem(m);
  544                         error = EMSGSIZE;
  545                         goto fail;
  546                 }
  547                 break;
  548 #endif
  549 #ifdef INET6
  550         case AF_INET6:
  551                 /* total packet length will be computed in ip6_output() */
  552                 break;
  553 #endif
  554         }
  555     }
  556 
  557         /*
  558          * pre-compute and cache intermediate key
  559          */
  560         error = esp_schedule(algo, sav);
  561         if (error) {
  562                 m_freem(m);
  563                 stat->out_inval++;
  564                 goto fail;
  565         }
  566 
  567         /*
  568          * encrypt the packet, based on security association
  569          * and the algorithm specified.
  570          */
  571         if (!algo->encrypt)
  572                 panic("internal error: no encrypt function");
  573         if ((*algo->encrypt)(m, espoff, plen + extendsiz, sav, algo, ivlen)) {
  574                 /* m is already freed */
  575                 ipseclog((LOG_ERR, "packet encryption failure\n"));
  576                 stat->out_inval++;
  577                 error = EINVAL;
  578                 goto fail;
  579         }
  580 
  581         /*
  582          * calculate ICV if required.
  583          */
  584         if (!sav->replay)
  585                 goto noantireplay;
  586         if (!sav->key_auth)
  587                 goto noantireplay;
  588         if (sav->alg_auth == SADB_AALG_NONE)
  589                 goto noantireplay;
  590 
  591     {
  592         const struct ah_algorithm *aalgo;
  593         u_char authbuf[AH_MAXSUMSIZE];
  594         struct mbuf *n;
  595         u_char *p;
  596         size_t siz;
  597 #ifdef INET
  598         struct ip *ip;
  599 #endif
  600 
  601         aalgo = ah_algorithm_lookup(sav->alg_auth);
  602         if (!aalgo)
  603                 goto noantireplay;
  604         siz = ((aalgo->sumsiz)(sav) + 3) & ~(4 - 1);
  605         if (AH_MAXSUMSIZE < siz)
  606                 panic("assertion failed for AH_MAXSUMSIZE");
  607 
  608         if (esp_auth(m, espoff, m->m_pkthdr.len - espoff, sav, authbuf)) {
  609                 ipseclog((LOG_ERR, "ESP checksum generation failure\n"));
  610                 m_freem(m);
  611                 error = EINVAL;
  612                 stat->out_inval++;
  613                 goto fail;
  614         }
  615 
  616         n = m;
  617         while (n->m_next)
  618                 n = n->m_next;
  619 
  620         if (!(n->m_flags & M_EXT) && siz < M_TRAILINGSPACE(n)) { /* XXX */
  621                 n->m_len += siz;
  622                 m->m_pkthdr.len += siz;
  623                 p = mtod(n, u_char *) + n->m_len - siz;
  624         } else {
  625                 struct mbuf *nn;
  626 
  627                 MGET(nn, M_DONTWAIT, MT_DATA);
  628                 if (!nn) {
  629                         ipseclog((LOG_DEBUG, "can't alloc mbuf in esp%d_output",
  630                             afnumber));
  631                         m_freem(m);
  632                         error = ENOBUFS;
  633                         goto fail;
  634                 }
  635                 nn->m_len = siz;
  636                 nn->m_next = NULL;
  637                 n->m_next = nn;
  638                 n = nn;
  639                 m->m_pkthdr.len += siz;
  640                 p = mtod(nn, u_char *);
  641         }
  642         bcopy(authbuf, p, siz);
  643 
  644         /* modify IP header (for ESP header part only) */
  645         switch (af) {
  646 #ifdef INET
  647         case AF_INET:
  648                 ip = mtod(m, struct ip *);
  649                 if (siz < (IP_MAXPACKET - ntohs(ip->ip_len)))
  650                         ip->ip_len = htons(ntohs(ip->ip_len) + siz);
  651                 else {
  652                         ipseclog((LOG_ERR,
  653                             "IPv4 ESP output: size exceeds limit\n"));
  654                         ipsecstat.out_inval++;
  655                         m_freem(m);
  656                         error = EMSGSIZE;
  657                         goto fail;
  658                 }
  659                 break;
  660 #endif
  661 #ifdef INET6
  662         case AF_INET6:
  663                 /* total packet length will be computed in ip6_output() */
  664                 break;
  665 #endif
  666         }
  667     }
  668 
  669 noantireplay:
  670         if (!m) {
  671                 ipseclog((LOG_ERR,
  672                     "NULL mbuf after encryption in esp%d_output", afnumber));
  673         } else
  674                 stat->out_success++;
  675         stat->out_esphist[sav->alg_enc]++;
  676         key_sa_recordxfer(sav, m);
  677         return 0;
  678 
  679 fail:
  680 #if 1
  681         return error;
  682 #else
  683         panic("something bad in esp_output");
  684 #endif
  685 }
  686 
  687 #ifdef INET
  688 int
  689 esp4_output(m, isr)
  690         struct mbuf *m;
  691         struct ipsecrequest *isr;
  692 {
  693         struct ip *ip;
  694         if (m->m_len < sizeof(struct ip)) {
  695                 ipseclog((LOG_DEBUG, "esp4_output: first mbuf too short\n"));
  696                 m_freem(m);
  697                 return 0;
  698         }
  699         ip = mtod(m, struct ip *);
  700         /* XXX assumes that m->m_next points to payload */
  701         return esp_output(m, &ip->ip_p, m->m_next, isr, AF_INET);
  702 }
  703 #endif /* INET */
  704 
  705 #ifdef INET6
  706 int
  707 esp6_output(m, nexthdrp, md, isr)
  708         struct mbuf *m;
  709         u_char *nexthdrp;
  710         struct mbuf *md;
  711         struct ipsecrequest *isr;
  712 {
  713         if (m->m_len < sizeof(struct ip6_hdr)) {
  714                 ipseclog((LOG_DEBUG, "esp6_output: first mbuf too short\n"));
  715                 m_freem(m);
  716                 return 0;
  717         }
  718         return esp_output(m, nexthdrp, md, isr, AF_INET6);
  719 }
  720 #endif /* INET6 */

Cache object: 2cb3fd699f6650ae66389c48c8e92d45


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