From 37d55dca34ef8f60be2d05ba4cdf4e1083bb0956 Mon Sep 17 00:00:00 2001
From: Darren Reed <darrenr@FreeBSD.org>
Date: Thu, 25 Apr 2002 03:31:39 +0000
Subject: [PATCH] bring in changes from 3.4.26.

---
 sys/contrib/ipfilter/netinet/IPFILTER.LICENCE |   5 +-
 sys/contrib/ipfilter/netinet/QNX_OCL.txt      |   2 +
 sys/contrib/ipfilter/netinet/fil.c            |   7 +-
 sys/contrib/ipfilter/netinet/ip_auth.c        |   6 +-
 sys/contrib/ipfilter/netinet/ip_compat.h      |  80 +++----
 sys/contrib/ipfilter/netinet/ip_fil.c         |   5 +-
 sys/contrib/ipfilter/netinet/ip_fil.h         |  25 +-
 sys/contrib/ipfilter/netinet/ip_frag.c        |   2 +-
 sys/contrib/ipfilter/netinet/ip_log.c         |   1 +
 sys/contrib/ipfilter/netinet/ip_nat.c         | 120 +++++++---
 sys/contrib/ipfilter/netinet/ip_nat.h         |   2 +
 sys/contrib/ipfilter/netinet/ip_state.c       | 216 +++++++++++++-----
 sys/contrib/ipfilter/netinet/ip_state.h       |  27 ++-
 sys/contrib/ipfilter/netinet/ipl.h            |   2 +-
 14 files changed, 339 insertions(+), 161 deletions(-)

diff --git a/sys/contrib/ipfilter/netinet/IPFILTER.LICENCE b/sys/contrib/ipfilter/netinet/IPFILTER.LICENCE
index dfb199c5f962..1ee473da33f1 100644
--- a/sys/contrib/ipfilter/netinet/IPFILTER.LICENCE
+++ b/sys/contrib/ipfilter/netinet/IPFILTER.LICENCE
@@ -1,7 +1,7 @@
-Copyright (C) 1993-2001 by Darren Reed.
-
 $FreeBSD$
 
+Copyright (C) 1993-2002 by Darren Reed.
+
 The author accepts no responsibility for the use of this software and
 provides it on an ``as is'' basis without express or implied warranty.
 
@@ -27,3 +27,4 @@ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 SUCH DAMAGE.
 
 I hate legalese, don't you ?
+
diff --git a/sys/contrib/ipfilter/netinet/QNX_OCL.txt b/sys/contrib/ipfilter/netinet/QNX_OCL.txt
index 6aa33eaf6b06..b62377679670 100644
--- a/sys/contrib/ipfilter/netinet/QNX_OCL.txt
+++ b/sys/contrib/ipfilter/netinet/QNX_OCL.txt
@@ -1,3 +1,5 @@
+$FreeBSD$
+
    End User License Certificate (EULA) End User License Certificate
    (EULA) 
    Support Support 
diff --git a/sys/contrib/ipfilter/netinet/fil.c b/sys/contrib/ipfilter/netinet/fil.c
index dd5cad1e43cd..bffb4b298923 100644
--- a/sys/contrib/ipfilter/netinet/fil.c
+++ b/sys/contrib/ipfilter/netinet/fil.c
@@ -213,9 +213,7 @@ fr_info_t *fin;
 	fin->fin_data[1] = 0;
 	fin->fin_rule = -1;
 	fin->fin_group = -1;
-#ifdef	_KERNEL
 	fin->fin_icode = ipl_unreach;
-#endif
 	v = fin->fin_v;
 	fi->fi_v = v;
 	fin->fin_hlen = hlen;
@@ -265,6 +263,7 @@ fr_info_t *fin;
 	fin->fin_off = off;
 	fin->fin_plen = plen;
 	fin->fin_dp = (char *)tcp;
+	fin->fin_misc = 0;
 	off <<= 3;
 
 	switch (p)
@@ -297,7 +296,7 @@ fr_info_t *fin;
 			}
 		}
 
-		if (!(plen >= hlen + minicmpsz))
+		if (!(plen >= minicmpsz))
 			fi->fi_fl |= FI_SHORT;
 
 		break;
