Subject: IPSEC_NAT_T for FAST_IPSEC
To: None <tech-net@NetBSD.org>
From: None <degroote@netbsd.org>
List: tech-net
Date: 06/19/2007 23:46:21
--X1bOJ3K7DJ5YkBrT
Content-Type: text/plain; charset=utf-8
Content-Disposition: inline

Hi

I have finished to add support of IPSEC_NAT_T for FAST_IPSEC. Tke key
management part is more or less directly taken from manu@ work so most of
congrats is for him :D 

Can you review the following patch and if possible test it on a real
configuration (I have done some tests but only on virtual networks).  

If nobody object, I will commit it next week.

-- 
Arnaud Degroote
degroote@netbsd.org

--X1bOJ3K7DJ5YkBrT
Content-Type: text/plain; charset=utf-8
Content-Disposition: attachment; filename="ipsec_nat_t.diff"

Index: netinet/udp_usrreq.c
===================================================================
RCS file: /cvsroot/src/sys/netinet/udp_usrreq.c,v
retrieving revision 1.159
diff -u -r1.159 udp_usrreq.c
--- netinet/udp_usrreq.c	12 May 2007 02:03:15 -0000	1.159
+++ netinet/udp_usrreq.c	19 Jun 2007 20:59:56 -0000
@@ -1528,7 +1528,7 @@
 	m_tag_prepend(n, tag);
 
 #ifdef FAST_IPSEC
-	ipsec4_common_input(n, iphdrlen);
+	ipsec4_common_input(n, iphdrlen, IPPROTO_ESP);
 #else
 	esp4_input(n, iphdrlen);
 #endif
Index: netipsec/ipsec_input.c
===================================================================
RCS file: /cvsroot/src/sys/netipsec/ipsec_input.c,v
retrieving revision 1.16
diff -u -r1.16 ipsec_input.c
--- netipsec/ipsec_input.c	4 Mar 2007 21:17:54 -0000	1.16
+++ netipsec/ipsec_input.c	19 Jun 2007 20:59:58 -0000
@@ -116,7 +116,12 @@
 	union sockaddr_union dst_address;
 	struct secasvar *sav;
 	u_int32_t spi;
+	u_int16_t sport = 0;
+	u_int16_t dport = 0;
 	int s, error;
+#ifdef IPSEC_NAT_T
+	struct m_tag * tag = NULL;
+#endif
 
 	IPSEC_ISTAT(sproto, espstat.esps_input, ahstat.ahs_input,
 		ipcompstat.ipcomps_input);
@@ -149,7 +154,19 @@
 		u_int16_t cpi;
 		m_copydata(m, skip + sizeof(u_int16_t), sizeof(u_int16_t), &cpi);
 		spi = ntohl(htons(cpi));
+	} else {
+		panic("ipsec_common_input called with bad protocol number :"
+		      "%d\n", sproto);
 	}
+		
+
+#ifdef IPSEC_NAT_T
+	/* find the source port for NAT-T */
+	if ((tag = m_tag_find(m, PACKET_TAG_IPSEC_NAT_T_PORTS, NULL))) {
+		sport = ((u_int16_t *)(tag + 1))[0];
+		dport = ((u_int16_t *)(tag + 1))[1];
+	}
+#endif
 
 	/*
 	 * Find the SA and (indirectly) call the appropriate
@@ -187,12 +204,12 @@
 	s = splsoftnet();
 
 	/* NB: only pass dst since key_allocsa follows RFC2401 */
-	sav = KEY_ALLOCSA(&dst_address, sproto, spi);
+	sav = KEY_ALLOCSA(&dst_address, sproto, spi, sport, dport);
 	if (sav == NULL) {
 		DPRINTF(("ipsec_common_input: no key association found for"
-			  " SA %s/%08lx/%u\n",
+			  " SA %s/%08lx/%u/%u\n",
 			  ipsec_address(&dst_address),
-			  (u_long) ntohl(spi), sproto));
+			  (u_long) ntohl(spi), sproto, ntohs(dport)));
 		IPSEC_ISTAT(sproto, espstat.esps_notdb, ahstat.ahs_notdb,
 		    ipcompstat.ipcomps_notdb);
 		splx(s);
