Subject: None
To: None <burgess@neonramp.com, tech-net@netbsd.org>
From: Jun-ichiro itojun Hagino <itojun@iijlab.net>
List: tech-net
Date: 02/02/2001 10:49:31
	the following patch is equivalent to
	http://mail-index.netbsd.org/current-users/2001/01/23/0005.html,
	but for NetBSD 1.5.1_ALPHA (the latest code on netbsd-1-5 branch).
	it should apply much cleaner against 1.5.

	it should change:
	- ipf to only look at wire-format packet.  ipf will not touch
	  ipsec-decapsulated packet on inbound, nor packet before encapsulation
	  on outbound.
	see 
	http://www.netbsd.org/Documentation/network/ipsec/#ipf-interaction
	for more details.

itojun


Index: sys/mbuf.h
===================================================================
RCS file: /cvsroot/syssrc/sys/sys/mbuf.h,v
retrieving revision 1.49.4.2
diff -u -r1.49.4.2 mbuf.h
--- sys/mbuf.h	2000/08/30 06:23:08	1.49.4.2
+++ sys/mbuf.h	2001/02/02 01:47:22
@@ -92,11 +92,6 @@
 #define	MLEN		(MSIZE - sizeof(struct m_hdr))	/* normal data len */
 #define	MHLEN		(MLEN - sizeof(struct pkthdr))	/* data len w/pkthdr */
 
-/*
- * NOTE: MINCLSIZE is changed to MHLEN + 1, to avoid allocating chained
- * non-external mbufs in the driver.  This has no impact on performance
- * seen from the packet statistics, and avoid header pullups in network code.
- */
 #define	MINCLSIZE	(MHLEN+MLEN+1)	/* smallest amount to put in cluster */
 #define	M_MAXCOMPRESS	(MHLEN / 2)	/* max amount to copy for compression */
 
@@ -395,10 +390,18 @@
  * MFREE(struct mbuf *m, struct mbuf *n)
  * Free a single mbuf and associated external storage.
  * Place the successor, if any, in n.
