-/* $KAME: ah_output.c,v 1.17 2000/03/09 08:54:48 itojun Exp $ */
+/*
+ * Copyright (c) 2008-2011 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/ah_output.c,v 1.1.2.3 2001/07/03 11:01:49 ume Exp $ */
+/* $KAME: ah_output.c,v 1.30 2001/02/21 00:50:53 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
*/
#define _IP_VHL
-#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__NetBSD__)
-#include "opt_inet.h"
-#endif
#include <sys/param.h>
#include <sys/systm.h>
#endif
#include <netinet6/ipsec.h>
+#if INET6
+#include <netinet6/ipsec6.h>
+#endif
#include <netinet6/ah.h>
+#if INET6
+#include <netinet6/ah6.h>
+#endif
#include <netkey/key.h>
#include <netkey/keydb.h>
-#include <netkey/key_debug.h>
#include <net/net_osdep.h>
-static struct in_addr *ah4_finaldst __P((struct mbuf *));
+#if INET
+static struct in_addr *ah4_finaldst(struct mbuf *);
+#endif
+
+extern lck_mtx_t *sadb_mutex;
/*
* compute AH header size.
ah_hdrsiz(isr)
struct ipsecrequest *isr;
{
- struct ah_algorithm *algo;
- size_t hdrsiz;
/* sanity check */
if (isr == NULL)
if (isr->saidx.proto != IPPROTO_AH)
panic("unsupported mode passed to ah_hdrsiz");
- if (isr->sav == NULL)
- goto estimate;
- if (isr->sav->state != SADB_SASTATE_MATURE
- && isr->sav->state != SADB_SASTATE_DYING)
- goto estimate;
+#if 0
+ {
- /* we need transport mode AH. */
- algo = &ah_algorithms[isr->sav->alg_auth];
- if (!algo)
- goto estimate;
+ lck_mtx_lock(sadb_mutex);
+ const struct ah_algorithm *algo;
+ size_t hdrsiz;
- /*
- * XXX
- * right now we don't calcurate the padding size. simply
- * treat the padding size as constant, for simplicity.
- *
- * XXX variable size padding support
- */
- hdrsiz = (((*algo->sumsiz)(isr->sav) + 3) & ~(4 - 1));
- if (isr->sav->flags & SADB_X_EXT_OLD)
- hdrsiz += sizeof(struct ah);
- else
- hdrsiz += sizeof(struct newah);
+ /*%%%%% this needs to change - no sav in ipsecrequest any more */
+ if (isr->sav == NULL)
+ goto estimate;
+ if (isr->sav->state != SADB_SASTATE_MATURE
+ && isr->sav->state != SADB_SASTATE_DYING)
+ goto estimate;
+
+ /* we need transport mode AH. */
+ algo = ah_algorithm_lookup(isr->sav->alg_auth);
+ if (!algo)
+ 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
+ */
+ hdrsiz = (((*algo->sumsiz)(isr->sav) + 3) & ~(4 - 1));
+ if (isr->sav->flags & SADB_X_EXT_OLD)
+ hdrsiz += sizeof(struct ah);
+ else
+ hdrsiz += sizeof(struct newah);
+
+ lck_mtx_unlock(sadb_mutex);
+ return hdrsiz;
+ }
- return hdrsiz;
+estimate:
+#endif
- estimate:
+ //lck_mtx_unlock(sadb_mutex);
/* ASSUMING:
* sizeof(struct newah) > sizeof(struct ah).
* 16 = (16 + 3) & ~(4 - 1).
return sizeof(struct newah) + 16;
}
+#if INET
/*
* Modify the packet so that it includes the authentication data.
* The mbuf passed must start with IPv4 header.
* the function does not modify m.
*/
int
-ah4_output(m, isr)
+ah4_output(m, sav)
struct mbuf *m;
- struct ipsecrequest *isr;
+ struct secasvar *sav;
{
- struct secasvar *sav = isr->sav;
- struct ah_algorithm *algo;
+ const struct ah_algorithm *algo;
u_int32_t spi;
u_char *ahdrpos;
u_char *ahsumpos = NULL;
size_t plen = 0; /*AH payload size in bytes*/
size_t ahlen = 0; /*plen + sizeof(ah)*/
struct ip *ip;
- struct in_addr dst;
+ struct in_addr dst = { 0 };
struct in_addr *finaldst;
int error;
/* sanity checks */
if ((sav->flags & SADB_X_EXT_OLD) == 0 && !sav->replay) {
- struct ip *ip;
-
ip = mtod(m, struct ip *);
ipseclog((LOG_DEBUG, "ah4_output: internal error: "
"sav->replay is null: %x->%x, SPI=%u\n",
(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++;
+ IPSEC_STAT_INCREMENT(ipsecstat.out_inval);
m_freem(m);
return EINVAL;
}
- algo = &ah_algorithms[sav->alg_auth];
+ algo = ah_algorithm_lookup(sav->alg_auth);
+ if (!algo) {
+ ipseclog((LOG_ERR, "ah4_output: unsupported algorithm: "
+ "SPI=%u\n", (u_int32_t)ntohl(sav->spi)));
+ IPSEC_STAT_INCREMENT(ipsecstat.out_inval);
+ m_freem(m);
+ return EINVAL;
+ }
spi = sav->spi;
/*
if (sav->flags & SADB_X_EXT_OLD) {
struct ah *ahdr;
- ahdr = (struct ah *)ahdrpos;
+ ahdr = (struct ah *)(void *)ahdrpos;
ahsumpos = (u_char *)(ahdr + 1);
ahdr->ah_len = plen >> 2;
ahdr->ah_nxt = ip->ip_p;
} else {
struct newah *ahdr;
- ahdr = (struct newah *)ahdrpos;
+ ahdr = (struct newah *)(void *)ahdrpos;
ahsumpos = (u_char *)(ahdr + 1);
ahdr->ah_len = (plen >> 2) + 1; /* plus one for seq# */
ahdr->ah_nxt = ip->ip_p;
ipseclog((LOG_WARNING,
"replay counter overflowed. %s\n",
ipsec_logsastr(sav)));
- ipsecstat.out_inval++;
+ IPSEC_STAT_INCREMENT(ipsecstat.out_inval);
m_freem(m);
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.
ip->ip_len = htons(ntohs(ip->ip_len) + ahlen);
else {
ipseclog((LOG_ERR, "IPv4 AH output: size exceeds limit\n"));
- ipsecstat.out_inval++;
+ IPSEC_STAT_INCREMENT(ipsecstat.out_inval);
m_freem(m);
return EMSGSIZE;
}
* calcurate the checksum, based on security association
* and the algorithm specified.
*/
- error = ah4_calccksum(m, (caddr_t)ahsumpos, algo, sav);
+ error = ah4_calccksum(m, (caddr_t)ahsumpos, plen, algo, sav);
if (error) {
ipseclog((LOG_ERR,
"error after ah4_calccksum, called from ah4_output"));
+ m_freem(m);
m = NULL;
- ipsecstat.out_inval++;
+ IPSEC_STAT_INCREMENT(ipsecstat.out_inval);
return error;
}
ip = mtod(m, struct ip *); /*just to make sure*/
ip->ip_dst.s_addr = dst.s_addr;
}
+ lck_mtx_lock(sadb_stat_mutex);
ipsecstat.out_success++;
ipsecstat.out_ahhist[sav->alg_auth]++;
+ lck_mtx_unlock(sadb_stat_mutex);
key_sa_recordxfer(sav, m);
return 0;
}
+#endif
/* Calculate AH length */
int
ah_hdrlen(sav)
struct secasvar *sav;
{
- struct ah_algorithm *algo;
+ const struct ah_algorithm *algo;
int plen, ahlen;
- algo = &ah_algorithms[sav->alg_auth];
+ algo = ah_algorithm_lookup(sav->alg_auth);
+ if (!algo)
+ return 0;
if (sav->flags & SADB_X_EXT_OLD) {
/* RFC 1826 */
plen = ((*algo->sumsiz)(sav) + 3) & ~(4 - 1); /*XXX pad to 8byte?*/
* Fill in the Authentication Header and calculate checksum.
*/
int
-ah6_output(m, nexthdrp, md, isr)
+ah6_output(m, nexthdrp, md, sav)
struct mbuf *m;
u_char *nexthdrp;
struct mbuf *md;
- struct ipsecrequest *isr;
+ struct secasvar *sav;
{
struct mbuf *mprev;
struct mbuf *mah;
- struct secasvar *sav = isr->sav;
- struct ah_algorithm *algo;
+ const struct ah_algorithm *algo;
u_int32_t spi;
u_char *ahsumpos = NULL;
size_t plen; /*AH payload size in bytes*/
if ((sav->flags & SADB_X_EXT_OLD) == 0 && !sav->replay) {
ipseclog((LOG_DEBUG, "ah6_output: internal error: "
- "sav->replay is null: SPI=%u\n",
- (u_int32_t)ntohl(sav->spi)));
- ipsec6stat.out_inval++;
+ "sav->replay is null: SPI=%u\n",
+ (u_int32_t)ntohl(sav->spi)));
+ IPSEC_STAT_INCREMENT(ipsec6stat.out_inval);
m_freem(m);
return EINVAL;
}
- algo = &ah_algorithms[sav->alg_auth];
+ algo = ah_algorithm_lookup(sav->alg_auth);
+ if (!algo) {
+ ipseclog((LOG_ERR, "ah6_output: unsupported algorithm: "
+ "SPI=%u\n", (u_int32_t)ntohl(sav->spi)));
+ IPSEC_STAT_INCREMENT(ipsec6stat.out_inval);
+ m_freem(m);
+ return EINVAL;
+ }
spi = sav->spi;
/*
if ((sav->flags & SADB_X_EXT_CYCSEQ) == 0) {
/* XXX Is it noisy ? */
ipseclog((LOG_WARNING,
- "replay counter overflowed. %s\n",
+ "replay counter overflowed. %s\n",
ipsec_logsastr(sav)));
- ipsecstat.out_inval++;
+ IPSEC_STAT_INCREMENT(ipsec6stat.out_inval);
m_freem(m);
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.
* calcurate the checksum, based on security association
* and the algorithm specified.
*/
- error = ah6_calccksum(m, (caddr_t)ahsumpos, algo, sav);
+ error = ah6_calccksum(m, (caddr_t)ahsumpos, plen, algo, sav);
if (error) {
- ipsec6stat.out_inval++;
+ IPSEC_STAT_INCREMENT(ipsec6stat.out_inval);
m_freem(m);
} else {
- ipsec6stat.out_success++;
+ IPSEC_STAT_INCREMENT(ipsec6stat.out_success);
key_sa_recordxfer(sav, m);
}
- ipsec6stat.out_ahhist[sav->alg_auth]++;
+ IPSEC_STAT_INCREMENT(ipsec6stat.out_ahhist[sav->alg_auth]);
return(error);
}
#endif
+#if INET
/*
* Find the final destination if there is loose/strict source routing option.
* Returns NULL if there's no source routing options.
q = (u_char *)(ip + 1);
i = 0;
while (i < optlen) {
+ if (i + IPOPT_OPTVAL >= optlen)
+ return NULL;
+ if (q[i + IPOPT_OPTVAL] == IPOPT_EOL ||
+ q[i + IPOPT_OPTVAL] == IPOPT_NOP ||
+ i + IPOPT_OLEN < optlen)
+ ;
+ else
+ return NULL;
+
switch (q[i + IPOPT_OPTVAL]) {
case IPOPT_EOL:
i = optlen; /* bye */
break;
case IPOPT_LSRR:
case IPOPT_SSRR:
- if (q[i + IPOPT_OLEN] <= 0
- || optlen - i < q[i + IPOPT_OLEN]) {
+ if (q[i + IPOPT_OLEN] < 2 + sizeof(struct in_addr) ||
+ optlen - i < q[i + IPOPT_OLEN]) {
ipseclog((LOG_ERR,
"ip_finaldst: invalid IP option "
"(code=%02x len=%02x)\n",
return NULL;
}
i += q[i + IPOPT_OLEN] - sizeof(struct in_addr);
- return (struct in_addr *)(q + i);
+ return (struct in_addr *)(void *)(q + i);
default:
- if (q[i + IPOPT_OLEN] <= 0
- || optlen - i < q[i + IPOPT_OLEN]) {
+ if (q[i + IPOPT_OLEN] < 2 ||
+ optlen - i < q[i + IPOPT_OLEN]) {
ipseclog((LOG_ERR,
"ip_finaldst: invalid IP option "
"(code=%02x len=%02x)\n",
}
return NULL;
}
+#endif