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

Cache object: 578861e9fb2b4e92407f442ae03dc212


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