+ *
+ * we do need to check non-first mbuf for m_aux, since some of existing
+ * code does not call M_PREPEND properly.
+ * (example: call to bpf_mtap from drivers)
  */
 #define	MFREE(m, n) \
 	MBUFLOCK( \
 		mbstat.m_mtypes[(m)->m_type]--; \
+		if (((m)->m_flags & M_PKTHDR) != 0 && (m)->m_pkthdr.aux) { \
+			m_freem((m)->m_pkthdr.aux); \
+			(m)->m_pkthdr.aux = NULL; \
+		} \
 		if ((m)->m_flags & M_EXT) { \
 			_MEXTREMOVE((m)); \
 		} \
Index: kern/uipc_mbuf.c
===================================================================
RCS file: /cvsroot/syssrc/sys/kern/uipc_mbuf.c,v
retrieving revision 1.45.4.1
diff -u -r1.45.4.1 uipc_mbuf.c
--- kern/uipc_mbuf.c	2000/08/19 07:55:31	1.45.4.1
+++ kern/uipc_mbuf.c	2001/02/02 01:47:24
@@ -350,10 +350,6 @@
 
 	if (m == NULL)
 		return;
-	if ((m->m_flags & M_PKTHDR) != 0 && m->m_pkthdr.aux) {
-		m_freem(m->m_pkthdr.aux);
-		m->m_pkthdr.aux = NULL;
-	}
 	do {
 		MFREE(m, n);
 		m = n;
Index: netinet/ip_icmp.c
===================================================================
RCS file: /cvsroot/syssrc/sys/netinet/ip_icmp.c,v
retrieving revision 1.47.2.3
diff -u -r1.47.2.3 ip_icmp.c
--- netinet/ip_icmp.c	2000/08/16 01:22:22	1.47.2.3
+++ netinet/ip_icmp.c	2001/02/02 01:47:26
@@ -808,7 +808,7 @@
 #endif
 #ifdef IPSEC
 	/* Don't lookup socket */
-	ipsec_setsocket(m, NULL);
+	(void)ipsec_setsocket(m, NULL);
 #endif
 	(void) ip_output(m, opts, NULL, 0, NULL);
 }
Index: netinet/ip_input.c
===================================================================
RCS file: /cvsroot/syssrc/sys/netinet/ip_input.c,v
retrieving revision 1.114.4.3
diff -u -r1.114.4.3 ip_input.c
--- netinet/ip_input.c	2000/10/17 00:59:49	1.114.4.3
+++ netinet/ip_input.c	2001/02/02 01:47:29
@@ -459,6 +459,14 @@
 #endif
 
 #ifdef PFIL_HOOKS
+#ifdef IPSEC
+	/*
+	 * let ipfilter look at packet on the wire,
+	 * not the decapsulated packet.
+	 */
+	if (ipsec_gethist(m, NULL))
+		goto nofilt;
+#endif
 	/*
 	 * Run through list of hooks for input packets.  If there are any
 	 * filters which require that additional packets in the flow are
@@ -479,6 +487,9 @@
 				return;
 			ip = mtod(m, struct ip *);
 		}
+#ifdef IPSEC
+nofilt:;
+#endif
 #endif /* PFIL_HOOKS */
 
 	/*
@@ -1439,7 +1450,7 @@
 
 #ifdef IPSEC
 	/* Don't lookup socket in forwading case */
-	ipsec_setsocket(m, NULL);
+	(void)ipsec_setsocket(m, NULL);
 #endif
 	error = ip_output(m, (struct mbuf *)0, &ipforward_rt,
 	    (IP_FORWARDING | (ip_directedbcast ? IP_ALLOWBROADCAST : 0)), 0);
Index: netinet/ip_mroute.c
===================================================================
RCS file: /cvsroot/syssrc/sys/netinet/ip_mroute.c,v
retrieving revision 1.50
diff -u -r1.50 ip_mroute.c
--- netinet/ip_mroute.c	2000/04/19 06:30:55	1.50
+++ netinet/ip_mroute.c	2001/02/02 01:47:32
@@ -1690,7 +1690,7 @@
 		/* If tunnel options */
 #ifdef IPSEC
 		/* Don't lookup socket in forwading case */
-		ipsec_setsocket(m, NULL);
+		(void)ipsec_setsocket(m, NULL);
 #endif
 		ip_output(m, (struct mbuf *)0, &vifp->v_route,
 			  IP_FORWARDING, (struct ip_moptions *)0);
@@ -1707,7 +1707,7 @@
 
 #ifdef IPSEC
 		/* Don't lookup socket in forwading case */
-		ipsec_setsocket(m, NULL);
+		(void)ipsec_setsocket(m, NULL);
 #endif
 		error = ip_output(m, (struct mbuf *)0, (struct route *)0,
 				  IP_FORWARDING|IP_MULTICASTOPTS, &imo);
Index: netinet/ip_output.c
===================================================================
RCS file: /cvsroot/syssrc/sys/netinet/ip_output.c,v
retrieving revision 1.74
diff -u -r1.74 ip_output.c
--- netinet/ip_output.c	2000/05/10 03:31:30	1.74
+++ netinet/ip_output.c	2001/02/02 01:47:35
@@ -204,7 +204,7 @@
 
 #ifdef IPSEC
 	so = ipsec_getsocket(m);
-	ipsec_setsocket(m, NULL);
+	(void)ipsec_setsocket(m, NULL);
 #endif /*IPSEC*/
 
 #ifdef	DIAGNOSTIC
@@ -417,26 +417,6 @@
 		m->m_flags &= ~M_BCAST;
 
 sendit:
-#ifdef PFIL_HOOKS
-	/*
-	 * Run through list of hooks for output packets.
-	 */
-	m1 = m;
-	pfh = pfil_hook_get(PFIL_OUT, &inetsw[ip_protox[IPPROTO_IP]].pr_pfh);
-	for (; pfh; pfh = pfh->pfil_link.tqe_next)
-		if (pfh->pfil_func) {
-		    	rv = pfh->pfil_func(ip, hlen, ifp, 1, &m1);
-			if (rv) {
-				error = EHOSTUNREACH;
-				goto done;
-			}
-			m = m1;
-			if (m == NULL)
-				goto done;
-			ip = mtod(m, struct ip *);
-		}
-#endif /* PFIL_HOOKS */
-
 #ifdef IPSEC
 	/* get SP for this packet */
 	if (so == NULL)
@@ -556,6 +536,26 @@
 skip_ipsec:
 #endif /*IPSEC*/
 
+#ifdef PFIL_HOOKS
+	/*
+	 * Run through list of hooks for output packets.
+	 */
+	m1 = m;
+	pfh = pfil_hook_get(PFIL_OUT, &inetsw[ip_protox[IPPROTO_IP]].pr_pfh);
+	for (; pfh; pfh = pfh->pfil_link.tqe_next)
+		if (pfh->pfil_func) {
+		    	rv = pfh->pfil_func(ip, hlen, ifp, 1, &m1);
+			if (rv) {
+				error = EHOSTUNREACH;
+				goto done;
+			}
+			m = m1;
+			if (m == NULL)
+				goto done;
+			ip = mtod(m, struct ip *);
+		}
+#endif /* PFIL_HOOKS */
+
 	/*
 	 * If small enough for mtu of path, can just send directly.
 	 */
@@ -577,6 +577,10 @@
 		HTONS(ip->ip_off);
 		ip->ip_sum = 0;
 		ip->ip_sum = in_cksum(m, hlen);
+#ifdef IPSEC
+		/* clean ipsec history once it goes out of the node */
+		ipsec_delaux(m);
+#endif
 		error = (*ifp->if_output)(ifp, m, sintosa(dst), ro->ro_rt);
 		goto done;
 	}