Index: netipsec/ipsec_netbsd.c
===================================================================
RCS file: /cvsroot/src/sys/netipsec/ipsec_netbsd.c,v
retrieving revision 1.26
diff -u -r1.26 ipsec_netbsd.c
--- netipsec/ipsec_netbsd.c	11 Apr 2007 22:21:41 -0000	1.26
+++ netipsec/ipsec_netbsd.c	19 Jun 2007 20:59:58 -0000
@@ -112,7 +112,7 @@
 		 */
 		ah = (struct ah *)((char *)ip + (ip->ip_hl << 2));
 		sav = KEY_ALLOCSA((const union sockaddr_union *)sa,
-					   	IPPROTO_AH, ah->ah_spi);
+					   	IPPROTO_AH, ah->ah_spi, 0, 0);
 
 		if (sav) {
         	if (sav->state == SADB_SASTATE_MATURE ||
@@ -163,7 +163,7 @@
 		 */
 		esp = (struct esp *)((char *)ip + (ip->ip_hl << 2));
 		sav = KEY_ALLOCSA((const union sockaddr_union *)sa,
-					   	IPPROTO_ESP, esp->esp_spi);
+					   	IPPROTO_ESP, esp->esp_spi, 0, 0);
 
 		if (sav) {
         	if (sav->state == SADB_SASTATE_MATURE ||
@@ -249,7 +249,7 @@
                         * to the address in the ICMP message payload.
                         */
                        sav = KEY_ALLOCSA((const union sockaddr_union*)sa,
-                                         IPPROTO_AH, ahp->ah_spi);
+                                         IPPROTO_AH, ahp->ah_spi, 0, 0);
 
                        if (sav) {
                                if (sav->state == SADB_SASTATE_MATURE ||
@@ -357,7 +357,7 @@
 			 */
 
 			sav = KEY_ALLOCSA((const union sockaddr_union*)sa,
-					  IPPROTO_ESP, espp->esp_spi);
+					  IPPROTO_ESP, espp->esp_spi, 0, 0);
 
 			if (sav) {
 				if (sav->state == SADB_SASTATE_MATURE ||
Index: netipsec/ipsec_output.c
===================================================================
RCS file: /cvsroot/src/sys/netipsec/ipsec_output.c,v
retrieving revision 1.21
diff -u -r1.21 ipsec_output.c
--- netipsec/ipsec_output.c	10 Feb 2007 09:43:05 -0000	1.21
+++ netipsec/ipsec_output.c	19 Jun 2007 20:59:59 -0000
@@ -72,6 +72,9 @@
 #ifdef INET6
 #include <netinet/icmp6.h>
 #endif
+#ifdef IPSEC_NAT_T
+#include <netinet/udp.h>
+#endif
 
 #include <netipsec/ipsec.h>
 #include <netipsec/ipsec_var.h>
@@ -99,6 +102,18 @@
 	struct secasvar *sav;
 	struct secasindex *saidx;
 	int error;
+#ifdef INET
+	struct ip * ip;
+#endif /* INET */
+#ifdef INET6
+	struct ip6_hdr * ip6;
+#endif /* INET6 */
+#ifdef IPSEC_NAT_T
+	struct mbuf * mo;
+	struct udphdr *udp = NULL;
+	uint64_t * data = NULL;
+	int hlen, roff;
+#endif /* IPSEC_NAT_T */
 
 	IPSEC_SPLASSERT_SOFTNET("ipsec_process_done");
 
@@ -109,11 +124,57 @@
 	IPSEC_ASSERT(sav->sah != NULL, ("ipsec_process_done: null SAH"));
 
 	saidx = &sav->sah->saidx;
+
+#ifdef IPSEC_NAT_T
+	if(sav->natt_type != 0) {
+		ip = mtod(m, struct ip *);
+
+		hlen = sizeof(struct udphdr);
+		if (sav->natt_type == UDP_ENCAP_ESPINUDP_NON_IKE) 
+			hlen += sizeof(uint64_t);
+
+		mo = m_makespace(m, sizeof(struct ip), hlen, &roff);
+		if (mo == NULL) {
+			DPRINTF(("ipsec_process_done : failed to inject" 
+				 "%u byte UDP for SA %s/%08lx\n",
+					 hlen, ipsec_address(&saidx->dst),
+					 (u_long) ntohl(sav->spi)));
+			error = ENOBUFS;
+			goto bad;
+		}
+		
+		udp = (struct udphdr*) (mtod(mo, char*) + roff);
+		data = (uint64_t*) (udp + 1);
+
+		if (sav->natt_type == UDP_ENCAP_ESPINUDP_NON_IKE)
+			*data = 0; /* NON-IKE Marker */
+
+		if (sav->natt_type == UDP_ENCAP_ESPINUDP_NON_IKE)
+			udp->uh_sport = htons(UDP_ENCAP_ESPINUDP_PORT);
+		else
+			udp->uh_sport = key_portfromsaddr(&saidx->src);
+		
+		udp->uh_dport = key_portfromsaddr(&saidx->dst);
+		udp->uh_sum = 0;
+#ifdef _IP_VHL
+        	udp->uh_ulen = htons(m->m_pkthdr.len - 
+				    (IP_VHL_HL(ip->ip_vhl) << 2));
+#else
+        	udp->uh_ulen = htons(m->m_pkthdr.len - (ip->ip_hl << 2));
+#endif
+	}
+#endif /* IPSEC_NAT_T */
+	
 	switch (saidx->dst.sa.sa_family) {
 #ifdef INET
 	case AF_INET:
 		/* Fix the header length, for AH processing. */
-		mtod(m, struct ip *)->ip_len = htons(m->m_pkthdr.len);
+		ip = mtod(m, struct ip *);
+		ip->ip_len = htons(m->m_pkthdr.len);
+#ifdef IPSEC_NAT_T
+		if (sav->natt_type != 0)
+			ip->ip_p = IPPROTO_UDP;
+#endif /* IPSEC_NAT_T */
 		break;
 #endif /* INET */
 #ifdef INET6
@@ -128,8 +189,12 @@
 			error = ENXIO;	/*?*/
 			goto bad;
 		}
-		mtod(m, struct ip6_hdr *)->ip6_plen =
-			htons(m->m_pkthdr.len - sizeof(struct ip6_hdr));
+		ip6 = mtod(m, struct ip6_hdr *);
+		ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(struct ip6_hdr));
+#ifdef IPSEC_NAT_T
+		if (sav->natt_type != 0)
+			ip6->ip6_nxt = IPPROTO_UDP;
+#endif /* IPSEC_NAT_T */
 		break;
 #endif /* INET6 */
 	default:
@@ -190,7 +255,6 @@
 	 */
 	switch (saidx->dst.sa.sa_family) {
 #ifdef INET
-	struct ip *ip;
 	case AF_INET:
 		ip = mtod(m, struct ip *);
 #ifdef __FreeBSD__
Index: netipsec/key.c
===================================================================
RCS file: /cvsroot/src/sys/netipsec/key.c,v
retrieving revision 1.47
diff -u -r1.47 key.c
--- netipsec/key.c	8 May 2007 14:03:05 -0000	1.47
+++ netipsec/key.c	19 Jun 2007 21:00:01 -0000
@@ -1,7 +1,7 @@
 /*	$NetBSD: key.c,v 1.47 2007/05/08 14:03:05 degroote Exp $	*/
 /*	$FreeBSD: src/sys/netipsec/key.c,v 1.3.2.3 2004/02/14 22:23:23 bms Exp $	*/
 /*	$KAME: key.c,v 1.191 2001/06/27 10:46:49 sakane Exp $	*/
-
+	
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
  * All rights reserved.
@@ -353,16 +353,10 @@
  * set parameters into secasindex buffer.
  * Must allocate secasindex buffer before calling this function.
  */
-#define KEY_SETSECASIDX(p, m, r, s, d, idx) \
-do { \
-	bzero((idx), sizeof(struct secasindex));                             \
-	(idx)->proto = (p);                                                  \
-	(idx)->mode = (m);                                                   \
-	(idx)->reqid = (r);                                                  \
-	bcopy((s), &(idx)->src, ((const struct sockaddr *)(s))->sa_len);     \
-	bcopy((d), &(idx)->dst, ((const struct sockaddr *)(d))->sa_len);     \
-} while (0)
-
+static int 
+key_setsecasidx __P((int, int, int, const struct sadb_address *, 
+		     const struct sadb_address *, struct secasindex *));
+	
 /* key statistics */
 struct _keystat {
 	u_long getspi_count; /* the avarage of count to try to get new SPI */
@@ -399,6 +393,10 @@
 	const struct sadb_msghdr *));
 static struct mbuf * key_setspddump __P((int *errorp, pid_t));
 static struct mbuf * key_setspddump_chain __P((int *errorp, int *lenp, pid_t pid));
+#ifdef IPSEC_NAT_T
+static int key_nat_map __P((struct socket *, struct mbuf *,
+	const struct sadb_msghdr *));
+#endif
 static struct mbuf *key_setdumpsp __P((struct secpolicy *,
 	u_int8_t, u_int32_t, pid_t));
 static u_int key_getspreqmsglen __P((struct secpolicy *));
@@ -419,6 +417,12 @@
 static int key_mature __P((struct secasvar *));
 static struct mbuf *key_setdumpsa __P((struct secasvar *, u_int8_t,
 	u_int8_t, u_int32_t, u_int32_t));
+#ifdef IPSEC_NAT_T
+static struct mbuf *key_setsadbxport __P((u_int16_t, u_int16_t));
+static struct mbuf *key_setsadbxtype __P((u_int16_t));
+#endif
+static void key_porttosaddr __P((union sockaddr_union *, u_int16_t));
+static int key_checksalen __P((const union sockaddr_union *));
 static struct mbuf *key_setsadbmsg __P((u_int8_t, u_int16_t, u_int8_t,
 	u_int32_t, pid_t, u_int16_t));
 static struct mbuf *key_setsadbsa __P((struct secasvar *));
@@ -454,6 +458,10 @@
 	const struct sadb_msghdr *));
 static u_int32_t key_do_getnewspi __P((struct sadb_spirange *,
 					struct secasindex *));
+#ifdef IPSEC_NAT_T
+static int key_handle_natt_info __P((struct secasvar *, 
+				     const struct sadb_msghdr *));
+#endif
 static int key_update __P((struct socket *, struct mbuf *,
 	const struct sadb_msghdr *));
 #ifdef IPSEC_DOSEQCHECK
@@ -1037,24 +1045,34 @@
  * Note that, however, we do need to keep source address in IPsec SA.
  * IKE specification and PF_KEY specification do assume that we
  * keep source address in IPsec SA.  We see a tricky situation here.
+ *
+ * sport and dport are used for NAT-T. network order is always used.
  */
 struct secasvar *
 key_allocsa(
 	const union sockaddr_union *dst,
 	u_int proto,
 	u_int32_t spi,
+	u_int16_t sport,
+	u_int16_t dport,
 	const char* where, int tag)
 {
 	struct secashead *sah;
 	struct secasvar *sav;
 	u_int stateidx, state;
 	int s;
+	int chkport = 0;
 
 	int must_check_spi = 1;
 	int must_check_alg = 0;
 	u_int16_t cpi = 0;
 	u_int8_t algo = 0;
 
+#ifdef IPSEC_NAT_T
+	if ((sport != 0) && (dport != 0))
+		chkport = 1;
+#endif
+
 	IPSEC_ASSERT(dst != NULL, ("key_allocsa: null dst address"));
 
 	KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
@@ -1108,12 +1126,16 @@
 					continue;
 
 #if 0	/* don't check src */
+	/* Fix port in src->sa */
+				
 				/* check src address */
 				if (key_sockaddrcmp(&src->sa, &sav->sah->saidx.src.sa, 0) != 0)
 					continue;
 #endif
+				/* fix port of dst address XXX*/
+				key_porttosaddr(__UNCONST(dst), dport);
 				/* check dst address */
-				if (key_sockaddrcmp(&dst->sa, &sav->sah->saidx.dst.sa, 0) != 0)
+				if (key_sockaddrcmp(&dst->sa, &sav->sah->saidx.dst.sa, chkport) != 0)
 					continue;
 				SA_ADDREF(sav);
 				goto done;
@@ -2546,6 +2568,68 @@
 	return error;
 }
 
+#ifdef IPSEC_NAT_T
+/*
+ * SADB_X_NAT_T_NEW_MAPPING. Unused by racoon as of 2005/04/23
+ */
+static int
+key_nat_map(so, m, mhp)
+	struct socket *so;
+	struct mbuf *m;
+	const struct sadb_msghdr *mhp;
+{
+	struct sadb_x_nat_t_type *type;
+	struct sadb_x_nat_t_port *sport;
+	struct sadb_x_nat_t_port *dport;
+	struct sadb_address *addr;
+	struct sadb_x_nat_t_frag *frag;
+
+	/* sanity check */
+	if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL)
+		panic("key_nat_map: NULL pointer is passed.");
+
+	if (mhp->ext[SADB_X_EXT_NAT_T_TYPE] == NULL ||
+		mhp->ext[SADB_X_EXT_NAT_T_SPORT] == NULL ||
+		mhp->ext[SADB_X_EXT_NAT_T_DPORT] == NULL) {
+		ipseclog((LOG_DEBUG, "key_nat_map: invalid message.\n"));
+		return key_senderror(so, m, EINVAL);
+	}
+	if ((mhp->extlen[SADB_X_EXT_NAT_T_TYPE] < sizeof(*type)) ||
+		(mhp->extlen[SADB_X_EXT_NAT_T_SPORT] < sizeof(*sport)) ||
+		(mhp->extlen[SADB_X_EXT_NAT_T_DPORT] < sizeof(*dport))) {
+		ipseclog((LOG_DEBUG, "key_nat_map: invalid message.\n"));
+		return key_senderror(so, m, EINVAL);
+	}
+
+	if ((mhp->ext[SADB_X_EXT_NAT_T_OA] != NULL) &&
+		(mhp->extlen[SADB_X_EXT_NAT_T_OA] < sizeof(*addr))) {
+		ipseclog((LOG_DEBUG, "key_nat_map: invalid message\n"));
+		return key_senderror(so, m, EINVAL);
+	}
+
+	if ((mhp->ext[SADB_X_EXT_NAT_T_FRAG] != NULL) &&
+		(mhp->extlen[SADB_X_EXT_NAT_T_FRAG] < sizeof(*frag))) {
+		ipseclog((LOG_DEBUG, "key_nat_map: invalid message\n"));
+		return key_senderror(so, m, EINVAL);
+	}
+
+	type = (struct sadb_x_nat_t_type *)mhp->ext[SADB_X_EXT_NAT_T_TYPE];
+	sport = (struct sadb_x_nat_t_port *)mhp->ext[SADB_X_EXT_NAT_T_SPORT];
+	dport = (struct sadb_x_nat_t_port *)mhp->ext[SADB_X_EXT_NAT_T_DPORT];
+	addr = (struct sadb_address *)mhp->ext[SADB_X_EXT_NAT_T_OA];
+	frag = (struct sadb_x_nat_t_frag *) mhp->ext[SADB_X_EXT_NAT_T_FRAG];
+
+	printf("sadb_nat_map called\n");
+
+	/*
+	 * XXX handle that, it should also contain a SA, or anything
+	 * that enable to update the SA information.
+	 */
+
+	return 0;
+}
+#endif /* IPSEC_NAT_T */
+
 static struct mbuf *
 key_setdumpsp(sp, type, seq, pid)
 	struct secpolicy *sp;
@@ -3128,6 +3212,10 @@
 	sav->tdb_encalgxform = NULL;	/* encoding algorithm */
 	sav->tdb_authalgxform = NULL;	/* authentication algorithm */
 	sav->tdb_compalgxform = NULL;	/* compression algorithm */
+#ifdef IPSEC_NAT_T
+	sav->natt_type = 0;
+	sav->esp_frag = 0;
+#endif
 
 	/* SA */
 	if (mhp->ext[SADB_EXT_SA] != NULL) {
@@ -3463,6 +3551,12 @@
 		SADB_EXT_ADDRESS_DST, SADB_EXT_ADDRESS_PROXY, SADB_EXT_KEY_AUTH,
 		SADB_EXT_KEY_ENCRYPT, SADB_EXT_IDENTITY_SRC,
 		SADB_EXT_IDENTITY_DST, SADB_EXT_SENSITIVITY,
+#ifdef IPSEC_NAT_T
+		SADB_X_EXT_NAT_T_TYPE, SADB_X_EXT_NAT_T_SPORT,
+		SADB_X_EXT_NAT_T_DPORT, SADB_X_EXT_NAT_T_OA,
+		SADB_X_EXT_NAT_T_FRAG,
+#endif
+
 	};
 
 	m = key_setsadbmsg(type, 0, satype, seq, pid, sav->refcnt);
@@ -3539,6 +3633,31 @@
 			p = sav->lft_s;
 			break;
 
+#ifdef IPSEC_NAT_T
+		case SADB_X_EXT_NAT_T_TYPE:
+			if ((m = key_setsadbxtype(sav->natt_type)) == NULL)
+				goto fail;
+			break;
+		
+		case SADB_X_EXT_NAT_T_DPORT:
+			if ((m = key_setsadbxport(
+				key_portfromsaddr(&sav->sah->saidx.dst),
+				SADB_X_EXT_NAT_T_DPORT)) == NULL)
+				goto fail;
+			break;
+
+		case SADB_X_EXT_NAT_T_SPORT:
+			if ((m = key_setsadbxport(
+				key_portfromsaddr(&sav->sah->saidx.src),
+				SADB_X_EXT_NAT_T_SPORT)) == NULL)
+				goto fail;
+			break;
+
+		case SADB_X_EXT_NAT_T_OA:
+		case SADB_X_EXT_NAT_T_FRAG:
+			continue;
+#endif
+
 		case SADB_EXT_ADDRESS_PROXY:
 		case SADB_EXT_IDENTITY_SRC:
 		case SADB_EXT_IDENTITY_DST:
@@ -3592,6 +3711,155 @@
 	return NULL;
 }
 
