X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/1c79356b52d46aa6b508fb032f5ae709b1f2897b..6d2010ae8f7a6078e10b361c6962983bab233e0f:/bsd/netinet6/esp_output.c diff --git a/bsd/netinet6/esp_output.c b/bsd/netinet6/esp_output.c index 26a1b0ca6..8d16d2c62 100644 --- a/bsd/netinet6/esp_output.c +++ b/bsd/netinet6/esp_output.c @@ -1,4 +1,33 @@ -/* $KAME: esp_output.c,v 1.17 2000/02/22 14:04:15 itojun Exp $ */ +/* + * Copyright (c) 2008 Apple Inc. All rights reserved. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. + * + * Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ + */ + +/* $FreeBSD: src/sys/netinet6/esp_output.c,v 1.1.2.3 2002/04/28 05:40:26 suz Exp $ */ +/* $KAME: esp_output.c,v 1.44 2001/07/26 06:53:15 jinmei Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -30,9 +59,6 @@ */ #define _IP_VHL -#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__NetBSD__) -#include "opt_inet.h" -#endif /* * RFC1827/2406 Encapsulated Security Payload. @@ -58,6 +84,7 @@ #include #include #include +#include /* for nat traversal */ #if INET6 #include @@ -66,16 +93,35 @@ #endif #include +#if INET6 +#include +#endif #include +#if INET6 +#include +#endif #include +#if INET6 +#include +#endif #include #include -#include #include -static int esp_output __P((struct mbuf *, u_char *, struct mbuf *, - struct ipsecrequest *, int)); +#include +#define DBG_LAYER_BEG NETDBG_CODE(DBG_NETIPSEC, 1) +#define DBG_LAYER_END NETDBG_CODE(DBG_NETIPSEC, 3) +#define DBG_FNC_ESPOUT NETDBG_CODE(DBG_NETIPSEC, (4 << 8)) +#define DBG_FNC_ENCRYPT NETDBG_CODE(DBG_NETIPSEC, (5 << 8)) + +static int esp_output(struct mbuf *, u_char *, struct mbuf *, + int, struct secasvar *sav); + +extern int esp_udp_encap_port; +extern u_int32_t natt_now; + +extern lck_mtx_t *sadb_mutex; /* * compute ESP header size. @@ -84,66 +130,84 @@ size_t esp_hdrsiz(isr) struct ipsecrequest *isr; { - struct secasvar *sav; - struct esp_algorithm *algo; - size_t ivlen; - size_t authlen; - size_t hdrsiz; /* sanity check */ if (isr == NULL) panic("esp_hdrsiz: NULL was passed.\n"); - sav = isr->sav; - - if (isr->saidx.proto != IPPROTO_ESP) - panic("unsupported mode passed to esp_hdrsiz"); - - if (sav == NULL) - goto estimate; - if (sav->state != SADB_SASTATE_MATURE - && sav->state != SADB_SASTATE_DYING) - goto estimate; - - /* we need transport mode ESP. */ - algo = &esp_algorithms[sav->alg_enc]; - if (!algo) - goto estimate; - ivlen = sav->ivlen; - if (ivlen < 0) - goto estimate; - /* - * XXX - * right now we don't calcurate the padding size. simply - * treat the padding size as constant, for simplicity. - * - * XXX variable size padding support - */ - if (sav->flags & SADB_X_EXT_OLD) { - /* RFC 1827 */ - hdrsiz = sizeof(struct esp) + ivlen + 9; - } else { - /* RFC 2406 */ - if (sav->replay && sav->alg_auth && sav->key_auth) - authlen = (*ah_algorithms[sav->alg_auth].sumsiz)(sav); +#if 0 + lck_mtx_lock(sadb_mutex); + { + struct secasvar *sav; + const struct esp_algorithm *algo; + const struct ah_algorithm *aalgo; + size_t ivlen; + size_t authlen; + size_t hdrsiz; + size_t maxpad; + + /*%%%% this needs to change - no sav in ipsecrequest any more */ + sav = isr->sav; + + if (isr->saidx.proto != IPPROTO_ESP) + panic("unsupported mode passed to esp_hdrsiz"); + + if (sav == NULL) + goto estimate; + if (sav->state != SADB_SASTATE_MATURE + && sav->state != SADB_SASTATE_DYING) + goto estimate; + + /* we need transport mode ESP. */ + algo = esp_algorithm_lookup(sav->alg_enc); + if (!algo) + goto estimate; + ivlen = sav->ivlen; + if (ivlen < 0) + goto estimate; + + if (algo->padbound) + maxpad = algo->padbound; else - authlen = 0; - hdrsiz = sizeof(struct newesp) + ivlen + 9 + authlen; + maxpad = 4; + maxpad += 1; /* maximum 'extendsiz' is padbound + 1, see esp_output */ + + if (sav->flags & SADB_X_EXT_OLD) { + /* RFC 1827 */ + hdrsiz = sizeof(struct esp) + ivlen + maxpad; + } else { + /* RFC 2406 */ + aalgo = ah_algorithm_lookup(sav->alg_auth); + if (aalgo && sav->replay && sav->key_auth) + authlen = (aalgo->sumsiz)(sav); + else + authlen = 0; + hdrsiz = sizeof(struct newesp) + ivlen + maxpad + authlen; + } + + /* + * If the security association indicates that NATT is required, + * add the size of the NATT encapsulation header: + */ + if ((sav->flags & SADB_X_EXT_NATT) != 0) hdrsiz += sizeof(struct udphdr) + 4; + + lck_mtx_unlock(sadb_mutex); + return hdrsiz; } - - return hdrsiz; - - estimate: +estimate: + lck_mtx_unlock(sadb_mutex); +#endif /* * ASSUMING: - * sizeof(struct newesp) > sizeof(struct esp). - * 8 = ivlen for CBC mode (RFC2451). - * 9 = (maximum padding length without random padding length) + * sizeof(struct newesp) > sizeof(struct esp). (8) + * esp_max_ivlen() = max ivlen for CBC mode + * 17 = (maximum padding length without random padding length) * + (Pad Length field) + (Next Header field). - * 16 = maximum ICV we support. + * 64 = maximum ICV we support. + * sizeof(struct udphdr) in case NAT traversal is used */ - return sizeof(struct newesp) + 8 + 9 + 16; + return sizeof(struct newesp) + esp_max_ivlen() + 17 + AH_MAXSUMSIZE + sizeof(struct udphdr); } /* @@ -167,19 +231,18 @@ esp_hdrsiz(isr) * <-----------------> espoff */ static int -esp_output(m, nexthdrp, md, isr, af) +esp_output(m, nexthdrp, md, af, sav) struct mbuf *m; u_char *nexthdrp; struct mbuf *md; - struct ipsecrequest *isr; int af; + struct secasvar *sav; { struct mbuf *n; struct mbuf *mprev; struct esp *esp; struct esptail *esptail; - struct secasvar *sav = isr->sav; - struct esp_algorithm *algo; + const struct esp_algorithm *algo; u_int32_t spi; u_int8_t nxt = 0; size_t plen; /*payload length to be encrypted*/ @@ -188,20 +251,28 @@ esp_output(m, nexthdrp, md, isr, af) int afnumber; size_t extendsiz; int error = 0; + struct ipsecstat *stat; + struct udphdr *udp = NULL; + int udp_encapsulate = (sav->flags & SADB_X_EXT_NATT && af == AF_INET && + (esp_udp_encap_port & 0xFFFF) != 0); + KERNEL_DEBUG(DBG_FNC_ESPOUT | DBG_FUNC_START, sav->ivlen,0,0,0,0); switch (af) { #if INET case AF_INET: afnumber = 4; + stat = &ipsecstat; break; #endif #if INET6 case AF_INET6: afnumber = 6; + stat = &ipsec6stat; break; #endif default: ipseclog((LOG_ERR, "esp_output: unsupported af %d\n", af)); + KERNEL_DEBUG(DBG_FNC_ESPOUT | DBG_FUNC_END, 1,0,0,0,0); return 0; /* no change at all */ } @@ -219,29 +290,34 @@ esp_output(m, nexthdrp, md, isr, af) (u_int32_t)ntohl(ip->ip_src.s_addr), (u_int32_t)ntohl(ip->ip_dst.s_addr), (u_int32_t)ntohl(sav->spi))); - ipsecstat.out_inval++; - m_freem(m); - return EINVAL; + IPSEC_STAT_INCREMENT(ipsecstat.out_inval); + break; } #endif /*INET*/ #if INET6 case AF_INET6: - { - struct ip6_hdr *ip6; - - ip6 = mtod(m, struct ip6_hdr *); ipseclog((LOG_DEBUG, "esp6_output: internal error: " "sav->replay is null: SPI=%u\n", (u_int32_t)ntohl(sav->spi))); - ipsec6stat.out_inval++; - m_freem(m); - return EINVAL; - } + IPSEC_STAT_INCREMENT(ipsec6stat.out_inval); + break; #endif /*INET6*/ + default: + panic("esp_output: should not reach here"); } + m_freem(m); + KERNEL_DEBUG(DBG_FNC_ESPOUT | DBG_FUNC_END, 2,0,0,0,0); + return EINVAL; } - algo = &esp_algorithms[sav->alg_enc]; /*XXX*/ + algo = esp_algorithm_lookup(sav->alg_enc); + if (!algo) { + ipseclog((LOG_ERR, "esp_output: unsupported algorithm: " + "SPI=%u\n", (u_int32_t)ntohl(sav->spi))); + m_freem(m); + KERNEL_DEBUG(DBG_FNC_ESPOUT | DBG_FUNC_END, 3,0,0,0,0); + return EINVAL; + } spi = sav->spi; ivlen = sav->ivlen; /* should be okey */ @@ -262,9 +338,9 @@ esp_output(m, nexthdrp, md, isr, af) #if INET6 struct ip6_hdr *ip6 = NULL; #endif - size_t esplen; /*sizeof(struct esp/newesp)*/ - size_t esphlen; /*sizeof(struct esp/newesp) + ivlen*/ - size_t hlen = 0; /*ip header len*/ + size_t esplen; /* sizeof(struct esp/newesp) */ + size_t esphlen; /* sizeof(struct esp/newesp) + ivlen */ + size_t hlen = 0; /* ip header len */ if (sav->flags & SADB_X_EXT_OLD) { /* RFC 1827 */ @@ -284,6 +360,7 @@ esp_output(m, nexthdrp, md, isr, af) ipseclog((LOG_DEBUG, "esp%d_output: md is not in chain\n", afnumber)); m_freem(m); + KERNEL_DEBUG(DBG_FNC_ESPOUT | DBG_FUNC_END, 4,0,0,0,0); return EINVAL; } @@ -318,15 +395,56 @@ esp_output(m, nexthdrp, md, isr, af) goto fail; } mprev->m_next = md; + + /* + * Translate UDP source port back to its original value. + * SADB_X_EXT_NATT_MULTIPLEUSERS is only set for transort mode. + */ + if ((sav->flags & SADB_X_EXT_NATT_MULTIPLEUSERS) != 0) { + /* if not UDP - drop it */ + if (ip->ip_p != IPPROTO_UDP) { + IPSEC_STAT_INCREMENT(ipsecstat.out_inval); + m_freem(m); + error = EINVAL; + goto fail; + } + + udp = mtod(md, struct udphdr *); + + /* if src port not set in sav - find it */ + if (sav->natt_encapsulated_src_port == 0) + if (key_natt_get_translated_port(sav) == 0) { + m_freem(m); + error = EINVAL; + goto fail; + } + if (sav->remote_ike_port == htons(udp->uh_dport)) { + /* translate UDP port */ + udp->uh_dport = sav->natt_encapsulated_src_port; + udp->uh_sum = 0; /* don't need checksum with ESP auth */ + } else { + /* drop the packet - can't translate the port */ + IPSEC_STAT_INCREMENT(ipsecstat.out_inval); + m_freem(m); + error = EINVAL; + goto fail; + } + } + espoff = m->m_pkthdr.len - plen; + + if (udp_encapsulate) { + esphlen += sizeof(struct udphdr); + espoff += sizeof(struct udphdr); + } /* * grow the mbuf to accomodate ESP header. * before: IP ... payload - * after: IP ... ESP IV payload + * after: IP ... [UDP] ESP IV payload */ - if (M_LEADINGSPACE(md) < esphlen) { + if (M_LEADINGSPACE(md) < esphlen || (md->m_flags & M_EXT) != 0) { MGET(n, M_DONTWAIT, MT_DATA); if (!n) { m_freem(m); @@ -337,16 +455,25 @@ esp_output(m, nexthdrp, md, isr, af) mprev->m_next = n; n->m_next = md; m->m_pkthdr.len += esphlen; - esp = mtod(n, struct esp *); + if (udp_encapsulate) { + udp = mtod(n, struct udphdr *); + esp = (struct esp *)((caddr_t)udp + sizeof(struct udphdr)); + } else { + esp = mtod(n, struct esp *); + } } else { md->m_len += esphlen; md->m_data -= esphlen; m->m_pkthdr.len += esphlen; esp = mtod(md, struct esp *); + if (udp_encapsulate) { + udp = mtod(md, struct udphdr *); + esp = (struct esp *)((caddr_t)udp + sizeof(struct udphdr)); + } else { + esp = mtod(md, struct esp *); + } } - nxt = *nexthdrp; - *nexthdrp = IPPROTO_ESP; switch (af) { #if INET case AF_INET: @@ -355,7 +482,7 @@ esp_output(m, nexthdrp, md, isr, af) else { ipseclog((LOG_ERR, "IPv4 ESP output: size exceeds limit\n")); - ipsecstat.out_inval++; + IPSEC_STAT_INCREMENT(ipsecstat.out_inval); m_freem(m); error = EMSGSIZE; goto fail; @@ -381,12 +508,15 @@ esp_output(m, nexthdrp, md, isr, af) ipseclog((LOG_WARNING, "replay counter overflowed. %s\n", ipsec_logsastr(sav))); - ipsecstat.out_inval++; + IPSEC_STAT_INCREMENT(stat->out_inval); m_freem(m); + KERNEL_DEBUG(DBG_FNC_ESPOUT | DBG_FUNC_END, 5,0,0,0,0); return EINVAL; } } + lck_mtx_lock(sadb_mutex); sav->replay->count++; + lck_mtx_unlock(sadb_mutex); /* * XXX sequence number must not be cycled, if the SA is * installed by IKE daemon. @@ -397,7 +527,6 @@ esp_output(m, nexthdrp, md, isr, af) { /* * find the last mbuf. make some room for ESP trailer. - * XXX new-esp authentication data */ #if INET struct ip *ip = NULL; @@ -405,6 +534,7 @@ esp_output(m, nexthdrp, md, isr, af) size_t padbound; u_char *extend; int i; + int randpadmax; if (algo->padbound) padbound = algo->padbound; @@ -418,13 +548,62 @@ esp_output(m, nexthdrp, md, isr, af) if (extendsiz == 1) extendsiz = padbound + 1; + /* random padding */ + switch (af) { +#if INET + case AF_INET: + randpadmax = ip4_esp_randpad; + break; +#endif +#if INET6 + case AF_INET6: + randpadmax = ip6_esp_randpad; + break; +#endif + default: + randpadmax = -1; + break; + } + if (randpadmax < 0 || plen + extendsiz >= randpadmax) + ; + else { + int pad; + + /* round */ + randpadmax = (randpadmax / padbound) * padbound; + pad = (randpadmax - plen + extendsiz) / padbound; + + if (pad > 0) + pad = (random() % pad) * padbound; + else + pad = 0; + + /* + * make sure we do not pad too much. + * MLEN limitation comes from the trailer attachment + * code below. + * 256 limitation comes from sequential padding. + * also, the 1-octet length field in ESP trailer imposes + * limitation (but is less strict than sequential padding + * as length field do not count the last 2 octets). + */ + if (extendsiz + pad <= MLEN && extendsiz + pad < 256) + extendsiz += pad; + } + +#if DIAGNOSTIC + if (extendsiz > MLEN || extendsiz >= 256) + panic("extendsiz too big in esp_output"); +#endif + n = m; while (n->m_next) n = n->m_next; /* - * if M_EXT, the external part may be shared among - * two consequtive TCP packets. + * if M_EXT, the external mbuf data may be shared among + * two consequtive TCP packets, and it may be unsafe to use the + * trailing space. */ if (!(n->m_flags & M_EXT) && extendsiz < M_TRAILINGSPACE(n)) { extend = mtod(n, u_char *) + n->m_len; @@ -450,8 +629,7 @@ esp_output(m, nexthdrp, md, isr, af) } switch (sav->flags & SADB_X_EXT_PMASK) { case SADB_X_EXT_PRAND: - for (i = 0; i < extendsiz; i++) - extend[i] = random() & 0xff; + key_randomfill(extend, extendsiz); break; case SADB_X_EXT_PZERO: bzero(extend, extendsiz); @@ -461,6 +639,22 @@ esp_output(m, nexthdrp, md, isr, af) extend[i] = (i + 1) & 0xff; break; } + + nxt = *nexthdrp; + if (udp_encapsulate) { + *nexthdrp = IPPROTO_UDP; + + /* Fill out the UDP header */ + udp->uh_sport = ntohs((u_short)esp_udp_encap_port); + udp->uh_dport = ntohs(sav->remote_ike_port); +// udp->uh_len set later, after all length tweaks are complete + udp->uh_sum = 0; + + /* Update last sent so we know if we need to send keepalive */ + sav->natt_last_activity = natt_now; + } else { + *nexthdrp = IPPROTO_ESP; + } /* initialize esp trailer. */ esptail = (struct esptail *) @@ -478,7 +672,7 @@ esp_output(m, nexthdrp, md, isr, af) else { ipseclog((LOG_ERR, "IPv4 ESP output: size exceeds limit\n")); - ipsecstat.out_inval++; + IPSEC_STAT_INCREMENT(ipsecstat.out_inval); m_freem(m); error = EMSGSIZE; goto fail; @@ -493,30 +687,32 @@ esp_output(m, nexthdrp, md, isr, af) } } + /* + * pre-compute and cache intermediate key + */ + error = esp_schedule(algo, sav); + if (error) { + m_freem(m); + IPSEC_STAT_INCREMENT(stat->out_inval); + goto fail; + } + /* * encrypt the packet, based on security association * and the algorithm specified. */ if (!algo->encrypt) panic("internal error: no encrypt function"); + KERNEL_DEBUG(DBG_FNC_ENCRYPT | DBG_FUNC_START, 0,0,0,0,0); if ((*algo->encrypt)(m, espoff, plen + extendsiz, sav, algo, ivlen)) { + /* m is already freed */ ipseclog((LOG_ERR, "packet encryption failure\n")); - m_freem(m); - switch (af) { -#if INET - case AF_INET: - ipsecstat.out_inval++; - break; -#endif -#if INET6 - case AF_INET6: - ipsec6stat.out_inval++; - break; -#endif - } + IPSEC_STAT_INCREMENT(stat->out_inval); error = EINVAL; + KERNEL_DEBUG(DBG_FNC_ENCRYPT | DBG_FUNC_END, 1,error,0,0,0); goto fail; } + KERNEL_DEBUG(DBG_FNC_ENCRYPT | DBG_FUNC_END, 2,0,0,0,0); /* * calculate ICV if required. @@ -525,110 +721,109 @@ esp_output(m, nexthdrp, md, isr, af) goto noantireplay; if (!sav->key_auth) goto noantireplay; - if (!sav->alg_auth) + if (sav->key_auth == SADB_AALG_NONE) goto noantireplay; - { - u_char authbuf[AH_MAXSUMSIZE]; - struct mbuf *n; - u_char *p; - size_t siz; - struct ip *ip; - - siz = (((*ah_algorithms[sav->alg_auth].sumsiz)(sav) + 3) & ~(4 - 1)); - if (AH_MAXSUMSIZE < siz) - panic("assertion failed for AH_MAXSUMSIZE"); - - if (esp_auth(m, espoff, m->m_pkthdr.len - espoff, sav, authbuf)) - goto noantireplay; - - n = m; - while (n->m_next) - n = n->m_next; - - if (!(n->m_flags & M_EXT) && siz < M_TRAILINGSPACE(n)) { /*XXX*/ - n->m_len += siz; - m->m_pkthdr.len += siz; - p = mtod(n, u_char *) + n->m_len - siz; - } else { - struct mbuf *nn; - MGET(nn, M_DONTWAIT, MT_DATA); - if (!nn) { - ipseclog((LOG_DEBUG, "can't alloc mbuf in esp%d_output", - afnumber)); + { + const struct ah_algorithm *aalgo; + u_char authbuf[AH_MAXSUMSIZE]; + u_char *p; + size_t siz; + #if INET + struct ip *ip; + #endif + + aalgo = ah_algorithm_lookup(sav->alg_auth); + if (!aalgo) + goto noantireplay; + siz = ((aalgo->sumsiz)(sav) + 3) & ~(4 - 1); + if (AH_MAXSUMSIZE < siz) + panic("assertion failed for AH_MAXSUMSIZE"); + + if (esp_auth(m, espoff, m->m_pkthdr.len - espoff, sav, authbuf)) { + ipseclog((LOG_ERR, "ESP checksum generation failure\n")); m_freem(m); - error = ENOBUFS; + error = EINVAL; + IPSEC_STAT_INCREMENT(stat->out_inval); goto fail; } - nn->m_len = siz; - nn->m_next = NULL; - n->m_next = nn; - n = nn; - m->m_pkthdr.len += siz; - p = mtod(nn, u_char *); - } - bcopy(authbuf, p, siz); - - /* modify IP header (for ESP header part only) */ - switch (af) { -#if INET - case AF_INET: - ip = mtod(m, struct ip *); - if (siz < (IP_MAXPACKET - ntohs(ip->ip_len))) - ip->ip_len = htons(ntohs(ip->ip_len) + siz); - else { - ipseclog((LOG_ERR, - "IPv4 ESP output: size exceeds limit\n")); - ipsecstat.out_inval++; - m_freem(m); - error = EMSGSIZE; - goto fail; + + n = m; + while (n->m_next) + n = n->m_next; + + if (!(n->m_flags & M_EXT) && siz < M_TRAILINGSPACE(n)) { /* XXX */ + n->m_len += siz; + m->m_pkthdr.len += siz; + p = mtod(n, u_char *) + n->m_len - siz; + } else { + struct mbuf *nn; + + MGET(nn, M_DONTWAIT, MT_DATA); + if (!nn) { + ipseclog((LOG_DEBUG, "can't alloc mbuf in esp%d_output", + afnumber)); + m_freem(m); + error = ENOBUFS; + goto fail; + } + nn->m_len = siz; + nn->m_next = NULL; + n->m_next = nn; + n = nn; + m->m_pkthdr.len += siz; + p = mtod(nn, u_char *); } - break; -#endif -#if INET6 - case AF_INET6: - /* total packet length will be computed in ip6_output() */ - break; -#endif - } - } - -noantireplay: - if (!m) { - ipseclog((LOG_ERR, - "NULL mbuf after encryption in esp%d_output", afnumber)); - } else { + bcopy(authbuf, p, siz); + + /* modify IP header (for ESP header part only) */ switch (af) { -#if INET + #if INET case AF_INET: - ipsecstat.out_success++; + ip = mtod(m, struct ip *); + if (siz < (IP_MAXPACKET - ntohs(ip->ip_len))) + ip->ip_len = htons(ntohs(ip->ip_len) + siz); + else { + ipseclog((LOG_ERR, + "IPv4 ESP output: size exceeds limit\n")); + IPSEC_STAT_INCREMENT(ipsecstat.out_inval); + m_freem(m); + error = EMSGSIZE; + goto fail; + } break; -#endif -#if INET6 + #endif + #if INET6 case AF_INET6: - ipsec6stat.out_success++; + /* total packet length will be computed in ip6_output() */ break; -#endif + #endif } + } + + if (udp_encapsulate) { + struct ip *ip; + ip = mtod(m, struct ip *); + udp->uh_ulen = htons(ntohs(ip->ip_len) - (IP_VHL_HL(ip->ip_vhl) << 2)); } - switch (af) { -#if INET - case AF_INET: - ipsecstat.out_esphist[sav->alg_enc]++; - break; -#endif -#if INET6 - case AF_INET6: - ipsec6stat.out_esphist[sav->alg_enc]++; - break; -#endif - } + + +noantireplay: + lck_mtx_lock(sadb_mutex); + if (!m) { + ipseclog((LOG_ERR, + "NULL mbuf after encryption in esp%d_output", afnumber)); + } else + stat->out_success++; + stat->out_esphist[sav->alg_enc]++; + lck_mtx_unlock(sadb_mutex); key_sa_recordxfer(sav, m); + KERNEL_DEBUG(DBG_FNC_ESPOUT | DBG_FUNC_END, 6,0,0,0,0); return 0; fail: #if 1 + KERNEL_DEBUG(DBG_FNC_ESPOUT | DBG_FUNC_END, 7,error,0,0,0); return error; #else panic("something bad in esp_output"); @@ -637,35 +832,35 @@ fail: #if INET int -esp4_output(m, isr) +esp4_output(m, sav) struct mbuf *m; - struct ipsecrequest *isr; + struct secasvar *sav; { struct ip *ip; if (m->m_len < sizeof(struct ip)) { ipseclog((LOG_DEBUG, "esp4_output: first mbuf too short\n")); m_freem(m); - return NULL; + return EINVAL; } ip = mtod(m, struct ip *); /* XXX assumes that m->m_next points to payload */ - return esp_output(m, &ip->ip_p, m->m_next, isr, AF_INET); + return esp_output(m, &ip->ip_p, m->m_next, AF_INET, sav); } #endif /*INET*/ #if INET6 int -esp6_output(m, nexthdrp, md, isr) +esp6_output(m, nexthdrp, md, sav) struct mbuf *m; u_char *nexthdrp; struct mbuf *md; - struct ipsecrequest *isr; + struct secasvar *sav; { if (m->m_len < sizeof(struct ip6_hdr)) { ipseclog((LOG_DEBUG, "esp6_output: first mbuf too short\n")); m_freem(m); - return NULL; + return EINVAL; } - return esp_output(m, nexthdrp, md, isr, AF_INET6); + return esp_output(m, nexthdrp, md, AF_INET6, sav); } #endif /*INET6*/