@@ -700,6 +704,10 @@
 				ia->ia_ifa.ifa_data.ifad_outbytes +=
 					ntohs(ip->ip_len);
 			}
+#endif
+#ifdef IPSEC
+			/* clean ipsec history once it goes out of the node */
+			ipsec_delaux(m);
 #endif
 			error = (*ifp->if_output)(ifp, m, sintosa(dst),
 			    ro->ro_rt);
Index: netinet/raw_ip.c
===================================================================
RCS file: /cvsroot/syssrc/sys/netinet/raw_ip.c,v
retrieving revision 1.53
diff -u -r1.53 raw_ip.c
--- netinet/raw_ip.c	2000/03/30 13:25:04	1.53
+++ netinet/raw_ip.c	2001/02/02 01:47:36
@@ -279,7 +279,10 @@
 		ipstat.ips_rawout++;
 	}
 #ifdef IPSEC
-	ipsec_setsocket(m, inp->inp_socket);
+	if (ipsec_setsocket(m, inp->inp_socket) != 0) {
+		m_freem(m);
+		return ENOBUFS;
+	}
 #endif /*IPSEC*/
 	return (ip_output(m, opts, &inp->inp_route, flags, inp->inp_moptions, &inp->inp_errormtu));
 }
Index: netinet/tcp_input.c
===================================================================
RCS file: /cvsroot/syssrc/sys/netinet/tcp_input.c,v
retrieving revision 1.108.4.7
diff -u -r1.108.4.7 tcp_input.c
--- netinet/tcp_input.c	2000/08/16 01:22:22	1.108.4.7
+++ netinet/tcp_input.c	2001/02/02 01:47:42
@@ -3409,7 +3409,10 @@
 		else
 			so = NULL;
 		/* use IPsec policy on listening socket, on SYN ACK */
-		ipsec_setsocket(m, so);
+		if (ipsec_setsocket(m, so) != 0) {
+			m_freem(m);
+			return ENOBUFS;
+		}
 	}
 #endif
 	m->m_pkthdr.rcvif = NULL;
Index: netinet/tcp_output.c
===================================================================
RCS file: /cvsroot/syssrc/sys/netinet/tcp_output.c,v
retrieving revision 1.56.4.3
diff -u -r1.56.4.3 tcp_output.c
--- netinet/tcp_output.c	2000/11/10 00:12:43	1.56.4.3
+++ netinet/tcp_output.c	2001/02/02 01:47:44
@@ -1024,7 +1024,11 @@
 		}
 	}
 #ifdef IPSEC
-	ipsec_setsocket(m, so);
+	if (ipsec_setsocket(m, so) != 0) {
+		m_freem(m);
+		error = ENOBUFS;
+		goto out;
+	}
 #endif /*IPSEC*/
 
 	switch (af) {
Index: netinet/tcp_subr.c
===================================================================
RCS file: /cvsroot/syssrc/sys/netinet/tcp_subr.c,v
retrieving revision 1.91.4.3
diff -u -r1.91.4.3 tcp_subr.c
--- netinet/tcp_subr.c	2000/10/17 00:48:30	1.91.4.3
+++ netinet/tcp_subr.c	2001/02/02 01:47:47
@@ -618,7 +618,7 @@
 	}
 
 #ifdef IPSEC