@@ -1512,7 +1511,7 @@ nodata:
  * SUCH DAMAGE.
  *
  *	@(#)uipc_mbuf.c	8.2 (Berkeley) 1/4/94
- * $Id: fil.c,v 2.35.2.58 2002/03/13 02:23:13 darrenr Exp $
+ * $Id: fil.c,v 2.35.2.59 2002/03/25 11:07:37 darrenr Exp $
  */
 /*
  * Copy data from an mbuf chain starting "off" bytes from the beginning,
diff --git a/sys/contrib/ipfilter/netinet/ip_auth.c b/sys/contrib/ipfilter/netinet/ip_auth.c
index ee3a7d71e16f..cdbfb921cb0a 100644
--- a/sys/contrib/ipfilter/netinet/ip_auth.c
+++ b/sys/contrib/ipfilter/netinet/ip_auth.c
@@ -410,6 +410,7 @@ fr_authioctlloop:
 			RWLOCK_EXIT(&ipf_auth);
 			return 0;
 		}
+		RWLOCK_EXIT(&ipf_auth);
 #ifdef	_KERNEL
 # if	SOLARIS
 		mutex_enter(&ipf_authmx);
@@ -422,7 +423,6 @@ fr_authioctlloop:
 		error = SLEEP(&fr_authnext, "fr_authnext");
 # endif
 #endif
-		RWLOCK_EXIT(&ipf_auth);
 		if (!error)
 			goto fr_authioctlloop;
 		break;
@@ -452,7 +452,7 @@ fr_authioctlloop:
 #ifdef	_KERNEL
 		if (m && au->fra_info.fin_out) {
 # if SOLARIS
-			error = fr_qout(fra->fra_q, m);
+			error = (fr_qout(fra->fra_q, m) == 0) ? EINVAL : 0;
 # else /* SOLARIS */
 			struct route ro;
 
@@ -474,7 +474,7 @@ fr_authioctlloop:
 				fr_authstats.fas_sendok++;
 		} else if (m) {
 # if SOLARIS
-			error = fr_qin(fra->fra_q, m);
+			error = (fr_qin(fra->fra_q, m) == 0) ? EINVAL : 0;
 # else /* SOLARIS */
 			if (! IF_HANDOFF(&ipintrq, m, NULL))
 				error = ENOBUFS;
diff --git a/sys/contrib/ipfilter/netinet/ip_compat.h b/sys/contrib/ipfilter/netinet/ip_compat.h
index d4b7bf6c5463..bf67827e476a 100644
--- a/sys/contrib/ipfilter/netinet/ip_compat.h
+++ b/sys/contrib/ipfilter/netinet/ip_compat.h
@@ -104,7 +104,6 @@ struct  ether_addr {
 # include <sys/sysmacros.h>
 #endif
 
-
 /*
  * This is a workaround for <sys/uio.h> troubles on FreeBSD and OpenBSD.
  */
@@ -198,10 +197,6 @@ typedef	 int	minor_t;
 #endif /* SOLARIS */
 #define	IPMINLEN(i, h)	((i)->ip_len >= ((i)->ip_hl * 4 + sizeof(struct h)))
 
-#if defined(__FreeBSD__) && (__FreeBSD__ >= 5) && defined(_KERNEL)
-# include <machine/in_cksum.h>
-#endif
-
 #ifndef	IP_OFFMASK
 #define	IP_OFFMASK	0x1fff
 #endif
@@ -216,6 +211,30 @@ typedef	 int	minor_t;
 #endif /* BSD > 199306 */
 
 
+#if defined(__FreeBSD__) && (defined(KERNEL) || defined(_KERNEL))
+# include <sys/param.h>
+# ifndef __FreeBSD_version
+#  include <sys/osreldate.h>
+# endif
+# ifdef IPFILTER_LKM
+#  define       ACTUALLY_LKM_NOT_KERNEL
+# endif
+# if defined(__FreeBSD_version) && (__FreeBSD_version < 300000)
+#  include <machine/spl.h>
+# else
+#  if (__FreeBSD_version >= 300000) && (__FreeBSD_version < 400000)
+#   if defined(IPFILTER_LKM) && !defined(ACTUALLY_LKM_NOT_KERNEL)
+#    define	ACTUALLY_LKM_NOT_KERNEL
+#   endif
+#  endif
+# endif
+#endif /* __FreeBSD__ && KERNEL */
+
+#if defined(__FreeBSD_version) && (__FreeBSD_version >= 500000) && \
+    defined(_KERNEL)
+# include <machine/in_cksum.h>
+#endif
+
 /*
  * These operating systems already take care of the problem for us.
  */
@@ -231,6 +250,13 @@ typedef u_int32_t       u_32_t;
 #   include "opt_inet6.h"
 #  endif
 #  ifdef INET6
+#   define USE_INET6     
+#  endif   
+# endif
+# if !defined(_KERNEL) && !defined(IPFILTER_LKM)
+#  if (defined(__FreeBSD_version) && (__FreeBSD_version >= 400000)) || \
+      (defined(OpenBSD) && (OpenBSD >= 200111)) || \
+      (defined(__NetBSD_Version__) && (__NetBSD_Version__ >= 105000000))
 #   define USE_INET6
 #  endif
 # endif
@@ -342,40 +368,9 @@ union	i6addr	{
 #define	IPOPT_EIP	145	/* EIP */
 #define	IPOPT_FINN	205	/* FINN */
 
-
-#if defined(__FreeBSD__) && (defined(KERNEL) || defined(_KERNEL))
-# ifdef IPFILTER_LKM
-#  ifndef __FreeBSD_cc_version
-#   include <osreldate.h>
-#  else
-#   if __FreeBSD_cc_version < 430000
-#    include <osreldate.h>
-#   else
-#    include <sys/param.h>
-#   endif
-#  endif
-#  define       ACTUALLY_LKM_NOT_KERNEL
-# else
-#  ifndef __FreeBSD_cc_version
-#   include <sys/osreldate.h>
-#  else
-#   if __FreeBSD_cc_version < 430000
-#    include <sys/osreldate.h>
-#   else
-#    include <sys/param.h>
-#   endif
-#  endif
-# endif
-# if __FreeBSD__ < 3
-#  include <machine/spl.h>
-# else
-#  if __FreeBSD__ == 3
-#   if defined(IPFILTER_LKM) && !defined(ACTUALLY_LKM_NOT_KERNEL)
-#    define	ACTUALLY_LKM_NOT_KERNEL
-#   endif
-#  endif
-# endif
-#endif /* __FreeBSD__ && KERNEL */
+#ifndef	TCPOPT_WSCALE
+# define	TCPOPT_WSCALE	3
+#endif
 
 /*
  * Build some macros and #defines to enable the same code to compile anywhere
@@ -581,7 +576,8 @@ extern	void	m_copyback __P((struct mbuf *, int, int, caddr_t));
        defined(__FreeBSD__) || defined(__OpenBSD__) || defined(_BSDI_VERSION)
 #   include <vm/vm.h>
 #  endif
-#  if !defined(__FreeBSD__) || (defined (__FreeBSD__) && __FreeBSD__>=3)
+#  if !defined(__FreeBSD__) || (defined (__FreeBSD_version) && \
+      (__FreeBSD_version >= 300000))
 #   if (defined(__NetBSD_Version__) && (__NetBSD_Version__ >= 105180000)) || \
        (defined(OpenBSD) && (OpenBSD >= 200111))
 #    include <uvm/uvm_extern.h>
@@ -590,9 +586,9 @@ extern	void	m_copyback __P((struct mbuf *, int, int, caddr_t));
 extern	vm_map_t	kmem_map;
 #   endif
 #   include <sys/proc.h>
-#  else /* !__FreeBSD__ || (__FreeBSD__ && __FreeBSD__>=3) */
+#  else /* !__FreeBSD__ || (__FreeBSD__ && __FreeBSD_version >= 300000) */
 #   include <vm/vm_kern.h>
-#  endif /* !__FreeBSD__ || (__FreeBSD__ && __FreeBSD__>=3) */
+#  endif /* !__FreeBSD__ || (__FreeBSD__ && __FreeBSD_version >= 300000) */
 #  ifdef	M_PFIL
 #   define	KMALLOC(a, b)	MALLOC((a), b, sizeof(*(a)), M_PFIL, M_NOWAIT)
 #   define	KMALLOCS(a, b, c)	MALLOC((a), b, (c), M_PFIL, M_NOWAIT)
diff --git a/sys/contrib/ipfilter/netinet/ip_fil.c b/sys/contrib/ipfilter/netinet/ip_fil.c
index 643592c7b336..3a41c5c088f6 100644
--- a/sys/contrib/ipfilter/netinet/ip_fil.c
+++ b/sys/contrib/ipfilter/netinet/ip_fil.c
@@ -26,6 +26,7 @@
 # endif
 #endif
 #ifdef __sgi
+# define _KMEMUSER
 # include <sys/ptimers.h>
 #endif
 #ifndef	_KERNEL
@@ -2142,8 +2143,8 @@ struct uio *uio;
 			num = io->iov_len;
 			if (num > left)
 				num = left;
-			start = io->iov_base + offset;
-			if (start > io->iov_base + io->iov_len) {
+			start = (char *)io->iov_base + offset;
+			if (start > (char *)io->iov_base + io->iov_len) {
 				offset -= io->iov_len;
 				ioc++;
 				continue;
diff --git a/sys/contrib/ipfilter/netinet/ip_fil.h b/sys/contrib/ipfilter/netinet/ip_fil.h
index b63769a4a2f0..5088fb3503bb 100644
--- a/sys/contrib/ipfilter/netinet/ip_fil.h
+++ b/sys/contrib/ipfilter/netinet/ip_fil.h
@@ -56,8 +56,8 @@
 # define	SIOCFRSYN	_IOW('r', 73, u_int)
 # define	SIOCFRZST	_IOWR('r', 74, struct friostat *)
 # define	SIOCZRLST	_IOWR('r', 75, struct frentry *)
-# define	SIOCAUTHW	_IOWR('r', 76, struct frauth_t *)
-# define	SIOCAUTHR	_IOWR('r', 77, struct frauth_t *)
+# define	SIOCAUTHW	_IOWR('r', 76, struct frauth *)
+# define	SIOCAUTHR	_IOWR('r', 77, struct frauth *)
 # define	SIOCATHST	_IOWR('r', 78, struct fr_authstat *)
 # define	SIOCSTLCK	_IOWR('r', 79, u_int)
 # define	SIOCSTPUT	_IOWR('r', 80, struct ipstate_save *)
@@ -81,8 +81,8 @@
 # define	SIOCFRSYN	_IOW(r, 73, u_int)
 # define	SIOCFRZST	_IOWR(r, 74, struct friostat *)
 # define	SIOCZRLST	_IOWR(r, 75, struct frentry *)
-# define	SIOCAUTHW	_IOWR(r, 76, struct frauth_t *)
-# define	SIOCAUTHR	_IOWR(r, 77, struct frauth_t *)
+# define	SIOCAUTHW	_IOWR(r, 76, struct frauth *)
+# define	SIOCAUTHR	_IOWR(r, 77, struct frauth *)
 # define	SIOCATHST	_IOWR(r, 78, struct fr_authstat *)
 # define	SIOCSTLCK	_IOWR(r, 79, u_int)
 # define	SIOCSTPUT	_IOWR(r, 80, struct ipstate_save *)
@@ -136,12 +136,11 @@ typedef	struct	fr_info	{
 	void	*fin_ifp;		/* interface packet is `on' */
 	struct	fr_ip	fin_fi;		/* IP Packet summary */
 	u_short	fin_data[2];		/* TCP/UDP ports, ICMP code/type */
-	u_char	fin_out;		/* in or out ? 1 == out, 0 == in */
-	u_char	fin_rev;		/* state only: 1 = reverse */
+	u_int	fin_out;		/* in or out ? 1 == out, 0 == in */
 	u_short	fin_hlen;		/* length of IP header in bytes */
+	u_char	fin_rev;		/* state only: 1 = reverse */
 	u_char	fin_tcpf;		/* TCP header flags (SYN, ACK, etc) */
-	/* From here on is packet specific */
-	u_char	fin_icode;		/* ICMP error to return */
+	u_int	fin_icode;		/* ICMP error to return */
 	u_32_t	fin_rule;		/* rule # last matched */
 	u_32_t	fin_group;		/* group number, -1 for none */
 	struct	frentry *fin_fr;	/* last matching rule */
@@ -150,6 +149,7 @@ typedef	struct	fr_info	{
 	u_short	fin_off;
 	u_short	fin_dlen;		/* length of data portion of packet */
 	u_short	fin_id;			/* IP packet id field */
+	u_int	fin_misc;
 	void	*fin_mp;		/* pointer to pointer to mbuf */
 #if SOLARIS
 	void	*fin_qfm;		/* pointer to mblk where pkt starts */
@@ -171,6 +171,11 @@ typedef	struct	fr_info	{
 #define	FI_CSIZE	offsetof(fr_info_t, fin_icode)
 #define	FI_LCSIZE	offsetof(fr_info_t, fin_dp)
 
+/*
+ * For fin_misc
+ */
+#define	FM_BADSTATE	0x00000001
+
 /*
  * Size for copying cache fr_info structure
  */
@@ -422,10 +427,10 @@ typedef	struct	iplog	{
 typedef	struct	ipflog	{
 #if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199603)) || \
         (defined(OpenBSD) && (OpenBSD >= 199603))
-	u_char	fl_ifname[LIFNAMSIZ];
+	char	fl_ifname[LIFNAMSIZ];
 #else
 	u_int	fl_unit;
-	u_char	fl_ifname[LIFNAMSIZ];
+	char	fl_ifname[LIFNAMSIZ];
 #endif
 	u_char	fl_plen;	/* extra data after hlen */
 	u_char	fl_hlen;	/* length of IP headers saved */
diff --git a/sys/contrib/ipfilter/netinet/ip_frag.c b/sys/contrib/ipfilter/netinet/ip_frag.c
index 7b7c7e5d930a..6ebbdcef23c6 100644
--- a/sys/contrib/ipfilter/netinet/ip_frag.c
+++ b/sys/contrib/ipfilter/netinet/ip_frag.c
@@ -584,9 +584,9 @@ void ipfr_slowtimer()
 
 	if (fr_running <= 0) 
 		return;
+	READ_ENTER(&ipf_solaris);
 #endif
 
-	READ_ENTER(&ipf_solaris);
 #if defined(__sgi) && defined(_KERNEL)
 	ipfilter_sgi_intfsync();
 #endif
diff --git a/sys/contrib/ipfilter/netinet/ip_log.c b/sys/contrib/ipfilter/netinet/ip_log.c
index 189e68200714..7126b208dd1e 100644
--- a/sys/contrib/ipfilter/netinet/ip_log.c
+++ b/sys/contrib/ipfilter/netinet/ip_log.c
@@ -90,6 +90,7 @@
 # include <net/route.h>
 # include <netinet/in.h>
 # ifdef __sgi
+#  define _KMEMUSER
 #  include <sys/ddi.h>
 #  ifdef IFF_DRVRLOCK /* IRIX6 */
 #   include <sys/hashing.h>
diff --git a/sys/contrib/ipfilter/netinet/ip_nat.c b/sys/contrib/ipfilter/netinet/ip_nat.c
index 60dd7ed73c98..2e10f83f0491 100644
--- a/sys/contrib/ipfilter/netinet/ip_nat.c
+++ b/sys/contrib/ipfilter/netinet/ip_nat.c
@@ -427,7 +427,7 @@ caddr_t data;
 int mode;
 {
 	register ipnat_t *nat, *nt, *n = NULL, **np = NULL;
-	int error = 0, ret, arg;
+	int error = 0, ret, arg, getlock;
 	ipnat_t natd;
 	u_32_t i, j;
 
@@ -438,9 +438,15 @@ int mode;
 
 	nat = NULL;     /* XXX gcc -Wuninitialized */
 	KMALLOC(nt, ipnat_t *);
-	if ((cmd == SIOCADNAT) || (cmd == SIOCRMNAT))
-		error = IRCOPYPTR(data, (char *)&natd, sizeof(natd));
-	else if (cmd == SIOCIPFFL) {	/* SIOCFLNAT & SIOCCNATL */
+	getlock = (mode & NAT_LOCKHELD) ? 0 : 1;
+	if ((cmd == SIOCADNAT) || (cmd == SIOCRMNAT)) {
+		if (mode & NAT_SYSSPACE) {
+			bcopy(data, (char *)&natd, sizeof(natd));
+			error = 0;
+		} else {
+			error = IRCOPYPTR(data, (char *)&natd, sizeof(natd));
+		}
+	} else if (cmd == SIOCIPFFL) {	/* SIOCFLNAT & SIOCCNATL */
 		error = IRCOPY(data, (char *)&arg, sizeof(arg));
 		if (error)
 			error = EFAULT;
@@ -452,7 +458,8 @@ int mode;
 	/*
 	 * For add/delete, look to see if the NAT entry is already present
 	 */
-	WRITE_ENTER(&ipf_nat);
+	if (getlock == 1)
+		WRITE_ENTER(&ipf_nat);
 	if ((cmd == SIOCADNAT) || (cmd == SIOCRMNAT)) {
 		nat = &natd;
 		nat->in_flags &= IPN_USERFLAGS;
@@ -717,7 +724,8 @@ int mode;
 		error = EINVAL;
 		break;
 	}
-	RWLOCK_EXIT(&ipf_nat);			/* READ/WRITE */
+	if (getlock == 1)
+		RWLOCK_EXIT(&ipf_nat);			/* READ/WRITE */
 done:
 	if (nt)
 		KFREE(nt);
@@ -833,7 +841,7 @@ caddr_t data;
 			return ENOMEM;
 		bcopy((char *)&ipn, (char *)ipnn, sizeof(ipn));
 
-		bcopy((char *)aps, ipnn->ipn_data, sizeof(*aps));
+		bcopy((char *)aps, (char *)ipnn->ipn_data, sizeof(*aps));
 		if (aps->aps_data) {
 			bcopy(aps->aps_data, ipnn->ipn_data + sizeof(*aps),
 			      aps->aps_psiz);
@@ -1652,11 +1660,12 @@ int dir;
 {
 	u_32_t sum1, sum2, sumd, sumd2 = 0;
 	struct in_addr in;
+	int flags, dlen;
 	icmphdr_t *icmp;
 	udphdr_t *udp;
+	tcphdr_t *tcp;
 	nat_t *nat;
 	ip_t *oip;
-	int flags;
 
 	if ((fin->fin_fl & FI_SHORT) || (fin->fin_off != 0))
 		return NULL;
@@ -1675,6 +1684,13 @@ int dir;
 	else if (oip->ip_p == IPPROTO_UDP)
 		flags = IPN_UDP;
 	udp = (udphdr_t *)((((char *)oip) + (oip->ip_hl << 2)));
+	dlen = ip->ip_len - ((char *)udp - (char *)ip);
+	/*
+	 * XXX - what if this is bogus hl and we go off the end ?
+	 * In this case, nat_icmplookup() will have returned NULL.
+	 */
+	tcp = (tcphdr_t *)udp;
+
 	/*
 	 * Need to adjust ICMP header to include the real IP#'s and
 	 * port #'s.  Only apply a checksum change relative to the
@@ -1697,8 +1713,6 @@ int dir;
 	 * change in the UDP and TCP checksums require yet another
 	 * adjustment of the ICMP checksum of the ICMP error message.
 	 *
-	 * For the moment we forget about TCP, because that checksum is not
-	 * in the first 8 bytes, so it will not be available in most cases.
 	 */
 
 	if (oip->ip_dst.s_addr == nat->nat_oip.s_addr) {
@@ -1756,15 +1770,25 @@ int dir;
 			sumd2 = sumd;
 		}
 
-#if 0
+#if 1
 		/*
 		 * Fix TCP pseudo header checksum to compensate for the 
 		 * IP address change. Before we can do the change, we
 		 * must make sure that oip is sufficient large to hold
 		 * the TCP checksum (normally it does not!).
 		 */
-		if (oip->ip_p == IPPROTO_TCP) {
+		if (oip->ip_p == IPPROTO_TCP && dlen >= 18) {
 		
+			sum1 = ntohs(tcp->th_sum);
+			fix_datacksum(&tcp->th_sum, sumd);
+			sum2 = ntohs(tcp->th_sum);
+
+			/*
+			 * Fix ICMP checksum to compensate the TCP 
+			 * checksum adjustment.
+			 */
+			CALC_SUMD(sum1, sum2, sumd);
+			sumd2 = sumd;
 		}
 #endif
 	} else {
@@ -1815,15 +1839,25 @@ int dir;
 			sumd2 = sumd;
 		}
 		
-#if 0
+#if 1
 		/* 
 		 * Fix TCP pseudo header checksum to compensate for the 
 		 * IP address change. Before we can do the change, we
 		 * must make sure that oip is sufficient large to hold
 		 * the TCP checksum (normally it does not!).
 		 */
-		if (oip->ip_p == IPPROTO_TCP) {
+		if (oip->ip_p == IPPROTO_TCP && dlen >= 18) {
 		
+			sum1 = ntohs(tcp->th_sum);
+			fix_datacksum(&tcp->th_sum, sumd);
+			sum2 = ntohs(tcp->th_sum);
+
+			/*
+			 * Fix ICMP checksum to compensate the TCP
+			 * checksum adjustment.
+			 */
+			CALC_SUMD(sum1, sum2, sumd);
+			sumd2 = sumd;
 		};
 #endif
 		
@@ -1831,14 +1865,6 @@ int dir;
 	}
 
 	if ((flags & IPN_TCPUDP) != 0) {
-		tcphdr_t *tcp;
-
-		/*
-		 * XXX - what if this is bogus hl and we go off the end ?
-		 * In this case, nat_icmpinlookup() will have returned NULL.
-		 */
-		tcp = (tcphdr_t *)udp;
-
 		/*
 		 * Step 2 :
 		 * For offending TCP/UDP IP packets, translate the ports as
@@ -1854,8 +1880,9 @@ int dir;
 		 *
 		 * To further complicate: the TCP checksum is not in the first
 		 * 8 bytes of the offending ip packet, so it most likely is not
-		 * available (we might have to fix that if the encounter a
-		 * device that returns more than 8 data bytes on icmp error)
+		 * available. Some OSses like Solaris return enough bytes to
+		 * include the TCP checksum. So we have to check if the
+		 * ip->ip_len actually holds the TCP checksum of the oip!
 		 */
 
 		if (nat->nat_oport == tcp->th_dport) {
@@ -1893,6 +1920,27 @@ int dir;
 					CALC_SUMD(sum1, sum2, sumd);
 					sumd2 += sumd;
 				}
+
+				/*
+				 * Fix tcp checksum (if present) to compensate
+				 * port adjustment. NOTE : the offending IP
+				 * packet flows the other direction compared to
+				 * the ICMP message.
+				 */
+				if (oip->ip_p == IPPROTO_TCP && dlen >= 18) {
+
+					sum1 = ntohs(tcp->th_sum);
+					fix_datacksum(&tcp->th_sum, sumd);
+					sum2 = ntohs(tcp->th_sum);
+
+					/*
+					 * Fix ICMP checksum to 
+					 * compensate TCP checksum 
+					 * adjustment.
+					 */
+					CALC_SUMD(sum1, sum2, sumd);
+					sumd2 += sumd;
+				}
 			}
 		} else {
 			if (tcp->th_dport != nat->nat_outport) {
@@ -1928,6 +1976,26 @@ int dir;
 					CALC_SUMD(sum1, sum2, sumd);
 					sumd2 += sumd;
 				}
+
+				/*
+				 * Fix tcp checksum (if present) to compensate
+				 * port adjustment. NOTE : the offending IP
+				 * packet flows the other direction compared to
+				 * the ICMP message.
+				 */
+				if (oip->ip_p == IPPROTO_TCP && dlen >= 18) {
+
+					sum1 = ntohs(tcp->th_sum);
+					fix_datacksum(&tcp->th_sum, sumd);
+					sum2 = ntohs(tcp->th_sum);
+
+					/*
+					 * Fix ICMP checksum to compensate
+					 * UDP checksum adjustment.
+					 */
+					CALC_SUMD(sum1, sum2, sumd);
+					sumd2 += sumd;
+				}
 			}
 		}
 		if (sumd2) {
@@ -2437,7 +2505,7 @@ maskloop:
 				csump = &tcp->th_sum;
 				MUTEX_ENTER(&nat->nat_lock);
 				fr_tcp_age(&nat->nat_age,
-					   nat->nat_tcpstate, fin, 1);
+					   nat->nat_tcpstate, fin, 1, 0);
 				if (nat->nat_age < fr_defnaticmpage)
 					nat->nat_age = fr_defnaticmpage;
 #ifdef LARGE_NAT
@@ -2645,7 +2713,7 @@ maskloop:
 				csump = &tcp->th_sum;
 				MUTEX_ENTER(&nat->nat_lock);
 				fr_tcp_age(&nat->nat_age,
-					   nat->nat_tcpstate, fin, 0);
+					   nat->nat_tcpstate, fin, 0, 0);
 				if (nat->nat_age < fr_defnaticmpage)
 					nat->nat_age = fr_defnaticmpage;
 #ifdef LARGE_NAT
diff --git a/sys/contrib/ipfilter/netinet/ip_nat.h b/sys/contrib/ipfilter/netinet/ip_nat.h
index be0bb8307a36..f1258be1444c 100644
--- a/sys/contrib/ipfilter/netinet/ip_nat.h
+++ b/sys/contrib/ipfilter/netinet/ip_nat.h
@@ -277,6 +277,8 @@ typedef	struct	natlog {
 			    (sd) = (s2) - (s1); \
 			    (sd) = ((sd) & 0xffff) + ((sd) >> 16); }
 
+#define	NAT_SYSSPACE		0x80000000
+#define	NAT_LOCKHELD		0x40000000
 
 extern	u_int	ipf_nattable_sz;
 extern	u_int	ipf_natrules_sz;
diff --git a/sys/contrib/ipfilter/netinet/ip_state.c b/sys/contrib/ipfilter/netinet/ip_state.c
index 322e59f76f02..350cd1f1b30f 100644
--- a/sys/contrib/ipfilter/netinet/ip_state.c
+++ b/sys/contrib/ipfilter/netinet/ip_state.c
@@ -125,6 +125,7 @@ static ips_stat_t *fr_statetstats __P((void));
 static void fr_delstate __P((ipstate_t *));
 static int fr_state_remove __P((caddr_t));
 static void fr_ipsmove __P((ipstate_t **, ipstate_t *, u_int));
+static int fr_tcpoptions __P((tcphdr_t *));
 int fr_stputent __P((caddr_t));
 int fr_stgetent __P((caddr_t));
 void fr_stinsert __P((ipstate_t *));
@@ -300,7 +301,7 @@ caddr_t data;
 		if ((sp->is_p == st.is_p) && (sp->is_v == st.is_v) &&
 		    !bcmp((char *)&sp->is_src, (char *)&st.is_src,
 			  sizeof(st.is_src)) &&
-		    !bcmp((char *)&sp->is_dst, (char *)&st.is_src,
+		    !bcmp((char *)&sp->is_dst, (char *)&st.is_dst,
 			  sizeof(st.is_dst)) &&
 		    !bcmp((char *)&sp->is_ps, (char *)&st.is_ps,
 			  sizeof(st.is_ps))) {
@@ -580,7 +581,8 @@ u_int flags;
 	void *ifp;
 	int out;
 
-	if (fr_state_lock || (fin->fin_off != 0) || (fin->fin_fl & FI_SHORT))
+	if (fr_state_lock || (fin->fin_off != 0) || (fin->fin_fl & FI_SHORT) ||
+	    (fin->fin_misc & FM_BADSTATE))
 		return NULL;
 	if (ips_num == fr_statemax) {
 		ips_stats.iss_max++;
@@ -621,6 +623,8 @@ u_int flags;
 
 	switch (is->is_p)
 	{
+		int off;
+
 #ifdef	USE_INET6
 	case IPPROTO_ICMPV6 :
 		ic = (struct icmp *)fin->fin_dp;
@@ -682,15 +686,22 @@ u_int flags;
 			hv += is->is_dport;
 		}
 		is->is_send = ntohl(tcp->th_seq) + fin->fin_dlen -
-			      (tcp->th_off << 2) +
+			      (off = (tcp->th_off << 2)) +
 			      ((tcp->th_flags & TH_SYN) ? 1 : 0) +
 			      ((tcp->th_flags & TH_FIN) ? 1 : 0);
 		is->is_maxsend = is->is_send;
-		is->is_dend = 0;
 		is->is_maxdwin = 1;
 		is->is_maxswin = ntohs(tcp->th_win);
 		if (is->is_maxswin == 0)
 			is->is_maxswin = 1;
+
+		if ((tcp->th_flags & TH_OPENING) == TH_SYN)
+			is->is_fsm = 1;
+
+		if ((tcp->th_flags & TH_SYN) &&
+		    ((tcp->th_off << 2) >= (sizeof(*tcp) + 4)))
+			is->is_swscale = fr_tcpoptions(tcp);
+
 		/*
 		 * If we're creating state for a starting connection, start the
 		 * timer on it as we'll never see an error if it fails to
@@ -787,7 +798,7 @@ u_int flags;
 	is->is_me = stsave;
 	if (is->is_p == IPPROTO_TCP) {
 		fr_tcp_age(&is->is_age, is->is_state, fin,
-			   0); /* 0 = packet from the source */
+			   0, is->is_fsm); /* 0 = packet from the source */
 	}
 #ifdef	IPFILTER_LOG
 	ipstate_log(is, ISL_NEW);
@@ -800,6 +811,46 @@ u_int flags;
 }
 
 
+static int fr_tcpoptions(tcp)
+tcphdr_t *tcp;
+{
+	u_char *opt, *last;
+	int wscale;
+
+	opt = (u_char *) (tcp + 1);
+	last = ((u_char *)tcp) + (tcp->th_off << 2);
+
+	/* If we don't find wscale here, we need to clear it */
+	wscale = -2;
+
+	/* Termination condition picked such that opt[0 .. 2] exist */
+	while ((opt < last - 2)  && (*opt != TCPOPT_EOL)) {
+		switch (*opt) {
+		case TCPOPT_NOP:
+			opt++;
+			continue;
+		case TCPOPT_WSCALE:
+			/* Proper length ? */
+			if (opt[1] == 3) {
+				if (opt[2] > 14)
+					wscale = 14;
+				else
+					wscale = opt[2];
+			}
+			break;
+		default:
+			/* Unknown options must be two bytes+ */
+			if (opt[1] < 2)
+				break;
+			opt += opt[1];
+			continue;
+		}
+		break;
+	}
+	return wscale;
+}
+
+
 
 /*
  * check to see if a packet with TCP headers fits within the TCP window.
@@ -815,9 +866,10 @@ tcphdr_t *tcp;
 	register tcp_seq seq, ack, end;
 	register int ackskew;
 	tcpdata_t  *fdata, *tdata;
-	u_short	win, maxwin;
-	int ret = 0;
+	u_32_t	win, maxwin;
+	int ret = 0, off;
 	int source;
+	int wscale;
 
 	/*
 	 * Find difference between last checked packet and this packet.
@@ -827,15 +879,29 @@ tcphdr_t *tcp;
 		source = 0;
 	fdata = &is->is_tcp.ts_data[!source];
 	tdata = &is->is_tcp.ts_data[source];
+	off = tcp->th_off << 2;
 	seq = ntohl(tcp->th_seq);
 	ack = ntohl(tcp->th_ack);
 	win = ntohs(tcp->th_win);
-	end = seq + fin->fin_dlen - (tcp->th_off << 2) +
+	end = seq + fin->fin_dlen - off +
 	       ((tcp->th_flags & TH_SYN) ? 1 : 0) +
 	       ((tcp->th_flags & TH_FIN) ? 1 : 0);
 
+
+	if ((tcp->th_flags & TH_SYN) && (off >= sizeof(*tcp) + 4))
+		wscale = fr_tcpoptions(tcp);
+	else
+		wscale = -1;
+
 	MUTEX_ENTER(&is->is_lock);
-	if (fdata->td_end == 0) {
+
+	if (wscale >= 0)
+		fdata->td_wscale = wscale;
+	else if (wscale == -2)
+		fdata->td_wscale = tdata->td_wscale = 0;
+
+	if ((fdata->td_end == 0) &&
+	    (!is->is_fsm || ((tcp->th_flags & TH_OPENING) == TH_OPENING))) {
 		/*
 		 * Must be a (outgoing) SYN-ACK in reply to a SYN.
 		 */
@@ -855,6 +921,7 @@ tcphdr_t *tcp;
 	if (seq == end)
 		seq = end = fdata->td_end;
 
+	win <<= fdata->td_wscale;
 	maxwin = tdata->td_maxwin;
 	ackskew = tdata->td_end - ack;
 
@@ -880,29 +947,33 @@ tcphdr_t *tcp;
 		 * Thus, when ackskew is negative but still seems to belong
 		 * to this session, we bump up the destinations end value.
 		 */
-		if (ackskew < 0)
-			tdata->td_end = ack;
-
-		/* update max window seen */
-		if (fdata->td_maxwin < win)
-			fdata->td_maxwin = win;
-		if (SEQ_GT(end, fdata->td_end))
-			fdata->td_end = end;
-		if (SEQ_GE(ack + win, tdata->td_maxend)) {
-			tdata->td_maxend = ack + win;
-			if (win == 0)
-				tdata->td_maxend++;
-		}
-
-		ATOMIC_INCL(ips_stats.iss_hits);
 		/*
 		 * Nearing end of connection, start timeout.
 		 */
 		/* source ? 0 : 1 -> !source */
-		fr_tcp_age(&is->is_age, is->is_state, fin, !source);
-		ret = 1;
+		if (fr_tcp_age(&is->is_age, is->is_state, fin, !source,
+			       (int)is->is_fsm) == 0) {
+			if (ackskew < 0)
+				tdata->td_end = ack;
+
+			/* update max window seen */
+			if (fdata->td_maxwin < win)
+				fdata->td_maxwin = win;
+			if (SEQ_GT(end, fdata->td_end))
+				fdata->td_end = end;
+			if (SEQ_GE(ack + win, tdata->td_maxend)) {
+				tdata->td_maxend = ack + win;
+				if (win == 0)
+					tdata->td_maxend++;
+			}
+
+			ATOMIC_INCL(ips_stats.iss_hits);
+			ret = 1;
+		}
 	}
 	MUTEX_EXIT(&is->is_lock);
+	if ((ret == 0) && (tcp->th_flags != TH_SYN))
+		fin->fin_misc |= FM_BADSTATE;
 	return ret;
 }
 
@@ -1081,9 +1152,9 @@ fr_info_t *fin;
 	register ipstate_t *is, **isp;
 	register u_short sport, dport;
 	register u_char	pr;
+	u_short savelen, ohlen;
 	union i6addr dst, src;
 	struct icmp *ic;
-	u_short savelen;
 	icmphdr_t *icmp;
 	fr_info_t ofin;
 	int type, len;
@@ -1112,14 +1183,15 @@ fr_info_t *fin;
 		return NULL;
 
 	oip = (ip_t *)((char *)ic + ICMPERR_ICMPHLEN);
-	if (fin->fin_plen < ICMPERR_MAXPKTLEN + ((oip->ip_hl - 5) << 2))
+	ohlen = oip->ip_hl << 2;
+	if (fin->fin_plen < ICMPERR_MAXPKTLEN + ohlen - sizeof(*oip))
 		return NULL;
 
 	/*
 	 * Sanity checks.
 	 */
 	len = fin->fin_dlen - ICMPERR_ICMPHLEN;
-	if ((len <= 0) || ((oip->ip_hl << 2) > len))
+	if ((len <= 0) || (ohlen > len))
 		return NULL;
 
 	/*
@@ -1159,7 +1231,7 @@ fr_info_t *fin;
 	switch (oip->ip_p)
 	{
 	case IPPROTO_ICMP :
-		icmp = (icmphdr_t *)((char *)oip + (oip->ip_hl << 2));
+		icmp = (icmphdr_t *)((char *)oip + ohlen);
 
 		/*
 		 * a ICMP error can only be generated as a result of an
@@ -1189,7 +1261,7 @@ fr_info_t *fin;
 		savelen = oip->ip_len;
 		oip->ip_len = len;
 		ofin.fin_v = 4;
-		fr_makefrip(oip->ip_hl << 2, oip, &ofin);
+		fr_makefrip(ohlen, oip, &ofin);
 		oip->ip_len = savelen;
 		ofin.fin_ifp = fin->fin_ifp;
 		ofin.fin_out = !fin->fin_out;
@@ -1211,12 +1283,14 @@ fr_info_t *fin;
 	
 	case IPPROTO_TCP :
 	case IPPROTO_UDP :
+		if (fin->fin_plen < ICMPERR_MAXPKTLEN)
+			return NULL;
 		break;
 	default :
 		return NULL;
 	}
 
-	tcp = (tcphdr_t *)((char *)oip + (oip->ip_hl << 2));
+	tcp = (tcphdr_t *)((char *)oip + ohlen);
 	dport = tcp->th_dport;
 	sport = tcp->th_sport;
 
@@ -1241,7 +1315,7 @@ fr_info_t *fin;
 	savelen = oip->ip_len;
 	oip->ip_len = len;
 	ofin.fin_v = 4;
-	fr_makefrip(oip->ip_hl << 2, oip, &ofin);
+	fr_makefrip(ohlen, oip, &ofin);
 	oip->ip_len = savelen;
 	ofin.fin_ifp = fin->fin_ifp;
 	ofin.fin_out = !fin->fin_out;
@@ -1483,9 +1557,8 @@ retry_tcpudp:
 			    fr_matchsrcdst(is, src, dst, fin, tcp)) {
 				rev = fin->fin_rev;
 				if ((pr == IPPROTO_TCP)) {
-					if (!fr_tcpstate(is, fin, ip, tcp)) {
-						continue;
-					}
+					if (!fr_tcpstate(is, fin, ip, tcp))
+						is = NULL;
 				} else if ((pr == IPPROTO_UDP)) {
 					if (is->is_frage[rev] != 0)
 						is->is_age = is->is_frage[rev];
@@ -1506,6 +1579,7 @@ retry_tcpudp:
 			}
 			break;
 		}
+
 		RWLOCK_EXIT(&ipf_state);
 		if (!tryagain && ips_wild) {
 			hv -= dport;
@@ -1705,15 +1779,16 @@ void fr_timeoutstate()
  *    dir == 1 : a packet from dest to source
  *
  */
-void fr_tcp_age(age, state, fin, dir)
+int fr_tcp_age(age, state, fin, dir, fsm)
 u_long *age;
 u_char *state;
 fr_info_t *fin;
-int dir;
+int dir, fsm;
 {
 	tcphdr_t *tcp = (tcphdr_t *)fin->fin_dp;
 	u_char flags = tcp->th_flags;
 	int dlen, ostate;
+	u_long newage;
 
 	ostate = state[1 - dir];
 
@@ -1727,10 +1802,10 @@ int dir;
 			*age = fr_tcpclosewait;
 			state[dir] = TCPS_CLOSE_WAIT;
 		}
-		return;
+		return 0;
 	}
 
-	*age = fr_tcptimeout; /* default 4 mins */
+	newage = 0;
 
 	switch(state[dir])
 	{
@@ -1741,11 +1816,11 @@ int dir;
 			 * CLOSED -> SYN_RECEIVED
 			 */
 			state[dir] = TCPS_SYN_RECEIVED;
-			*age = fr_tcptimeout;
-		} else if ((flags & (TH_SYN|TH_ACK)) == TH_SYN) {
+			newage = fr_tcptimeout;
+		} else if ((flags & TH_OPENING) == TH_SYN) {
 			/* 'dir' sent S, CLOSED -> SYN_SENT */
 			state[dir] = TCPS_SYN_SENT;
-			*age = fr_tcptimeout;
+			newage = fr_tcptimeout;
 		}
 		/*
 		 * The next piece of code makes it possible to get
@@ -1754,12 +1829,12 @@ int dir;
 		 * does not work when a strict 'flags S keep state' is
 		 * used for tcp connections of course
 		 */
-		if ((flags & (TH_FIN|TH_SYN|TH_RST|TH_ACK)) == TH_ACK) {
+		if (!fsm && (flags & (TH_FIN|TH_SYN|TH_RST|TH_ACK)) == TH_ACK) {
 			/* we saw an A, guess 'dir' is in ESTABLISHED mode */
 			if (state[1 - dir] == TCPS_CLOSED ||
 			    state[1 - dir] == TCPS_ESTABLISHED) {
 				state[dir] = TCPS_ESTABLISHED;
-				*age = fr_tcpidletimeout;
+				newage = fr_tcpidletimeout;
 			}
 		}
 		/*
@@ -1774,14 +1849,24 @@ int dir;
 		break;
 
 	case TCPS_SYN_SENT: /* 2 */
-		if ((flags & (TH_SYN|TH_FIN|TH_ACK)) == TH_ACK) {
+		if (flags == TH_SYN) {
+			/*
+			 * A retransmitted SYN packet.  We do not reset the
+			 * timeout here to fr_tcptimeout because a connection
+			 * connect timeout does not renew after every packet
+			 * that is sent.  We need to set newage to something
+			 * to indicate the packet has passed the check for its
+			 * flags being valid in the TCP FSM.
+			 */
+			newage = *age;
+		} else if ((flags & (TH_SYN|TH_FIN|TH_ACK)) == TH_ACK) {
 			/*
 			 * We see an A from 'dir' which is in SYN_SENT
 			 * state: 'dir' sent an A in response to an SA
 			 * which it received, SYN_SENT -> ESTABLISHED
 			 */
 			state[dir] = TCPS_ESTABLISHED;
-			*age = fr_tcpidletimeout;
+			newage = fr_tcpidletimeout;
 		} else if (flags & TH_FIN) {
 			/*
 			 * We see an F from 'dir' which is in SYN_SENT
@@ -1789,7 +1874,7 @@ int dir;
 			 * connection; SYN_SENT -> FIN_WAIT_1
 			 */
 			state[dir] = TCPS_FIN_WAIT_1;
-			*age = fr_tcpidletimeout; /* or fr_tcptimeout? */
+			newage = fr_tcpidletimeout; /* or fr_tcptimeout? */
 		} else if ((flags & TH_OPENING) == TH_OPENING) {
 			/*
 			 * We see an SA from 'dir' which is already in
@@ -1797,7 +1882,7 @@ int dir;
 			 * simultaneous open; SYN_SENT -> SYN_RECEIVED
 			 */
 			state[dir] = TCPS_SYN_RECEIVED;
-			*age = fr_tcptimeout;
+			newage = fr_tcptimeout;
 		}
 		break;
 
@@ -1809,7 +1894,7 @@ int dir;
 			 * SYN_RECEIVED -> ESTABLISHED
 			 */
 			state[dir] = TCPS_ESTABLISHED;
-			*age = fr_tcpidletimeout;
+			newage = fr_tcpidletimeout;
 		} else if (flags & TH_FIN) {
 			/*
 			 * We see an F from 'dir' which is in SYN_RECEIVED
@@ -1817,7 +1902,7 @@ int dir;
 			 * SYN_RECEIVED -> FIN_WAIT_1
 			 */
 			state[dir] = TCPS_FIN_WAIT_1;
-			*age = fr_tcpidletimeout;
+			newage = fr_tcpidletimeout;
 		}
 		break;
 
@@ -1829,7 +1914,7 @@ int dir;
 			 * ESTABLISHED -> FIN_WAIT_1
 			 */
 			state[dir] = TCPS_FIN_WAIT_1;
-			*age = fr_tcphalfclosed;
+			newage = fr_tcphalfclosed;
 		} else if (flags & TH_ACK) {
 			/* an ACK, should we exclude other flags here? */
 			if (ostate == TCPS_FIN_WAIT_1) {
@@ -1841,13 +1926,13 @@ int dir;
 				 * a half-closed connection
 				 */
 				state[dir] = TCPS_CLOSE_WAIT;
-				*age = fr_tcphalfclosed;
+				newage = fr_tcphalfclosed;
 			} else if (ostate < TCPS_CLOSE_WAIT)
 				/*
 				 * Still a fully established connection,
 				 * reset timeout
 				 */
-				*age = fr_tcpidletimeout;
+				newage = fr_tcpidletimeout;
 		}
 		break;
 
@@ -1857,7 +1942,7 @@ int dir;
 			 * Application closed and 'dir' sent a FIN, we're now
 			 * going into LAST_ACK state
 			 */
-			*age  = fr_tcplastack;
+			newage  = fr_tcplastack;
 			state[dir] = TCPS_LAST_ACK;
 		} else {
 			/*
@@ -1865,7 +1950,7 @@ int dir;
 			 * closed already and we did not close our side yet;
 			 * reset timeout
 			 */
-			*age  = fr_tcphalfclosed;
+			newage  = fr_tcphalfclosed;
 		}
 		break;
 
@@ -1882,14 +1967,14 @@ int dir;
 			 * packet here? does the window code guarantee that?
 			 */
 			state[dir] = TCPS_TIME_WAIT;
-			*age = fr_tcptimeout;
+			newage = fr_tcptimeout;
 		} else
 			/*
 			 * We closed our side of the connection already but the
 			 * other side is still active (ESTABLISHED/CLOSE_WAIT);
 			 * continue with this half-closed connection
 			 */
-			*age = fr_tcphalfclosed;
+			newage = fr_tcphalfclosed;
 		break;
 
 	case TCPS_CLOSING: /* 7 */
@@ -1903,7 +1988,7 @@ int dir;
 				 * There is still data to be delivered, reset
 				 * timeout
 				 */
-				*age  = fr_tcplastack;
+				newage  = fr_tcplastack;
 		}
 		/*
 		 * We cannot detect when we go out of LAST_ACK state to CLOSED
@@ -1918,9 +2003,16 @@ int dir;
 		break;
 
 	case TCPS_TIME_WAIT: /* 10 */
+		newage = fr_tcptimeout; /* default 4 mins */
 		/* we're in 2MSL timeout now */
 		break;
 	}
+
+	if (newage != 0) {
+		*age = newage;
+		return 0;
+	}
+	return -1;
 }
 
 
@@ -2070,8 +2162,14 @@ fr_info_t *fin;
 	hv = (pr = oip->ip6_nxt);
 	src.in6 = oip->ip6_src;
 	hv += src.in4.s_addr;
+	hv += src.i6[1];
+	hv += src.i6[2];
+	hv += src.i6[3];
 	dst.in6 = oip->ip6_dst;
 	hv += dst.in4.s_addr;
+	hv += dst.i6[1];
+	hv += dst.i6[2];
+	hv += dst.i6[3];
 	hv += dport;
 	hv += sport;
 	hv %= fr_statesize;
diff --git a/sys/contrib/ipfilter/netinet/ip_state.h b/sys/contrib/ipfilter/netinet/ip_state.h
index a645868af7d7..780e30b732cf 100644
--- a/sys/contrib/ipfilter/netinet/ip_state.h
+++ b/sys/contrib/ipfilter/netinet/ip_state.h
@@ -43,7 +43,8 @@ typedef struct icmpstate {
 typedef	struct	tcpdata	{
 	u_32_t	td_end;
 	u_32_t	td_maxend;
-	u_short	td_maxwin;
+	u_32_t	td_maxwin;
+	u_char	td_wscale;
 } tcpdata_t;
 
 typedef	struct tcpstate {
@@ -59,20 +60,22 @@ typedef struct ipstate {
 	struct	ipstate	*is_hnext;
 	struct	ipstate	**is_phnext;
 	struct	ipstate	**is_me;
+	frentry_t	*is_rule;
+	U_QUAD_T	is_pkts;
+	U_QUAD_T	is_bytes;
+	union	i6addr	is_src;
+	union	i6addr	is_dst;
+	void	*is_ifp[4];
 	u_long	is_age;
 	u_int	is_frage[2];	/* age from filter rule, forward & reverse */
 	u_int	is_pass;
-	U_QUAD_T	is_pkts;
-	U_QUAD_T	is_bytes;
-	void	*is_ifp[4];
-	frentry_t	*is_rule;
-	union	i6addr	is_src;
-	union	i6addr	is_dst;
 	u_char	is_p;			/* Protocol */
-	u_char	is_v;
-	u_int	is_hv;
+	u_char	is_v;			/* IP version */
+	u_char	is_fsm;			/* 1 = following FSM, 0 = not */
+	u_char	is_xxx;			/* pad */
+	u_int	is_hv;			/* hash value for this in the table */
 	u_32_t	is_rulen;		/* rule number */
-	u_32_t	is_flags;
+	u_32_t	is_flags;		/* flags for this structure */
 	u_32_t	is_opt;			/* packet options set */
 	u_32_t	is_optmsk;		/*    "      "    mask */
 	u_short	is_sec;			/* security options set */
@@ -101,6 +104,8 @@ typedef struct ipstate {
 #define is_dend		is_tcp.ts_data[1].td_end
 #define is_maxswin	is_tcp.ts_data[0].td_maxwin
 #define is_maxdwin	is_tcp.ts_data[1].td_maxwin
+#define is_swscale	is_tcp.ts_data[0].td_wscale
+#define is_dwscale	is_tcp.ts_data[1].td_wscale
 #define is_maxsend	is_tcp.ts_data[0].td_maxend
 #define is_maxdend	is_tcp.ts_data[1].td_maxend
 #define	is_sport	is_tcp.ts_sport
@@ -192,7 +197,7 @@ extern	ipstate_t *fr_addstate __P((ip_t *, fr_info_t *, ipstate_t **, u_int));
 extern	frentry_t *fr_checkstate __P((ip_t *, fr_info_t *));
 extern	void	ip_statesync __P((void *));
 extern	void	fr_timeoutstate __P((void));
-extern	void	fr_tcp_age __P((u_long *, u_char *, fr_info_t *, int));
+extern	int	fr_tcp_age __P((u_long *, u_char *, fr_info_t *, int, int));
 extern	void	fr_stateunload __P((void));
 extern	void	ipstate_log __P((struct ipstate *, u_int));
 #if defined(__NetBSD__) || defined(__OpenBSD__)
diff --git a/sys/contrib/ipfilter/netinet/ipl.h b/sys/contrib/ipfilter/netinet/ipl.h
index fdb289a85591..96a2a208cfb8 100644
--- a/sys/contrib/ipfilter/netinet/ipl.h
+++ b/sys/contrib/ipfilter/netinet/ipl.h
@@ -10,6 +10,6 @@
 #ifndef	__IPL_H__
 #define	__IPL_H__
 
-#define	IPL_VERSION	"IP Filter: v3.4.25"
+#define	IPL_VERSION	"IP Filter: v3.4.26"
 
 #endif