+
+#ifdef IPSEC_NAT_T
+/*
+ * set a type in sadb_x_nat_t_type
+ */
+static struct mbuf *
+key_setsadbxtype(type)
+	u_int16_t type;
+{
+	struct mbuf *m;
+	size_t len;
+	struct sadb_x_nat_t_type *p;
+
+	len = PFKEY_ALIGN8(sizeof(struct sadb_x_nat_t_type));
+
+	m = key_alloc_mbuf(len);
+	if (!m || m->m_next) {	/*XXX*/
+		if (m)
+			m_freem(m);
+		return NULL;
+	}
+
+	p = mtod(m, struct sadb_x_nat_t_type *);
+
+	bzero(p, len);
+	p->sadb_x_nat_t_type_len = PFKEY_UNIT64(len);
+	p->sadb_x_nat_t_type_exttype = SADB_X_EXT_NAT_T_TYPE;
+	p->sadb_x_nat_t_type_type = type;
+
+	return m;
+}
+/*
+ * set a port in sadb_x_nat_t_port. port is in network order
+ */
+static struct mbuf *
+key_setsadbxport(port, type)
+	u_int16_t port;
+	u_int16_t type;
+{
+	struct mbuf *m;
+	size_t len;
+	struct sadb_x_nat_t_port *p;
+
+	len = PFKEY_ALIGN8(sizeof(struct sadb_x_nat_t_port));
+
+	m = key_alloc_mbuf(len);
+	if (!m || m->m_next) {	/*XXX*/
+		if (m)
+			m_freem(m);
+		return NULL;
+	}
+
+	p = mtod(m, struct sadb_x_nat_t_port *);
+
+	bzero(p, len);
+	p->sadb_x_nat_t_port_len = PFKEY_UNIT64(len);
+	p->sadb_x_nat_t_port_exttype = type;
+	p->sadb_x_nat_t_port_port = port;
+
+	return m;
+}
+
+/* 
+ * Get port from sockaddr, port is in network order
+ */
+u_int16_t 
+key_portfromsaddr(saddr)
+	const union sockaddr_union *saddr;
+{
+	u_int16_t port;
+
+	switch (saddr->sa.sa_family) {
+	case AF_INET: {
+		port = saddr->sin.sin_port;
+		break;
+	}
+#ifdef INET6
+	case AF_INET6: {
+		port = saddr->sin6.sin6_port;
+		break;
+	}
+#endif
+	default:
+		printf("key_portfromsaddr: unexpected address family\n");
+		port = 0;
+		break;
+	}
+
+	return port;
+}
+
+#endif /* IPSEC_NAT_T */
+
+/*
+ * Set port is struct sockaddr. port is in network order
+ */
+static void
+key_porttosaddr(saddr, port)
+	union sockaddr_union *saddr;
+	u_int16_t port;
+{
+	switch (saddr->sa.sa_family) {
+	case AF_INET: {
+		saddr->sin.sin_port = port;
+		break;
+	}
+#ifdef INET6
+	case AF_INET6: {
+		saddr->sin6.sin6_port = port;
+		break;
+	}
+#endif
+	default:
+		printf("key_porttosaddr: unexpected address family %d\n", 
+			saddr->sa.sa_family);
+		break;
+	}
+
+	return;
+}
+
+/*
+ * Safety check sa_len 
+ */
+static int
+key_checksalen(saddr)
+        const union sockaddr_union *saddr;
+{
+        switch (saddr->sa.sa_family) {
+        case AF_INET:
+                if (saddr->sa.sa_len != sizeof(struct sockaddr_in))
+                        return -1;
+                break;
+#ifdef INET6
+        case AF_INET6:
+                if (saddr->sa.sa_len != sizeof(struct sockaddr_in6))
+                        return -1;
+                break;
+#endif
+        default:
+                printf("key_checksalen: unexpected sa_family %d\n",
+                    saddr->sa.sa_family);
+                return -1;
+                break;
+        }
+	return 0;
+}
+
+
 /*
  * set data into sadb_msg.
  */