-	ipsec_setsocket(m, NULL);
+	(void)ipsec_setsocket(m, NULL);
 #endif /*IPSEC*/
 
 	/*
@@ -632,7 +632,10 @@
 	if (tp != NULL && tp->t_inpcb != NULL) {
 		ro = &tp->t_inpcb->inp_route;
 #ifdef IPSEC
-		ipsec_setsocket(m, tp->t_inpcb->inp_socket);
+		if (ipsec_setsocket(m, tp->t_inpcb->inp_socket) != 0) {
+			m_freem(m);
+			return ENOBUFS;
+		}
 #endif
 #ifdef DIAGNOSTIC
 		if (family != AF_INET)
@@ -648,7 +651,10 @@
 	else if (tp != NULL && tp->t_in6pcb != NULL) {
 		ro = (struct route *)&tp->t_in6pcb->in6p_route;
 #ifdef IPSEC
-		ipsec_setsocket(m, tp->t_in6pcb->in6p_socket);
+		if (ipsec_setsocket(m, tp->t_in6pcb->in6p_socket) != 0) {
+			m_freem(m);
+			return ENOBUFS;
+		}
 #endif
 #ifdef DIAGNOSTIC
 		if (family == AF_INET) {
Index: netinet/udp_usrreq.c
===================================================================
RCS file: /cvsroot/syssrc/sys/netinet/udp_usrreq.c,v
retrieving revision 1.66.4.3
diff -u -r1.66.4.3 udp_usrreq.c
--- netinet/udp_usrreq.c	2000/12/15 03:29:16	1.66.4.3
+++ netinet/udp_usrreq.c	2001/02/02 01:47:50
@@ -1254,7 +1254,10 @@
 	udpstat.udps_opackets++;
 
 #ifdef IPSEC
-	ipsec_setsocket(m, inp->inp_socket);
+	if (ipsec_setsocket(m, inp->inp_socket) != 0) {
+		error = ENOBUFS;
+		goto release;
+	}
 #endif /*IPSEC*/
 
 	return (ip_output(m, inp->inp_options, &inp->inp_route,
Index: netinet6/ah_input.c
===================================================================
RCS file: /cvsroot/syssrc/sys/netinet6/ah_input.c,v
retrieving revision 1.15.2.4
diff -u -r1.15.2.4 ah_input.c
--- netinet6/ah_input.c	2000/10/02 23:41:31	1.15.2.4
+++ netinet6/ah_input.c	2001/02/02 01:47:51
@@ -382,7 +382,7 @@
 	}
 
 	/* was it transmitted over the IPsec tunnel SA? */
-	if (ipsec4_tunnel_validate(ip, nxt, sav) && nxt == IPPROTO_IPV4) {
+	if (ipsec4_tunnel_validate(ip, nxt, sav)) {
 		/*
 		 * strip off all the headers that precedes AH.
 		 *	IP xx AH IP' payload -> IP' payload
@@ -454,6 +454,11 @@
 #endif
 
 		key_sa_recordxfer(sav, m);
+		if (ipsec_addhist(m, IPPROTO_AH, spi) != 0 ||
+		    ipsec_addhist(m, IPPROTO_IPV4, 0) != 0) {
+			ipsecstat.in_nomem++;
+			goto fail;
+		}
 
 		s = splimp();
 		if (IF_QFULL(&ipintrq)) {
@@ -536,6 +541,10 @@
 		/* forget about IP hdr checksum, the check has already been passed */
 
 		key_sa_recordxfer(sav, m);
+		if (ipsec_addhist(m, IPPROTO_AH, spi) != 0) {
+			ipsecstat.in_nomem++;
+			goto fail;
+		}
 
 		if (nxt != IPPROTO_DONE)
 			(*inetsw[ip_protox[nxt]].pr_input)(m, off, nxt);
@@ -797,7 +806,7 @@
 	}
 
 	/* was it transmitted over the IPsec tunnel SA? */
-	if (ipsec6_tunnel_validate(ip6, nxt, sav) && nxt == IPPROTO_IPV6) {
+	if (ipsec6_tunnel_validate(ip6, nxt, sav)) {
 		/*
 		 * strip off all the headers that precedes AH.
 		 *	IP6 xx AH IP6' payload -> IP6' payload
@@ -859,6 +868,11 @@
 #endif
 
 		key_sa_recordxfer(sav, m);
+		if (ipsec_addhist(m, IPPROTO_AH, spi) != 0 ||
+		    ipsec_addhist(m, IPPROTO_IPV6, 0) != 0) {
+			ipsec6stat.in_nomem++;
+			goto fail;
+		}
 
 		s = splimp();
 		if (IF_QFULL(&ip6intrq)) {
@@ -937,6 +951,10 @@
 		ip6->ip6_plen = htons(ntohs(ip6->ip6_plen) - stripsiz);
 
 		key_sa_recordxfer(sav, m);
+		if (ipsec_addhist(m, IPPROTO_AH, spi) != 0) {
+			ipsec6stat.in_nomem++;
+			goto fail;
+		}
 	}
 
 	*offp = off;
Index: netinet6/esp_input.c
===================================================================
RCS file: /cvsroot/syssrc/sys/netinet6/esp_input.c,v
retrieving revision 1.1.1.1.2.5
diff -u -r1.1.1.1.2.5 esp_input.c
--- netinet6/esp_input.c	2000/10/02 23:41:32	1.1.1.1.2.5
+++ netinet6/esp_input.c	2001/02/02 01:47:53
@@ -380,6 +380,11 @@
 #endif
 
 		key_sa_recordxfer(sav, m);
+		if (ipsec_addhist(m, IPPROTO_ESP, spi) != 0 ||
+		    ipsec_addhist(m, IPPROTO_IPV4, 0) != 0) {
+			ipsecstat.in_nomem++;
+			goto bad;
+		}
 
 		s = splimp();
 		if (IF_QFULL(&ipintrq)) {
@@ -417,6 +422,10 @@
 		ip->ip_p = nxt;
 
 		key_sa_recordxfer(sav, m);
+		if (ipsec_addhist(m, IPPROTO_ESP, spi) != 0) {
+			ipsecstat.in_nomem++;
+			goto bad;
+		}
 
 		if (nxt != IPPROTO_DONE)
 			(*inetsw[ip_protox[nxt]].pr_input)(m, off, nxt);
@@ -736,6 +745,11 @@
 #endif
 
 		key_sa_recordxfer(sav, m);
+		if (ipsec_addhist(m, IPPROTO_ESP, spi) != 0 || 
+		    ipsec_addhist(m, IPPROTO_IPV6, 0) != 0) {
+			ipsec6stat.in_nomem++;
+			goto bad;
+		}
 
 		s = splimp();
 		if (IF_QFULL(&ip6intrq)) {
@@ -839,6 +853,10 @@
 		ip6->ip6_plen = htons(ntohs(ip6->ip6_plen) - stripsiz);
 
 		key_sa_recordxfer(sav, m);
+		if (ipsec_addhist(m, IPPROTO_ESP, spi) != 0) {
+			ipsec6stat.in_nomem++;
+			goto bad;
+		}
 	}
 
 	*offp = off;
Index: netinet6/icmp6.c
===================================================================
RCS file: /cvsroot/syssrc/sys/netinet6/icmp6.c,v
retrieving revision 1.33.2.6
diff -u -r1.33.2.6 icmp6.c
--- netinet6/icmp6.c	2001/01/26 01:18:25	1.33.2.6
+++ netinet6/icmp6.c	2001/02/02 01:47:57
@@ -1862,7 +1862,7 @@
 	m->m_flags &= ~(M_BCAST|M_MCAST);
 #ifdef IPSEC
 	/* Don't lookup socket */
-	ipsec_setsocket(m, NULL);
+	(void)ipsec_setsocket(m, NULL);
 #endif /*IPSEC*/
 
 #ifdef COMPAT_RFC1885
@@ -2377,7 +2377,7 @@
 	/* send the packet to outside... */
 #ifdef IPSEC
 	/* Don't lookup socket */
-	ipsec_setsocket(m, NULL);
+	(void)ipsec_setsocket(m, NULL);
 #endif /*IPSEC*/
 	ip6_output(m, NULL, NULL, 0, NULL, &outif);
 	if (outif) {
Index: netinet6/ip6_output.c
===================================================================
RCS file: /cvsroot/syssrc/sys/netinet6/ip6_output.c,v
retrieving revision 1.23
diff -u -r1.23 ip6_output.c
--- netinet6/ip6_output.c	2000/06/20 02:24:42	1.23
+++ netinet6/ip6_output.c	2001/02/02 01:48:01
@@ -170,7 +170,7 @@
 
 	/* for AH processing. stupid to have "socket" variable in IP layer... */
 	so = ipsec_getsocket(m);
-	ipsec_setsocket(m, NULL);
+	(void)ipsec_setsocket(m, NULL);
 	ip6 = mtod(m, struct ip6_hdr *);
 #endif /* IPSEC */
 
@@ -874,6 +874,10 @@
 			}
 		}
 #endif
+#ifdef IPSEC
+		/* clean ipsec history once it goes out of the node */
+		ipsec_delaux(m);
+#endif
 #ifdef OLDIP6OUTPUT
 		error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst,
 					  ro->ro_rt);
@@ -1005,6 +1009,10 @@
 						m->m_pkthdr.len;
 				}
 			}
