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

Cache object: 8436fd0ee6a446398488f7d96d26412e


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