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

Cache object: 55df97b67f7b15456f020aae2db0c39e


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