+#endif
+#ifdef IPSEC
+			/* clean ipsec history once it goes out of the node */
+			ipsec_delaux(m);
 #endif
 #ifdef OLDIP6OUTPUT
 			error = (*ifp->if_output)(ifp, m,
Index: netinet6/ipcomp_input.c
===================================================================
RCS file: /cvsroot/syssrc/sys/netinet6/ipcomp_input.c,v
retrieving revision 1.10.4.2
diff -u -r1.10.4.2 ipcomp_input.c
--- netinet6/ipcomp_input.c	2000/10/02 23:41:32	1.10.4.2
+++ netinet6/ipcomp_input.c	2001/02/02 01:48:02
@@ -1,5 +1,5 @@
 /*	$NetBSD: ipcomp_input.c,v 1.10.4.2 2000/10/02 23:41:32 itojun Exp $	*/
-/*	$KAME: ipcomp_input.c,v 1.19 2000/10/01 12:37:20 itojun Exp $	*/
+/*	$KAME: ipcomp_input.c,v 1.22 2001/01/23 08:59:37 itojun Exp $	*/
 
 /*
  * Copyright (C) 1999 WIDE Project.
@@ -209,6 +209,10 @@
 
 	if (sav) {
 		key_sa_recordxfer(sav, m);
+		if (ipsec_addhist(m, IPPROTO_IPCOMP, (u_int32_t)cpi) != 0) {
+			ipsecstat.in_nomem++;
+			goto fail;
+		}
 		key_freesav(sav);
 		sav = NULL;
 	}
@@ -320,6 +324,10 @@
 
 	if (sav) {
 		key_sa_recordxfer(sav, m);
+		if (ipsec_addhist(m, IPPROTO_IPCOMP, (u_int32_t)cpi) != 0) {
+			ipsec6stat.in_nomem++;
+			goto fail;
+		}
 		key_freesav(sav);
 		sav = NULL;
 	}
Index: netinet6/ipsec.c
===================================================================
RCS file: /cvsroot/syssrc/sys/netinet6/ipsec.c,v
retrieving revision 1.23.2.3
diff -u -r1.23.2.3 ipsec.c
--- netinet6/ipsec.c	2000/11/10 01:15:26	1.23.2.3
+++ netinet6/ipsec.c	2001/02/02 01:48:07
@@ -1,5 +1,5 @@
 /*	$NetBSD: ipsec.c,v 1.23.2.3 2000/11/10 01:15:26 tv Exp $	*/
-/*	$KAME: ipsec.c,v 1.83 2000/11/09 17:45:30 itojun Exp $	*/
+/*	$KAME: ipsec.c,v 1.87 2001/01/23 08:59:38 itojun Exp $	*/
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -152,6 +152,9 @@
 #ifdef INET6
 static int ipsec6_encapsulate __P((struct mbuf *, struct secasvar *));
 #endif
+static struct mbuf *ipsec_addaux __P((struct mbuf *));
+static struct mbuf *ipsec_findaux __P((struct mbuf *));
+static void ipsec_optaux __P((struct mbuf *, struct mbuf *));
 
 /*
  * For OUTBOUND packet having a socket. Searching SPD for packet,
@@ -3258,27 +3261,78 @@
 	return(NULL);
 }
 
+static struct mbuf *
+ipsec_addaux(m)
+	struct mbuf *m;
+{
+	struct mbuf *n;
+
+	n = m_aux_find(m, AF_INET, IPPROTO_ESP);
+	if (!n)
+		n = m_aux_add(m, AF_INET, IPPROTO_ESP);
+	if (!n)
+		return n;	/* ENOBUFS */
+	n->m_len = sizeof(struct socket *);
+	bzero(mtod(n, void *), n->m_len);
+	return n;
+}
+
+static struct mbuf *
+ipsec_findaux(m)
+	struct mbuf *m;
+{
+	struct mbuf *n;
+
+	n = m_aux_find(m, AF_INET, IPPROTO_ESP);
+#ifdef DIAGNOSTIC
+	if (n && n->m_len < sizeof(struct socket *))
+		panic("invalid ipsec m_aux");
+#endif
+	return n;
+}
+
 void