@@ -3961,6 +4229,8 @@
 	const struct secasindex *saidx1,
 	int flag)
 {
+	int chkport = 0;
+
 	/* sanity */
 	if (saidx0 == NULL && saidx1 == NULL)
 		return 1;
@@ -3998,10 +4268,20 @@
 				return 0;
 		}
 
-		if (key_sockaddrcmp(&saidx0->src.sa, &saidx1->src.sa, 0) != 0) {
+	/*
+	 * If NAT-T is enabled, check ports for tunnel mode.
+	 * Don't do it for transport mode, as there is no
+	 * port information available in the SP.
+	 */
+#ifdef IPSEC_NAT_T
+	if (saidx1->mode == IPSEC_MODE_TUNNEL)
+		chkport = 1;
+#endif
+
+		if (key_sockaddrcmp(&saidx0->src.sa, &saidx1->src.sa, chkport) != 0) {
 			return 0;
 		}
-		if (key_sockaddrcmp(&saidx0->dst.sa, &saidx1->dst.sa, 0) != 0) {
+		if (key_sockaddrcmp(&saidx0->dst.sa, &saidx1->dst.sa, chkport) != 0) {
 			return 0;
 		}
 	}
@@ -4597,6 +4877,40 @@
 	/* NOTREACHED */
 }
 