+ipsec_delaux(m)
+	struct mbuf *m;
+{
+	struct mbuf *n;
+
+	n = m_aux_find(m, AF_INET, IPPROTO_ESP);
+	if (n)
+		m_aux_delete(m, n);
+}
+
+/* if the aux buffer is unnecessary, nuke it. */
+static void
+ipsec_optaux(m, n)
+	struct mbuf *m;
+	struct mbuf *n;
+{
+
+	if (!n)
+		return;
+	if (n->m_len == sizeof(struct socket *) && !*mtod(n, struct socket **))
+		ipsec_delaux(m);
+}
+
+int
 ipsec_setsocket(m, so)
 	struct mbuf *m;
 	struct socket *so;
 {
 	struct mbuf *n;
 
-	n = m_aux_find(m, AF_INET, IPPROTO_ESP);
-	if (so && !n)
-		n = m_aux_add(m, AF_INET, IPPROTO_ESP);
-	if (n) {
-		if (so) {
-			*mtod(n, struct socket **) = so;
-			/*
-			 * XXX think again about it when we put decryption
-			 * histrory into aux mbuf
-			 */
-			n->m_len = sizeof(struct socket *);
-		} else
-			m_aux_delete(m, n);
-	}
+	/* if so == NULL, don't insist on getting the aux mbuf */
+	if (so) {
+		n = ipsec_addaux(m);
+		if (!n)
+			return ENOBUFS;
+	} else
+		n = ipsec_findaux(m);
+	if (n && n->m_len >= sizeof(struct socket *))
+		*mtod(n, struct socket **) = so;
+	ipsec_optaux(m, n);
+	return 0;
 }
 
 struct socket *
@@ -3287,11 +3341,68 @@
 {
 	struct mbuf *n;
 
-	n = m_aux_find(m, AF_INET, IPPROTO_ESP);
+	n = ipsec_findaux(m);
 	if (n && n->m_len >= sizeof(struct socket *))
 		return *mtod(n, struct socket **);
 	else
 		return NULL;
+}
+
+int
+ipsec_addhist(m, proto, spi)
+	struct mbuf *m;
+	int proto;
+	u_int32_t spi;
+{
+	struct mbuf *n;
+	struct ipsec_history *p;
+
+	n = ipsec_addaux(m);
+	if (!n)
+		return ENOBUFS;
+	if (M_TRAILINGSPACE(n) < sizeof(*p))
+		return ENOSPC;	/*XXX*/
+	p = (struct ipsec_history *)(mtod(n, caddr_t) + n->m_len);
+	n->m_len += sizeof(*p);
+	bzero(p, sizeof(*p));
+	p->ih_proto = proto;
+	p->ih_spi = spi;
+	return 0;
+}
+
+struct ipsec_history *
+ipsec_gethist(m, lenp)
+	struct mbuf *m;
+	int *lenp;
+{
+	struct mbuf *n;
+	int l;
+
+	n = ipsec_findaux(m);
+	if (!n)
+		return NULL;
+	l = n->m_len;
+	if (sizeof(struct socket *) > l)
+		return NULL;
+	if ((l - sizeof(struct socket *)) % sizeof(struct ipsec_history))
+		return NULL;
+	/* XXX does it make more sense to divide by sizeof(ipsec_history)? */
+	if (lenp)
+		*lenp = l - sizeof(struct socket *);
+	return (struct ipsec_history *)
+	    (mtod(n, caddr_t) + sizeof(struct socket *));
+}
+
+void
+ipsec_clearhist(m)
+	struct mbuf *m;
+{
+	struct mbuf *n;
+
+	n = ipsec_findaux(m);
+	if ((n) && n->m_len > sizeof(struct socket *))
+		n->m_len = sizeof(struct socket *);
+	ipsec_optaux(m, n);
 }
 
 /*
Index: netinet6/ipsec.h
===================================================================
RCS file: /cvsroot/syssrc/sys/netinet6/ipsec.h,v
retrieving revision 1.14.2.2
diff -u -r1.14.2.2 ipsec.h
--- netinet6/ipsec.h	2000/09/29 06:42:43	1.14.2.2
+++ netinet6/ipsec.h	2001/02/02 01:48:08
@@ -261,6 +261,11 @@
 	struct sockaddr *dst;
 };
 
+struct ipsec_history {
+	int ih_proto;
+	u_int32_t ih_spi;
+};
+
 extern int ipsec_debug;
 
 #ifdef INET
@@ -370,8 +375,12 @@
 	struct secasvar *));
 #endif
 extern struct mbuf *ipsec_copypkt __P((struct mbuf *));
-extern void ipsec_setsocket __P((struct mbuf *, struct socket *));
+extern void ipsec_delaux __P((struct mbuf *));
+extern int ipsec_setsocket __P((struct mbuf *, struct socket *));
 extern struct socket *ipsec_getsocket __P((struct mbuf *));
+extern int ipsec_addhist __P((struct mbuf *, int, u_int32_t)); 
+extern struct ipsec_history *ipsec_gethist __P((struct mbuf *, int *));
+extern void ipsec_clearhist __P((struct mbuf *));
 
 extern int ipsec_sysctl __P((int *, u_int, void *, size_t *, void *, size_t));
 extern int ipsec6_sysctl __P((int *, u_int, void *, size_t *, void *, size_t));
Index: netinet6/nd6_nbr.c
===================================================================
RCS file: /cvsroot/syssrc/sys/netinet6/nd6_nbr.c,v
retrieving revision 1.22
diff -u -r1.22 nd6_nbr.c
--- netinet6/nd6_nbr.c	2000/05/19 01:40:19	1.22
+++ netinet6/nd6_nbr.c	2001/02/02 01:48:11
@@ -1,5 +1,5 @@
 /*	$NetBSD: nd6_nbr.c,v 1.22 2000/05/19 01:40:19 itojun Exp $	*/