+static int 
+key_setsecasidx(proto, mode, reqid, src, dst, saidx)
+	int proto;
+	int mode;
+	int reqid;
+	const struct sadb_address * src;
+	const struct sadb_address * dst;
+	struct secasindex * saidx;
+{
+	const union sockaddr_union * src_u = 
+		(const union sockaddr_union *) src;
+	const union sockaddr_union * dst_u =
+		(const union sockaddr_union *) dst;  
+
+	/* sa len safety check */
+	if (key_checksalen(src_u) != 0)
+		return -1;
+	if (key_checksalen(dst_u) != 0)
+		return -1;
+	
+	memset(saidx, 0, sizeof(*saidx));
+	saidx->proto = proto;
+	saidx->mode = mode;
+	saidx->reqid = reqid;
+	memcpy(&saidx->src, src_u, src_u->sa.sa_len);
+	memcpy(&saidx->dst, dst_u, dst_u->sa.sa_len);
+
+#ifndef IPSEC_NAT_T
+	key_porttosaddr(&((saidx)->src),0);				     \
+	key_porttosaddr(&((saidx)->dst),0);
+#endif
+	return 0;
+}
+
 /* %%% PF_KEY */
 /*
  * SADB_GETSPI processing is to receive
@@ -4657,42 +4971,10 @@
 		return key_senderror(so, m, EINVAL);
 	}
 
-	/* make sure if port number is zero. */
-	switch (((struct sockaddr *)(src0 + 1))->sa_family) {
-	case AF_INET:
-		if (((struct sockaddr *)(src0 + 1))->sa_len !=
-		    sizeof(struct sockaddr_in))
-			return key_senderror(so, m, EINVAL);
-		((struct sockaddr_in *)(src0 + 1))->sin_port = 0;
-		break;
-	case AF_INET6:
-		if (((struct sockaddr *)(src0 + 1))->sa_len !=
-		    sizeof(struct sockaddr_in6))
-			return key_senderror(so, m, EINVAL);
-		((struct sockaddr_in6 *)(src0 + 1))->sin6_port = 0;
-		break;
-	default:
-		; /*???*/
-	}
-	switch (((struct sockaddr *)(dst0 + 1))->sa_family) {
-	case AF_INET:
-		if (((struct sockaddr *)(dst0 + 1))->sa_len !=
-		    sizeof(struct sockaddr_in))
-			return key_senderror(so, m, EINVAL);
-		((struct sockaddr_in *)(dst0 + 1))->sin_port = 0;
-		break;
-	case AF_INET6:
-		if (((struct sockaddr *)(dst0 + 1))->sa_len !=
-		    sizeof(struct sockaddr_in6))
-			return key_senderror(so, m, EINVAL);
-		((struct sockaddr_in6 *)(dst0 + 1))->sin6_port = 0;
-		break;
-	default:
-		; /*???*/
-	}
 
-	/* XXX boundary check against sa_len */
-	KEY_SETSECASIDX(proto, mode, reqid, src0 + 1, dst0 + 1, &saidx);
+	if ((error = key_setsecasidx(proto, mode, reqid, src0 + 1, 
+				     dst0 + 1, &saidx)) != 0)
+		return key_senderror(so, m, EINVAL);
 
 	/* SPI allocation */
 	spi = key_do_getnewspi((struct sadb_spirange *)mhp->ext[SADB_EXT_SPIRANGE],
@@ -4872,6 +5154,76 @@
 	return newspi;
 }
 
+#ifdef IPSEC_NAT_T
+/* Handle IPSEC_NAT_T info if present */
+static int
+key_handle_natt_info(sav,mhp)
+	struct secasvar *sav;
+	const struct sadb_msghdr *mhp;
+{
+
+	if (mhp->ext[SADB_X_EXT_NAT_T_OA] != NULL)
+		printf("update: NAT-T OA present\n");
+
+	if ((mhp->ext[SADB_X_EXT_NAT_T_TYPE] != NULL) &&
+	    (mhp->ext[SADB_X_EXT_NAT_T_SPORT] != NULL) &&
+	    (mhp->ext[SADB_X_EXT_NAT_T_DPORT] != NULL)) {
+		struct sadb_x_nat_t_type *type;
+		struct sadb_x_nat_t_port *sport;
+		struct sadb_x_nat_t_port *dport;
+		struct sadb_address *addr;
+		struct sadb_x_nat_t_frag *frag;
+
+		if ((mhp->extlen[SADB_X_EXT_NAT_T_TYPE] < sizeof(*type)) ||
+		    (mhp->extlen[SADB_X_EXT_NAT_T_SPORT] < sizeof(*sport)) ||
+		    (mhp->extlen[SADB_X_EXT_NAT_T_DPORT] < sizeof(*dport))) {
+			ipseclog((LOG_DEBUG, "key_update: "
+			    "invalid message.\n"));
+			return -1;
+		}
+
+		if ((mhp->ext[SADB_X_EXT_NAT_T_OA] != NULL) &&
+		    (mhp->extlen[SADB_X_EXT_NAT_T_OA] < sizeof(*addr))) {
+			ipseclog((LOG_DEBUG, "key_update: invalid message\n"));
+			return -1;
+		}
+
+		if ((mhp->ext[SADB_X_EXT_NAT_T_FRAG] != NULL) &&
+		    (mhp->extlen[SADB_X_EXT_NAT_T_FRAG] < sizeof(*frag))) {
+			ipseclog((LOG_DEBUG, "key_update: invalid message\n"));
+			return -1;
+		}
+
+		type = (struct sadb_x_nat_t_type *)
+		    mhp->ext[SADB_X_EXT_NAT_T_TYPE];
+		sport = (struct sadb_x_nat_t_port *)
+		    mhp->ext[SADB_X_EXT_NAT_T_SPORT];
+		dport = (struct sadb_x_nat_t_port *)
+		    mhp->ext[SADB_X_EXT_NAT_T_DPORT];
+		addr = (struct sadb_address *)
+		    mhp->ext[SADB_X_EXT_NAT_T_OA];
+		frag = (struct sadb_x_nat_t_frag *)
+		    mhp->ext[SADB_X_EXT_NAT_T_FRAG];
+
+		if (type)
+			sav->natt_type = type->sadb_x_nat_t_type_type;
+		if (sport)
+			key_porttosaddr(&sav->sah->saidx.src, 
+			    sport->sadb_x_nat_t_port_port);
+		if (dport)
+			key_porttosaddr(&sav->sah->saidx.dst,
+			    dport->sadb_x_nat_t_port_port);
+		if (frag)
+			sav->esp_frag = frag->sadb_x_nat_t_frag_fraglen;
+		else
+			sav->esp_frag = IP_MAXPACKET;
+	}
+
+	return 0;
+}
+#endif
+
+
 /*
  * SADB_UPDATE processing
  * receive
@@ -4944,8 +5296,10 @@
 	src0 = (struct sadb_address *)(mhp->ext[SADB_EXT_ADDRESS_SRC]);
 	dst0 = (struct sadb_address *)(mhp->ext[SADB_EXT_ADDRESS_DST]);
 
-	/* XXX boundary check against sa_len */
-	KEY_SETSECASIDX(proto, mode, reqid, src0 + 1, dst0 + 1, &saidx);
+	if ((error = key_setsecasidx(proto, mode, reqid, src0 + 1, 
+				     dst0 + 1, &saidx)) != 0)
+		return key_senderror(so, m, EINVAL);
+
 
 	/* get a SA header */
 	if ((sah = key_getsah(&saidx)) == NULL) {
@@ -5013,6 +5367,11 @@
 		return key_senderror(so, m, 0);
 	}
 
+#ifdef IPSEC_NAT_T
+	if ((error = key_handle_natt_info(sav,mhp)) != 0)
+		return key_senderror(so, m, EINVAL);
+#endif /* IPSEC_NAT_T */
+
     {
 	struct mbuf *n;
 
@@ -5139,8 +5498,9 @@
 	src0 = (struct sadb_address *)mhp->ext[SADB_EXT_ADDRESS_SRC];
 	dst0 = (struct sadb_address *)mhp->ext[SADB_EXT_ADDRESS_DST];
 
-	/* XXX boundary check against sa_len */
-	KEY_SETSECASIDX(proto, mode, reqid, src0 + 1, dst0 + 1, &saidx);
+	if ((error = key_setsecasidx(proto, mode, reqid, src0 + 1,
+				     dst0 + 1, &saidx)) != 0)
+		return key_senderror(so, m, EINVAL);
 
 	/* get a SA header */
 	if ((newsah = key_getsah(&saidx)) == NULL) {
@@ -5175,6 +5535,11 @@
 		return key_senderror(so, m, error);
 	}
 
+#ifdef IPSEC_NAT_T
+	if ((error = key_handle_natt_info(newsav, mhp)) != 0)
+		return key_senderror(so, m, EINVAL);
+#endif /* IPSEC_NAT_T */
+
 	/*
 	 * don't call key_freesav() here, as we would like to keep the SA
 	 * in the database on success.
@@ -5326,6 +5691,7 @@
 	struct secashead *sah;
 	struct secasvar *sav = NULL;
 	u_int16_t proto;
+	int error;
 
 	/* sanity check */
 	if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL)
@@ -5366,8 +5732,9 @@
 	src0 = (struct sadb_address *)(mhp->ext[SADB_EXT_ADDRESS_SRC]);
 	dst0 = (struct sadb_address *)(mhp->ext[SADB_EXT_ADDRESS_DST]);
 