-/*	$KAME: nd6_nbr.c,v 1.36 2000/05/17 12:35:59 jinmei Exp $	*/
+/*	$KAME: nd6_nbr.c,v 1.51 2001/01/20 17:27:00 itojun Exp $	*/
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -493,7 +493,7 @@
 
 #ifdef IPSEC
 	/* Don't lookup socket */
-	ipsec_setsocket(m, NULL);
+	(void)ipsec_setsocket(m, NULL);
 #endif
 	ip6_output(m, NULL, NULL, dad ? IPV6_DADOUTPUT : 0, &im6o, &outif);
 	if (outif) {
@@ -913,7 +913,7 @@
 
 #ifdef IPSEC
 	/* Don't lookup socket */
-	ipsec_setsocket(m, NULL);
+	(void)ipsec_setsocket(m, NULL);
 #endif
 	ip6_output(m, NULL, NULL, 0, &im6o, &outif);
 	if (outif) {
Index: netinet6/raw_ip6.c
===================================================================
RCS file: /cvsroot/syssrc/sys/netinet6/raw_ip6.c,v
retrieving revision 1.23
diff -u -r1.23 raw_ip6.c
--- netinet6/raw_ip6.c	2000/05/29 00:03:18	1.23
+++ netinet6/raw_ip6.c	2001/02/02 01:48:12
@@ -458,6 +458,13 @@
 		*p = in6_cksum(m, ip6->ip6_nxt, sizeof(*ip6), plen);
 	}
 
+#ifdef IPSEC
+	if (ipsec_setsocket(m, so) != 0) {
+		error = ENOBUFS;
+		goto bad;
+	}
+#endif /*IPSEC*/
+
 	error = ip6_output(m, optp, &in6p->in6p_route, 0, in6p->in6p_moptions,
 			   &oifp);
 	if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) {
Index: netinet6/udp6_usrreq.c
===================================================================
RCS file: /cvsroot/syssrc/sys/netinet6/udp6_usrreq.c,v
retrieving revision 1.30.2.2
diff -u -r1.30.2.2 udp6_usrreq.c
--- netinet6/udp6_usrreq.c	2000/11/10 00:13:30	1.30.2.2
+++ netinet6/udp6_usrreq.c	2001/02/02 01:48:14
@@ -733,7 +733,10 @@
 
 		udp6stat.udp6s_opackets++;
 #ifdef IPSEC
-		ipsec_setsocket(m, in6p->in6p_socket);
+		if (ipsec_setsocket(m, in6p->in6p_socket) != 0) {
+			error = ENOBUFS;
+			goto release;
+		}
 #endif /*IPSEC*/
 		error = ip6_output(m, in6p->in6p_outputopts, &in6p->in6p_route,
 			    0, in6p->in6p_moptions, NULL);
@@ -761,7 +764,7 @@
 
 		udpstat.udps_opackets++;
 #ifdef IPSEC
-		ipsec_setsocket(m, NULL);	/*XXX*/
+		(void)ipsec_setsocket(m, NULL);	/*XXX*/
 #endif /*IPSEC*/
 		error = ip_output(m, NULL, &in6p->in6p_route, 0 /*XXX*/);
 		break;