-	/* XXX boundary check against sa_len */
-	KEY_SETSECASIDX(proto, IPSEC_MODE_ANY, 0, src0 + 1, dst0 + 1, &saidx);
+	if ((error = key_setsecasidx(proto, IPSEC_MODE_ANY, 0, src0 + 1, 
+				     dst0 + 1, &saidx)) != 0)
+		return key_senderror(so, m, EINVAL);
 
 	/* get a SA header */
 	LIST_FOREACH(sah, &sahtree, chain) {
@@ -5428,12 +5795,14 @@
 	struct secashead *sah;
 	struct secasvar *sav, *nextsav;
 	u_int stateidx, state;
+	int error;
 
 	src0 = (struct sadb_address *)(mhp->ext[SADB_EXT_ADDRESS_SRC]);
 	dst0 = (struct sadb_address *)(mhp->ext[SADB_EXT_ADDRESS_DST]);
 
-	/* XXX boundary check against sa_len */
-	KEY_SETSECASIDX(proto, IPSEC_MODE_ANY, 0, src0 + 1, dst0 + 1, &saidx);
+	if ((error = key_setsecasidx(proto, IPSEC_MODE_ANY, 0, src0 + 1,
+				     dst0 + 1, &saidx)) != 0)
+		return key_senderror(so, m, EINVAL);
 
 	LIST_FOREACH(sah, &sahtree, chain) {
 		if (sah->state == SADB_SASTATE_DEAD)
@@ -5513,6 +5882,7 @@
 	struct secashead *sah;
 	struct secasvar *sav = NULL;
 	u_int16_t proto;
+	int error;
 
 	/* sanity check */
 	if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL)
@@ -5541,8 +5911,10 @@
 	src0 = (struct sadb_address *)mhp->ext[SADB_EXT_ADDRESS_SRC];
 	dst0 = (struct sadb_address *)mhp->ext[SADB_EXT_ADDRESS_DST];
 
-	/* XXX boundary check against sa_len */
-	KEY_SETSECASIDX(proto, IPSEC_MODE_ANY, 0, src0 + 1, dst0 + 1, &saidx);
+
+	if ((error = key_setsecasidx(proto, IPSEC_MODE_ANY, 0, src0 + 1,
+				     dst0 + 1, &saidx)) != 0)
+		return key_senderror(so, m, EINVAL);
 
 	/* get a SA header */
 	LIST_FOREACH(sah, &sahtree, chain) {
@@ -6225,8 +6597,9 @@
 	src0 = (struct sadb_address *)mhp->ext[SADB_EXT_ADDRESS_SRC];
 	dst0 = (struct sadb_address *)mhp->ext[SADB_EXT_ADDRESS_DST];
 
-	/* XXX boundary check against sa_len */
-	KEY_SETSECASIDX(proto, IPSEC_MODE_ANY, 0, src0 + 1, dst0 + 1, &saidx);
+	if ((error = key_setsecasidx(proto, IPSEC_MODE_ANY, 0, src0 + 1,
+				     dst0 + 1, &saidx)) != 0)
+		return key_senderror(so, m, EINVAL);
 
 	/* get a SA index */
 	LIST_FOREACH(sah, &sahtree, chain) {
@@ -6913,7 +7286,9 @@
 	key_spdadd,	/* SADB_X_SPDSETIDX */
 	NULL,		/* SADB_X_SPDEXPIRE */
 	key_spddelete2,	/* SADB_X_SPDDELETE2 */
-	NULL,		/* SADB_X_NAT_T_NEW_MAPPING */
+#ifdef IPSEC_NAT_T
+       key_nat_map,	/* SADB_X_NAT_T_NEW_MAPPING */
+#endif
 };
 
 /*
@@ -7255,6 +7630,13 @@
 		case SADB_EXT_SPIRANGE:
 		case SADB_X_EXT_POLICY:
 		case SADB_X_EXT_SA2:
+#ifdef IPSEC_NAT_T
+		case SADB_X_EXT_NAT_T_TYPE:
+		case SADB_X_EXT_NAT_T_SPORT:
+		case SADB_X_EXT_NAT_T_DPORT:
+		case SADB_X_EXT_NAT_T_OA:
+		case SADB_X_EXT_NAT_T_FRAG:
+#endif
 			/* duplicate check */
 			/*
 			 * XXX Are there duplication payloads of either
Index: netipsec/key.h
===================================================================
RCS file: /cvsroot/src/sys/netipsec/key.h,v
retrieving revision 1.6
diff -u -r1.6 key.h
--- netipsec/key.h	4 Mar 2007 06:03:29 -0000	1.6
+++ netipsec/key.h	19 Jun 2007 21:00:02 -0000
@@ -36,6 +36,8 @@
 
 #ifdef _KERNEL
 
+#include "opt_ipsec.h"
+
 struct secpolicy;
 struct secpolicyindex;
 struct ipsecrequest;
@@ -78,11 +80,11 @@
 	_key_freesp(spp, __FILE__, __LINE__)
 
 extern struct secasvar *key_allocsa(const union sockaddr_union *, 
-		u_int, u_int32_t,const char*, int);
+		u_int, u_int32_t, u_int16_t, u_int16_t, const char*, int);
 extern void key_freesav(struct secasvar **, const char*, int);
 
-#define	KEY_ALLOCSA(dst, proto, spi)				\
-	key_allocsa(dst, proto, spi, __FILE__, __LINE__)
+#define	KEY_ALLOCSA(dst, proto, spi, sport, dport)				\
+	key_allocsa(dst, proto, spi, sport, dport,  __FILE__, __LINE__)
 #define	KEY_FREESAV(psav)					\
 	key_freesav(psav, __FILE__, __LINE__)
 
@@ -111,6 +113,12 @@
 extern void key_sa_routechange __P((struct sockaddr *));
 extern void key_sa_stir_iv __P((struct secasvar *));
 
+#ifdef IPSEC_NAT_T
+u_int16_t key_portfromsaddr __P((const union sockaddr_union *));
+#endif
+
+
+
 #ifdef MALLOC_DECLARE
 MALLOC_DECLARE(M_SECA);
 #endif /* MALLOC_DECLARE */
Index: netipsec/keydb.h
===================================================================
RCS file: /cvsroot/src/sys/netipsec/keydb.h,v
retrieving revision 1.4
diff -u -r1.4 keydb.h
--- netipsec/keydb.h	4 Mar 2007 19:54:49 -0000	1.4
+++ netipsec/keydb.h	19 Jun 2007 21:00:02 -0000
@@ -36,6 +36,8 @@
 
 #ifdef _KERNEL
 
+#include "opt_ipsec.h"
+
 #include <netipsec/key_var.h>
 #include <net/route.h>
 #include <netinet/in.h>
@@ -125,6 +127,11 @@
 	struct auth_hash *tdb_authalgxform;	/* authentication algorithm */
 	struct comp_algo *tdb_compalgxform;	/* compression algorithm */
 	u_int64_t tdb_cryptoid;		/* crypto session id */
+
+#ifdef IPSEC_NAT_T
+	u_int16_t natt_type;
+	u_int16_t esp_frag;
+#endif
 };
 
 /* replay prevention */
Index: netipsec/xform_ah.c
===================================================================
RCS file: /cvsroot/src/sys/netipsec/xform_ah.c,v
retrieving revision 1.17
diff -u -r1.17 xform_ah.c
--- netipsec/xform_ah.c	25 Mar 2007 22:11:18 -0000	1.17
+++ netipsec/xform_ah.c	19 Jun 2007 21:00:02 -0000
@@ -794,6 +794,11 @@
 	u_int8_t nxt;
 	char *ptr;
 	int s, authsize;
+	u_int16_t dport = 0;
+	u_int16_t sport = 0;
+#ifdef IPSEC_NAT_T
+	struct m_tag * tag = NULL;
+#endif
 
 	crd = crp->crp_desc;
 
@@ -805,9 +810,18 @@
 	mtag = (struct m_tag *) tc->tc_ptr;
 	m = (struct mbuf *) crp->crp_buf;
 
+
+#ifdef IPSEC_NAT_T
+	/* find the source port for NAT-T */
+	if ((tag = m_tag_find(m, PACKET_TAG_IPSEC_NAT_T_PORTS, NULL))) {
+		sport = ((u_int16_t *)(tag + 1))[0];
+		dport = ((u_int16_t *)(tag + 1))[1];
+	}
+#endif
+
 	s = splsoftnet();
 
-	sav = KEY_ALLOCSA(&tc->tc_dst, tc->tc_proto, tc->tc_spi);
+	sav = KEY_ALLOCSA(&tc->tc_dst, tc->tc_proto, tc->tc_spi, sport, dport);
 	if (sav == NULL) {
 		ahstat.ahs_notdb++;
 		DPRINTF(("ah_input_cb: SA expired while in crypto\n"));
@@ -1208,7 +1222,7 @@
 	s = splsoftnet();
 
 	isr = tc->tc_isr;
-	sav = KEY_ALLOCSA(&tc->tc_dst, tc->tc_proto, tc->tc_spi);
+	sav = KEY_ALLOCSA(&tc->tc_dst, tc->tc_proto, tc->tc_spi, 0, 0);
 	if (sav == NULL) {
 		ahstat.ahs_notdb++;
 		DPRINTF(("ah_output_cb: SA expired while in crypto\n"));
Index: netipsec/xform_esp.c
===================================================================
RCS file: /cvsroot/src/sys/netipsec/xform_esp.c,v
retrieving revision 1.15
diff -u -r1.15 xform_esp.c
--- netipsec/xform_esp.c	4 Mar 2007 21:17:55 -0000	1.15
+++ netipsec/xform_esp.c	19 Jun 2007 21:00:02 -0000
@@ -469,6 +469,11 @@
 	struct secasvar *sav;
 	struct secasindex *saidx;
 	void *ptr;
+	u_int16_t dport = 0;
+	u_int16_t sport = 0;
+#ifdef IPSEC_NAT_T
+	struct m_tag * tag = NULL;
+#endif
 
 	crd = crp->crp_desc;
 	IPSEC_ASSERT(crd != NULL, ("esp_input_cb: null crypto descriptor!"));
@@ -480,9 +485,17 @@
 	mtag = (struct m_tag *) tc->tc_ptr;
 	m = (struct mbuf *) crp->crp_buf;
 
+#ifdef IPSEC_NAT_T
+	/* find the source port for NAT-T */
+	if ((tag = m_tag_find(m, PACKET_TAG_IPSEC_NAT_T_PORTS, NULL))) {
+		sport = ((u_int16_t *)(tag + 1))[0];
+		dport = ((u_int16_t *)(tag + 1))[1];
+	}
+#endif
+
 	s = splsoftnet();
 
-	sav = KEY_ALLOCSA(&tc->tc_dst, tc->tc_proto, tc->tc_spi);
+	sav = KEY_ALLOCSA(&tc->tc_dst, tc->tc_proto, tc->tc_spi, sport, dport);
 	if (sav == NULL) {
 		espstat.esps_notdb++;
 		DPRINTF(("esp_input_cb: SA expired while in crypto "
@@ -920,7 +933,7 @@
 	s = splsoftnet();
 
 	isr = tc->tc_isr;
-	sav = KEY_ALLOCSA(&tc->tc_dst, tc->tc_proto, tc->tc_spi);
+	sav = KEY_ALLOCSA(&tc->tc_dst, tc->tc_proto, tc->tc_spi, 0, 0);
 	if (sav == NULL) {
 		espstat.esps_notdb++;
 		DPRINTF(("esp_output_cb: SA expired while in crypto "
Index: netipsec/xform_ipcomp.c
===================================================================
RCS file: /cvsroot/src/sys/netipsec/xform_ipcomp.c,v
retrieving revision 1.13
diff -u -r1.13 xform_ipcomp.c
--- netipsec/xform_ipcomp.c	4 Mar 2007 21:17:55 -0000	1.13
+++ netipsec/xform_ipcomp.c	19 Jun 2007 21:00:02 -0000
@@ -226,6 +226,11 @@
 	int s, hlen = IPCOMP_HLENGTH, error, clen;
 	u_int8_t nproto;
 	void *addr;
+	u_int16_t dport = 0;
+	u_int16_t sport = 0;
+#ifdef IPSEC_NAT_T
+	struct m_tag * tag = NULL;
+#endif
 
 	crd = crp->crp_desc;
 
@@ -236,9 +241,17 @@
 	mtag = (struct mtag *) tc->tc_ptr;
 	m = (struct mbuf *) crp->crp_buf;
 
+#ifdef IPSEC_NAT_T
+	/* find the source port for NAT-T */
+	if ((tag = m_tag_find(m, PACKET_TAG_IPSEC_NAT_T_PORTS, NULL))) {
+		sport = ((u_int16_t *)(tag + 1))[0];
+		dport = ((u_int16_t *)(tag + 1))[1];
+	}
+#endif
+
 	s = splsoftnet();
 
-	sav = KEY_ALLOCSA(&tc->tc_dst, tc->tc_proto, tc->tc_spi);
+	sav = KEY_ALLOCSA(&tc->tc_dst, tc->tc_proto, tc->tc_spi, sport, dport);
 	if (sav == NULL) {
 		ipcompstat.ipcomps_notdb++;
 		DPRINTF(("ipcomp_input_cb: SA expired while in crypto\n"));
@@ -491,7 +504,7 @@
 	s = splsoftnet();
 
 	isr = tc->tc_isr;
-	sav = KEY_ALLOCSA(&tc->tc_dst, tc->tc_proto, tc->tc_spi);
+	sav = KEY_ALLOCSA(&tc->tc_dst, tc->tc_proto, tc->tc_spi, 0, 0);
 	if (sav == NULL) {
 		ipcompstat.ipcomps_notdb++;
 		DPRINTF(("ipcomp_output_cb: SA expired while in crypto\n"));

--X1bOJ3K7DJ5YkBrT--