[Midnightbsd-cvs] src: ipfilter/netinet: Sync ipfilter with freebsd

laffer1 at midnightbsd.org laffer1 at midnightbsd.org
Thu Sep 18 22:15:16 EDT 2008


Log Message:
-----------
Sync ipfilter with freebsd

Modified Files:
--------------
    src/sys/contrib/ipfilter/netinet:
        fil.c (r1.1.1.1 -> r1.2)
        ip_auth.c (r1.1.1.1 -> r1.2)
        ip_auth.h (r1.1.1.1 -> r1.2)
        ip_compat.h (r1.1.1.1 -> r1.2)
        ip_fil.h (r1.1.1.1 -> r1.2)
        ip_fil_freebsd.c (r1.1.1.1 -> r1.2)
        ip_frag.c (r1.1.1.1 -> r1.2)
        ip_frag.h (r1.1.1.1 -> r1.2)
        ip_ftp_pxy.c (r1.1.1.1 -> r1.2)
        ip_htable.c (r1.1.1.1 -> r1.2)
        ip_htable.h (r1.1.1.1 -> r1.2)
        ip_ipsec_pxy.c (r1.1.1.1 -> r1.2)
        ip_irc_pxy.c (r1.1.1.1 -> r1.2)
        ip_log.c (r1.1.1.1 -> r1.2)
        ip_lookup.c (r1.1.1.1 -> r1.2)
        ip_lookup.h (r1.1.1.1 -> r1.2)
        ip_nat.c (r1.1.1.1 -> r1.2)
        ip_nat.h (r1.1.1.1 -> r1.2)
        ip_netbios_pxy.c (r1.1.1.1 -> r1.2)
        ip_pool.c (r1.1.1.1 -> r1.2)
        ip_pool.h (r1.1.1.1 -> r1.2)
        ip_pptp_pxy.c (r1.1.1.1 -> r1.2)
        ip_proxy.c (r1.1.1.1 -> r1.2)
        ip_proxy.h (r1.1.1.1 -> r1.2)
        ip_raudio_pxy.c (r1.1.1.1 -> r1.2)
        ip_rcmd_pxy.c (r1.1.1.1 -> r1.2)
        ip_rpcb_pxy.c (r1.1.1.1 -> r1.2)
        ip_scan.c (r1.1.1.1 -> r1.2)
        ip_scan.h (r1.1.1.1 -> r1.2)
        ip_state.c (r1.1.1.1 -> r1.2)
        ip_state.h (r1.1.1.1 -> r1.2)
        ip_sync.c (r1.1.1.1 -> r1.2)
        ip_sync.h (r1.1.1.1 -> r1.2)
        ipl.h (r1.1.1.1 -> r1.2)
        mlfk_ipl.c (r1.1.1.1 -> r1.2)

-------------- next part --------------
Index: ipl.h
===================================================================
RCS file: /home/cvs/src/sys/contrib/ipfilter/netinet/ipl.h,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/contrib/ipfilter/netinet/ipl.h -L sys/contrib/ipfilter/netinet/ipl.h -u -r1.1.1.1 -r1.2
--- sys/contrib/ipfilter/netinet/ipl.h
+++ sys/contrib/ipfilter/netinet/ipl.h
@@ -1,4 +1,4 @@
-/*	$FreeBSD: src/sys/contrib/ipfilter/netinet/ipl.h,v 1.23 2005/04/25 18:43:14 darrenr Exp $	*/
+/*	$FreeBSD: src/sys/contrib/ipfilter/netinet/ipl.h,v 1.26.2.1 2007/10/31 05:00:38 darrenr Exp $	*/
 
 /*
  * Copyright (C) 1993-2001, 2003 by Darren Reed.
@@ -6,15 +6,15 @@
  * See the IPFILTER.LICENCE file for details on licencing.
  *
  * @(#)ipl.h	1.21 6/5/96
- * $FreeBSD: src/sys/contrib/ipfilter/netinet/ipl.h,v 1.23 2005/04/25 18:43:14 darrenr Exp $
- * Id: ipl.h,v 2.52.2.9 2005/03/30 14:14:05 darrenr Exp
+ * $FreeBSD: src/sys/contrib/ipfilter/netinet/ipl.h,v 1.26.2.1 2007/10/31 05:00:38 darrenr Exp $
+ * Id: ipl.h,v 2.52.2.30 2007/10/16 09:41:00 darrenr Exp $
  */
 
 #ifndef	__IPL_H__
 #define	__IPL_H__
 
-#define	IPL_VERSION	"IP Filter: v4.1.8"
+#define	IPL_VERSION	"IP Filter: v4.1.28"
 
-#define	IPFILTER_VERSION	4010800
+#define	IPFILTER_VERSION	4012800
 
 #endif
Index: ip_log.c
===================================================================
RCS file: /home/cvs/src/sys/contrib/ipfilter/netinet/ip_log.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/contrib/ipfilter/netinet/ip_log.c -L sys/contrib/ipfilter/netinet/ip_log.c -u -r1.1.1.1 -r1.2
--- sys/contrib/ipfilter/netinet/ip_log.c
+++ sys/contrib/ipfilter/netinet/ip_log.c
@@ -1,12 +1,12 @@
-/*	$FreeBSD: src/sys/contrib/ipfilter/netinet/ip_log.c,v 1.29 2005/04/25 18:43:14 darrenr Exp $	*/
+/*	$FreeBSD: src/sys/contrib/ipfilter/netinet/ip_log.c,v 1.33.2.1 2007/10/31 05:00:38 darrenr Exp $	*/
 
 /*
  * Copyright (C) 1997-2003 by Darren Reed.
  *
  * See the IPFILTER.LICENCE file for details on licencing.
  *
- * $FreeBSD: src/sys/contrib/ipfilter/netinet/ip_log.c,v 1.29 2005/04/25 18:43:14 darrenr Exp $
- * Id: ip_log.c,v 2.75.2.6 2004/10/16 07:59:27 darrenr Exp
+ * $FreeBSD: src/sys/contrib/ipfilter/netinet/ip_log.c,v 1.33.2.1 2007/10/31 05:00:38 darrenr Exp $
+ * Id: ip_log.c,v 2.75.2.19 2007/09/09 11:32:06 darrenr Exp $
  */
 #include <sys/param.h>
 #if defined(KERNEL) || defined(_KERNEL)
@@ -17,7 +17,11 @@
 #endif
 #if defined(__NetBSD__) && (NetBSD >= 199905) && !defined(IPFILTER_LKM) && \
     defined(_KERNEL)
-# include "opt_ipfilter_log.h"
+# if (__NetBSD_Version__ < 399001400)
+#  include "opt_ipfilter_log.h"
+# else
+#  include "opt_ipfilter.h"
+# endif
 #endif
 #if defined(__FreeBSD__) && !defined(IPFILTER_LKM)
 # if defined(_KERNEL)
@@ -62,12 +66,18 @@
 # endif
 #endif /* _KERNEL */
 #if !SOLARIS && !defined(__hpux) && !defined(linux)
-# if (NetBSD > 199609) || (OpenBSD > 199603) || (__FreeBSD_version >= 300000)
+# if (defined(NetBSD) && NetBSD > 199609) || \
+     (defined(OpenBSD) && OpenBSD > 199603) || \
+     (__FreeBSD_version >= 300000)
 #  include <sys/dirent.h>
 # else
 #  include <sys/dir.h>
 # endif
 # include <sys/mbuf.h>
+# include <sys/select.h>
+# if __FreeBSD_version >= 500000
+#  include <sys/selinfo.h>
+# endif
 #else
 # if !defined(__hpux) && defined(_KERNEL)
 #  include <sys/filio.h>
@@ -146,15 +156,15 @@
 # if defined(linux) && defined(_KERNEL)
 wait_queue_head_t	iplh_linux[IPL_LOGSIZE];
 # endif
-# if SOLARIS
+# if SOLARIS && defined(_KERNEL)
 extern	kcondvar_t	iplwait;
+extern	struct pollhead	iplpollhead[IPL_LOGSIZE];
 # endif
 
 iplog_t	**iplh[IPL_LOGSIZE], *iplt[IPL_LOGSIZE], *ipll[IPL_LOGSIZE];
 int	iplused[IPL_LOGSIZE];
 static fr_info_t	iplcrc[IPL_LOGSIZE];
 int	ipl_suppress = 1;
-int	ipl_buffer_sz;
 int	ipl_logmax = IPL_LOGMAX;
 int	ipl_logall = 0;
 int	ipl_log_init = 0;
@@ -251,16 +261,23 @@
 	ipflog_t ipfl;
 	u_char p;
 	mb_t *m;
-# if (SOLARIS || defined(__hpux)) && defined(_KERNEL)
+# if (SOLARIS || defined(__hpux)) && defined(_KERNEL) && \
+  !defined(_INET_IP_STACK_H)
 	qif_t *ifp;
 # else
 	struct ifnet *ifp;
 # endif /* SOLARIS || __hpux */
 
-	ipfl.fl_nattag.ipt_num[0] = 0;
 	m = fin->fin_m;
+	if (m == NULL)
+		return -1;
+
+	ipfl.fl_nattag.ipt_num[0] = 0;
 	ifp = fin->fin_ifp;
-	hlen = fin->fin_hlen;
+	if (fin->fin_exthdr != NULL)
+		hlen = (char *)fin->fin_dp - (char *)fin->fin_ip;
+	else
+		hlen = fin->fin_hlen;
 	/*
 	 * calculate header size.
 	 */
@@ -321,14 +338,16 @@
 	 * Get the interface number and name to which this packet is
 	 * currently associated.
 	 */
-# if (SOLARIS || defined(__hpux)) && defined(_KERNEL)
+# if (SOLARIS || defined(__hpux)) && defined(_KERNEL) && \
+     !defined(_INET_IP_STACK_H)
 	ipfl.fl_unit = (u_int)ifp->qf_ppa;
-	COPYIFNAME(ifp, ipfl.fl_ifname);
+	COPYIFNAME(fin->fin_v, ifp, ipfl.fl_ifname);
 # else
 #  if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199603)) || \
       (defined(OpenBSD) && (OpenBSD >= 199603)) || defined(linux) || \
-      (defined(__FreeBSD__) && (__FreeBSD_version >= 501113))
-	COPYIFNAME(ifp, ipfl.fl_ifname);
+      (defined(__FreeBSD__) && (__FreeBSD_version >= 501113)) || \
+      (SOLARIS && defined(_INET_IP_STACK_H))
+	COPYIFNAME(fin->fin_v, ifp, ipfl.fl_ifname);
 #  else
 	ipfl.fl_unit = (u_int)ifp->if_unit;
 #   if defined(_KERNEL)
@@ -337,7 +356,7 @@
 			if ((ipfl.fl_ifname[2] = ifp->if_name[2]))
 				ipfl.fl_ifname[3] = ifp->if_name[3];
 #   else
-	(void) strncpy(ipfl.fl_ifname, IFNAME(ifp), sizeof(ipfl.fl_ifname));
+	COPYIFNAME(fin->fin_v, ifp, ipfl.fl_ifname);
 	ipfl.fl_ifname[sizeof(ipfl.fl_ifname) - 1] = '\0';
 #   endif
 #  endif
@@ -413,13 +432,11 @@
 size_t *itemsz;
 int *types, cnt;
 {
-	caddr_t buf, ptr;
+	u_char *buf, *ptr;
 	iplog_t *ipl;
 	size_t len;
 	int i;
-# if defined(_KERNEL) && !defined(MENTAT) && defined(USE_SPL)
-	int s;
-# endif
+	SPL_INT(s);
 
 	/*
 	 * Check to see if this log record has a CRC which matches the last
@@ -452,7 +469,7 @@
 	 * check that we have space to record this information and can
 	 * allocate that much.
 	 */
-	KMALLOCS(buf, caddr_t, len);
+	KMALLOCS(buf, u_char *, len);
 	if (buf == NULL)
 		return -1;
 	SPL_NET(s);
@@ -491,7 +508,7 @@
 		if (types[i] == 0) {
 			bcopy(items[i], ptr, itemsz[i]);
 		} else if (types[i] == 1) {
-			COPYDATA(items[i], 0, itemsz[i], ptr);
+			COPYDATA(items[i], 0, itemsz[i], (char *)ptr);
 		}
 		ptr += itemsz[i];
 	}
@@ -508,9 +525,11 @@
 # if SOLARIS && defined(_KERNEL)
 	cv_signal(&iplwait);
 	MUTEX_EXIT(&ipl_mutex);
+	pollwakeup(&iplpollhead[dev], POLLRDNORM);
 # else
 	MUTEX_EXIT(&ipl_mutex);
-	WAKEUP(iplh,dev);
+	WAKEUP(iplh, dev);
+	POLLWAKEUP(dev);
 # endif
 	SPL_X(s);
 # ifdef	IPL_SELECT
@@ -539,9 +558,7 @@
 	size_t dlen, copied;
 	int error = 0;
 	iplog_t *ipl;
-# if defined(_KERNEL) && !defined(MENTAT) && defined(USE_SPL)
-	int s;
-# endif
+	SPL_INT(s);
 
 	/*
 	 * Sanity checks.  Make sure the minor # is valid and we're copying
@@ -616,7 +633,7 @@
 		iplused[unit] -= dlen;
 		MUTEX_EXIT(&ipl_mutex);
 		SPL_X(s);
-		error = UIOMOVE((caddr_t)ipl, dlen, UIO_READ, uio);
+		error = UIOMOVE(ipl, dlen, UIO_READ, uio);
 		if (error) {
 			SPL_NET(s);
 			MUTEX_ENTER(&ipl_mutex);
@@ -626,7 +643,7 @@
 			break;
 		}
 		MUTEX_ENTER(&ipl_mutex);
-		KFREES((caddr_t)ipl, dlen);
+		KFREES(ipl, dlen);
 		SPL_NET(s);
 	}
 	if (!iplt[unit]) {
@@ -653,15 +670,13 @@
 {
 	iplog_t *ipl;
 	int used;
-# if defined(_KERNEL) && !defined(MENTAT) && defined(USE_SPL)
-	int s;
-# endif
+	SPL_INT(s);
 
 	SPL_NET(s);
 	MUTEX_ENTER(&ipl_mutex);
 	while ((ipl = iplt[unit]) != NULL) {
 		iplt[unit] = ipl->ipl_next;
-		KFREES((caddr_t)ipl, ipl->ipl_dsize);
+		KFREES(ipl, ipl->ipl_dsize);
 	}
 	iplh[unit] = &iplt[unit];
 	ipll[unit] = NULL;
@@ -672,4 +687,19 @@
 	SPL_X(s);
 	return used;
 }
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipflog_canread                                              */
+/* Returns:     int    - 0 == no data to read, 1 = data present             */
+/* Parameters:  unit(I) - device we are reading from                        */
+/*                                                                          */
+/* Returns an indication of whether or not there is data present in the     */
+/* current buffer for the selected ipf device.                              */
+/* ------------------------------------------------------------------------ */
+int ipflog_canread(unit)
+int unit;
+{
+	return iplt[unit] != NULL;
+}
 #endif /* IPFILTER_LOG */
Index: ip_compat.h
===================================================================
RCS file: /home/cvs/src/sys/contrib/ipfilter/netinet/ip_compat.h,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/contrib/ipfilter/netinet/ip_compat.h -L sys/contrib/ipfilter/netinet/ip_compat.h -u -r1.1.1.1 -r1.2
--- sys/contrib/ipfilter/netinet/ip_compat.h
+++ sys/contrib/ipfilter/netinet/ip_compat.h
@@ -1,13 +1,11 @@
-/*	$FreeBSD: src/sys/contrib/ipfilter/netinet/ip_compat.h,v 1.28 2005/05/16 16:22:55 darrenr Exp $	*/
-
 /*
  * Copyright (C) 1993-2001, 2003 by Darren Reed.
  *
  * See the IPFILTER.LICENCE file for details on licencing.
  *
  * @(#)ip_compat.h	1.8 1/14/96
- * $FreeBSD: src/sys/contrib/ipfilter/netinet/ip_compat.h,v 1.28 2005/05/16 16:22:55 darrenr Exp $
- * Id: ip_compat.h,v 2.142.2.25 2005/03/28 09:33:36 darrenr Exp
+ * $FreeBSD: src/sys/contrib/ipfilter/netinet/ip_compat.h,v 1.33.2.1 2007/10/31 05:00:37 darrenr Exp $
+ * Id: ip_compat.h,v 2.142.2.57 2007/10/10 09:51:42 darrenr Exp $
  */
 
 #ifndef	__IP_COMPAT_H__
@@ -37,7 +35,7 @@
 #ifndef	SOLARIS
 #define	SOLARIS	(defined(sun) && (defined(__svr4__) || defined(__SVR4)))
 #endif
-#if SOLARIS2 >= 8
+#if defined(SOLARIS2) && SOLARIS2 >= 8
 # ifndef	USE_INET6
 #  define	USE_INET6
 # endif
@@ -142,7 +140,7 @@
 # include	<sys/ioccom.h>
 # include	<sys/sysmacros.h>
 # include	<sys/kmem.h>
-# if SOLARIS2 >= 10
+# if defined(SOLARIS2) && SOLARIS2 >= 10
 #  include	<sys/procset.h>
 #  include	<sys/proc.h>
 #  include	<sys/devops.h>
@@ -156,7 +154,7 @@
 #  undef	RES_INIT
 # endif /* _KERNEL */
 
-# if SOLARIS2 >= 8
+# if defined(SOLARIS2) && SOLARIS2 >= 8
 #  include <netinet/ip6.h>
 #  include <netinet/icmp6.h>
 # endif
@@ -171,13 +169,18 @@
 # ifdef i386
 #  define _SYS_PROMIF_H
 # endif
+# ifndef _KERNEL
+#  include "radix_ipf.h"
+# else
+#  include "radix_ipf_local.h"
+# endif
 # include <inet/ip.h>
 # undef COPYOUT
 # include <inet/ip_ire.h>
 # ifndef	KERNEL
 #  undef	_KERNEL
 # endif
-# if SOLARIS2 >= 8
+# if defined(SOLARIS2) && SOLARIS2 >= 8
 #  define SNPRINTF	snprintf
 
 #  include <inet/ip_if.h>
@@ -192,7 +195,7 @@
 };
 # endif /* SOLARIS2 >= 8 */
 
-# if SOLARIS2 >= 6
+# if defined(SOLARIS2) && SOLARIS2 >= 6
 #  include <sys/atomic.h>
 typedef	uint32_t	u_32_t;
 # else
@@ -203,8 +206,28 @@
 # ifdef _KERNEL
 #  define	KRWLOCK_T		krwlock_t
 #  define	KMUTEX_T		kmutex_t
-#  include "qif.h"
-#  include "pfil.h"
+
+#  if !defined(FW_HOOKS)
+#   include "qif.h"
+#   include "pfil.h"
+#  else
+#   include <sys/neti.h>
+
+extern net_data_t ipfipv4;
+extern net_data_t ipfipv6;
+
+typedef struct qpktinfo {
+        void		*qpi_data;
+	mblk_t		**qpi_mp;
+	mblk_t		*qpi_m;
+        uintptr_t	qpi_real;
+	int		qpi_flags;
+        int		qpi_num;
+        int		qpi_off;
+} qpktinfo_t;
+#   define	QF_GROUP		0x01
+#  endif
+
 #  if SOLARIS2 >= 6
 #   if SOLARIS2 == 6
 #    define	ATOMIC_INCL(x)		atomic_add_long((uint32_t*)&(x), 1)
@@ -241,11 +264,12 @@
 #  define	MUTEX_EXIT(x)		mutex_exit(&(x)->ipf_lk)
 #  define	COPYIN(a,b,c)	copyin((caddr_t)(a), (caddr_t)(b), (c))
 #  define	COPYOUT(a,b,c)	copyout((caddr_t)(a), (caddr_t)(b), (c))
-#  define	BCOPYIN(a,b,c)	(void) copyin((caddr_t)(a), (caddr_t)(b), (c))
-#  define	BCOPYOUT(a,b,c)	(void) copyout((caddr_t)(a), (caddr_t)(b), (c))
+#  define	BCOPYIN(a,b,c)	copyin((caddr_t)(a), (caddr_t)(b), (c))
+#  define	BCOPYOUT(a,b,c)	copyout((caddr_t)(a), (caddr_t)(b), (c))
 #  define	UIOMOVE(a,b,c,d)	uiomove((caddr_t)a,b,c,d)
 #  define	KFREE(x)	kmem_free((char *)(x), sizeof(*(x)))
 #  define	KFREES(x,s)	kmem_free((char *)(x), (s))
+#  define	SPL_SCHED(x)	;
 #  define	SPL_NET(x)	;
 #  define	SPL_IMP(x)	;
 #  undef	SPL_X
@@ -261,10 +285,24 @@
 #  define	GET_MINOR(x)	getminor(x)
 extern	void	*get_unit __P((char *, int));
 #  define	GETIFP(n, v)	get_unit(n, v)
-#  define	IFNAME(x)	((qif_t *)x)->qf_name
-#  define	COPYIFNAME(x, b) \
+#  if defined(_INET_IP_STACK_H)
+#   define	 COPYIFNAME(v, x, b) \
+				do { \
+					if ((v) == 4) { \
+						(void) net_getifname(ipfipv4,\
+							(uintptr_t)x, b, \
+							LIFNAMSIZ); \
+					} else { \
+						(void) net_getifname(ipfipv6,\
+							(uintptr_t)x, b, \
+							LIFNAMSIZ); \
+					} \
+				} while (0)
+#  else
+#   define	 COPYIFNAME(v, x, b) \
 				(void) strncpy(b, ((qif_t *)x)->qf_name, \
 					       LIFNAMSIZ)
+#  endif
 #  define	GETKTIME(x)	uniqtime((struct timeval *)x)
 #  define	MSGDSIZE(x)	msgdsize(x)
 #  define	M_LEN(x)	((x)->b_wptr - (x)->b_rptr)
@@ -273,12 +311,16 @@
 #  define	MTYPE(m)	((m)->b_datap->db_type)
 #  define	FREE_MB_T(m)	freemsg(m)
 #  define	m_next		b_cont
-#  define	CACHE_HASH(x)	(((qpktinfo_t *)(x)->fin_qpi)->qpi_num & 7)
+#  if !defined(_INET_IP_STACK_H)
+#   define	CACHE_HASH(x)	(((qpktinfo_t *)(x)->fin_qpi)->qpi_num & 7)
+#  else
+#   define	CACHE_HASH(x)	((uintptr_t)(x)->fin_ifp & 7)
+#  endif
 #  define	IPF_PANIC(x,y)	if (x) { printf y; cmn_err(CE_PANIC, "ipf_panic"); }
 typedef mblk_t mb_t;
 # endif /* _KERNEL */
 
-# if (SOLARIS2 >= 7)
+# if defined(SOLARIS2) && (SOLARIS2 >= 7)
 #  ifdef lint
 #   define ALIGN32(ptr)    (ptr ? 0L : 0L)
 #   define ALIGN16(ptr)    (ptr ? 0L : 0L)
@@ -288,7 +330,7 @@
 #  endif
 # endif
 
-# if SOLARIS2 < 6
+# if defined(SOLARIS2) && SOLARIS2 < 6
 typedef	struct uio	uio_t;
 # endif
 typedef	int		ioctlcmd_t;
@@ -418,21 +460,14 @@
 #  define	RW_DESTROY(x)
 #  define	COPYIN(a,b,c)	copyin((caddr_t)(a), (caddr_t)(b), (c))
 #  define	COPYOUT(a,b,c)	copyout((caddr_t)(a), (caddr_t)(b), (c))
-#  if HPUXREV >= 1111
-#   define	BCOPYIN(a,b,c)	0; bcopy((caddr_t)(a), (caddr_t)(b), (c))
-#   define	BCOPYOUT(a,b,c)	0; bcopy((caddr_t)(a), (caddr_t)(b), (c))
-#  else
-#   define	BCOPYIN(a,b,c)	bcopy((caddr_t)(a), (caddr_t)(b), (c))
-#   define	BCOPYOUT(a,b,c)	bcopy((caddr_t)(a), (caddr_t)(b), (c))
-#  endif
+#  define	SPL_SCHED(x)	;
 #  define	SPL_NET(x)	;
 #  define	SPL_IMP(x)	;
 #  undef	SPL_X
 #  define	SPL_X(x)	;
 extern	void	*get_unit __P((char *, int));
 #  define	GETIFP(n, v)	get_unit(n, v)
-#  define	IFNAME(x, b)	((ill_t *)x)->ill_name
-#  define	COPYIFNAME(x, b) \
+#  define	COPYIFNAME(v, x, b) \
 				(void) strncpy(b, ((qif_t *)x)->qf_name, \
 					       LIFNAMSIZ)
 #  define	UIOMOVE(a,b,c,d)	uiomove((caddr_t)a,b,c,d)
@@ -444,6 +479,7 @@
 				  wakeup(id + x); \
 				  spinunlock(_l); \
 				}
+#  define	POLLWAKEUP(x)	;
 #  define	KMALLOC(a, b)	MALLOC((a), b, sizeof(*(a)), M_IOSYS, M_NOWAIT)
 #  define	KMALLOCS(a, b, c)	MALLOC((a), b, (c), M_IOSYS, M_NOWAIT)
 #  define	KFREE(x)	kmem_free((char *)(x), sizeof(*(x)))
@@ -576,11 +612,10 @@
 #  define	MTOD(m,t)	mtod(m,t)
 #  define	COPYIN(a,b,c)	(bcopy((caddr_t)(a), (caddr_t)(b), (c)), 0)
 #  define	COPYOUT(a,b,c)	(bcopy((caddr_t)(a), (caddr_t)(b), (c)), 0)
-#  define	BCOPYIN(a,b,c)	(bcopy((caddr_t)(a), (caddr_t)(b), (c)), 0)
-#  define	BCOPYOUT(a,b,c)	(bcopy((caddr_t)(a), (caddr_t)(b), (c)), 0)
 #  define	UIOMOVE(a,b,c,d)	uiomove((caddr_t)a,b,c,d)
 #  define	SLEEP(id, n)	sleep((id), PZERO+1)
 #  define	WAKEUP(id,x)	wakeup(id+x)
+#  define	POLLWAKEUP(x)	;
 #  define	KFREE(x)	kmem_free((char *)(x), sizeof(*(x)))
 #  define	KFREES(x,s)	kmem_free((char *)(x), (s))
 #  define	GETIFP(n,v)	ifunit(n)
@@ -592,6 +627,7 @@
 #  define	USE_SPL		1
 #  define	SPL_IMP(x)	(x) = splimp()
 #  define	SPL_NET(x)	(x) = splnet()
+#  define	SPL_SCHED(x)	(x) = splsched()
 #  define	SPL_X(x)	(void) splx(x)
 extern	void	m_copydata __P((struct mbuf *, int, int, caddr_t));
 extern	void	m_copyback __P((struct mbuf *, int, int, caddr_t));
@@ -599,6 +635,7 @@
 #  define	M_LEN(x)	(x)->m_len
 #  define	M_DUPLICATE(x)	m_copy((x), 0, M_COPYALL)
 #  define	GETKTIME(x)	microtime((struct timeval *)x)
+#  define	IFNAME(x)	((struct ifnet *)x)->if_name
 #  define	CACHE_HASH(x)	((IFNAME(fin->fin_ifp)[0] + \
 				  ((struct ifnet *)fin->fin_ifp)->if_unit) & 7)
 #  define	IPF_PANIC(x,y)	if (x) { printf y; panic("ipf_panic"); }
@@ -652,6 +689,7 @@
 					  simple_unlock(&ipf_rw); }
 #  define	ATOMIC_DEC(x)		{ simple_lock(&ipf_rw); (x)--; \
 					  simple_unlock(&ipf_rw); }
+#  define	SPL_SCHED(x)		;
 #  define	SPL_NET(x)		;
 #  define	SPL_IMP(x)		;
 #  undef	SPL_X
@@ -662,10 +700,9 @@
 #  define	GETIFP(n, v)		ifunit(n)
 #  define	GET_MINOR		getminor
 #  define	WAKEUP(id,x)		wakeup(id + x)
+#  define	POLLWAKEUP(x)		;
 #  define	COPYIN(a,b,c)	copyin((caddr_t)(a), (caddr_t)(b), (c))
 #  define	COPYOUT(a,b,c)	copyout((caddr_t)(a), (caddr_t)(b), (c))
-#  define	BCOPYIN(a,b,c)	bcopy((caddr_t)(a), (caddr_t)(b), (c))
-#  define	BCOPYOUT(a,b,c)	bcopy((caddr_t)(a), (caddr_t)(b), (c))
 #  define	KMALLOC(a, b)	MALLOC((a), b, sizeof(*(a)), M_PFILT, M_NOWAIT)
 #  define	KMALLOCS(a, b, c)	MALLOC((a), b, (c), M_PFILT, \
 					    ((c) > 4096) ? M_WAITOK : M_NOWAIT)
@@ -675,6 +712,7 @@
 #  define	M_LEN(x)	(x)->m_len
 #  define	M_DUPLICATE(x)	m_copy((x), 0, M_COPYALL)
 #  define	GETKTIME(x)	microtime((struct timeval *)x)
+#  define	IFNAME(x)	((struct ifnet *)x)->if_name
 #  define	CACHE_HASH(x)	((IFNAME(fin->fin_ifp)[0] + \
 				  ((struct ifnet *)fin->fin_ifp)->if_unit) & 7)
 #  define	IPF_PANIC(x,y)	if (x) { printf y; panic("ipf_panic"); }
@@ -718,6 +756,14 @@
 /*                                  N E T B S D                            */
 /* ----------------------------------------------------------------------- */
 #ifdef __NetBSD__
+# if (NetBSD >= 199905) && !defined(IPFILTER_LKM) && defined(_KERNEL)
+#  include "opt_ipfilter.h"
+# endif
+# if defined(_KERNEL)
+#  include <sys/systm.h>
+# else
+#  include <stddef.h>
+# endif
 # if defined(_KERNEL) && !defined(IPFILTER_LKM)
 #  include "bpfilter.h"
 #  if defined(__NetBSD_Version__) && (__NetBSD_Version__ >= 104110000)
@@ -731,7 +777,14 @@
 #  endif
 # endif
 
+# if (__NetBSD_Version__ >= 499000000)
+typedef	char *	caddr_t;
+# endif
+
 # ifdef _KERNEL
+#  if (__NetBSD_Version__ >= 399001400)
+#   define	KMALLOCS(a, b, c)	(a) = (b)malloc((c), _M_IPF, M_NOWAIT)
+#  endif
 #  define	MSGDSIZE(x)	mbufchainlen(x)
 #  define	M_LEN(x)	(x)->m_len
 #  define	M_DUPLICATE(x)	m_copy((x), 0, M_COPYALL)
@@ -739,22 +792,20 @@
 #  define	IPF_PANIC(x,y)	if (x) { printf y; panic("ipf_panic"); }
 #  define	COPYIN(a,b,c)	copyin((caddr_t)(a), (caddr_t)(b), (c))
 #  define	COPYOUT(a,b,c)	copyout((caddr_t)(a), (caddr_t)(b), (c))
-#  define	BCOPYIN(a,b,c)	bcopy((caddr_t)(a), (caddr_t)(b), (c))
-#  define	BCOPYOUT(a,b,c)	bcopy((caddr_t)(a), (caddr_t)(b), (c))
 typedef struct mbuf mb_t;
 # endif /* _KERNEL */
 # if (NetBSD <= 1991011) && (NetBSD >= 199606)
 #  define	IFNAME(x)	((struct ifnet *)x)->if_xname
-#  define	COPYIFNAME(x, b) \
+#  define	COPYIFNAME(v, x, b) \
 				(void) strncpy(b, \
 					       ((struct ifnet *)x)->if_xname, \
 					       LIFNAMSIZ)
 #  define	CACHE_HASH(x)	((((struct ifnet *)fin->fin_ifp)->if_index)&7)
 # else
+#  define	IFNAME(x)	((struct ifnet *)x)->if_name
 #  define	CACHE_HASH(x)	((IFNAME(fin->fin_ifp)[0] + \
 				  ((struct ifnet *)fin->fin_ifp)->if_unit) & 7)
 # endif
-
 typedef	struct uio	uio_t;
 typedef	u_long		ioctlcmd_t;  
 typedef	int		minor_t;
@@ -796,8 +847,6 @@
 #  endif
 #  define	COPYIN(a,b,c)	copyin((caddr_t)(a), (caddr_t)(b), (c))
 #  define	COPYOUT(a,b,c)	copyout((caddr_t)(a), (caddr_t)(b), (c))
-#  define	BCOPYIN(a,b,c)	bcopy((caddr_t)(a), (caddr_t)(b), (c))
-#  define	BCOPYOUT(a,b,c)	bcopy((caddr_t)(a), (caddr_t)(b), (c))
 
 #  if (__FreeBSD_version >= 500043)
 #   define NETBSD_PF
@@ -806,24 +855,66 @@
 
 # if (__FreeBSD_version >= 500043)
 #  include <sys/mutex.h>
-#  include <sys/sx.h>
+#  if (__FreeBSD_version > 700014)
+#   include <sys/rwlock.h>
+#    define	KRWLOCK_T		struct rwlock
+#    ifdef _KERNEL
+#     define	READ_ENTER(x)		rw_rlock(&(x)->ipf_lk)
+#     define	WRITE_ENTER(x)		rw_wlock(&(x)->ipf_lk)
+#     define	MUTEX_DOWNGRADE(x)	rw_downgrade(&(x)->ipf_lk)
+#     define	RWLOCK_INIT(x, y)	rw_init(&(x)->ipf_lk, (y))
+#     define	RW_DESTROY(x)		rw_destroy(&(x)->ipf_lk)
+#     define	RWLOCK_EXIT(x)		do { \
+					    if (rw_wowned(&(x)->ipf_lk)) \
+						rw_wunlock(&(x)->ipf_lk); \
+ 					    else \
+						rw_runlock(&(x)->ipf_lk); \
+					} while (0)
+#   endif
+#  else
+#   include <sys/sx.h>
 /*
  * Whilst the sx(9) locks on FreeBSD have the right semantics and interface
  * for what we want to use them for, despite testing showing they work -
  * with a WITNESS kernel, it generates LOR messages.
  */
-#  define	KMUTEX_T		struct mtx
-#  if 1
-#   define	KRWLOCK_T		struct mtx
-#  else
-#   define	KRWLOCK_T		struct sx
+#   ifdef _KERNEL
+#    if (__FreeBSD_version < 700000)
+#     define	KRWLOCK_T		struct mtx
+#     define	READ_ENTER(x)		mtx_lock(&(x)->ipf_lk)
+#     define	WRITE_ENTER(x)		mtx_lock(&(x)->ipf_lk)
+#     define	RWLOCK_EXIT(x)		mtx_unlock(&(x)->ipf_lk)
+#     define	MUTEX_DOWNGRADE(x)	;
+#     define	RWLOCK_INIT(x,y)	mtx_init(&(x)->ipf_lk, (y), NULL,\
+						 MTX_DEF)
+#     define	RW_DESTROY(x)		mtx_destroy(&(x)->ipf_lk)
+#    else
+#     define	KRWLOCK_T		struct sx
+#     define	READ_ENTER(x)		sx_slock(&(x)->ipf_lk)
+#     define	WRITE_ENTER(x)		sx_xlock(&(x)->ipf_lk)
+#     define	MUTEX_DOWNGRADE(x)	sx_downgrade(&(x)->ipf_lk)
+#     define	RWLOCK_INIT(x, y)	sx_init(&(x)->ipf_lk, (y))
+#     define	RW_DESTROY(x)		sx_destroy(&(x)->ipf_lk)
+#     ifdef sx_unlock
+#      define	RWLOCK_EXIT(x)		sx_unlock(&(x)->ipf_lk)
+#     else
+#      define	RWLOCK_EXIT(x)		do { \
+					    if ((x)->ipf_lk.sx_cnt < 0) \
+						sx_xunlock(&(x)->ipf_lk); \
+					    else \
+						sx_sunlock(&(x)->ipf_lk); \
+					} while (0)
+#     endif
+#    endif
+#   endif
 #  endif
+#  define	KMUTEX_T		struct mtx
 # endif
 
 # if (__FreeBSD_version >= 501113)
 #  include <net/if_var.h>
 #  define	IFNAME(x)	((struct ifnet *)x)->if_xname
-#  define	COPYIFNAME(x, b) \
+#  define	COPYIFNAME(v, x, b) \
 				(void) strncpy(b, \
 					       ((struct ifnet *)x)->if_xname, \
 					       LIFNAMSIZ)
@@ -831,6 +922,7 @@
 # if (__FreeBSD_version >= 500043)
 #  define	CACHE_HASH(x)	((((struct ifnet *)fin->fin_ifp)->if_index) & 7)
 # else
+#  define	IFNAME(x)	((struct ifnet *)x)->if_name
 #  define	CACHE_HASH(x)	((IFNAME(fin->fin_ifp)[0] + \
 				  ((struct ifnet *)fin->fin_ifp)->if_unit) & 7)
 # endif
@@ -852,36 +944,6 @@
 						 MTX_DEF)
 #   define	MUTEX_DESTROY(x)	mtx_destroy(&(x)->ipf_lk)
 #   define	MUTEX_NUKE(x)		bzero((x), sizeof(*(x)))
-/*
- * Whilst the sx(9) locks on FreeBSD have the right semantics and interface
- * for what we want to use them for, despite testing showing they work -
- * with a WITNESS kernel, it generates LOR messages.
- */
-#   if 1
-#    define	READ_ENTER(x)		mtx_lock(&(x)->ipf_lk)
-#    define	WRITE_ENTER(x)		mtx_lock(&(x)->ipf_lk)
-#    define	RWLOCK_EXIT(x)		mtx_unlock(&(x)->ipf_lk)
-#    define	MUTEX_DOWNGRADE(x)	;
-#    define	RWLOCK_INIT(x,y)	mtx_init(&(x)->ipf_lk, (y), NULL,\
-						 MTX_DEF)
-#    define	RW_DESTROY(x)		mtx_destroy(&(x)->ipf_lk)
-#   else
-#    define	READ_ENTER(x)		sx_slock(&(x)->ipf_lk)
-#    define	WRITE_ENTER(x)		sx_xlock(&(x)->ipf_lk)
-#    define	MUTEX_DOWNGRADE(x)	sx_downgrade(&(x)->ipf_lk)
-#    define	RWLOCK_INIT(x, y)	sx_init(&(x)->ipf_lk, (y))
-#    define	RW_DESTROY(x)		sx_destroy(&(x)->ipf_lk)
-#    ifdef sx_unlock
-#     define	RWLOCK_EXIT(x)		sx_unlock(x)
-#    else
-#     define	RWLOCK_EXIT(x)		do { \
-					    if ((x)->ipf_lk.sx_cnt < 0) \
-						sx_xunlock(&(x)->ipf_lk); \
-					    else \
-						sx_sunlock(&(x)->ipf_lk); \
-					} while (0)
-#    endif
-#   endif
 #   include <machine/atomic.h>
 #   define	ATOMIC_INC(x)		{ mtx_lock(&ipf_rw.ipf_lk); (x)++; \
 					  mtx_unlock(&ipf_rw.ipf_lk); }
@@ -889,16 +951,19 @@
 					  mtx_unlock(&ipf_rw.ipf_lk); }
 #   define	ATOMIC_INCL(x)		atomic_add_long(&(x), 1)
 #   define	ATOMIC_INC64(x)		ATOMIC_INC(x)
-#   define	ATOMIC_INC32(x)		atomic_add_32(&(x), 1)
+#   define	ATOMIC_INC32(x)		atomic_add_32((u_int *)&(x), 1)
 #   define	ATOMIC_INC16(x)		atomic_add_16(&(x), 1)
 #   define	ATOMIC_DECL(x)		atomic_add_long(&(x), -1)
 #   define	ATOMIC_DEC64(x)		ATOMIC_DEC(x)
-#   define	ATOMIC_DEC32(x)		atomic_add_32(&(x), -1)
+#   define	ATOMIC_DEC32(x)		atomic_add_32((u_int *)&(x), -1)
 #   define	ATOMIC_DEC16(x)		atomic_add_16(&(x), -1)
 #   define	SPL_X(x)	;
 #   define	SPL_NET(x)	;
 #   define	SPL_IMP(x)	;
+#   define	SPL_SCHED(x)	;
 extern	int	in_cksum __P((struct mbuf *, int));
+#  else
+#   define	SPL_SCHED(x)	x = splhigh()
 #  endif /* __FreeBSD_version >= 500043 */
 #  define	MSGDSIZE(x)	mbufchainlen(x)
 #  define	M_LEN(x)	(x)->m_len
@@ -955,8 +1020,6 @@
 #  endif
 #  define	COPYIN(a,b,c)	copyin((caddr_t)(a), (caddr_t)(b), (c))
 #  define	COPYOUT(a,b,c)	copyout((caddr_t)(a), (caddr_t)(b), (c))
-#  define	BCOPYIN(a,b,c)	bcopy((caddr_t)(a), (caddr_t)(b), (c))
-#  define	BCOPYOUT(a,b,c)	bcopy((caddr_t)(a), (caddr_t)(b), (c))
 #  define	GETKTIME(x)	microtime((struct timeval *)x)
 #  define	MSGDSIZE(x)	mbufchainlen(x)
 #  define	M_LEN(x)	(x)->m_len
@@ -966,12 +1029,13 @@
 # endif /* _KERNEL */
 # if (OpenBSD >= 199603)
 #  define	IFNAME(x, b)	((struct ifnet *)x)->if_xname
-#  define	COPYIFNAME(x, b) \
+#  define	COPYIFNAME(v, x, b) \
 				(void) strncpy(b, \
 					       ((struct ifnet *)x)->if_xname, \
 					       LIFNAMSIZ)
 #  define	CACHE_HASH(x)	((((struct ifnet *)fin->fin_ifp)->if_index)&7)
 # else
+#  define	IFNAME(x, b)	((struct ifnet *)x)->if_name
 #  define	CACHE_HASH(x)	((IFNAME(fin->fin_ifp)[0] + \
 				  ((struct ifnet *)fin->fin_ifp)->if_unit) & 7)
 # endif
@@ -999,6 +1063,7 @@
 #  define	MSGDSIZE(x)	mbufchainlen(x)
 #  define	M_LEN(x)	(x)->m_len
 #  define	M_DUPLICATE(x)	m_copy((x), 0, M_COPYALL)
+#  define	IFNAME(x, b)	((struct ifnet *)x)->if_name
 #  define	CACHE_HASH(x)	((IFNAME(fin->fin_ifp)[0] + \
 				  ((struct ifnet *)fin->fin_ifp)->if_unit) & 7)
 typedef struct mbuf mb_t;
@@ -1025,6 +1090,7 @@
 #  define	MSGDSIZE(x)	mbufchainlen(x)
 #  define	M_LEN(x)	(x)->m_len
 #  define	M_DUPLICATE(x)	m_copy((x), 0, M_COPYALL)
+#  define	IFNAME(x, b)	((struct ifnet *)x)->if_name
 #  define	CACHE_HASH(x)	((IFNAME(fin->fin_ifp)[0] + \
 				  ((struct ifnet *)fin->fin_ifp)->if_unit) & 7)
 #  define	GETIFP(n, v)	ifunit(n, IFNAMSIZ)
@@ -1032,6 +1098,7 @@
 #  define	KFREES(x,s)	kmem_free((char *)(x), (s))
 #  define	SLEEP(id, n)	sleep((id), PZERO+1)
 #  define	WAKEUP(id,x)	wakeup(id + x)
+#  define	POLLWAKEUP(x)	;
 #  define	UIOMOVE(a,b,c,d)	uiomove((caddr_t)a,b,c,d)
 #  define	IPF_PANIC(x,y)	if (x) { printf y; panic("ipf_panic"); }
 
@@ -1057,7 +1124,7 @@
 #if defined(linux) && !defined(OS_RECOGNISED)
 #include <linux/config.h>
 #include <linux/version.h>
-# if LINUX >= 20600
+# if (LINUX >= 20600) && defined(_KERNEL)
 #  define	 HDR_T_PRIVATE	1
 # endif
 # undef USE_INET6
@@ -1070,15 +1137,18 @@
 
 # ifdef _KERNEL
 #  define	IPF_PANIC(x,y)	if (x) { printf y; panic("ipf_panic"); }
-#  define	BCOPYIN(a,b,c)	bcopy((caddr_t)(a), (caddr_t)(b), (c))
-#  define	BCOPYOUT(a,b,c)	bcopy((caddr_t)(a), (caddr_t)(b), (c))
 #  define	COPYIN(a,b,c)	copy_from_user((caddr_t)(b), (caddr_t)(a), (c))
 #  define	COPYOUT(a,b,c)	copy_to_user((caddr_t)(b), (caddr_t)(a), (c))
 #  define	FREE_MB_T(m)	kfree_skb(m)
 #  define	GETKTIME(x)	do_gettimeofday((struct timeval *)x)
-#  define	SLEEP(x,s)	0, interruptible_sleep_on(x##_linux)
-#  define	WAKEUP(x,y)	wake_up(x##_linux + y)
-#  define	UIOMOVE(a,b,c,d)	uiomove(a,b,c,d)
+#  define	POLLWAKEUP(x)	;
+#  ifdef wait_event_interruptible
+#   define	SLEEP(x,s)	wait_event_interruptible((*(x##_linux)), 0)
+#  else
+#   define	SLEEP(x,s)	0, interruptible_sleep_on(x##_linux)
+#  endif
+#   define	WAKEUP(x,y)	wake_up(x##_linux + y)
+#  define	UIOMOVE(a,b,c,d)	uiomove((caddr_t)a,b,c,d)
 #  define	USE_MUTEXES
 #  define	KRWLOCK_T		rwlock_t
 #  define	KMUTEX_T		spinlock_t
@@ -1089,7 +1159,7 @@
 #  define	MUTEX_NUKE(x)		bzero(&(x)->ipf_lk, sizeof((x)->ipf_lk))
 #  define	READ_ENTER(x)		ipf_read_enter(x)
 #  define	WRITE_ENTER(x)		ipf_write_enter(x)
-#  define	RWLOCK_INIT(x,y)	rwlock_init(&(x)->ipf_lk)
+#  define	RWLOCK_INIT(x,y)	ipf_rw_init(x, y)
 #  define	RW_DESTROY(x)		do { } while (0)
 #  define	RWLOCK_EXIT(x)		ipf_rw_exit(x)
 #  define	MUTEX_DOWNGRADE(x)	ipf_rw_downgrade(x)
@@ -1109,6 +1179,7 @@
 					MUTEX_EXIT(&ipf_rw)
 #  define	ATOMIC_DEC16(x)		MUTEX_ENTER(&ipf_rw); (x)--; \
 					MUTEX_EXIT(&ipf_rw)
+#  define	SPL_SCHED(x)		do { } while (0)
 #  define	SPL_IMP(x)		do { } while (0)
 #  define	SPL_NET(x)		do { } while (0)
 #  define	SPL_X(x)		do { } while (0)
@@ -1123,6 +1194,7 @@
 #  define	mbuf	sk_buff
 
 #  define	mtod(m, t)	((t)(m)->data)
+#  define	m_data		data
 #  define	m_len		len
 #  define	m_next		next
 #  define	M_DUPLICATE(m)	skb_clone((m), in_interrupt() ? GFP_ATOMIC : \
@@ -1170,7 +1242,7 @@
 
 # endif	/* _KERNEL */
 
-# define	COPYIFNAME(x, b) \
+# define	COPYIFNAME(v, x, b) \
 				(void) strncpy(b, \
 					       ((struct ifnet *)x)->if_xname, \
 					       LIFNAMSIZ)
@@ -1207,6 +1279,116 @@
 #endif
 
 
+/* ----------------------------------------------------------------------- */
+/*                                    A I X                                */
+/* ----------------------------------------------------------------------- */
+#if defined(_AIX51)
+# undef		MENTAT
+
+# include <sys/lock.h>
+# include <sys/sysmacros.h>
+
+# ifdef _KERNEL
+#  define rw_read_locked(x)		0
+#  include <net/net_globals.h>
+#  include <net/net_malloc.h>
+#  define	KMUTEX_T		simple_lock_t
+#  define	KRWLOCK_T		complex_lock_t
+#  define	USE_MUTEXES		1
+#  define	USE_SPL			1
+#  define	READ_ENTER(x)		lock_read((x)->ipf_lk)
+#  define	WRITE_ENTER(x)		lock_write((x)->ipf_lk)
+#  define	MUTEX_DOWNGRADE(x)	lock_write_to_read((x)->ipf_lk)
+#  define	RWLOCK_INIT(x, y)	lock_alloc(&(x)->ipf_lk, \
+						   LOCK_ALLOC_PIN, \
+						   (u_short)y, 0); \
+					lock_init((x)->ipf_lk, TRUE)
+#  define	RWLOCK_EXIT(x)		lock_done((x)->ipf_lk)
+#  define	RW_DESTROY(x)		lock_free(&(x)->ipf_lk)
+#  define	MUTEX_ENTER(x)		simple_lock((x)->ipf_lk)
+#  define	MUTEX_INIT(x, y)	lock_alloc(&(x)->ipf_lk, \
+						   LOCK_ALLOC_PIN, \
+						   (u_short)y, 0); \
+					simple_lock_init((x)->ipf_lk)
+#  define	MUTEX_DESTROY(x)	lock_free(&(x)->ipf_lk)
+#  define	MUTEX_EXIT(x)		simple_unlock((x)->ipf_lk)
+#  define	MUTEX_NUKE(x)		bzero(&(x)->ipf_lk, sizeof((x)->ipf_lk))
+#   define	ATOMIC_INC64(x)		{ MUTEX_ENTER(&ipf_rw); (x)++; \
+					  MUTEX_EXIT(&ipf_rw); }
+#   define	ATOMIC_DEC64(x)		{ MUTEX_ENTER(&ipf_rw); (x)--; \
+					  MUTEX_EXIT(&ipf_rw); }
+#   define	ATOMIC_INC32(x)		{ MUTEX_ENTER(&ipf_rw); (x)++; \
+					  MUTEX_EXIT(&ipf_rw); }
+#   define	ATOMIC_DEC32(x)		{ MUTEX_ENTER(&ipf_rw); (x)--; \
+					  MUTEX_EXIT(&ipf_rw); }
+#   define	ATOMIC_INCL(x)		{ MUTEX_ENTER(&ipf_rw); (x)++; \
+					  MUTEX_EXIT(&ipf_rw); }
+#   define	ATOMIC_DECL(x)		{ MUTEX_ENTER(&ipf_rw); (x)--; \
+					  MUTEX_EXIT(&ipf_rw); }
+#   define	ATOMIC_INC(x)		{ MUTEX_ENTER(&ipf_rw); (x)++; \
+					  MUTEX_EXIT(&ipf_rw); }
+#   define	ATOMIC_DEC(x)		{ MUTEX_ENTER(&ipf_rw); (x)--; \
+					  MUTEX_EXIT(&ipf_rw); }
+#  define	SPL_SCHED(x)		x = splsched()
+#  define	SPL_NET(x)		x = splnet()
+#  define	SPL_IMP(x)		x = splimp()
+#  undef	SPL_X
+#  define	SPL_X(x)		splx(x)
+#  define	UIOMOVE(a,b,c,d)	uiomove((caddr_t)a,b,c,d)
+extern void* getifp __P((char *, int));
+#  define	GETIFP(n, v)		getifp(n, v)
+#  define	GET_MINOR		minor
+#  define	SLEEP(id, n)	sleepx((id), PZERO+1, 0)
+#  define	WAKEUP(id,x)	wakeup(id)
+#  define	POLLWAKEUP(x)	;
+#  define	COPYIN(a,b,c)	copyin((caddr_t)(a), (caddr_t)(b), (c))
+#  define	COPYOUT(a,b,c)	copyout((caddr_t)(a), (caddr_t)(b), (c))
+#  define	KMALLOC(a, b)	MALLOC((a), b, sizeof(*(a)), M_TEMP, M_NOWAIT)
+#  define	KMALLOCS(a, b, c)	MALLOC((a), b, (c), M_TEMP, \
+					    ((c) > 4096) ? M_WAITOK : M_NOWAIT)
+#  define	KFREE(x)	FREE((x), M_TEMP)
+#  define	KFREES(x,s)	FREE((x), M_TEMP)
+#  define	MSGDSIZE(x)	mbufchainlen(x)
+#  define	M_LEN(x)	(x)->m_len
+#  define	M_DUPLICATE(x)	m_copy((x), 0, M_COPYALL)
+#  define	GETKTIME(x)
+#  define	IFNAME(x, b)	((struct ifnet *)x)->if_name
+#  define	CACHE_HASH(x)	((IFNAME(fin->fin_ifp)[0] + \
+				  ((struct ifnet *)fin->fin_ifp)->if_unit) & 7)
+#  define	IPF_PANIC(x,y)
+typedef struct mbuf mb_t;
+# endif /* _KERNEL */
+
+/*
+ * These are from's Solaris' #defines for little endian.
+ */
+#if !defined(IP6F_MORE_FRAG)
+# define	IP6F_MORE_FRAG		0x0100
+#endif
+#if !defined(IP6F_RESERVED_MASK)
+# define	IP6F_RESERVED_MASK	0x0600
+#endif
+#if !defined(IP6F_OFF_MASK)
+# define	IP6F_OFF_MASK		0xf8ff
+#endif
+
+struct ip6_ext {
+	u_char	ip6e_nxt;
+	u_char	ip6e_len;
+};
+
+typedef	int		ioctlcmd_t;  
+typedef	int		minor_t;
+/*
+ * Really, any arch where sizeof(long) != sizeof(int).
+ */
+typedef unsigned int    u_32_t;
+# define	U_32_T	1
+
+# define OS_RECOGNISED 1
+#endif	/* _AIX51 */
+
+
 #ifndef	OS_RECOGNISED
 #error	ip_compat.h does not recognise this platform/OS.
 #endif
@@ -1222,8 +1404,11 @@
  * For BSD kernels, if bpf is in the kernel, enable ipfilter to use bpf in
  * filter rules.
  */
-#if !defined(IPFILTER_BPF) && ((NBPF > 0) || (NBPFILTER > 0) || (DEV_BPF >0))
-# define IPFILTER_BPF
+#if !defined(IPFILTER_BPF)
+# if (defined(NBPF) && (NBPF > 0)) || (defined(DEV_BPF) && (DEV_BPF > 0)) || \
+     (defined(NBPFILTER) && (NBPFILTER > 0))
+#  define	IPFILTER_BPF
+# endif
 #endif
 
 /*
@@ -1235,7 +1420,7 @@
 	u_int	eMm_magic;
 	int	eMm_held;
 	int	eMm_heldat;
-#ifdef __hpux
+#if defined(__hpux) || defined(__linux)
 	char	eMm_fill[8];
 #endif
 } eMmutex_t;
@@ -1291,10 +1476,11 @@
 #endif
 
 #if defined(linux) && defined(_KERNEL)
-extern	INLINE	void	ipf_read_enter __P((ipfrwlock_t *));
-extern	INLINE	void	ipf_write_enter __P((ipfrwlock_t *));
-extern	INLINE	void	ipf_rw_exit __P((ipfrwlock_t *));
-extern	INLINE	void	ipf_rw_downgrade __P((ipfrwlock_t *));
+extern	void	ipf_read_enter __P((ipfrwlock_t *));
+extern	void	ipf_write_enter __P((ipfrwlock_t *));
+extern	void	ipf_rw_exit __P((ipfrwlock_t *));
+extern	void	ipf_rw_init __P((ipfrwlock_t *, char *));
+extern	void	ipf_rw_downgrade __P((ipfrwlock_t *));
 #endif
 
 /*
@@ -1314,12 +1500,15 @@
 # define	M_LEN(x)	(x)->mb_len
 # define	M_DUPLICATE(x)	(x)
 # define	GETKTIME(x)	gettimeofday((struct timeval *)(x), NULL)
+# undef		MTOD
 # define	MTOD(m, t)	((t)(m)->mb_buf)
 # define	FREE_MB_T(x)
 # define	SLEEP(x,y)	1;
 # define	WAKEUP(x,y)	;
+# define	POLLWAKEUP(y)	;
 # define	IPF_PANIC(x,y)	;
 # define	PANIC(x,y)	;
+# define	SPL_SCHED(x)	;
 # define	SPL_NET(x)	;
 # define	SPL_IMP(x)	;
 # define	SPL_X(x)	;
@@ -1328,18 +1517,17 @@
 # define	KFREE(x)	free(x)
 # define	KFREES(x,s)	free(x)
 # define	GETIFP(x, v)	get_unit(x,v)
-# define	COPYIN(a,b,c)	(bcopy((a), (b), (c)), 0)
-# define	COPYOUT(a,b,c)	(bcopy((a), (b), (c)), 0)
-# define	BCOPYIN(a,b,c)	(bcopy((a), (b), (c)), 0)
-# define	BCOPYOUT(a,b,c)	(bcopy((a), (b), (c)), 0)
+# define	COPYIN(a,b,c)	bcopywrap((a), (b), (c))
+# define	COPYOUT(a,b,c)	bcopywrap((a), (b), (c))
 # define	COPYDATA(m, o, l, b)	bcopy(MTOD((mb_t *)m, char *) + (o), \
 					      (b), (l))
 # define	COPYBACK(m, o, l, b)	bcopy((b), \
 					      MTOD((mb_t *)m, char *) + (o), \
 					      (l))
-# define	UIOMOVE(a,b,c,d)	ipfuiomove(a,b,c,d)
+# define	UIOMOVE(a,b,c,d)	ipfuiomove((caddr_t)a,b,c,d)
 extern	void	m_copydata __P((mb_t *, int, int, caddr_t));
 extern	int	ipfuiomove __P((caddr_t, int, int, struct uio *));
+extern	int	bcopywrap __P((void *, void *, size_t));
 # ifndef CACHE_HASH
 #  define	CACHE_HASH(x)	((IFNAME(fin->fin_ifp)[0] + \
 				  ((struct ifnet *)fin->fin_ifp)->if_unit) & 7)
@@ -1461,12 +1649,15 @@
 #   endif /* M_PFIL */
 #  endif /* IPFILTER_M_IPFILTER */
 #  define	KMALLOC(a, b)	MALLOC((a), b, sizeof(*(a)), _M_IPF, M_NOWAIT)
-#  define	KMALLOCS(a, b, c)	MALLOC((a), b, (c), _M_IPF, M_NOWAIT)
+#  if !defined(KMALLOCS)
+#   define	KMALLOCS(a, b, c)	MALLOC((a), b, (c), _M_IPF, M_NOWAIT)
+#  endif
 #  define	KFREE(x)	FREE((x), _M_IPF)
 #  define	KFREES(x,s)	FREE((x), _M_IPF)
-#  define	UIOMOVE(a,b,c,d)	uiomove(a,b,d)
+#  define	UIOMOVE(a,b,c,d)	uiomove((caddr_t)a,b,d)
 #  define	SLEEP(id, n)	tsleep((id), PPAUSE|PCATCH, n, 0)
 #  define	WAKEUP(id,x)	wakeup(id+x)
+#  define	POLLWAKEUP(x)	selwakeup(ipfselwait+x)
 #  define	GETIFP(n, v)	ifunit(n)
 # endif /* (Free)BSD */
 
@@ -1478,6 +1669,9 @@
 #   define	SPL_IMP(x)	x = splimp()
 #   define	SPL_NET(x)	x = splnet()
 #  endif /* NetBSD && (NetBSD <= 1991011) && (NetBSD >= 199407) */
+#  if !defined(SPL_SCHED)
+#   define	SPL_SCHED(x)	x = splsched()
+#  endif
 #  define	SPL_X(x)	(void) splx(x)
 # endif /* !USE_MUTEXES */
 
@@ -1492,8 +1686,6 @@
 # ifndef COPYIN
 #  define	COPYIN(a,b,c)	(bcopy((caddr_t)(a), (caddr_t)(b), (c)), 0)
 #  define	COPYOUT(a,b,c)	(bcopy((caddr_t)(a), (caddr_t)(b), (c)), 0)
-#  define	BCOPYIN(a,b,c)	(bcopy((caddr_t)(a), (caddr_t)(b), (c)), 0)
-#  define	BCOPYOUT(a,b,c)	(bcopy((caddr_t)(a), (caddr_t)(b), (c)), 0)
 # endif
 
 # ifndef KMALLOC
@@ -1508,18 +1700,27 @@
 # define	PANIC(x,y)	if (x) panic y
 #endif /* _KERNEL */
 
-#ifndef	IFNAME
+#if !defined(IFNAME) && !defined(_KERNEL)
 # define	IFNAME(x)	((struct ifnet *)x)->if_name
 #endif
 #ifndef	COPYIFNAME
 # define	NEED_FRGETIFNAME
 extern	char	*fr_getifname __P((struct ifnet *, char *));
-# define	COPYIFNAME(x, b) \
+# define	COPYIFNAME(v, x, b) \
 				fr_getifname((struct ifnet *)x, b)
 #endif
 
 #ifndef ASSERT
-# define	ASSERT(x)
+# ifdef _KERNEL
+#  define	ASSERT(x)
+# else
+#  define	ASSERT(x)	do { if (!(x)) abort(); } while (0)
+# endif
+#endif
+
+#ifndef BCOPYIN
+#  define	BCOPYIN(a,b,c)	(bcopy((caddr_t)(a), (caddr_t)(b), (c)), 0)
+#  define	BCOPYOUT(a,b,c)	(bcopy((caddr_t)(a), (caddr_t)(b), (c)), 0)
 #endif
 
 /*
@@ -1564,6 +1765,12 @@
 # define	ATOMIC_DEC(x)		(x)--
 #endif
 
+#if defined(USE_SPL) && defined(_KERNEL)
+# define	SPL_INT(x)	int x
+#else
+# define	SPL_INT(x)
+#endif
+
 /*
  * If there are no atomic operations for bit sizes defined, define them to all
  * use a generic one that works for all sizes.
@@ -1592,9 +1799,6 @@
 # define	FR_GROUPLEN	16
 #endif
 
-#ifdef offsetof
-# undef	offsetof
-#endif
 #ifndef offsetof
 # define offsetof(t,m) (int)((&((t *)0L)->m))
 #endif
@@ -1614,7 +1818,7 @@
 # define	IP_HL(x)	(x)->ip_hl
 #endif
 #ifndef	IP_HL_A
-# define	IP_HL_A(x,y)	(x)->ip_hl = (y)
+# define	IP_HL_A(x,y)	(x)->ip_hl = ((y) & 0xf)
 #endif
 #ifndef	TCP_X2
 # define	TCP_X2(x)	(x)->th_x2
@@ -2038,9 +2242,10 @@
 #ifndef	IPPROTO_DSTOPTS
 # define	IPPROTO_DSTOPTS	60
 #endif
-#ifndef	IPPROTO_FRAGMENT
-# define	IPPROTO_FRAGMENT	44
+#ifndef	IPPROTO_MOBILITY
+# define	IPPROTO_MOBILITY	135
 #endif
+
 #ifndef	ICMP_ROUTERADVERT
 # define	ICMP_ROUTERADVERT	9
 #endif
@@ -2221,21 +2426,21 @@
 /*
  * TCP States
  */
-#define IPF_TCPS_CLOSED		0	/* closed */
-#define IPF_TCPS_LISTEN		1	/* listening for connection */
-#define IPF_TCPS_SYN_SENT	2	/* active, have sent syn */
-#define IPF_TCPS_SYN_RECEIVED	3	/* have send and received syn */
-#define IPF_TCPS_HALF_ESTAB	4	/* for connections not fully "up" */
+#define IPF_TCPS_LISTEN		0	/* listening for connection */
+#define IPF_TCPS_SYN_SENT	1	/* active, have sent syn */
+#define IPF_TCPS_SYN_RECEIVED	2	/* have send and received syn */
+#define IPF_TCPS_HALF_ESTAB	3	/* for connections not fully "up" */
 /* states < IPF_TCPS_ESTABLISHED are those where connections not established */
-#define IPF_TCPS_ESTABLISHED	5	/* established */
-#define IPF_TCPS_CLOSE_WAIT	6	/* rcvd fin, waiting for close */
+#define IPF_TCPS_ESTABLISHED	4	/* established */
+#define IPF_TCPS_CLOSE_WAIT	5	/* rcvd fin, waiting for close */
 /* states > IPF_TCPS_CLOSE_WAIT are those where user has closed */
-#define IPF_TCPS_FIN_WAIT_1	7	/* have closed, sent fin */
-#define IPF_TCPS_CLOSING	8	/* closed xchd FIN; await FIN ACK */
-#define IPF_TCPS_LAST_ACK	9	/* had fin and close; await FIN ACK */
+#define IPF_TCPS_FIN_WAIT_1	6	/* have closed, sent fin */
+#define IPF_TCPS_CLOSING	7	/* closed xchd FIN; await FIN ACK */
+#define IPF_TCPS_LAST_ACK	8	/* had fin and close; await FIN ACK */
 /* states > IPF_TCPS_CLOSE_WAIT && < IPF_TCPS_FIN_WAIT_2 await ACK of FIN */
-#define IPF_TCPS_FIN_WAIT_2	10	/* have closed, fin is acked */
-#define IPF_TCPS_TIME_WAIT	11	/* in 2*msl quiet wait after close */
+#define IPF_TCPS_FIN_WAIT_2	9	/* have closed, fin is acked */
+#define IPF_TCPS_TIME_WAIT	10	/* in 2*msl quiet wait after close */
+#define IPF_TCPS_CLOSED		11	/* closed */
 #define IPF_TCP_NSTATES		12
 
 #define	TCP_MSL			120
@@ -2274,7 +2479,7 @@
 /*
  * ICMP error replies have an IP header (20 bytes), 8 bytes of ICMP data,
  * another IP header and then 64 bits of data, totalling 56.  Of course,
- * the last 64 bits is dependant on that being available.
+ * the last 64 bits is dependent on that being available.
  */
 #define	ICMPERR_ICMPHLEN	8
 #define	ICMPERR_IPICMPHLEN	(20 + 8)
Index: fil.c
===================================================================
RCS file: /home/cvs/src/sys/contrib/ipfilter/netinet/fil.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/contrib/ipfilter/netinet/fil.c -L sys/contrib/ipfilter/netinet/fil.c -u -r1.1.1.1 -r1.2
--- sys/contrib/ipfilter/netinet/fil.c
+++ sys/contrib/ipfilter/netinet/fil.c
@@ -1,4 +1,4 @@
-/*	$FreeBSD: src/sys/contrib/ipfilter/netinet/fil.c,v 1.46 2005/06/23 14:19:02 darrenr Exp $	*/
+/*	$FreeBSD: src/sys/contrib/ipfilter/netinet/fil.c,v 1.52.2.2 2007/12/01 00:53:41 darrenr Exp $	*/
 
 /*
  * Copyright (C) 1993-2003 by Darren Reed.
@@ -17,7 +17,11 @@
 #include <sys/time.h>
 #if defined(__NetBSD__)
 # if (NetBSD >= 199905) && !defined(IPFILTER_LKM) && defined(_KERNEL)
-#  include "opt_ipfilter_log.h"
+#  if (__NetBSD_Version__ < 301000000)
+#   include "opt_ipfilter_log.h"
+#  else
+#   include "opt_ipfilter.h"
+#  endif
 # endif
 #endif
 #if defined(_KERNEL) && defined(__FreeBSD_version) && \
@@ -34,7 +38,12 @@
 #else
 # include <sys/ioctl.h>
 #endif
-#include <sys/fcntl.h>
+#if (defined(__SVR4) || defined(__svr4__)) && defined(sun)
+# include <sys/filio.h>
+#endif
+#if !defined(_AIX51)
+# include <sys/fcntl.h>
+#endif
 #if defined(_KERNEL)
 # include <sys/systm.h>
 # include <sys/file.h>
@@ -73,10 +82,17 @@
 #ifdef sun
 # include <net/af.h>
 #endif
-#if !defined(_KERNEL) && defined(__FreeBSD__)
+#if !defined(_KERNEL) && (defined(__FreeBSD__) || defined(SOLARIS2))
+# if (__FreeBSD_version >= 504000)
+#  undef _RADIX_H_
+# endif
+# include "radix_ipf.h"
+#endif
+#ifdef __osf__
 # include "radix_ipf.h"
+#else
+# include <net/route.h>
 #endif
-#include <net/route.h>
 #include <netinet/in.h>
 #include <netinet/in_systm.h>
 #include <netinet/ip.h>
@@ -88,13 +104,16 @@
 # include <netinet/in_var.h>
 #endif
 #include <netinet/tcp.h>
-#if !defined(__sgi) || defined(_KERNEL)
+#if (!defined(__sgi) && !defined(AIX)) || defined(_KERNEL)
 # include <netinet/udp.h>
 # include <netinet/ip_icmp.h>
 #endif
 #ifdef __hpux
 # undef _NET_ROUTE_INCLUDED
 #endif
+#ifdef __osf__
+# undef _RADIX_H_
+#endif
 #include "netinet/ip_compat.h"
 #ifdef	USE_INET6
 # include <netinet/icmp6.h>
@@ -136,8 +155,8 @@
 
 #if !defined(lint)
 static const char sccsid[] = "@(#)fil.c	1.36 6/5/96 (C) 1993-2000 Darren Reed";
-static const char rcsid[] = "@(#)$FreeBSD: src/sys/contrib/ipfilter/netinet/fil.c,v 1.46 2005/06/23 14:19:02 darrenr Exp $";
-/* static const char rcsid[] = "@(#)Id: fil.c,v 2.243.2.57 2005/03/28 10:47:50 darrenr Exp"; */
+static const char rcsid[] = "@(#)$FreeBSD: src/sys/contrib/ipfilter/netinet/fil.c,v 1.52.2.2 2007/12/01 00:53:41 darrenr Exp $";
+/* static const char rcsid[] = "@(#)$Id: fil.c,v 2.243.2.125 2007/10/10 09:27:20 darrenr Exp $"; */
 #endif
 
 #ifndef	_KERNEL
@@ -145,17 +164,11 @@
 # include "ipt.h"
 # include "bpf-ipf.h"
 extern	int	opts;
-
-# define	FR_VERBOSE(verb_pr)			verbose verb_pr
-# define	FR_DEBUG(verb_pr)			debug verb_pr
-#else /* #ifndef _KERNEL */
-# define	FR_VERBOSE(verb_pr)
-# define	FR_DEBUG(verb_pr)
 #endif /* _KERNEL */
 
 
 fr_info_t	frcache[2][8];
-struct	filterstats frstats[2] = { { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 } };
+struct	filterstats frstats[2];
 struct	frentry	*ipfilter[2][2] = { { NULL, NULL }, { NULL, NULL } },
 		*ipfilter6[2][2] = { { NULL, NULL }, { NULL, NULL } },
 		*ipacct6[2][2] = { { NULL, NULL }, { NULL, NULL } },
@@ -176,6 +189,7 @@
 u_short	fr_ip_id = 0;
 int	fr_chksrc = 0;	/* causes a system crash if enabled */
 int	fr_minttl = 4;
+int	fr_icmpminfragmtu = 68;
 u_long	fr_frouteok[2] = {0, 0};
 u_long	fr_userifqs = 0;
 u_long	fr_badcoalesces[2] = {0, 0};
@@ -221,6 +235,7 @@
 static	ipfunc_t	fr_findfunc __P((ipfunc_t));
 static	frentry_t	*fr_firewall __P((fr_info_t *, u_32_t *));
 static	int		fr_funcinit __P((frentry_t *fr));
+static	INLINE void	frpr_ah __P((fr_info_t *));
 static	INLINE void	frpr_esp __P((fr_info_t *));
 static	INLINE void	frpr_gre __P((fr_info_t *));
 static	INLINE void	frpr_udp __P((fr_info_t *));
@@ -229,16 +244,19 @@
 static	INLINE void	frpr_ipv4hdr __P((fr_info_t *));
 static	INLINE int	frpr_pullup __P((fr_info_t *, int));
 static	INLINE void	frpr_short __P((fr_info_t *, int));
-static	INLINE void	frpr_tcpcommon __P((fr_info_t *));
-static	INLINE void	frpr_udpcommon __P((fr_info_t *));
-static	INLINE int	fr_updateipid __P((fr_info_t *));
+static	INLINE int	frpr_tcpcommon __P((fr_info_t *));
+static	INLINE int	frpr_udpcommon __P((fr_info_t *));
+static	int		fr_updateipid __P((fr_info_t *));
 #ifdef	IPFILTER_LOOKUP
 static	int		fr_grpmapinit __P((frentry_t *fr));
-static	INLINE void	*fr_resolvelookup __P((u_int, u_int, lookupfunc_t *));
+static	INLINE void	*fr_resolvelookup __P((u_int, u_int, i6addr_t *, lookupfunc_t *));
 #endif
 static	void		frsynclist __P((frentry_t *, void *));
-static	ipftuneable_t	*fr_findtunebyname __P((char *));
+static	ipftuneable_t	*fr_findtunebyname __P((const char *));
 static	ipftuneable_t	*fr_findtunebycookie __P((void *, void **));
+static	int		ipf_geniter __P((ipftoken_t *, ipfgeniter_t *));
+static	int		ipf_frruleiter __P((void *, int, void *));
+static	void		ipf_unlinktoken __P((ipftoken_t *));
 
 
 /*
@@ -280,6 +298,7 @@
 	{ IPPROTO_AH,			0x000020 },
 	{ IPPROTO_NONE,			0x000040 },
 	{ IPPROTO_DSTOPTS,		0x000080 },
+	{ IPPROTO_MOBILITY,		0x000100 },
 	{ 0,				0 }
 };
 #endif
@@ -317,7 +336,7 @@
 	{ "fr_srcgrpmap", fr_srcgrpmap, fr_grpmapinit },
 	{ "fr_dstgrpmap", fr_dstgrpmap, fr_grpmapinit },
 #endif
-	{ "", NULL }
+	{ "", NULL, NULL }
 };
 
 
@@ -331,15 +350,20 @@
  * adding more code to a growing switch statement.
  */
 #ifdef USE_INET6
+static	INLINE int	frpr_ah6 __P((fr_info_t *));
+static	INLINE void	frpr_esp6 __P((fr_info_t *));
+static	INLINE void	frpr_gre6 __P((fr_info_t *));
 static	INLINE void	frpr_udp6 __P((fr_info_t *));
 static	INLINE void	frpr_tcp6 __P((fr_info_t *));
 static	INLINE void	frpr_icmp6 __P((fr_info_t *));
-static	INLINE void	frpr_ipv6hdr __P((fr_info_t *));
+static	INLINE int	frpr_ipv6hdr __P((fr_info_t *));
 static	INLINE void	frpr_short6 __P((fr_info_t *, int));
 static	INLINE int	frpr_hopopts6 __P((fr_info_t *));
+static	INLINE int	frpr_mobility6 __P((fr_info_t *));
 static	INLINE int	frpr_routing6 __P((fr_info_t *));
 static	INLINE int	frpr_dstopts6 __P((fr_info_t *));
 static	INLINE int	frpr_fragment6 __P((fr_info_t *));
+static	INLINE int	frpr_ipv6exthdr __P((fr_info_t *, int, int));
 
 
 /* ------------------------------------------------------------------------ */
@@ -352,37 +376,32 @@
 /* for IPv6 and marks the packet with FI_SHORT if so.  See function comment */
 /* for frpr_short() for more details.                                       */
 /* ------------------------------------------------------------------------ */
-static INLINE void frpr_short6(fin, min)
+static INLINE void frpr_short6(fin, xmin)
 fr_info_t *fin;
-int min;
+int xmin;
 {
-	fr_ip_t *fi = &fin->fin_fi;
-	int off;
 
-	off = fin->fin_off;
-	if (off == 0) {
-		if (fin->fin_plen < fin->fin_hlen + min)
-			fi->fi_flx |= FI_SHORT;
-	} else if (off < min) {
-		fi->fi_flx |= FI_SHORT;
-	}
+	if (fin->fin_dlen < xmin)
+		fin->fin_flx |= FI_SHORT;
 }
 
 
 /* ------------------------------------------------------------------------ */
 /* Function:    frpr_ipv6hdr                                                */
-/* Returns:     void                                                        */
+/* Returns:     int    - 0 = IPv6 packet intact, -1 = packet lost           */
 /* Parameters:  fin(I) - pointer to packet information                      */
 /*                                                                          */
 /* IPv6 Only                                                                */
 /* Copy values from the IPv6 header into the fr_info_t struct and call the  */
-/* per-protocol analyzer if it exists.                                      */
+/* per-protocol analyzer if it exists.  In validating the packet, a protocol*/
+/* analyzer may pullup or free the packet itself so we need to be vigiliant */
+/* of that possibility arising.                                             */
 /* ------------------------------------------------------------------------ */
-static INLINE void frpr_ipv6hdr(fin)
+static INLINE int frpr_ipv6hdr(fin)
 fr_info_t *fin;
 {
-	int p, go = 1, i, hdrcount, coalesced;
 	ip6_t *ip6 = (ip6_t *)fin->fin_ip;
+	int p, go = 1, i, hdrcount;
 	fr_ip_t *fi = &fin->fin_fi;
 
 	fin->fin_off = 0;
@@ -392,7 +411,6 @@
 	fi->fi_secmsk = 0;
 	fi->fi_auth = 0;
 
-	coalesced = (fin->fin_flx & FI_COALESCE) ? 1 : 0;
 	p = ip6->ip6_nxt;
 	fi->fi_ttl = ip6->ip6_hlim;
 	fi->fi_src.in6 = ip6->ip6_src;
@@ -419,48 +437,35 @@
 			break;
 
 		case IPPROTO_GRE :
-			frpr_gre(fin);
+			frpr_gre6(fin);
 			go = 0;
 			break;
 
 		case IPPROTO_HOPOPTS :
-			/*
-			 * Actually, hop by hop header is only allowed right
-			 * after IPv6 header!
-			 */
-			if (hdrcount != 0)
-				fin->fin_flx |= FI_BAD;
-
-			if (coalesced == 0) {
-				coalesced = fr_coalesce(fin);
-				if (coalesced != 1)
-					return;
-			}
 			p = frpr_hopopts6(fin);
 			break;
 
+		case IPPROTO_MOBILITY :
+			p = frpr_mobility6(fin);
+			break;
+
 		case IPPROTO_DSTOPTS :
-			if (coalesced == 0) {
-				coalesced = fr_coalesce(fin);
-				if (coalesced != 1)
-					return;
-			}
 			p = frpr_dstopts6(fin);
 			break;
 
 		case IPPROTO_ROUTING :
-			if (coalesced == 0) {
-				coalesced = fr_coalesce(fin);
-				if (coalesced != 1)
-					return;
-			}
 			p = frpr_routing6(fin);
 			break;
 
-		case IPPROTO_ESP :
-			frpr_esp(fin);
-			/*FALLTHROUGH*/
 		case IPPROTO_AH :
+			p = frpr_ah6(fin);
+			break;
+
+		case IPPROTO_ESP :
+			frpr_esp6(fin);
+			go = 0;
+			break;
+
 		case IPPROTO_IPV6 :
 			for (i = 0; ip6exthdr[i].ol_bit != 0; i++)
 				if (ip6exthdr[i].ol_val == p) {
@@ -475,12 +480,9 @@
 			break;
 
 		case IPPROTO_FRAGMENT :
-			if (coalesced == 0) {
-				coalesced = fr_coalesce(fin);
-				if (coalesced != 1)
-					return;
-			}
 			p = frpr_fragment6(fin);
+			if (fin->fin_off != 0)
+				go = 0;
 			break;
 
 		default :
@@ -494,9 +496,9 @@
 		 * extension headers (go != 0), the entire header may not have
 		 * been pulled up when the code gets to this point.  This is
 		 * only done for "go != 0" because the other header handlers
-		 * will all pullup their complete header and the other
-		 * indicator of an incomplete header is that this eas just an
-		 * extension header.
+		 * will all pullup their complete header.  The other indicator
+		 * of an incomplete packet is that this was just an extension
+		 * header.
 		 */
 		if ((go != 0) && (p != IPPROTO_NONE) &&
 		    (frpr_pullup(fin, 0) == -1)) {
@@ -505,19 +507,32 @@
 		}
 	}
 	fi->fi_p = p;
+
+	/*
+	 * Some of the above functions, like frpr_esp6(), can call fr_pullup
+	 * and destroy whatever packet was here.  The caller of this function
+	 * expects us to return -1 if there is a problem with fr_pullup.
+	 */
+	if (fin->fin_m == NULL)
+		return -1;
+
+	return 0;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    frpr_hopopts6                                               */
+/* Function:    frpr_ipv6exthdr                                             */
 /* Returns:     int    - value of the next header or IPPROTO_NONE if error  */
-/* Parameters:  fin(I) - pointer to packet information                      */
+/* Parameters:  fin(I)      - pointer to packet information                 */
+/*              multiple(I) - flag indicating yes/no if multiple occurances */
+/*                            of this extension header are allowed.         */
+/*              proto(I)    - protocol number for this extension header     */
 /*                                                                          */
 /* IPv6 Only                                                                */
-/* This is function checks pending hop by hop options extension header      */
 /* ------------------------------------------------------------------------ */
-static INLINE int frpr_hopopts6(fin)
+static INLINE int frpr_ipv6exthdr(fin, multiple, proto)
 fr_info_t *fin;
+int multiple, proto;
 {
 	struct ip6_ext *hdr;
 	u_short shift;
@@ -535,18 +550,35 @@
 		return IPPROTO_NONE;
 
 	hdr = fin->fin_dp;
-	shift = 8 + (hdr->ip6e_len << 3);
+	switch (proto)
+	{
+	case IPPROTO_FRAGMENT :
+		shift = 8;
+		break;
+	default :
+		shift = 8 + (hdr->ip6e_len << 3);
+		break;
+	}
+
 	if (shift > fin->fin_dlen) {	/* Nasty extension header length? */
 		fin->fin_flx |= FI_BAD;
 		return IPPROTO_NONE;
 	}
 
 	for (i = 0; ip6exthdr[i].ol_bit != 0; i++)
-		if (ip6exthdr[i].ol_val == IPPROTO_HOPOPTS) {
-			fin->fin_optmsk |= ip6exthdr[i].ol_bit;
+		if (ip6exthdr[i].ol_val == proto) {
+			/*
+			 * Most IPv6 extension headers are only allowed once.
+			 */
+			if ((multiple == 0) &&
+			    ((fin->fin_optmsk & ip6exthdr[i].ol_bit) != 0))
+				fin->fin_flx |= FI_BAD;
+			else
+				fin->fin_optmsk |= ip6exthdr[i].ol_bit;
 			break;
 		}
 
+	fin->fin_exthdr = fin->fin_dp;
 	fin->fin_dp = (char *)fin->fin_dp + shift;
 	fin->fin_dlen -= shift;
 
@@ -555,6 +587,36 @@
 
 
 /* ------------------------------------------------------------------------ */
+/* Function:    frpr_hopopts6                                               */
+/* Returns:     int    - value of the next header or IPPROTO_NONE if error  */
+/* Parameters:  fin(I) - pointer to packet information                      */
+/*                                                                          */
+/* IPv6 Only                                                                */
+/* This is function checks pending hop by hop options extension header      */
+/* ------------------------------------------------------------------------ */
+static INLINE int frpr_hopopts6(fin)
+fr_info_t *fin;
+{
+	return frpr_ipv6exthdr(fin, 0, IPPROTO_HOPOPTS);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    frpr_mobility6                                              */
+/* Returns:     int    - value of the next header or IPPROTO_NONE if error  */
+/* Parameters:  fin(I) - pointer to packet information                      */
+/*                                                                          */
+/* IPv6 Only                                                                */
+/* This is function checks the IPv6 mobility extension header               */
+/* ------------------------------------------------------------------------ */
+static INLINE int frpr_mobility6(fin)
+fr_info_t *fin;
+{
+	return frpr_ipv6exthdr(fin, 0, IPPROTO_MOBILITY);
+}
+
+
+/* ------------------------------------------------------------------------ */
 /* Function:    frpr_routing6                                               */
 /* Returns:     int    - value of the next header or IPPROTO_NONE if error  */
 /* Parameters:  fin(I) - pointer to packet information                      */
@@ -566,40 +628,25 @@
 fr_info_t *fin;
 {
 	struct ip6_ext *hdr;
-	u_short shift;
-	int i;
-
-	fin->fin_flx |= FI_V6EXTHDR;
-
-				/* 8 is default length of extension hdr */
-	if ((fin->fin_dlen - 8) < 0) {
-		fin->fin_flx |= FI_SHORT;
-		return IPPROTO_NONE;
-	}
 
-	if (frpr_pullup(fin, 8) == -1)
+	if (frpr_ipv6exthdr(fin, 0, IPPROTO_ROUTING) == IPPROTO_NONE)
 		return IPPROTO_NONE;
-	hdr = fin->fin_dp;
+	hdr = fin->fin_exthdr;
 
-	shift = 8 + (hdr->ip6e_len << 3);
-	/*
-	 * Nasty extension header length?
-	 */
-	if ((shift > fin->fin_dlen) || (shift < sizeof(struct ip6_hdr)) ||
-	    ((shift - sizeof(struct ip6_hdr)) & 15)) {
+	if ((hdr->ip6e_len & 1) != 0) {
+		/*
+		 * The routing header data is made up of 128 bit IPv6 addresses
+		 * which means it must be a multiple of 2 lots of 8 in length.
+		 */
 		fin->fin_flx |= FI_BAD;
+		/*
+		 * Compensate for the changes made in frpr_ipv6exthdr()
+		 */
+		fin->fin_dlen += 8 + (hdr->ip6e_len << 3);
+		fin->fin_dp = hdr;
 		return IPPROTO_NONE;
 	}
 
-	for (i = 0; ip6exthdr[i].ol_bit != 0; i++)
-		if (ip6exthdr[i].ol_val == IPPROTO_ROUTING) {
-			fin->fin_optmsk |= ip6exthdr[i].ol_bit;
-			break;
-		}
-
-	fin->fin_dp = (char *)fin->fin_dp + shift;
-	fin->fin_dlen -= shift;
-
 	return hdr->ip6e_nxt;
 }
 
@@ -611,56 +658,40 @@
 /*                                                                          */
 /* IPv6 Only                                                                */
 /* Examine the IPv6 fragment header and extract fragment offset information.*/
+/*                                                                          */
+/* We don't know where the transport layer header (or whatever is next is), */
+/* as it could be behind destination options (amongst others).  Because     */
+/* there is no fragment cache, there is no knowledge about whether or not an*/
+/* upper layer header has been seen (or where it ends) and thus we are not  */
+/* able to continue processing beyond this header with any confidence.      */
 /* ------------------------------------------------------------------------ */
 static INLINE int frpr_fragment6(fin)
 fr_info_t *fin;
 {
 	struct ip6_frag *frag;
-	struct ip6_ext *hdr;
-	int i;
-
-	fin->fin_flx |= (FI_FRAG|FI_V6EXTHDR);
+	int extoff;
 
-				/* 8 is default length of extension hdr */
-	if ((fin->fin_dlen - 8) < 0) {
-		fin->fin_flx |= FI_SHORT;
-		return IPPROTO_NONE;
-	}
-
-	/*
-	 * Only one frgament header is allowed per IPv6 packet but it need
-	 * not be the first nor last (not possible in some cases.)
-	 */
-	for (i = 0; ip6exthdr[i].ol_bit != 0; i++)
-		if (ip6exthdr[i].ol_val == IPPROTO_FRAGMENT)
-			break;
+	fin->fin_flx |= FI_FRAG;
 
-	if (fin->fin_optmsk & ip6exthdr[i].ol_bit) {
-		fin->fin_flx |= FI_BAD;
+	if (frpr_ipv6exthdr(fin, 0, IPPROTO_FRAGMENT) == IPPROTO_NONE)
 		return IPPROTO_NONE;
-	}
 
-	fin->fin_optmsk |= ip6exthdr[i].ol_bit;
+	extoff = (char *)fin->fin_exthdr - (char *)fin->fin_dp;
 
 	if (frpr_pullup(fin, sizeof(*frag)) == -1)
 		return IPPROTO_NONE;
-	hdr = fin->fin_dp;
 
+	fin->fin_exthdr = (char *)fin->fin_dp + extoff;
+	frag = fin->fin_exthdr;
 	/*
-	 * Length must be zero, i.e. it has no length.
+	 * Fragment but no fragmentation info set?  Bad packet...
 	 */
-	if (hdr->ip6e_len != 0) {
+	if (frag->ip6f_offlg == 0) {
 		fin->fin_flx |= FI_BAD;
 		return IPPROTO_NONE;
 	}
 
-	if ((int)(fin->fin_dlen - sizeof(*frag)) < 0) {
-		fin->fin_flx |= FI_SHORT;
-		return IPPROTO_NONE;
-	}
-
-	frag = fin->fin_dp;
-	fin->fin_off = frag->ip6f_offlg & IP6F_OFF_MASK;
+	fin->fin_off = ntohs(frag->ip6f_offlg & IP6F_OFF_MASK);
 	fin->fin_off <<= 3;
 	if (fin->fin_off != 0)
 		fin->fin_flx |= FI_FRAGBODY;
@@ -684,34 +715,7 @@
 static INLINE int frpr_dstopts6(fin)
 fr_info_t *fin;
 {
-	struct ip6_ext *hdr;
-	u_short shift;
-	int i;
-
-				/* 8 is default length of extension hdr */
-	if ((fin->fin_dlen - 8) < 0) {
-		fin->fin_flx |= FI_SHORT;
-		return IPPROTO_NONE;
-	}
-
-	if (frpr_pullup(fin, 8) == -1)
-		return IPPROTO_NONE;
-	hdr = fin->fin_dp;
-
-	shift = 8 + (hdr->ip6e_len << 3);
-	if (shift > fin->fin_dlen) {	/* Nasty extension header length? */
-		fin->fin_flx |= FI_BAD;
-		return IPPROTO_NONE;
-	}
-
-	for (i = 0; ip6exthdr[i].ol_bit != 0; i++)
-		if (ip6exthdr[i].ol_val == IPPROTO_DSTOPTS)
-			break;
-	fin->fin_optmsk |= ip6exthdr[i].ol_bit;
-	fin->fin_dp = (char *)fin->fin_dp + shift;
-	fin->fin_dlen -= shift;
-
-	return hdr->ip6e_nxt;
+	return frpr_ipv6exthdr(fin, 1, IPPROTO_DSTOPTS);
 }
 
 
@@ -730,10 +734,12 @@
 	int minicmpsz = sizeof(struct icmp6_hdr);
 	struct icmp6_hdr *icmp6;
 
-	if (frpr_pullup(fin, ICMP6ERR_MINPKTLEN + 8 - sizeof(ip6_t)) == -1)
+	if (frpr_pullup(fin, ICMP6ERR_MINPKTLEN - sizeof(ip6_t)) == -1)
 		return;
 
 	if (fin->fin_dlen > 1) {
+		ip6_t *ip6;
+
 		icmp6 = fin->fin_dp;
 
 		fin->fin_data[0] = *(u_short *)icmp6;
@@ -748,20 +754,34 @@
 		case ICMP6_PACKET_TOO_BIG :
 		case ICMP6_TIME_EXCEEDED :
 		case ICMP6_PARAM_PROB :
-			if ((fin->fin_m != NULL) &&
-			    (M_LEN(fin->fin_m) < fin->fin_plen)) {
+			fin->fin_flx |= FI_ICMPERR;
+			minicmpsz = ICMP6ERR_IPICMPHLEN - sizeof(ip6_t);
+			if (fin->fin_plen < ICMP6ERR_IPICMPHLEN)
+				break;
+
+			if (M_LEN(fin->fin_m) < fin->fin_plen) {
 				if (fr_coalesce(fin) != 1)
 					return;
 			}
-			fin->fin_flx |= FI_ICMPERR;
-			minicmpsz = ICMP6ERR_IPICMPHLEN - sizeof(ip6_t);
+
+			/*
+			 * If the destination of this packet doesn't match the
+			 * source of the original packet then this packet is
+			 * not correct.
+			 */
+			icmp6 = fin->fin_dp;
+			ip6 = (ip6_t *)((char *)icmp6 + ICMPERR_ICMPHLEN);
+			if (IP6_NEQ(&fin->fin_fi.fi_dst,
+				    (i6addr_t *)&ip6->ip6_src))
+				fin->fin_flx |= FI_BAD;
+
 			break;
 		default :
 			break;
 		}
 	}
 
-	frpr_short(fin, minicmpsz);
+	frpr_short6(fin, minicmpsz);
 }
 
 
@@ -772,16 +792,21 @@
 /*                                                                          */
 /* IPv6 Only                                                                */
 /* Analyse the packet for IPv6/UDP properties.                              */
+/* Is not expected to be called for fragmented packets.                     */
 /* ------------------------------------------------------------------------ */
 static INLINE void frpr_udp6(fin)
 fr_info_t *fin;
 {
 
-	fr_checkv6sum(fin);
+	frpr_short6(fin, sizeof(struct udphdr));
 
-	frpr_short(fin, sizeof(struct udphdr));
+	if (frpr_udpcommon(fin) == 0) {
+		u_char p = fin->fin_p;
 
-	frpr_udpcommon(fin);
+		fin->fin_p = IPPROTO_UDP;
+		fr_checkv6sum(fin);
+		fin->fin_p = p;
+	}
 }
 
 
@@ -792,16 +817,91 @@
 /*                                                                          */
 /* IPv6 Only                                                                */
 /* Analyse the packet for IPv6/TCP properties.                              */
+/* Is not expected to be called for fragmented packets.                     */
 /* ------------------------------------------------------------------------ */
 static INLINE void frpr_tcp6(fin)
 fr_info_t *fin;
 {
 
-	fr_checkv6sum(fin);
+	frpr_short6(fin, sizeof(struct tcphdr));
+
+	if (frpr_tcpcommon(fin) == 0) {
+		u_char p = fin->fin_p;
+
+		fin->fin_p = IPPROTO_TCP;
+		fr_checkv6sum(fin);
+		fin->fin_p = p;
+	}
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    frpr_esp6                                                   */
+/* Returns:     void                                                        */
+/* Parameters:  fin(I) - pointer to packet information                      */
+/*                                                                          */
+/* IPv6 Only                                                                */
+/* Analyse the packet for ESP properties.                                   */
+/* The minimum length is taken to be the SPI (32bits) plus a tail (32bits)  */
+/* even though the newer ESP packets must also have a sequence number that  */
+/* is 32bits as well, it is not possible(?) to determine the version from a */
+/* simple packet header.                                                    */
+/* ------------------------------------------------------------------------ */
+static INLINE void frpr_esp6(fin)
+fr_info_t *fin;
+{
+
+	frpr_short6(fin, sizeof(grehdr_t));
+
+	(void) frpr_pullup(fin, 8);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    frpr_ah6                                                    */
+/* Returns:     void                                                        */
+/* Parameters:  fin(I) - pointer to packet information                      */
+/*                                                                          */
+/* IPv6 Only                                                                */
+/* Analyse the packet for AH properties.                                    */
+/* The minimum length is taken to be the combination of all fields in the   */
+/* header being present and no authentication data (null algorithm used.)   */
+/* ------------------------------------------------------------------------ */
+static INLINE int frpr_ah6(fin)
+fr_info_t *fin;
+{
+	authhdr_t *ah;
+
+	frpr_short6(fin, 12);
+
+	if (frpr_pullup(fin, sizeof(*ah)) == -1)
+		return IPPROTO_NONE;
+
+	ah = (authhdr_t *)fin->fin_dp;
+	return ah->ah_next;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    frpr_gre6                                                   */
+/* Returns:     void                                                        */
+/* Parameters:  fin(I) - pointer to packet information                      */
+/*                                                                          */
+/* Analyse the packet for GRE properties.                                   */
+/* ------------------------------------------------------------------------ */
+static INLINE void frpr_gre6(fin)
+fr_info_t *fin;
+{
+	grehdr_t *gre;
+
+	frpr_short6(fin, sizeof(grehdr_t));
 
-	frpr_short(fin, sizeof(struct tcphdr));
+	if (frpr_pullup(fin, sizeof(grehdr_t)) == -1)
+		return;
 
-	frpr_tcpcommon(fin);
+	gre = fin->fin_dp;
+	if (GRE_REV(gre->gr_flags) == 1)
+		fin->fin_data[0] = gre->gr_call;
 }
 #endif	/* USE_INET6 */
 
@@ -815,23 +915,39 @@
 /* Short inline function to cut down on code duplication to perform a call  */
 /* to fr_pullup to ensure there is the required amount of data,             */
 /* consecutively in the packet buffer.                                      */
+/*                                                                          */
+/* This function pulls up 'extra' data at the location of fin_dp.  fin_dp   */
+/* points to the first byte after the complete layer 3 header, which will   */
+/* include all of the known extension headers for IPv6 or options for IPv4. */
+/*                                                                          */
+/* Since fr_pullup() expects the total length of bytes to be pulled up, it  */
+/* is necessary to add those we can already assume to be pulled up (fin_dp  */
+/* - fin_ip) to what is passed through.                                     */
 /* ------------------------------------------------------------------------ */
 static INLINE int frpr_pullup(fin, plen)
 fr_info_t *fin;
 int plen;
 {
-#if defined(_KERNEL)
 	if (fin->fin_m != NULL) {
 		if (fin->fin_dp != NULL)
 			plen += (char *)fin->fin_dp -
 				((char *)fin->fin_ip + fin->fin_hlen);
 		plen += fin->fin_hlen;
 		if (M_LEN(fin->fin_m) < plen) {
+#if defined(_KERNEL)
 			if (fr_pullup(fin->fin_m, fin, plen) == NULL)
 				return -1;
+#else
+			/*
+			 * Fake fr_pullup failing
+			 */
+			*fin->fin_mp = NULL;
+			fin->fin_m = NULL;
+			fin->fin_ip = NULL;
+			return -1;
+#endif
 		}
 	}
-#endif
 	return 0;
 }
 
@@ -839,28 +955,25 @@
 /* ------------------------------------------------------------------------ */
 /* Function:    frpr_short                                                  */
 /* Returns:     void                                                        */
-/* Parameters:  fin(I) - pointer to packet information                      */
-/*              min(I) - minimum header size                                */
+/* Parameters:  fin(I)  - pointer to packet information                     */
+/*              xmin(I) - minimum header size                               */
 /*                                                                          */
-/* Check if a packet is "short" as defined by min.  The rule we are         */
+/* Check if a packet is "short" as defined by xmin.  The rule we are        */
 /* applying here is that the packet must not be fragmented within the layer */
 /* 4 header.  That is, it must not be a fragment that has its offset set to */
 /* start within the layer 4 header (hdrmin) or if it is at offset 0, the    */
 /* entire layer 4 header must be present (min).                             */
 /* ------------------------------------------------------------------------ */
-static INLINE void frpr_short(fin, min)
+static INLINE void frpr_short(fin, xmin)
 fr_info_t *fin;
-int min;
+int xmin;
 {
-	fr_ip_t *fi = &fin->fin_fi;
-	int off;
 
-	off = fin->fin_off;
-	if (off == 0) {
-		if (fin->fin_plen < fin->fin_hlen + min)
-			fi->fi_flx |= FI_SHORT;
-	} else if (off < min) {
-		fi->fi_flx |= FI_SHORT;
+	if (fin->fin_off == 0) {
+		if (fin->fin_dlen < xmin)
+			fin->fin_flx |= FI_SHORT;
+	} else if (fin->fin_off < xmin) {
+		fin->fin_flx |= FI_SHORT;
 	}
 }
 
@@ -873,7 +986,7 @@
 /* IPv4 Only                                                                */
 /* Do a sanity check on the packet for ICMP (v4).  In nearly all cases,     */
 /* except extrememly bad packets, both type and code will be present.       */
-/* The expected minimum size of an ICMP packet is very much dependant on    */
+/* The expected minimum size of an ICMP packet is very much dependent on    */
 /* the type of it.                                                          */
 /*                                                                          */
 /* XXX - other ICMP sanity checks?                                          */
@@ -883,17 +996,24 @@
 {
 	int minicmpsz = sizeof(struct icmp);
 	icmphdr_t *icmp;
+	ip_t *oip;
 
-	if (frpr_pullup(fin, ICMPERR_ICMPHLEN) == -1)
+	if (fin->fin_off != 0) {
+		frpr_short(fin, ICMPERR_ICMPHLEN);
 		return;
+	}
 
-	fr_checkv4sum(fin);
+	if (frpr_pullup(fin, ICMPERR_ICMPHLEN) == -1)
+		return;
 
-	if (!fin->fin_off && (fin->fin_dlen > 1)) {
+	if (fin->fin_dlen > 1) {
 		icmp = fin->fin_dp;
 
 		fin->fin_data[0] = *(u_short *)icmp;
 
+		if (fin->fin_dlen >= 6)				/* ID field */
+			fin->fin_data[1] = icmp->icmp_id;
+
 		switch (icmp->icmp_type)
 		{
 		case ICMP_ECHOREPLY :
@@ -923,29 +1043,59 @@
 		 * type(1) + code(1) + cksum(2) + id(2) seq(2) + ip(20+)
 		 */
 		case ICMP_UNREACH :
+#ifdef icmp_nextmtu
+			if (icmp->icmp_code == ICMP_UNREACH_NEEDFRAG) {
+				if (icmp->icmp_nextmtu < fr_icmpminfragmtu)
+					fin->fin_flx |= FI_BAD;
+			}
+#endif
 		case ICMP_SOURCEQUENCH :
 		case ICMP_REDIRECT :
 		case ICMP_TIMXCEED :
 		case ICMP_PARAMPROB :
+			fin->fin_flx |= FI_ICMPERR;
 			if (fr_coalesce(fin) != 1)
 				return;
-			fin->fin_flx |= FI_ICMPERR;
-			break;
-		default :
-			break;
-		}
-
-		if (fin->fin_dlen >= 6)				/* ID field */
-			fin->fin_data[1] = icmp->icmp_id;
+			/*
+			 * ICMP error packets should not be generated for IP
+			 * packets that are a fragment that isn't the first
+			 * fragment.
+			 */
+			oip = (ip_t *)((char *)fin->fin_dp + ICMPERR_ICMPHLEN);
+			if ((ntohs(oip->ip_off) & IP_OFFMASK) != 0)
+				fin->fin_flx |= FI_BAD;
+
+			/*
+			 * If the destination of this packet doesn't match the
+			 * source of the original packet then this packet is
+			 * not correct.
+			 */
+			if (oip->ip_src.s_addr != fin->fin_daddr)
+				fin->fin_flx |= FI_BAD;
+
+			/*
+			 * If the destination of this packet doesn't match the
+			 * source of the original packet then this packet is
+			 * not correct.
+			 */
+			if (oip->ip_src.s_addr != fin->fin_daddr)
+				fin->fin_flx |= FI_BAD;
+			break;
+		default :
+			break;
+		}
 	}
 
 	frpr_short(fin, minicmpsz);
+
+	if ((fin->fin_flx & FI_FRAG) == 0)
+		fr_checkv4sum(fin);
 }
 
 
 /* ------------------------------------------------------------------------ */
 /* Function:    frpr_tcpcommon                                              */
-/* Returns:     void                                                        */
+/* Returns:     int    - 0 = header ok, 1 = bad packet, -1 = buffer error   */
 /* Parameters:  fin(I) - pointer to packet information                      */
 /*                                                                          */
 /* TCP header sanity checking.  Look for bad combinations of TCP flags,     */
@@ -953,20 +1103,18 @@
 /* If compiled with IPFILTER_CKSUM, check to see if the TCP checksum is     */
 /* valid and mark the packet as bad if not.                                 */
 /* ------------------------------------------------------------------------ */
-static INLINE void frpr_tcpcommon(fin)
+static INLINE int frpr_tcpcommon(fin)
 fr_info_t *fin;
 {
 	int flags, tlen;
 	tcphdr_t *tcp;
-	fr_ip_t *fi;
 
-	fi = &fin->fin_fi;
-	fi->fi_flx |= FI_TCPUDP;
+	fin->fin_flx |= FI_TCPUDP;
 	if (fin->fin_off != 0)
-		return;
+		return 0;
 
 	if (frpr_pullup(fin, sizeof(*tcp)) == -1)
-		return;
+		return -1;
 	tcp = fin->fin_dp;
 
 	if (fin->fin_dlen > 3) {
@@ -974,8 +1122,8 @@
 		fin->fin_dport = ntohs(tcp->th_dport);
 	}
 
-	if ((fi->fi_flx & FI_SHORT) != 0)
-		return;
+	if ((fin->fin_flx & FI_SHORT) != 0)
+		return 1;
 
 	/*
 	 * Use of the TCP data offset *must* result in a value that is at
@@ -984,7 +1132,7 @@
 	tlen = TCP_OFF(tcp) << 2;
 	if (tlen < sizeof(tcphdr_t)) {
 		fin->fin_flx |= FI_BAD;
-		return;
+		return 1;
 	}
 
 	flags = tcp->th_flags;
@@ -997,14 +1145,27 @@
 	 */
 	if ((flags & TH_URG) != 0 && (tcp->th_urp == 0)) {
 		fin->fin_flx |= FI_BAD;
+#if 0
 	} else if ((flags & TH_URG) == 0 && (tcp->th_urp != 0)) {
-		/* Ignore this case, it shows up in "real" traffic with */
-		/* bogus values in the urgent pointer field. */
-		;
+		/*
+		 * Ignore this case (#if 0) as it shows up in "real"
+		 * traffic with bogus values in the urgent pointer field.
+		 */
+		fin->fin_flx |= FI_BAD;
+#endif
 	} else if (((flags & (TH_SYN|TH_FIN)) != 0) &&
 		   ((flags & (TH_RST|TH_ACK)) == TH_RST)) {
 		/* TH_FIN|TH_RST|TH_ACK seems to appear "naturally" */
 		fin->fin_flx |= FI_BAD;
+#if 1
+	} else if (((flags & TH_SYN) != 0) &&
+		   ((flags & (TH_URG|TH_PUSH)) != 0)) {
+		/*
+		 * SYN with URG and PUSH set is not for normal TCP but it is
+		 * possible(?) with T/TCP...but who uses T/TCP?
+		 */
+		fin->fin_flx |= FI_BAD;
+#endif
 	} else if (!(flags & TH_ACK)) {
 		/*
 		 * If the ack bit isn't set, then either the SYN or
@@ -1038,12 +1199,13 @@
 	 * then that might add some weight to adding this...
 	 */
 	if (tlen == sizeof(tcphdr_t))
-		return;
+		return 0;
 
 	if (frpr_pullup(fin, tlen) == -1)
-		return;
+		return -1;
 
 #if 0
+	tcp = fin->fin_dp;
 	ip = fin->fin_ip;
 	s = (u_char *)(tcp + 1);
 	off = IP_HL(ip) << 2;
@@ -1080,31 +1242,31 @@
 		s += ol;
 	}
 #endif /* 0 */
+
+	return 0;
 }
 
 
 
 /* ------------------------------------------------------------------------ */
 /* Function:    frpr_udpcommon                                              */
-/* Returns:     void                                                        */
+/* Returns:     int    - 0 = header ok, 1 = bad packet                      */
 /* Parameters:  fin(I) - pointer to packet information                      */
 /*                                                                          */
 /* Extract the UDP source and destination ports, if present.  If compiled   */
 /* with IPFILTER_CKSUM, check to see if the UDP checksum is valid.          */
 /* ------------------------------------------------------------------------ */
-static INLINE void frpr_udpcommon(fin)
+static INLINE int frpr_udpcommon(fin)
 fr_info_t *fin;
 {
 	udphdr_t *udp;
-	fr_ip_t *fi;
 
-	fi = &fin->fin_fi;
-	fi->fi_flx |= FI_TCPUDP;
+	fin->fin_flx |= FI_TCPUDP;
 
 	if (!fin->fin_off && (fin->fin_dlen > 3)) {
 		if (frpr_pullup(fin, sizeof(*udp)) == -1) {
-			fi->fi_flx |= FI_SHORT;
-			return;
+			fin->fin_flx |= FI_SHORT;
+			return 1;
 		}
 
 		udp = fin->fin_dp;
@@ -1112,6 +1274,8 @@
 		fin->fin_sport = ntohs(udp->uh_sport);
 		fin->fin_dport = ntohs(udp->uh_dport);
 	}
+
+	return 0;
 }
 
 
@@ -1127,11 +1291,12 @@
 fr_info_t *fin;
 {
 
-	fr_checkv4sum(fin);
-
 	frpr_short(fin, sizeof(tcphdr_t));
 
-	frpr_tcpcommon(fin);
+	if (frpr_tcpcommon(fin) == 0) {
+		if ((fin->fin_flx & FI_FRAG) == 0)
+			fr_checkv4sum(fin);
+	}
 }
 
 
@@ -1147,11 +1312,12 @@
 fr_info_t *fin;
 {
 
-	fr_checkv4sum(fin);
-
 	frpr_short(fin, sizeof(udphdr_t));
 
-	frpr_udpcommon(fin);
+	if (frpr_udpcommon(fin) == 0) {
+		if ((fin->fin_flx & FI_FRAG) == 0)
+			fr_checkv4sum(fin);
+	}
 }
 
 
@@ -1169,15 +1335,42 @@
 static INLINE void frpr_esp(fin)
 fr_info_t *fin;
 {
-	if (frpr_pullup(fin, 8) == -1)
-		return;
 
-	if (fin->fin_v == 4)
+	if (fin->fin_off == 0) {
 		frpr_short(fin, 8);
-#ifdef USE_INET6
-	else if (fin->fin_v == 6)
-		frpr_short6(fin, sizeof(grehdr_t));
-#endif
+		(void) frpr_pullup(fin, 8);
+	}
+
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    frpr_ah                                                     */
+/* Returns:     void                                                        */
+/* Parameters:  fin(I) - pointer to packet information                      */
+/*                                                                          */
+/* Analyse the packet for AH properties.                                    */
+/* The minimum length is taken to be the combination of all fields in the   */
+/* header being present and no authentication data (null algorithm used.)   */
+/* ------------------------------------------------------------------------ */
+static INLINE void frpr_ah(fin)
+fr_info_t *fin;
+{
+	authhdr_t *ah;
+	int len;
+
+	frpr_short(fin, sizeof(*ah));
+
+	if (((fin->fin_flx & FI_SHORT) != 0) || (fin->fin_off != 0))
+		return;
+
+	if (frpr_pullup(fin, sizeof(*ah)) == -1)
+		return;
+
+	ah = (authhdr_t *)fin->fin_dp;
+
+	len = (ah->ah_plen + 2) << 2;
+	frpr_short(fin, len);
 }
 
 
@@ -1193,18 +1386,19 @@
 {
 	grehdr_t *gre;
 
-	if (frpr_pullup(fin, sizeof(grehdr_t)) == -1)
+	frpr_short(fin, sizeof(*gre));
+
+	if (fin->fin_off != 0)
 		return;
 
-	if (fin->fin_v == 4)
-		frpr_short(fin, sizeof(grehdr_t));
-#ifdef USE_INET6
-	else if (fin->fin_v == 6)
-		frpr_short6(fin, sizeof(grehdr_t));
-#endif
-	gre = fin->fin_dp;
-	if (GRE_REV(gre->gr_flags) == 1)
-		fin->fin_data[0] = gre->gr_call;
+	if (frpr_pullup(fin, sizeof(*gre)) == -1)
+		return;
+
+	if (fin->fin_off == 0) {
+		gre = fin->fin_dp;
+		if (GRE_REV(gre->gr_flags) == 1)
+			fin->fin_data[0] = gre->gr_call;
+	}
 }
 
 
@@ -1260,20 +1454,27 @@
 	 * set packet attribute flags based on the offset and
 	 * calculate the byte offset that it represents.
 	 */
-	if ((off & IP_MF) != 0) {
-		fi->fi_flx |= FI_FRAG;
-		if (fin->fin_dlen == 0)
-			fi->fi_flx |= FI_BAD;
-	}
-
 	off &= IP_MF|IP_OFFMASK;
 	if (off != 0) {
+		int morefrag = off & IP_MF;
+
 		fi->fi_flx |= FI_FRAG;
 		off &= IP_OFFMASK;
 		if (off != 0) {
 			fin->fin_flx |= FI_FRAGBODY;
 			off <<= 3;
-			if (off + fin->fin_dlen > 0xffff) {
+			if ((off + fin->fin_dlen > 65535) || 
+			    (fin->fin_dlen == 0) ||
+			    ((morefrag != 0) && ((fin->fin_dlen & 7) != 0))) {
+				/* 
+				 * The length of the packet, starting at its
+				 * offset cannot exceed 65535 (0xffff) as the 
+				 * length of an IP packet is only 16 bits.
+				 *
+				 * Any fragment that isn't the last fragment
+				 * must have a length greater than 0 and it
+				 * must be an even multiple of 8.
+				 */
 				fi->fi_flx |= FI_BAD;
 			}
 		}
@@ -1294,6 +1495,9 @@
 	case IPPROTO_ICMP :
 		frpr_icmp(fin);
 		break;
+	case IPPROTO_AH :
+		frpr_ah(fin);
+		break;
 	case IPPROTO_ESP :
 		frpr_esp(fin);
 		break;
@@ -1415,16 +1619,24 @@
 	fin->fin_rule = 0xffffffff;
 	fin->fin_group[0] = -1;
 	fin->fin_group[1] = '\0';
-	fin->fin_dlen = fin->fin_plen - hlen;
 	fin->fin_dp = (char *)ip + hlen;
 
 	v = fin->fin_v;
-	if (v == 4)
+	if (v == 4) {
+		fin->fin_plen = ip->ip_len;
+		fin->fin_dlen = fin->fin_plen - hlen;
+
 		frpr_ipv4hdr(fin);
 #ifdef	USE_INET6
-	else if (v == 6)
-		frpr_ipv6hdr(fin);
+	} else if (v == 6) {
+		fin->fin_plen = ntohs(((ip6_t *)ip)->ip6_plen);
+		fin->fin_dlen = fin->fin_plen;
+		fin->fin_plen += hlen;
+
+		if (frpr_ipv6hdr(fin) == -1)
+			return -1;
 #endif
+	}
 	if (fin->fin_ip == NULL)
 		return -1;
 	return 0;
@@ -1551,6 +1763,7 @@
 }
 
 
+
 /* ------------------------------------------------------------------------ */
 /* Function:    fr_ipfcheck                                                 */
 /* Returns:     int - 0 == match, 1 == no match                             */
@@ -1585,7 +1798,7 @@
 	 */
 	i = ((*lip & *lm) != *ld);
 	FR_DEBUG(("0. %#08x & %#08x != %#08x\n",
-		   *lip, *lm, *ld));
+		   ntohl(*lip), ntohl(*lm), ntohl(*ld)));
 	if (i)
 		return 1;
 
@@ -1596,7 +1809,7 @@
 	lip++, lm++, ld++;
 	i |= ((*lip & *lm) != *ld);
 	FR_DEBUG(("1. %#08x & %#08x != %#08x\n",
-		   *lip, *lm, *ld));
+		   ntohl(*lip), ntohl(*lm), ntohl(*ld)));
 	if (i)
 		return 1;
 
@@ -1619,20 +1832,20 @@
 #endif
 		i = ((*lip & *lm) != *ld);
 		FR_DEBUG(("2a. %#08x & %#08x != %#08x\n",
-			   *lip, *lm, *ld));
+			   ntohl(*lip), ntohl(*lm), ntohl(*ld)));
 		if (fi->fi_v == 6) {
 			lip++, lm++, ld++;
 			i |= ((*lip & *lm) != *ld);
 			FR_DEBUG(("2b. %#08x & %#08x != %#08x\n",
-				   *lip, *lm, *ld));
+				   ntohl(*lip), ntohl(*lm), ntohl(*ld)));
 			lip++, lm++, ld++;
 			i |= ((*lip & *lm) != *ld);
 			FR_DEBUG(("2c. %#08x & %#08x != %#08x\n",
-				   *lip, *lm, *ld));
+				   ntohl(*lip), ntohl(*lm), ntohl(*ld)));
 			lip++, lm++, ld++;
 			i |= ((*lip & *lm) != *ld);
 			FR_DEBUG(("2d. %#08x & %#08x != %#08x\n",
-				   *lip, *lm, *ld));
+				   ntohl(*lip), ntohl(*lm), ntohl(*ld)));
 		} else {
 			lip += 3;
 			lm += 3;
@@ -1661,20 +1874,20 @@
 #endif
 		i = ((*lip & *lm) != *ld);
 		FR_DEBUG(("3a. %#08x & %#08x != %#08x\n",
-			   *lip, *lm, *ld));
+			   ntohl(*lip), ntohl(*lm), ntohl(*ld)));
 		if (fi->fi_v == 6) {
 			lip++, lm++, ld++;
 			i |= ((*lip & *lm) != *ld);
 			FR_DEBUG(("3b. %#08x & %#08x != %#08x\n",
-				   *lip, *lm, *ld));
+				   ntohl(*lip), ntohl(*lm), ntohl(*ld)));
 			lip++, lm++, ld++;
 			i |= ((*lip & *lm) != *ld);
 			FR_DEBUG(("3c. %#08x & %#08x != %#08x\n",
-				   *lip, *lm, *ld));
+				   ntohl(*lip), ntohl(*lm), ntohl(*ld)));
 			lip++, lm++, ld++;
 			i |= ((*lip & *lm) != *ld);
 			FR_DEBUG(("3d. %#08x & %#08x != %#08x\n",
-				   *lip, *lm, *ld));
+				   ntohl(*lip), ntohl(*lm), ntohl(*ld)));
 		} else {
 			lip += 3;
 			lm += 3;
@@ -1754,9 +1967,9 @@
 fr_info_t *fin;
 u_32_t pass;
 {
-	int rulen, portcmp, off, logged, skip;
+	int rulen, portcmp, off, skip;
 	struct frentry *fr, *fnext;
-	u_32_t passt;
+	u_32_t passt, passo;
 
 	/*
 	 * Do not allow nesting deeper than 16 levels.
@@ -1773,7 +1986,6 @@
 		return pass;
 
 	skip = 0;
-	logged = 0;
 	portcmp = 0;
 	fin->fin_depth++;
 	fin->fin_fr = NULL;
@@ -1824,15 +2036,13 @@
 		case FR_T_BPFOPC|FR_T_BUILTIN :
 		    {
 			u_char *mc;
-			int wlen;
 
 			if (*fin->fin_mp == NULL)
 				continue;
 			if (fin->fin_v != fr->fr_v)
 				continue;
 			mc = (u_char *)fin->fin_m;
-			wlen = fin->fin_dlen + fin->fin_hlen;
-			if (!bpf_filter(fr->fr_data, mc, wlen, 0))
+			if (!bpf_filter(fr->fr_data, mc, fin->fin_plen, 0))
 				continue;
 			break;
 		    }
@@ -1878,24 +2088,23 @@
 		 * it, except for increasing the hit counter.
 		 */
 		if ((passt & FR_CALLNOW) != 0) {
+			frentry_t *frs;
+
 			ATOMIC_INC64(fr->fr_hits);
 			if ((fr->fr_func != NULL) &&
-			    (fr->fr_func != (ipfunc_t)-1)) {
-				frentry_t *frs;
+			    (fr->fr_func == (ipfunc_t)-1))
+				continue;
 
-				frs = fin->fin_fr;
-				fin->fin_fr = fr;
-				fr = (*fr->fr_func)(fin, &passt);
-				if (fr == NULL) {
-					fin->fin_fr = frs;
-					continue;
-				}
-				passt = fr->fr_flags;
-				fin->fin_fr = fr;
-			}
-		} else {
+			frs = fin->fin_fr;
 			fin->fin_fr = fr;
+			fr = (*fr->fr_func)(fin, &passt);
+			if (fr == NULL) {
+				fin->fin_fr = frs;
+				continue;
+			}
+			passt = fr->fr_flags;
 		}
+		fin->fin_fr = fr;
 
 #ifdef  IPFILTER_LOG
 		/*
@@ -1910,10 +2119,11 @@
 				ATOMIC_INCL(frstats[fin->fin_out].fr_skip);
 			}
 			ATOMIC_INCL(frstats[fin->fin_out].fr_pkl);
-			logged = 1;
+			fin->fin_flx |= FI_DONTCACHE;
 		}
 #endif /* IPFILTER_LOG */
 		fr->fr_bytes += (U_QUAD_T)fin->fin_plen;
+		passo = pass;
 		if (FR_ISSKIP(passt))
 			skip = fr->fr_arg;
 		else if ((passt & FR_LOGMASK) != FR_LOG)
@@ -1926,21 +2136,41 @@
 		(void) strncpy(fin->fin_group, fr->fr_group, FR_GROUPLEN);
 		if (fr->fr_grp != NULL) {
 			fin->fin_fr = *fr->fr_grp;
-			pass = fr_scanlist(fin, pass);
+			passt = fr_scanlist(fin, pass);
 			if (fin->fin_fr == NULL) {
 				fin->fin_rule = rulen;
 				(void) strncpy(fin->fin_group, fr->fr_group,
 					       FR_GROUPLEN);
 				fin->fin_fr = fr;
+				passt = pass;
 			}
-			if (fin->fin_flx & FI_DONTCACHE)
-				logged = 1;
+			pass = passt;
 		}
-		if (pass & FR_QUICK)
+
+		if (passt & FR_QUICK) {
+			/*
+			 * Finally, if we've asked to track state for this
+			 * packet, set it up.  Add state for "quick" rules
+			 * here so that if the action fails we can consider
+			 * the rule to "not match" and keep on processing
+			 * filter rules.
+			 */
+			if ((pass & FR_KEEPSTATE) &&
+			    !(fin->fin_flx & FI_STATE)) {
+				int out = fin->fin_out;
+
+				fin->fin_fr = fr;
+				if (fr_addstate(fin, NULL, 0) != NULL) {
+					ATOMIC_INCL(frstats[out].fr_ads);
+				} else {
+					ATOMIC_INCL(frstats[out].fr_bads);
+					pass = passo;
+					continue;
+				}
+			}
 			break;
+		}
 	}
-	if (logged)
-		fin->fin_flx |= FI_DONTCACHE;
 	fin->fin_depth--;
 	return pass;
 }
@@ -2022,18 +2252,22 @@
 	 * the result as if it were from the ACL's.
 	 */
 	fc = &frcache[out][CACHE_HASH(fin)];
+	READ_ENTER(&ipf_frcache);
 	if (!bcmp((char *)fin, (char *)fc, FI_CSIZE)) {
 		/*
-		 * copy cached data so we can unlock the mutex
-		 * earlier.
+		 * copy cached data so we can unlock the mutexes earlier.
 		 */
 		bcopy((char *)fc, (char *)fin, FI_COPYSIZE);
+		RWLOCK_EXIT(&ipf_frcache);
 		ATOMIC_INCL(frstats[out].fr_chit);
+
 		if ((fr = fin->fin_fr) != NULL) {
 			ATOMIC_INC64(fr->fr_hits);
 			pass = fr->fr_flags;
 		}
 	} else {
+		RWLOCK_EXIT(&ipf_frcache);
+
 #ifdef	USE_INET6
 		if (fin->fin_v == 6)
 			fin->fin_fr = ipfilter6[out][fr_active];
@@ -2042,9 +2276,13 @@
 			fin->fin_fr = ipfilter[out][fr_active];
 		if (fin->fin_fr != NULL)
 			pass = fr_scanlist(fin, fr_pass);
+
 		if (((pass & FR_KEEPSTATE) == 0) &&
-		    ((fin->fin_flx & FI_DONTCACHE) == 0))
+		    ((fin->fin_flx & FI_DONTCACHE) == 0)) {
+			WRITE_ENTER(&ipf_frcache);
 			bcopy((char *)fin, (char *)fc, FI_COPYSIZE);
+			RWLOCK_EXIT(&ipf_frcache);
+		}
 		if ((pass & FR_NOMATCH)) {
 			ATOMIC_INCL(frstats[out].fr_nom);
 		}
@@ -2109,21 +2347,6 @@
 		}
 	}
 
-	/*
-	 * Finally, if we've asked to track state for this packet, set it up.
-	 */
-	if ((pass & FR_KEEPSTATE) && !(fin->fin_flx & FI_STATE)) {
-		if (fr_addstate(fin, NULL, 0) != NULL) {
-			ATOMIC_INCL(frstats[out].fr_ads);
-		} else {
-			ATOMIC_INCL(frstats[out].fr_bads);
-			if (FR_ISPASS(pass)) {
-				pass &= ~FR_CMDMASK;
-				pass |= FR_BLOCK;
-			}
-		}
-	}
-
 	fr = fin->fin_fr;
 
 	if (passp != NULL)
@@ -2139,7 +2362,7 @@
 /*              User space:                                                 */
 /*                    -1 == packet blocked                                  */
 /*                     1 == packet not matched                              */
-/*                    -2 == requires authantication                         */
+/*                    -2 == requires authentication                         */
 /*              Kernel:                                                     */
 /*                   > 0 == filter error # for packet                       */
 /* Parameters: ip(I)   - pointer to start of IPv4/6 packet                  */
@@ -2186,10 +2409,6 @@
 	int v = IP_V(ip);
 	mb_t *mc = NULL;
 	mb_t *m;
-#ifdef USE_INET6
-	ip6_t *ip6;
-#endif
-
 	/*
 	 * The first part of fr_check() deals with making sure that what goes
 	 * into the filtering engine makes some sense.  Information about the
@@ -2201,8 +2420,12 @@
 # ifdef MENTAT
 	qpktinfo_t *qpi = qif;
 
+#  if !defined(_INET_IP_STACK_H)
 	if ((u_int)ip & 0x3)
 		return 2;
+#  endif
+# else
+	SPL_INT(s);
 # endif
 
 	READ_ENTER(&ipf_global);
@@ -2228,6 +2451,10 @@
 	if ((m->m_flags & M_MCAST) != 0)
 		fin->fin_flx |= FI_MBCAST|FI_MULTICAST;
 #  endif
+#  if defined(M_MLOOP)
+	if ((m->m_flags & M_MLOOP) != 0)
+		fin->fin_flx |= FI_MBCAST|FI_MULTICAST;
+#  endif
 #  if defined(M_BCAST)
 	if ((m->m_flags & M_BCAST) != 0)
 		fin->fin_flx |= FI_MBCAST|FI_BROADCAST;
@@ -2264,11 +2491,13 @@
 	fin->fin_out = out;
 	fin->fin_ifp = ifp;
 	fin->fin_error = ENETUNREACH;
-	fin->fin_hlen = (u_short )hlen;
+	fin->fin_hlen = (u_short)hlen;
 	fin->fin_dp = (char *)ip + hlen;
 
 	fin->fin_ipoff = (char *)ip - MTOD(m, char *);
 
+	SPL_NET(s);
+
 #ifdef	USE_INET6
 	if (v == 6) {
 		ATOMIC_INCL(frstats[out].fr_ipv6);
@@ -2277,25 +2506,23 @@
 		 * structures to handle comfortably, for now, so just drop
 		 * them.
 		 */
-		ip6 = (ip6_t *)ip;
-		fin->fin_plen = ntohs(ip6->ip6_plen);
-		if (fin->fin_plen == 0) {
+		if (((ip6_t *)ip)->ip6_plen == 0) {
 			pass = FR_BLOCK|FR_NOMATCH;
-			goto filtered;
+			goto finished;
 		}
-		fin->fin_plen += sizeof(ip6_t);
 	} else
 #endif
 	{
-#if (OpenBSD >= 200311) && defined(_KERNEL)
+#if (defined(OpenBSD) && OpenBSD >= 200311) && defined(_KERNEL)
 		ip->ip_len = ntohs(ip->ip_len);
 		ip->ip_off = ntohs(ip->ip_off);
 #endif
-		fin->fin_plen = ip->ip_len;
 	}
 
-	if (fr_makefrip(hlen, ip, fin) == -1)
+	if (fr_makefrip(hlen, ip, fin) == -1) {
+		pass = FR_BLOCK|FR_NOMATCH;
 		goto finished;
+	}
 
 	/*
 	 * For at least IPv6 packets, if a m_pullup() fails then this pointer
@@ -2319,8 +2546,7 @@
 		}
 #ifdef USE_INET6
 		else  if (v == 6) {
-			ip6 = (ip6_t *)ip;
-			if (ip6->ip6_hlim < fr_minttl) {
+			if (((ip6_t *)ip)->ip6_hlim < fr_minttl) {
 				ATOMIC_INCL(frstats[0].fr_badttl);
 				fin->fin_flx |= FI_LOWTTL;
 			}
@@ -2344,22 +2570,48 @@
 	fr = fr_checkauth(fin, &pass);
 	if (!out) {
 		if (fr_checknatin(fin, &pass) == -1) {
-			RWLOCK_EXIT(&ipf_mutex);
-			goto finished;
+			goto filterdone;
 		}
 	}
 	if (!out)
 		(void) fr_acctpkt(fin, NULL);
 
-	if (fr == NULL)
-		if ((fin->fin_flx & (FI_FRAG|FI_BAD)) == FI_FRAG)
+	if (fr == NULL) {
+		if ((fin->fin_flx & (FI_FRAG|FI_BAD)) == FI_FRAG) {
 			fr = fr_knownfrag(fin, &pass);
-	if (fr == NULL)
-		fr = fr_checkstate(fin, &pass);
+			/*
+			 * Reset the keep state flag here so that we don't
+			 * try and add a new state entry because of it, leading
+			 * to a blocked packet because the add will fail.
+			 */
+			if (fr != NULL)
+				pass &= ~FR_KEEPSTATE;
+		}
+		if (fr == NULL)
+			fr = fr_checkstate(fin, &pass);
+	}
 
 	if ((pass & FR_NOMATCH) || (fr == NULL))
 		fr = fr_firewall(fin, &pass);
 
+	/*
+	 * If we've asked to track state for this packet, set it up.
+	 * Here rather than fr_firewall because fr_checkauth may decide
+	 * to return a packet for "keep state"
+	 */
+	if ((pass & FR_KEEPSTATE) && (fin->fin_m != NULL) &&
+	    !(fin->fin_flx & FI_STATE)) {
+		if (fr_addstate(fin, NULL, 0) != NULL) {
+			ATOMIC_INCL(frstats[out].fr_ads);
+		} else {
+			ATOMIC_INCL(frstats[out].fr_bads);
+			if (FR_ISPASS(pass)) {
+				pass &= ~FR_CMDMASK;
+				pass |= FR_BLOCK;
+			}
+		}
+	}
+
 	fin->fin_fr = fr;
 
 	/*
@@ -2370,8 +2622,7 @@
 		(void) fr_acctpkt(fin, NULL);
 
 		if (fr_checknatout(fin, &pass) == -1) {
-			RWLOCK_EXIT(&ipf_mutex);
-			goto finished;
+			;
 		} else if ((fr_update_ipid != 0) && (v == 4)) {
 			if (fr_updateipid(fin) == -1) {
 				ATOMIC_INCL(frstats[1].fr_ipud);
@@ -2383,29 +2634,51 @@
 		}
 	}
 
+filterdone:
 #ifdef	IPFILTER_LOG
 	if ((fr_flags & FF_LOGGING) || (pass & FR_LOGMASK)) {
 		(void) fr_dolog(fin, &pass);
 	}
 #endif
 
-	if (fin->fin_state != NULL)
-		fr_statederef(fin, (ipstate_t **)&fin->fin_state);
-
-	if (fin->fin_nat != NULL)
-		fr_natderef((nat_t **)&fin->fin_nat);
+	/*
+	 * The FI_STATE flag is cleared here so that calling fr_checkstate
+	 * will work when called from inside of fr_fastroute.  Although
+	 * there is a similar flag, FI_NATED, for NAT, it does have the same
+	 * impact on code execution.
+	 */
+	if (fin->fin_state != NULL) {
+		fr_statederef((ipstate_t **)&fin->fin_state);
+		fin->fin_flx ^= FI_STATE;
+	}
+
+	if (fin->fin_nat != NULL) {
+		if (FR_ISBLOCK(pass) && (fin->fin_flx & FI_NEWNAT)) {
+			WRITE_ENTER(&ipf_nat);
+			nat_delete((nat_t *)fin->fin_nat, NL_DESTROY);
+			RWLOCK_EXIT(&ipf_nat);
+			fin->fin_nat = NULL;
+		} else {
+			fr_natderef((nat_t **)&fin->fin_nat);
+		}
+	}
 
 	/*
-	 * Only allow FR_DUP to work if a rule matched - it makes no sense to
-	 * set FR_DUP as a "default" as there are no instructions about where
-	 * to send the packet.  Use fin_m here because it may have changed
-	 * (without an update of 'm') in prior processing.
+	 * Up the reference on fr_lock and exit ipf_mutex.  fr_fastroute
+	 * only frees up the lock on ipf_global and the generation of a
+	 * packet below could cause a recursive call into IPFilter.
+	 * Hang onto the filter rule just in case someone decides to remove
+	 * or flush it in the meantime.
 	 */
-	if ((fr != NULL) && (pass & FR_DUP)) {
-		mc = M_DUPLICATE(fin->fin_m);
+	if (fr != NULL) {
+		MUTEX_ENTER(&fr->fr_lock);
+		fr->fr_ref++;
+		MUTEX_EXIT(&fr->fr_lock);
 	}
 
-	if (pass & (FR_RETRST|FR_RETICMP)) {
+	RWLOCK_EXIT(&ipf_mutex);
+
+	if ((pass & FR_RETMASK) != 0) {
 		/*
 		 * Should we return an ICMP packet to indicate error
 		 * status passing through the packet filter ?
@@ -2426,10 +2699,19 @@
 				ATOMIC_INCL(frstats[0].fr_ret);
 			} else if (((pass & FR_RETMASK) == FR_RETRST) &&
 				   !(fin->fin_flx & FI_SHORT)) {
-				if (fr_send_reset(fin) == 0) {
+				if (((fin->fin_flx & FI_OOW) != 0) ||
+				    (fr_send_reset(fin) == 0)) {
 					ATOMIC_INCL(frstats[1].fr_ret);
 				}
 			}
+
+			/*
+			 * When using return-* with auth rules, the auth code
+			 * takes over disposing of this packet.
+			 */
+			if (FR_ISAUTH(pass) && (fin->fin_m != NULL)) {
+				fin->fin_m = *fin->fin_mp = NULL;
+			}
 		} else {
 			if (pass & FR_RETRST)
 				fin->fin_error = ECONNRESET;
@@ -2442,13 +2724,7 @@
 	 * instructions about what to do with a packet.
 	 * Once we're finished return to our caller, freeing the packet if
 	 * we are dropping it (* BSD ONLY *).
-	 * Reassign m from fin_m as we may have a new buffer, now.
 	 */
-#if defined(USE_INET6) || (defined(__sgi) && defined(_KERNEL))
-filtered:
-#endif
-	m = fin->fin_m;
-
 	if (fr != NULL) {
 		frdest_t *fdp;
 
@@ -2459,26 +2735,26 @@
 			 * For fastroute rule, no destioation interface defined
 			 * so pass NULL as the frdest_t parameter
 			 */
-			(void) fr_fastroute(m, mp, fin, NULL);
+			(void) fr_fastroute(fin->fin_m, mp, fin, NULL);
 			m = *mp = NULL;
 		} else if ((fdp->fd_ifp != NULL) &&
 			   (fdp->fd_ifp != (struct ifnet *)-1)) {
 			/* this is for to rules: */
-			(void) fr_fastroute(m, mp, fin, fdp);
+			(void) fr_fastroute(fin->fin_m, mp, fin, fdp);
 			m = *mp = NULL;
 		}
 
 		/*
 		 * Generate a duplicated packet.
 		 */
-		if (mc != NULL)
-			(void) fr_fastroute(mc, &mc, fin, &fr->fr_dif);
-	}
+		if ((pass & FR_DUP) != 0) {
+			mc = M_DUPLICATE(fin->fin_m);
+			if (mc != NULL)
+				(void) fr_fastroute(mc, &mc, fin, &fr->fr_dif);
+		}
 
-	/*
-	 * This late because the likes of fr_fastroute() use fin_fr.
-	 */
-	RWLOCK_EXIT(&ipf_mutex);
+		(void) fr_derefrule(&fr);
+	}
 
 finished:
 	if (!FR_ISPASS(pass)) {
@@ -2492,14 +2768,16 @@
 #if defined(_KERNEL) && defined(__sgi)
 		if ((fin->fin_hbuf != NULL) &&
 		    (mtod(fin->fin_m, struct ip *) != fin->fin_ip)) {
-			COPYBACK(m, 0, fin->fin_plen, fin->fin_hbuf);
+			COPYBACK(fin->fin_m, 0, fin->fin_plen, fin->fin_hbuf);
 		}
 #endif
 	}
 
+	SPL_X(s);
 	RWLOCK_EXIT(&ipf_global);
+
 #ifdef _KERNEL
-# if OpenBSD >= 200311    
+# if defined(OpenBSD) && OpenBSD >= 200311    
 	if (FR_ISPASS(pass) && (v == 4)) {
 		ip = fin->fin_ip;
 		ip->ip_len = ntohs(ip->ip_len);
@@ -2637,6 +2915,7 @@
 /*              ip(I)      - pointer to IP header                           */
 /*              l4proto(I) - protocol to caclulate checksum for             */
 /*              l4hdr(I)   - pointer to layer 4 header                      */
+/*              l3len(I)   - length of layer 4 data plus layer 3 header     */
 /*                                                                          */
 /* Calculates the TCP checksum for the packet held in "m", using the data   */
 /* in the IP header "ip" to seed it.                                        */
@@ -2645,12 +2924,14 @@
 /* and the TCP header.  We also assume that data blocks aren't allocated in */
 /* odd sizes.                                                               */
 /*                                                                          */
+/* For IPv6, l3len excludes extension header size.                          */
+/*                                                                          */
 /* Expects ip_len to be in host byte order when called.                     */
 /* ------------------------------------------------------------------------ */
-u_short fr_cksum(m, ip, l4proto, l4hdr)
+u_short fr_cksum(m, ip, l4proto, l4hdr, l3len)
 mb_t *m;
 ip_t *ip;
-int l4proto;
+int l4proto, l3len;
 void *l4hdr;
 {
 	u_short *sp, slen, sumsave, l4hlen, *csump;
@@ -2675,7 +2956,7 @@
 	if (IP_V(ip) == 4) {
 #endif
 		hlen = IP_HL(ip) << 2;
-		slen = ip->ip_len - hlen;
+		slen = l3len - hlen;
 		sum = htons((u_short)l4proto);
 		sum += htons(slen);
 		sp = (u_short *)&ip->ip_src;
@@ -2687,7 +2968,7 @@
 	} else if (IP_V(ip) == 6) {
 		ip6 = (ip6_t *)ip;
 		hlen = sizeof(*ip6);
-		slen = ntohs(ip6->ip6_plen);
+		slen = l3len - hlen;
 		sum = htons((u_short)l4proto);
 		sum += htons(slen);
 		sp = (u_short *)&ip6->ip6_src;
@@ -2819,8 +3100,8 @@
 	 * In case we had to copy the IP & TCP header out of mbufs,
 	 * skip over the mbuf bits which are the header
 	 */
-	if ((caddr_t)ip != mtod(m, caddr_t)) {
-		hlen = (caddr_t)sp - (caddr_t)ip;
+	if ((char *)ip != mtod(m, char *)) {
+		hlen = (char *)sp - (char *)ip;
 		while (hlen) {
 			add = MIN(hlen, m->m_len);
 			sp = (u_short *)(mtod(m, caddr_t) + add);
@@ -2843,12 +3124,12 @@
 		goto nodata;
 
 	while (len > 1) {
-		if (((caddr_t)sp - mtod(m, caddr_t)) >= m->m_len) {
+		if (((char *)sp - mtod(m, char *)) >= m->m_len) {
 			m = m->m_next;
 			PANIC((!m),("fr_cksum(2): not enough data"));
 			sp = mtod(m, u_short *);
 		}
-		if (((caddr_t)(sp + 1) - mtod(m, caddr_t)) > m->m_len) {
+		if (((char *)(sp + 1) - mtod(m, char *)) > m->m_len) {
 			bytes.c[0] = *(u_char *)sp;
 			m = m->m_next;
 			PANIC((!m),("fr_cksum(3): not enough data"));
@@ -2875,6 +3156,12 @@
 #  endif /*  defined(BSD) || defined(sun) */
 # endif /* MENTAT */
 #else /* _KERNEL */
+	/*
+	 * Add up IP Header portion
+	 */
+	if (sp != (u_short *)l4hdr)
+		sp = (u_short *)l4hdr;
+
 	for (; slen > 1; slen -= 2)
 	        sum += *sp++;
 	if (slen)
@@ -2890,7 +3177,7 @@
 
 
 #if defined(_KERNEL) && ( ((BSD < 199103) && !defined(MENTAT)) || \
-    defined(__sgi) ) && !defined(linux)
+    defined(__sgi) ) && !defined(linux) && !defined(_AIX51)
 /*
  * Copyright (c) 1982, 1986, 1988, 1991, 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -2920,7 +3207,7 @@
  * SUCH DAMAGE.
  *
  *	@(#)uipc_mbuf.c	8.2 (Berkeley) 1/4/94
- * Id: fil.c,v 2.243.2.57 2005/03/28 10:47:50 darrenr Exp
+ * $Id: fil.c,v 2.243.2.125 2007/10/10 09:27:20 darrenr Exp $
  */
 /*
  * Copy data from an mbuf chain starting "off" bytes from the beginning,
@@ -2989,7 +3276,7 @@
 		m = m->m_next;
 	}
 	while (len > 0) {
-		mlen = min (m->m_len - off, len);
+		mlen = min(m->m_len - off, len);
 		bcopy(cp, off + mtod(m, caddr_t), (unsigned)mlen);
 		cp += mlen;
 		len -= mlen;
@@ -3038,7 +3325,7 @@
 	frgroup_t *fg, **fgp;
 
 	/*
-	 * Which list of groups to search in is dependant on which list of
+	 * Which list of groups to search in is dependent on which list of
 	 * rules are being operated on.
 	 */
 	fgp = &ipfgroups[unit][set];
@@ -3226,7 +3513,7 @@
 int *nfreedp;
 frentry_t **listp;
 {
-	int freed = 0, i;
+	int freed = 0;
 	frentry_t *fp;
 
 	while ((fp = *listp) != NULL) {
@@ -3237,8 +3524,7 @@
 		}
 		*listp = fp->fr_next;
 		if (fp->fr_grp != NULL) {
-			i = frflushlist(set, unit, nfreedp, fp->fr_grp);
-			fp->fr_ref -= i;
+			(void) frflushlist(set, unit, nfreedp, fp->fr_grp);
 		}
 
 		if (fp->fr_grhead != NULL) {
@@ -3331,8 +3617,9 @@
 /* slen bytes.                                                              */
 /* ------------------------------------------------------------------------ */
 char *memstr(src, dst, slen, dlen)
-char *src, *dst;
-int slen, dlen;
+const char *src;
+char *dst;
+size_t slen, dlen;
 {
 	char *s = NULL;
 
@@ -3510,13 +3797,15 @@
 		if (fr->fr_type == FR_T_IPF && fr->fr_satype == FRI_LOOKUP &&
 		    fr->fr_srcptr == NULL) {
 			fr->fr_srcptr = fr_resolvelookup(fr->fr_srctype,
-							 fr->fr_srcnum,
+							 fr->fr_srcsubtype,
+							 &fr->fr_slookup,
 							 &fr->fr_srcfunc);
 		}
 		if (fr->fr_type == FR_T_IPF && fr->fr_datype == FRI_LOOKUP &&
 		    fr->fr_dstptr == NULL) {
 			fr->fr_dstptr = fr_resolvelookup(fr->fr_dsttype,
-							 fr->fr_dstnum,
+							 fr->fr_dstsubtype,
+							 &fr->fr_dlookup,
 							 &fr->fr_dstfunc);
 		}
 #endif
@@ -3588,17 +3877,19 @@
 size_t size;
 {
 	caddr_t ca;
-	int err;
+	int error;
 
 # if SOLARIS
-	err = COPYIN(src, (caddr_t)&ca, sizeof(ca));
-	if (err != 0)
-		return err;
+	error = COPYIN(src, &ca, sizeof(ca));
+	if (error != 0)
+		return error;
 # else
 	bcopy(src, (caddr_t)&ca, sizeof(ca));
 # endif
-	err = COPYIN(ca, dst, size);
-	return err;
+	error = COPYIN(ca, dst, size);
+	if (error != 0)
+		error = EFAULT;
+	return error;
 }
 
 
@@ -3618,39 +3909,40 @@
 size_t size;
 {
 	caddr_t ca;
-	int err;
+	int error;
 
-# if SOLARIS
-	err = COPYIN(dst, (caddr_t)&ca, sizeof(ca));
-	if (err != 0)
-		return err;
-# else
 	bcopy(dst, (caddr_t)&ca, sizeof(ca));
-# endif
-	err = COPYOUT(src, ca, size);
-	return err;
+	error = COPYOUT(src, ca, size);
+	if (error != 0)
+		error = EFAULT;
+	return error;
 }
 #endif
 
 
 /* ------------------------------------------------------------------------ */
 /* Function:    fr_lock                                                     */
-/* Returns:     (void)                                                      */
+/* Returns:     int      - 0 = success, else error                          */
 /* Parameters:  data(I)  - pointer to lock value to set                     */
 /*              lockp(O) - pointer to location to store old lock value      */
 /*                                                                          */
 /* Get the new value for the lock integer, set it and return the old value  */
 /* in *lockp.                                                               */
 /* ------------------------------------------------------------------------ */
-void fr_lock(data, lockp)
+int fr_lock(data, lockp)
 caddr_t data;
 int *lockp;
 {
-	int arg;
+	int arg, err;
 
-	BCOPYIN(data, (caddr_t)&arg, sizeof(arg));
-	BCOPYOUT((caddr_t)lockp, data, sizeof(*lockp));
+	err = BCOPYIN(data, &arg, sizeof(arg));
+	if (err != 0)
+		return EFAULT;
+	err = BCOPYOUT(lockp, data, sizeof(*lockp));
+	if (err != 0)
+		return EFAULT;
 	*lockp = arg;
+	return 0;
 }
 
 
@@ -3804,7 +4096,8 @@
 /* Function:    fr_resolvelookup                                            */
 /* Returns:     void * - NULL = failure, else success.                      */
 /* Parameters:  type(I)     - type of lookup these parameters are for.      */
-/*              number(I)   - table number to use when searching            */
+/*              subtype(I)  - whether the info below contains number/name   */
+/*              info(I)     - pointer to name/number of the lookup data     */
 /*              funcptr(IO) - pointer to pointer for storing IP address     */
 /*                           searching function.                            */
 /*                                                                          */
@@ -3813,20 +4106,35 @@
 /* call to do the IP address search will be change, regardless of whether   */
 /* or not the "table" number exists.                                        */
 /* ------------------------------------------------------------------------ */
-static void *fr_resolvelookup(type, number, funcptr)
-u_int type, number;
+static void *fr_resolvelookup(type, subtype, info, funcptr)
+u_int type, subtype;
+i6addr_t *info;
 lookupfunc_t *funcptr;
 {
-	char name[FR_GROUPLEN];
+	char label[FR_GROUPLEN], *name;
 	iphtable_t *iph;
 	ip_pool_t *ipo;
 	void *ptr;
 
+	if (subtype == 0) {
 #if defined(SNPRINTF) && defined(_KERNEL)
-	SNPRINTF(name, sizeof(name), "%u", number);
+		SNPRINTF(label, sizeof(label), "%u", info->iplookupnum);
 #else
-	(void) sprintf(name, "%u", number);
+		(void) sprintf(label, "%u", info->iplookupnum);
 #endif
+		name = label;
+	} else if (subtype == 1) {
+		/*
+		 * Because iplookupname is currently only a 12 character
+		 * string and FR_GROUPLEN is 16, copy all of it into the
+		 * label buffer and add on a NULL at the end.
+		 */
+		strncpy(label, info->iplookupname, sizeof(info->iplookupname));
+		label[sizeof(info->iplookupname)] = '\0';
+		name = label;
+	} else {
+		return NULL;
+	}
 
 	READ_ENTER(&ip_poolrw);
 
@@ -3998,16 +4306,6 @@
 		fprev = &fg->fg_start;
 	}
 
-	ftail = fprev;
-	for (f = *ftail; (f = *ftail) != NULL; ftail = &f->fr_next) {
-		if (fp->fr_collect <= f->fr_collect) {
-			ftail = fprev;
-			f = NULL;
-			break;
-		}
-		fprev = ftail;
-	}
-
 	/*
 	 * Copy in extra data for the rule.
 	 */
@@ -4017,6 +4315,8 @@
 			if (!ptr)
 				return ENOMEM;
 			error = COPYIN(uptr, ptr, fp->fr_dsize);
+			if (error != 0)
+				error = EFAULT;
 		} else {
 			ptr = uptr;
 			error = 0;
@@ -4075,8 +4375,11 @@
 #ifdef	IPFILTER_LOOKUP
 		case FRI_LOOKUP :
 			fp->fr_srcptr = fr_resolvelookup(fp->fr_srctype,
-							 fp->fr_srcnum,
+							 fp->fr_srcsubtype,
+							 &fp->fr_slookup,
 							 &fp->fr_srcfunc);
+			if (fp->fr_srcptr == NULL)
+				return ESRCH;
 			break;
 #endif
 		default :
@@ -4100,12 +4403,14 @@
 #ifdef	IPFILTER_LOOKUP
 		case FRI_LOOKUP :
 			fp->fr_dstptr = fr_resolvelookup(fp->fr_dsttype,
-							 fp->fr_dstnum,
+							 fp->fr_dstsubtype,
+							 &fp->fr_dlookup,
 							 &fp->fr_dstfunc);
+			if (fp->fr_dstptr == NULL)
+				return ESRCH;
 			break;
 #endif
 		default :
-			
 			break;
 		}
 		break;
@@ -4143,10 +4448,24 @@
 		fp->fr_cksum += *p;
 
 	WRITE_ENTER(&ipf_mutex);
-	bzero((char *)frcache, sizeof(frcache));
 
-	for (; (f = *ftail) != NULL; ftail = &f->fr_next) {
-		if ((fp->fr_cksum != f->fr_cksum) ||
+	/*
+	 * Now that the filter rule lists are locked, we can walk the
+	 * chain of them without fear.
+	 */
+	ftail = fprev;
+	for (f = *ftail; (f = *ftail) != NULL; ftail = &f->fr_next) {
+		if (fp->fr_collect <= f->fr_collect) {
+			ftail = fprev;
+			f = NULL;
+			break;
+		}
+		fprev = ftail;
+	}
+	bzero((char *)frcache, sizeof(frcache));
+
+	for (; (f = *ftail) != NULL; ftail = &f->fr_next) {
+		if ((fp->fr_cksum != f->fr_cksum) ||
 		    (f->fr_dsize != fp->fr_dsize))
 			continue;
 		if (bcmp((char *)&f->fr_func, (char *)&fp->fr_func, FR_CMPSIZ))
@@ -4186,6 +4505,8 @@
 				if ((f->fr_dsize != 0) && (uptr != NULL))
 					error = COPYOUT(f->fr_data, uptr,
 							f->fr_dsize);
+					if (error != 0)
+						error = EFAULT;
 				if (error == 0) {
 					f->fr_hits = 0;
 					f->fr_bytes = 0;
@@ -4260,7 +4581,7 @@
 
 			/*
 			 * Return EBUSY if the rule is being reference by
-			 * something else (eg state information.
+			 * something else (eg state information.)
 			 */
 			if (f->fr_ref > 1) {
 				error = EBUSY;
@@ -4271,8 +4592,6 @@
 			    (f->fr_isc != (struct ipscan *)-1))
 				ipsc_detachfr(f);
 #endif
-			if ((fg != NULL) && (fg->fg_head != NULL))
-				fg->fg_head->fr_ref--;
 			if (unit == IPL_LOGAUTH) {
 				error = fr_preauthcmd(req, f, ftail);
 				goto done;
@@ -4282,7 +4601,7 @@
 			fr_fixskip(ftail, f, -1);
 			*ftail = f->fr_next;
 			f->fr_next = NULL;
-			(void)fr_derefrule(&f);
+			(void) fr_derefrule(&f);
 		}
 	} else {
 		/*
@@ -4300,8 +4619,6 @@
 			} else
 				f = fp;
 			if (f != NULL) {
-				if (fg != NULL && fg->fg_head!= NULL )
-					fg->fg_head->fr_ref++;
 				if (fp != f)
 					bcopy((char *)fp, (char *)f,
 					      sizeof(*f));
@@ -4401,8 +4718,11 @@
 void *data;
 {
 	ipfunc_resolve_t res, *ft;
+	int err;
 
-	BCOPYIN(data, &res, sizeof(res));
+	err = BCOPYIN(data, &res, sizeof(res));
+	if (err != 0)
+		return EFAULT;
 
 	if (res.ipfu_addr == NULL && res.ipfu_name[0] != '\0') {
 		for (ft = fr_availfuncs; ft->ipfu_addr != NULL; ft++)
@@ -4431,7 +4751,7 @@
 
 
 #if !defined(_KERNEL) || (!defined(__NetBSD__) && !defined(__OpenBSD__) && !defined(__FreeBSD__)) || \
-    (defined(__FreeBSD__) && (__FreeBSD_version < 490000)) || \
+    (defined(__FreeBSD__) && (__FreeBSD_version < 501000)) || \
     (defined(__NetBSD__) && (__NetBSD_Version__ < 105000000)) || \
     (defined(__OpenBSD__) && (OpenBSD < 200006))
 /*
@@ -4496,6 +4816,7 @@
 	frentry_t *fr;
 
 	fr = *frp;
+	*frp = NULL;
 
 	MUTEX_ENTER(&fr->fr_lock);
 	fr->fr_ref--;
@@ -4521,7 +4842,6 @@
 	} else {
 		MUTEX_EXIT(&fr->fr_lock);
 	}
-	*frp = NULL;
 	return -1;
 }
 
@@ -4747,7 +5067,7 @@
 		ifq->ifq_next->ifq_pnext = ifq->ifq_pnext;
 
 	MUTEX_DESTROY(&ifq->ifq_lock);
-	fr_userifqs--;
+	ATOMIC_DEC(fr_userifqs);
 	KFREE(ifq);
 }
 
@@ -4769,8 +5089,6 @@
 	ipftq_t *ifq;
 
 	ifq = tqe->tqe_ifq;
-	if (ifq == NULL)
-		return;
 
 	MUTEX_ENTER(&ifq->ifq_lock);
 
@@ -4842,24 +5160,21 @@
 	tqe->tqe_die = fr_ticks + ifq->ifq_ttl;
 
 	MUTEX_ENTER(&ifq->ifq_lock);
-	if (tqe->tqe_next == NULL) {		/* at the end already ? */
-		MUTEX_EXIT(&ifq->ifq_lock);
-		return;
-	}
-
-	/*
-	 * Remove from list
-	 */
-	*tqe->tqe_pnext = tqe->tqe_next;
-	tqe->tqe_next->tqe_pnext = tqe->tqe_pnext;
+	if (tqe->tqe_next != NULL) {		/* at the end already ? */
+		/*
+		 * Remove from list
+		 */
+		*tqe->tqe_pnext = tqe->tqe_next;
+		tqe->tqe_next->tqe_pnext = tqe->tqe_pnext;
 
-	/*
-	 * Make it the last entry.
-	 */
-	tqe->tqe_next = NULL;
-	tqe->tqe_pnext = ifq->ifq_tail;
-	*ifq->ifq_tail = tqe;
-	ifq->ifq_tail = &tqe->tqe_next;
+		/*
+		 * Make it the last entry.
+		 */
+		tqe->tqe_next = NULL;
+		tqe->tqe_pnext = ifq->ifq_tail;
+		*ifq->ifq_tail = tqe;
+		ifq->ifq_tail = &tqe->tqe_next;
+	}
 	MUTEX_EXIT(&ifq->ifq_lock);
 }
 
@@ -4911,46 +5226,44 @@
 	 * Is the operation here going to be a no-op ?
 	 */
 	MUTEX_ENTER(&oifq->ifq_lock);
-	if (oifq == nifq && *oifq->ifq_tail == tqe) {
-		MUTEX_EXIT(&oifq->ifq_lock);
-		return;
-	}
+	if ((oifq != nifq) || (*oifq->ifq_tail != tqe)) {
+		/*
+		 * Remove from the old queue
+		 */
+		*tqe->tqe_pnext = tqe->tqe_next;
+		if (tqe->tqe_next)
+			tqe->tqe_next->tqe_pnext = tqe->tqe_pnext;
+		else
+			oifq->ifq_tail = tqe->tqe_pnext;
+		tqe->tqe_next = NULL;
 
-	/*
-	 * Remove from the old queue
-	 */
-	*tqe->tqe_pnext = tqe->tqe_next;
-	if (tqe->tqe_next)
-		tqe->tqe_next->tqe_pnext = tqe->tqe_pnext;
-	else
-		oifq->ifq_tail = tqe->tqe_pnext;
-	tqe->tqe_next = NULL;
+		/*
+		 * If we're moving from one queue to another, release the
+		 * lock on the old queue and get a lock on the new queue.
+		 * For user defined queues, if we're moving off it, call
+		 * delete in case it can now be freed.
+		 */
+		if (oifq != nifq) {
+			tqe->tqe_ifq = NULL;
 
-	/*
-	 * If we're moving from one queue to another, release the lock on the
-	 * old queue and get a lock on the new queue.  For user defined queues,
-	 * if we're moving off it, call delete in case it can now be freed.
-	 */
-	if (oifq != nifq) {
-		tqe->tqe_ifq = NULL;
+			(void) fr_deletetimeoutqueue(oifq);
 
-		(void) fr_deletetimeoutqueue(oifq);
+			MUTEX_EXIT(&oifq->ifq_lock);
 
-		MUTEX_EXIT(&oifq->ifq_lock);
+			MUTEX_ENTER(&nifq->ifq_lock);
 
-		MUTEX_ENTER(&nifq->ifq_lock);
+			tqe->tqe_ifq = nifq;
+			nifq->ifq_ref++;
+		}
 
-		tqe->tqe_ifq = nifq;
-		nifq->ifq_ref++;
+		/*
+		 * Add to the bottom of the new queue
+		 */
+		tqe->tqe_die = fr_ticks + nifq->ifq_ttl;
+		tqe->tqe_pnext = nifq->ifq_tail;
+		*nifq->ifq_tail = tqe;
+		nifq->ifq_tail = &tqe->tqe_next;
 	}
-
-	/*
-	 * Add to the bottom of the new queue
-	 */
-	tqe->tqe_die = fr_ticks + nifq->ifq_ttl;
-	tqe->tqe_pnext = nifq->ifq_tail;
-	*nifq->ifq_tail = tqe;
-	nifq->ifq_tail = &tqe->tqe_next;
 	MUTEX_EXIT(&nifq->ifq_lock);
 }
 
@@ -4967,7 +5280,7 @@
 /* the fragment cache for non-leading fragments.  If a non-leading fragment */
 /* has no match in the cache, return an error.                              */
 /* ------------------------------------------------------------------------ */
-static INLINE int fr_updateipid(fin)
+static int fr_updateipid(fin)
 fr_info_t *fin;
 {
 	u_short id, ido, sums;
@@ -5019,7 +5332,7 @@
 {
 	static char namebuf[LIFNAMSIZ];
 # if defined(MENTAT) || defined(__FreeBSD__) || defined(__osf__) || \
-     defined(__sgi) || defined(linux) || \
+     defined(__sgi) || defined(linux) || defined(_AIX51) || \
      (defined(sun) && !defined(__SVR4) && !defined(__svr4__))
 	int unit, space;
 	char temp[20];
@@ -5031,7 +5344,7 @@
 	(void) strncpy(buffer, ifp->if_name, LIFNAMSIZ);
 	buffer[LIFNAMSIZ - 1] = '\0';
 # if defined(MENTAT) || defined(__FreeBSD__) || defined(__osf__) || \
-     defined(__sgi) || \
+     defined(__sgi) || defined(_AIX51) || \
      (defined(sun) && !defined(__SVR4) && !defined(__svr4__))
 	for (s = buffer; *s; s++)
 		;
@@ -5058,55 +5371,47 @@
 /*              data(I) - pointer to ioctl data                             */
 /*              cmd(I)  - ioctl command                                     */
 /*              mode(I) - mode value                                        */
+/*              uid(I)  - uid making the ioctl call                         */
+/*              ctx(I)  - pointer to context data                           */
 /*                                                                          */
 /* Based on the value of unit, call the appropriate ioctl handler or return */
 /* EIO if ipfilter is not running.   Also checks if write perms are req'd   */
 /* for the device in order to execute the ioctl.                            */
 /* ------------------------------------------------------------------------ */
-int fr_ioctlswitch(unit, data, cmd, mode)
-int unit, mode;
+int fr_ioctlswitch(unit, data, cmd, mode, uid, ctx)
+int unit, mode, uid;
 ioctlcmd_t cmd;
-void *data;
+void *data, *ctx;
 {
 	int error = 0;
 
 	switch (unit)
 	{
 	case IPL_LOGIPF :
-		error = -1;
+		error = fr_ipf_ioctl(data, cmd, mode, uid, ctx);
 		break;
 	case IPL_LOGNAT :
 		if (fr_running > 0)
-			error = fr_nat_ioctl(data, cmd, mode);
+			error = fr_nat_ioctl(data, cmd, mode, uid, ctx);
 		else
 			error = EIO;
 		break;
 	case IPL_LOGSTATE :
 		if (fr_running > 0)
-			error = fr_state_ioctl(data, cmd, mode);
+			error = fr_state_ioctl(data, cmd, mode, uid, ctx);
 		else
 			error = EIO;
 		break;
 	case IPL_LOGAUTH :
-		if (fr_running > 0) {
-			if ((cmd == (ioctlcmd_t)SIOCADAFR) ||
-			    (cmd == (ioctlcmd_t)SIOCRMAFR)) {
-				if (!(mode & FWRITE)) {
-					error = EPERM;
-				} else {
-					error = frrequest(unit, cmd, data,
-							  fr_active, 1);
-				}
-			} else {
-				error = fr_auth_ioctl(data, cmd, mode);
-			}
-		} else
+		if (fr_running > 0)
+			error = fr_auth_ioctl(data, cmd, mode, uid, ctx);
+		else
 			error = EIO;
 		break;
 	case IPL_LOGSYNC :
 #ifdef IPFILTER_SYNC
 		if (fr_running > 0)
-			error = fr_sync_ioctl(data, cmd, mode);
+			error = fr_sync_ioctl(data, cmd, mode, uid, ctx);
 		else
 #endif
 			error = EIO;
@@ -5114,7 +5419,7 @@
 	case IPL_LOGSCAN :
 #ifdef IPFILTER_SCAN
 		if (fr_running > 0)
-			error = fr_scan_ioctl(data, cmd, mode);
+			error = fr_scan_ioctl(data, cmd, mode, uid, ctx);
 		else
 #endif
 			error = EIO;
@@ -5122,7 +5427,7 @@
 	case IPL_LOGLOOKUP :
 #ifdef IPFILTER_LOOKUP
 		if (fr_running > 0)
-			error = ip_lookup_ioctl(data, cmd, mode);
+			error = ip_lookup_ioctl(data, cmd, mode, uid, ctx);
 		else
 #endif
 			error = EIO;
@@ -5140,9 +5445,7 @@
  * This array defines the expected size of objects coming into the kernel
  * for the various recognised object types.
  */
-#define	NUM_OBJ_TYPES	14
-
-static	int	fr_objbytes[NUM_OBJ_TYPES][2] = {
+static	int	fr_objbytes[IPFOBJ_COUNT][2] = {
 	{ 1,	sizeof(struct frentry) },		/* frentry */
 	{ 0,	sizeof(struct friostat) },
 	{ 0,	sizeof(struct fr_info) },
@@ -5156,7 +5459,13 @@
 	{ 1,	sizeof(struct ipstate) },		/* ipstate */
 	{ 0,	sizeof(struct ips_stat) },
 	{ 0,	sizeof(struct frauth) },
-	{ 0,	sizeof(struct ipftune) }
+	{ 0,	sizeof(struct ipftune) },
+	{ 0,	sizeof(struct nat) },			/* nat_t */
+	{ 0,	sizeof(struct ipfruleiter) },
+	{ 0,	sizeof(struct ipfgeniter) },
+	{ 0,	sizeof(struct ipftable) },
+	{ 0,	sizeof(struct ipflookupiter) },
+	{ 0,	sizeof(struct ipftq) * IPF_TCP_NSTATES },
 };
 
 
@@ -5179,10 +5488,12 @@
 	ipfobj_t obj;
 	int error = 0;
 
-	if ((type < 0) || (type > NUM_OBJ_TYPES-1))
+	if ((type < 0) || (type >= IPFOBJ_COUNT))
 		return EINVAL;
 
-	BCOPYIN((caddr_t)data, (caddr_t)&obj, sizeof(obj));
+	error = BCOPYIN(data, &obj, sizeof(obj));
+	if (error != 0)
+		return EFAULT;
 
 	if (obj.ipfo_type != type)
 		return EINVAL;
@@ -5191,8 +5502,9 @@
 	if ((fr_objbytes[type][0] & 1) != 0) {
 		if (obj.ipfo_size < fr_objbytes[type][1])
 			return EINVAL;
-	} else if (obj.ipfo_size != fr_objbytes[type][1])
+	} else if (obj.ipfo_size != fr_objbytes[type][1]) {
 		return EINVAL;
+	}
 #else
 	if (obj.ipfo_rev != IPFILTER_VERSION)
 		/* XXX compatibility hook here */
@@ -5207,12 +5519,12 @@
 #endif
 
 	if ((fr_objbytes[type][0] & 1) != 0) {
-		error = COPYIN((caddr_t)obj.ipfo_ptr, (caddr_t)ptr,
-				fr_objbytes[type][1]);
+		error = COPYIN(obj.ipfo_ptr, ptr, fr_objbytes[type][1]);
 	} else {
-		error = COPYIN((caddr_t)obj.ipfo_ptr, (caddr_t)ptr,
-				obj.ipfo_size);
+		error = COPYIN(obj.ipfo_ptr, ptr, obj.ipfo_size);
 	}
+	if (error != 0)
+		error = EFAULT;
 	return error;
 }
 
@@ -5239,12 +5551,14 @@
 	ipfobj_t obj;
 	int error;
 
-	if ((type < 0) || (type > NUM_OBJ_TYPES-1))
+	if ((type < 0) || (type >= IPFOBJ_COUNT))
 		return EINVAL;
 	if (((fr_objbytes[type][0] & 1) == 0) || (sz < fr_objbytes[type][1]))
 		return EINVAL;
 
-	BCOPYIN((caddr_t)data, (caddr_t)&obj, sizeof(obj));
+	error = BCOPYIN(data, &obj, sizeof(obj));
+	if (error != 0)
+		return EFAULT;
 
 	if (obj.ipfo_type != type)
 		return EINVAL;
@@ -5261,7 +5575,9 @@
 		return EINVAL;
 #endif
 
-	error = COPYIN((caddr_t)obj.ipfo_ptr, (caddr_t)ptr, sz);
+	error = COPYIN(obj.ipfo_ptr, ptr, sz);
+	if (error != 0)
+		error = EFAULT;
 	return error;
 }
 
@@ -5288,12 +5604,14 @@
 	ipfobj_t obj;
 	int error;
 
-	if ((type < 0) || (type > NUM_OBJ_TYPES-1) ||
+	if ((type < 0) || (type >= IPFOBJ_COUNT) ||
 	    ((fr_objbytes[type][0] & 1) == 0) ||
 	    (sz < fr_objbytes[type][1]))
 		return EINVAL;
 
-	BCOPYIN((caddr_t)data, (caddr_t)&obj, sizeof(obj));
+	error = BCOPYIN(data, &obj, sizeof(obj));
+	if (error != 0)
+		return EFAULT;
 
 	if (obj.ipfo_type != type)
 		return EINVAL;
@@ -5310,7 +5628,9 @@
 		return EINVAL;
 #endif
 
-	error = COPYOUT((caddr_t)ptr, (caddr_t)obj.ipfo_ptr, sz);
+	error = COPYOUT(ptr, obj.ipfo_ptr, sz);
+	if (error != 0)
+		error = EFAULT;
 	return error;
 }
 
@@ -5334,10 +5654,12 @@
 	ipfobj_t obj;
 	int error;
 
-	if ((type < 0) || (type > NUM_OBJ_TYPES-1))
+	if ((type < 0) || (type >= IPFOBJ_COUNT))
 		return EINVAL;
 
-	BCOPYIN((caddr_t)data, (caddr_t)&obj, sizeof(obj));
+	error = BCOPYIN(data, &obj, sizeof(obj));
+	if (error != 0)
+		return EFAULT;
 
 	if (obj.ipfo_type != type)
 		return EINVAL;
@@ -5361,7 +5683,9 @@
 		return EINVAL;
 #endif
 
-	error = COPYOUT((caddr_t)ptr, (caddr_t)obj.ipfo_ptr, obj.ipfo_size);
+	error = COPYOUT(ptr, obj.ipfo_ptr, obj.ipfo_size);
+	if (error != 0)
+		error = EFAULT;
 	return error;
 }
 
@@ -5385,6 +5709,12 @@
 	if ((fin->fin_flx & FI_NOCKSUM) != 0)
 		return 0;
 
+	if (fin->fin_cksum == 1)
+		return 0;
+
+	if (fin->fin_cksum == -1)
+		return -1;
+
 	/*
 	 * If the TCP packet isn't a fragment, isn't too short and otherwise
 	 * isn't already considered "bad", then validate the checksum.  If
@@ -5432,9 +5762,11 @@
 		if (csump != NULL)
 			hdrsum = *csump;
 
-		if (dosum)
+		if (dosum) {
 			sum = fr_cksum(fin->fin_m, fin->fin_ip,
-				       fin->fin_p, fin->fin_dp);
+				       fin->fin_p, fin->fin_dp,
+				       fin->fin_dlen + fin->fin_hlen);
+		}
 #if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) && defined(ICK_VALID)
 	}
 #endif
@@ -5445,8 +5777,11 @@
 		FR_DEBUG(("checkl4sum: %hx != %hx\n", sum, hdrsum));
 	}
 #endif
-	if (hdrsum == sum)
+	if (hdrsum == sum) {
+		fin->fin_cksum = 1;
 		return 0;
+	}
+	fin->fin_cksum = -1;
 	return -1;
 }
 
@@ -5635,96 +5970,104 @@
 ipftuneable_t ipf_tuneables[] = {
 	/* filtering */
 	{ { &fr_flags },	"fr_flags",		0,	0xffffffff,
-			sizeof(fr_flags),		0 },
+		sizeof(fr_flags),		0,	NULL },
 	{ { &fr_active },	"fr_active",		0,	0,
-			sizeof(fr_active),		IPFT_RDONLY },
+		sizeof(fr_active),		IPFT_RDONLY,	NULL },
 	{ { &fr_control_forwarding },	"fr_control_forwarding",	0, 1,
-			sizeof(fr_control_forwarding),	0 },
+		sizeof(fr_control_forwarding),	0,	NULL },
 	{ { &fr_update_ipid },	"fr_update_ipid",	0,	1,
-			sizeof(fr_update_ipid),		0 },
+		sizeof(fr_update_ipid),		0,	NULL },
 	{ { &fr_chksrc },	"fr_chksrc",		0,	1,
-			sizeof(fr_chksrc),		0 },
+		sizeof(fr_chksrc),		0,	NULL },
+	{ { &fr_minttl },	"fr_minttl",		0,	1,
+		sizeof(fr_minttl),		0,	NULL },
+	{ { &fr_icmpminfragmtu }, "fr_icmpminfragmtu",	0,	1,
+		sizeof(fr_icmpminfragmtu),	0,	NULL },
 	{ { &fr_pass },		"fr_pass",		0,	0xffffffff,
-			sizeof(fr_pass),		0 },
+		sizeof(fr_pass),		0,	NULL },
 	/* state */
 	{ { &fr_tcpidletimeout }, "fr_tcpidletimeout",	1,	0x7fffffff,
-			sizeof(fr_tcpidletimeout),	IPFT_WRDISABLED },
+		sizeof(fr_tcpidletimeout),	IPFT_WRDISABLED,	NULL },
 	{ { &fr_tcpclosewait },	"fr_tcpclosewait",	1,	0x7fffffff,
-			sizeof(fr_tcpclosewait),	IPFT_WRDISABLED },
+		sizeof(fr_tcpclosewait),	IPFT_WRDISABLED,	NULL },
 	{ { &fr_tcplastack },	"fr_tcplastack",	1,	0x7fffffff,
-			sizeof(fr_tcplastack),		IPFT_WRDISABLED },
+		sizeof(fr_tcplastack),		IPFT_WRDISABLED,	NULL },
 	{ { &fr_tcptimeout },	"fr_tcptimeout",	1,	0x7fffffff,
-			sizeof(fr_tcptimeout),		IPFT_WRDISABLED },
+		sizeof(fr_tcptimeout),		IPFT_WRDISABLED,	NULL },
 	{ { &fr_tcpclosed },	"fr_tcpclosed",		1,	0x7fffffff,
-			sizeof(fr_tcpclosed),		IPFT_WRDISABLED },
+		sizeof(fr_tcpclosed),		IPFT_WRDISABLED,	NULL },
 	{ { &fr_tcphalfclosed }, "fr_tcphalfclosed",	1,	0x7fffffff,
-			sizeof(fr_tcphalfclosed),	IPFT_WRDISABLED },
+		sizeof(fr_tcphalfclosed),	IPFT_WRDISABLED,	NULL },
 	{ { &fr_udptimeout },	"fr_udptimeout",	1,	0x7fffffff,
-			sizeof(fr_udptimeout),		IPFT_WRDISABLED },
+		sizeof(fr_udptimeout),		IPFT_WRDISABLED,	NULL },
 	{ { &fr_udpacktimeout }, "fr_udpacktimeout",	1,	0x7fffffff,
-			sizeof(fr_udpacktimeout),	IPFT_WRDISABLED },
+		sizeof(fr_udpacktimeout),	IPFT_WRDISABLED,	NULL },
 	{ { &fr_icmptimeout },	"fr_icmptimeout",	1,	0x7fffffff,
-			sizeof(fr_icmptimeout),		IPFT_WRDISABLED },
+		sizeof(fr_icmptimeout),		IPFT_WRDISABLED,	NULL },
 	{ { &fr_icmpacktimeout }, "fr_icmpacktimeout",	1,	0x7fffffff,
-			sizeof(fr_icmpacktimeout),	IPFT_WRDISABLED },
+		sizeof(fr_icmpacktimeout),	IPFT_WRDISABLED,	NULL },
 	{ { &fr_iptimeout }, "fr_iptimeout",		1,	0x7fffffff,
-			sizeof(fr_iptimeout),		IPFT_WRDISABLED },
+		sizeof(fr_iptimeout),		IPFT_WRDISABLED,	NULL },
 	{ { &fr_statemax },	"fr_statemax",		1,	0x7fffffff,
-			sizeof(fr_statemax),		0 },
+		sizeof(fr_statemax),		0,	NULL },
 	{ { &fr_statesize },	"fr_statesize",		1,	0x7fffffff,
-			sizeof(fr_statesize),		IPFT_WRDISABLED },
+		sizeof(fr_statesize),		IPFT_WRDISABLED,	NULL },
 	{ { &fr_state_lock },	"fr_state_lock",	0,	1,
-			sizeof(fr_state_lock),		IPFT_RDONLY },
+		sizeof(fr_state_lock),		IPFT_RDONLY,	NULL },
 	{ { &fr_state_maxbucket }, "fr_state_maxbucket", 1,	0x7fffffff,
-			sizeof(fr_state_maxbucket),	IPFT_WRDISABLED },
+		sizeof(fr_state_maxbucket),	IPFT_WRDISABLED,	NULL },
 	{ { &fr_state_maxbucket_reset }, "fr_state_maxbucket_reset",	0, 1,
-			sizeof(fr_state_maxbucket_reset), IPFT_WRDISABLED },
+		sizeof(fr_state_maxbucket_reset), IPFT_WRDISABLED,	NULL },
 	{ { &ipstate_logging },	"ipstate_logging",	0,	1,
-			sizeof(ipstate_logging),	0 },
+		sizeof(ipstate_logging),	0,	NULL },
 	/* nat */
 	{ { &fr_nat_lock },		"fr_nat_lock",		0,	1,
-			sizeof(fr_nat_lock),		IPFT_RDONLY },
+		sizeof(fr_nat_lock),		IPFT_RDONLY,	NULL },
 	{ { &ipf_nattable_sz },	"ipf_nattable_sz",	1,	0x7fffffff,
-			sizeof(ipf_nattable_sz),	IPFT_WRDISABLED },
+		sizeof(ipf_nattable_sz),	IPFT_WRDISABLED,	NULL },
 	{ { &ipf_nattable_max }, "ipf_nattable_max",	1,	0x7fffffff,
-			sizeof(ipf_nattable_max),	0 },
+		sizeof(ipf_nattable_max),	0,	NULL },
 	{ { &ipf_natrules_sz },	"ipf_natrules_sz",	1,	0x7fffffff,
-			sizeof(ipf_natrules_sz),	IPFT_WRDISABLED },
+		sizeof(ipf_natrules_sz),	IPFT_WRDISABLED,	NULL },
 	{ { &ipf_rdrrules_sz },	"ipf_rdrrules_sz",	1,	0x7fffffff,
-			sizeof(ipf_rdrrules_sz),	IPFT_WRDISABLED },
+		sizeof(ipf_rdrrules_sz),	IPFT_WRDISABLED,	NULL },
 	{ { &ipf_hostmap_sz },	"ipf_hostmap_sz",	1,	0x7fffffff,
-			sizeof(ipf_hostmap_sz),		IPFT_WRDISABLED },
+		sizeof(ipf_hostmap_sz),		IPFT_WRDISABLED,	NULL },
 	{ { &fr_nat_maxbucket }, "fr_nat_maxbucket",	1,	0x7fffffff,
-			sizeof(fr_nat_maxbucket),	IPFT_WRDISABLED },
+		sizeof(fr_nat_maxbucket),	0,			NULL },
 	{ { &fr_nat_maxbucket_reset },	"fr_nat_maxbucket_reset",	0, 1,
-			sizeof(fr_nat_maxbucket_reset),	IPFT_WRDISABLED },
+		sizeof(fr_nat_maxbucket_reset),	IPFT_WRDISABLED,	NULL },
 	{ { &nat_logging },		"nat_logging",		0,	1,
-			sizeof(nat_logging),		0 },
+		sizeof(nat_logging),		0,	NULL },
 	{ { &fr_defnatage },	"fr_defnatage",		1,	0x7fffffff,
-			sizeof(fr_defnatage),		IPFT_WRDISABLED },
+		sizeof(fr_defnatage),		IPFT_WRDISABLED,	NULL },
 	{ { &fr_defnatipage },	"fr_defnatipage",	1,	0x7fffffff,
-			sizeof(fr_defnatipage),		IPFT_WRDISABLED },
+		sizeof(fr_defnatipage),		IPFT_WRDISABLED,	NULL },
 	{ { &fr_defnaticmpage }, "fr_defnaticmpage",	1,	0x7fffffff,
-			sizeof(fr_defnaticmpage),	IPFT_WRDISABLED },
+		sizeof(fr_defnaticmpage),	IPFT_WRDISABLED,	NULL },
+	{ { &fr_nat_doflush }, "fr_nat_doflush",	0,	1,
+		sizeof(fr_nat_doflush),		0,	NULL },
+	/* proxy */
+	{ { &ipf_proxy_debug }, "ipf_proxy_debug",	0,	10,
+		sizeof(ipf_proxy_debug),	0,	0 },
 	/* frag */
 	{ { &ipfr_size },	"ipfr_size",		1,	0x7fffffff,
-			sizeof(ipfr_size),		IPFT_WRDISABLED },
+		sizeof(ipfr_size),		IPFT_WRDISABLED,	NULL },
 	{ { &fr_ipfrttl },	"fr_ipfrttl",		1,	0x7fffffff,
-			sizeof(fr_ipfrttl),		IPFT_WRDISABLED },
+		sizeof(fr_ipfrttl),		IPFT_WRDISABLED,	NULL },
 #ifdef IPFILTER_LOG
 	/* log */
 	{ { &ipl_suppress },	"ipl_suppress",		0,	1,
-			sizeof(ipl_suppress),		0 },
-	{ { &ipl_buffer_sz },	"ipl_buffer_sz",	0,	0,
-			sizeof(ipl_buffer_sz),		IPFT_RDONLY },
+		sizeof(ipl_suppress),		0,	NULL },
 	{ { &ipl_logmax },	"ipl_logmax",		0,	0x7fffffff,
-			sizeof(ipl_logmax),		IPFT_WRDISABLED },
+		sizeof(ipl_logmax),		IPFT_WRDISABLED,	NULL },
 	{ { &ipl_logall },	"ipl_logall",		0,	1,
-			sizeof(ipl_logall),		0 },
+		sizeof(ipl_logall),		0,	NULL },
 	{ { &ipl_logsize },	"ipl_logsize",		0,	0x80000,
-			sizeof(ipl_logsize),		0 },
+		sizeof(ipl_logsize),		0,	NULL },
 #endif
-	{ { NULL },		NULL,			0,	0 }
+	{ { NULL },		NULL,			0,	0,
+		0,				0,	NULL }
 };
 
 static ipftuneable_t *ipf_tunelist = NULL;
@@ -5789,7 +6132,7 @@
 /* to the matching structure.                                               */
 /* ------------------------------------------------------------------------ */
 static ipftuneable_t *fr_findtunebyname(name)
-char *name;
+const char *name;
 {
 	ipftuneable_t *ta;
 
@@ -6035,6 +6378,8 @@
 {
 	int i;
 
+	bzero(&frstats, sizeof(frstats));
+
 #ifdef IPFILTER_LOG
 	i = fr_loginit();
 	if (i < 0)
@@ -6132,18 +6477,18 @@
 /* the copyout may result in paging (ie network activity.)                  */
 /* ------------------------------------------------------------------------ */
 int	fr_zerostats(data)
-caddr_t	data;
+void	*data;
 {
 	friostat_t fio;
 	int error;
 
 	fr_getstat(&fio);
-	error = copyoutptr(&fio, data, sizeof(fio));
+	error = fr_outobj(data, &fio, IPFOBJ_IPFSTAT);
 	if (error)
 		return EFAULT;
 
 	WRITE_ENTER(&ipf_mutex);
-	bzero((char *)frstats, sizeof(*frstats) * 2);
+	bzero(&frstats, sizeof(frstats));
 	RWLOCK_EXIT(&ipf_mutex);
 
 	return 0;
@@ -6181,31 +6526,6 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_icmp4errortype                                           */
-/* Returns:     int - 1 == success, 0 == failure                            */
-/* Parameters:  icmptype(I) - ICMP type number                              */
-/*                                                                          */
-/* Tests to see if the ICMP type number passed is an error type or not.     */
-/* ------------------------------------------------------------------------ */
-int fr_icmp4errortype(icmptype)
-int icmptype;
-{
-
-	switch (icmptype)
-	{
-	case ICMP_SOURCEQUENCH :
-	case ICMP_PARAMPROB :
-	case ICMP_REDIRECT :
-	case ICMP_TIMXCEED :
-	case ICMP_UNREACH :
-		return 1;
-	default:
-		return 0;
-	}
-}
-
-
-/* ------------------------------------------------------------------------ */
 /* Function:    fr_resolvenic                                               */
 /* Returns:     void* - NULL = wildcard name, -1 = failed to find NIC, else */
 /*                      pointer to interface structure for NIC              */
@@ -6247,3 +6567,792 @@
 		nic = (void *)-1;
 	return nic;
 }
+
+
+ipftoken_t *ipftokenhead = NULL, **ipftokentail = &ipftokenhead;
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_expiretokens                                            */
+/* Returns:     None.                                                       */
+/* Parameters:  None.                                                       */
+/*                                                                          */
+/* This function is run every ipf tick to see if there are any tokens that  */
+/* have been held for too long and need to be freed up.                     */
+/* ------------------------------------------------------------------------ */
+void ipf_expiretokens()
+{
+	ipftoken_t *it;
+
+	WRITE_ENTER(&ipf_tokens);
+	while ((it = ipftokenhead) != NULL) {
+		if (it->ipt_die > fr_ticks)
+			break;
+
+		ipf_freetoken(it);
+	}
+	RWLOCK_EXIT(&ipf_tokens);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_deltoken                                                */
+/* Returns:     int     - 0 = success, else error                           */
+/* Parameters:  type(I) - the token type to match                           */
+/*              uid(I)  - uid owning the token                              */
+/*              ptr(I)  - context pointer for the token                     */
+/*                                                                          */
+/* This function looks for a a token in the current list that matches up    */
+/* the fields (type, uid, ptr).  If none is found, ESRCH is returned, else  */
+/* call ipf_freetoken() to remove it from the list.                         */
+/* ------------------------------------------------------------------------ */
+int ipf_deltoken(type, uid, ptr)
+int type, uid;
+void *ptr;
+{
+	ipftoken_t *it;
+	int error = ESRCH;
+
+	WRITE_ENTER(&ipf_tokens);
+	for (it = ipftokenhead; it != NULL; it = it->ipt_next)
+		if (ptr == it->ipt_ctx && type == it->ipt_type &&
+		    uid == it->ipt_uid) {
+			ipf_freetoken(it);
+			error = 0;
+			break;
+	}
+	RWLOCK_EXIT(&ipf_tokens);
+
+	return error;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_findtoken                                               */
+/* Returns:     ipftoken_t * - NULL if no memory, else pointer to token     */
+/* Parameters:  type(I) - the token type to match                           */
+/*              uid(I)  - uid owning the token                              */
+/*              ptr(I)  - context pointer for the token                     */
+/*                                                                          */
+/* This function looks for a live token in the list of current tokens that  */
+/* matches the tuple (type, uid, ptr).  If one cannot be found then one is  */
+/* allocated.  If one is found then it is moved to the top of the list of   */
+/* currently active tokens.                                                 */
+/*                                                                          */
+/* NOTE: It is by design that this function returns holding a read lock on  */
+/*       ipf_tokens.  Callers must make sure they release it!               */
+/* ------------------------------------------------------------------------ */
+ipftoken_t *ipf_findtoken(type, uid, ptr)
+int type, uid;
+void *ptr;
+{
+	ipftoken_t *it, *new;
+
+	KMALLOC(new, ipftoken_t *);
+
+	WRITE_ENTER(&ipf_tokens);
+	for (it = ipftokenhead; it != NULL; it = it->ipt_next) {
+		if (it->ipt_alive == 0)
+			continue;
+		if (ptr == it->ipt_ctx && type == it->ipt_type &&
+		    uid == it->ipt_uid)
+			break;
+	}
+
+	if (it == NULL) {
+		it = new;
+		new = NULL;
+		if (it == NULL)
+			return NULL;
+		it->ipt_data = NULL;
+		it->ipt_ctx = ptr;
+		it->ipt_uid = uid;
+		it->ipt_type = type;
+		it->ipt_next = NULL;
+		it->ipt_alive = 1;
+	} else {
+		if (new != NULL) {
+			KFREE(new);
+			new = NULL;
+		}
+
+		ipf_unlinktoken(it);
+	}
+	it->ipt_pnext = ipftokentail;
+	*ipftokentail = it;
+	ipftokentail = &it->ipt_next;
+	it->ipt_next = NULL;
+
+	it->ipt_die = fr_ticks + 2;
+
+	MUTEX_DOWNGRADE(&ipf_tokens);
+
+	return it;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_unlinktoken                                             */
+/* Returns:     None.                                                       */
+/* Parameters:  token(I) - pointer to token structure                       */
+/*                                                                          */
+/* This function unlinks a token structure from the linked list of tokens   */
+/* that "own" it.  The head pointer never needs to be explicitly adjusted   */
+/* but the tail does due to the linked list implementation.                 */
+/* ------------------------------------------------------------------------ */
+static void ipf_unlinktoken(token)
+ipftoken_t *token;
+{
+
+	if (ipftokentail == &token->ipt_next)
+		ipftokentail = token->ipt_pnext;
+
+	*token->ipt_pnext = token->ipt_next;
+	if (token->ipt_next != NULL)
+		token->ipt_next->ipt_pnext = token->ipt_pnext;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_freetoken                                               */
+/* Returns:     None.                                                       */
+/* Parameters:  token(I) - pointer to token structure                       */
+/*                                                                          */
+/* This function unlinks a token from the linked list and on the path to    */
+/* free'ing the data, it calls the dereference function that is associated  */
+/* with the type of data pointed to by the token as it is considered to     */
+/* hold a reference to it.                                                  */
+/* ------------------------------------------------------------------------ */
+void ipf_freetoken(token)
+ipftoken_t *token;
+{
+	void *data, **datap;
+
+	ipf_unlinktoken(token);
+
+	data = token->ipt_data;
+	datap = &data;
+
+	if ((data != NULL) && (data != (void *)-1)) {
+		switch (token->ipt_type)
+		{
+		case IPFGENITER_IPF :
+			(void) fr_derefrule((frentry_t **)datap);
+			break;
+		case IPFGENITER_IPNAT :
+			WRITE_ENTER(&ipf_nat);
+			fr_ipnatderef((ipnat_t **)datap);
+			RWLOCK_EXIT(&ipf_nat);
+			break;
+		case IPFGENITER_NAT :
+			fr_natderef((nat_t **)datap);
+			break;
+		case IPFGENITER_STATE :
+			fr_statederef((ipstate_t **)datap);
+			break;
+		case IPFGENITER_FRAG :
+#ifdef USE_MUTEXES
+			fr_fragderef((ipfr_t **)datap, &ipf_frag);
+#else
+			fr_fragderef((ipfr_t **)datap);
+#endif
+			break;
+		case IPFGENITER_NATFRAG :
+#ifdef USE_MUTEXES
+			fr_fragderef((ipfr_t **)datap, &ipf_natfrag);
+#else
+			fr_fragderef((ipfr_t **)datap);
+#endif
+			break;
+		case IPFGENITER_HOSTMAP :
+			WRITE_ENTER(&ipf_nat);
+			fr_hostmapdel((hostmap_t **)datap);
+			RWLOCK_EXIT(&ipf_nat);
+			break;
+		default :
+#ifdef IPFILTER_LOOKUP
+			ip_lookup_iterderef(token->ipt_type, data);
+#endif
+			break;
+		}
+	}
+
+	KFREE(token);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_getnextrule                                             */
+/* Returns:     int - 0 = success, else error                               */
+/* Parameters:  t(I)   - pointer to destination information to resolve      */
+/*              ptr(I) - pointer to ipfobj_t to copyin from user space      */
+/*                                                                          */
+/* This function's first job is to bring in the ipfruleiter_t structure via */
+/* the ipfobj_t structure to determine what should be the next rule to      */
+/* return. Once the ipfruleiter_t has been brought in, it then tries to     */
+/* find the 'next rule'.  This may include searching rule group lists or    */
+/* just be as simple as looking at the 'next' field in the rule structure.  */
+/* When we have found the rule to return, increase its reference count and  */
+/* if we used an existing rule to get here, decrease its reference count.   */
+/* ------------------------------------------------------------------------ */
+int ipf_getnextrule(ipftoken_t *t, void *ptr)
+{
+	frentry_t *fr, *next, zero;
+	int error, count, out;
+	ipfruleiter_t it;
+	frgroup_t *fg;
+	char *dst;
+
+	if (t == NULL || ptr == NULL)
+		return EFAULT;
+	error = fr_inobj(ptr, &it, IPFOBJ_IPFITER);
+	if (error != 0)
+		return error;
+	if ((it.iri_inout < 0) || (it.iri_inout > 3))
+		return EINVAL;
+	if ((it.iri_active != 0) && (it.iri_active != 1))
+		return EINVAL;
+	if (it.iri_nrules == 0)
+		return ENOSPC;
+	if (it.iri_rule == NULL)
+		return EFAULT;
+
+	out = it.iri_inout & F_OUT;
+	fr = t->ipt_data;
+	READ_ENTER(&ipf_mutex);
+	if (fr == NULL) {
+		if (*it.iri_group == '\0') {
+			if ((it.iri_inout & F_ACIN) != 0) {
+				if (it.iri_v == 4)
+					next = ipacct[out][it.iri_active];
+				else
+					next = ipacct6[out][it.iri_active];
+			} else {
+				if (it.iri_v == 4)
+					next = ipfilter[out][it.iri_active];
+				else
+					next = ipfilter6[out][it.iri_active];
+			}
+		} else {
+			fg = fr_findgroup(it.iri_group, IPL_LOGIPF,
+					  it.iri_active, NULL);
+			if (fg != NULL)
+				next = fg->fg_start;
+			else
+				next = NULL;
+		}
+	} else {
+		next = fr->fr_next;
+	}
+
+	dst = (char *)it.iri_rule;
+	count = it.iri_nrules;
+	/*
+	 * The ipfruleiter may ask for more than 1 rule at a time to be
+	 * copied out, so long as that many exist in the list to start with!
+	 */
+	for (;;) {
+		if (next != NULL) {
+			if (count == 1) {
+				MUTEX_ENTER(&next->fr_lock);
+				next->fr_ref++;
+				MUTEX_EXIT(&next->fr_lock);
+				t->ipt_data = next;
+			}
+		} else {
+			bzero(&zero, sizeof(zero));
+			next = &zero;
+			count = 1;
+			t->ipt_data = NULL;
+		}
+		RWLOCK_EXIT(&ipf_mutex);
+
+		error = COPYOUT(next, dst, sizeof(*next));
+		if (error != 0)
+			return EFAULT;
+
+		if (next->fr_data != NULL) {
+			dst += sizeof(*next);
+			error = COPYOUT(next->fr_data, dst, next->fr_dsize);
+			if (error != 0)
+				error = EFAULT;
+			else
+				dst += next->fr_dsize;
+		}
+
+		if ((count == 1) || (error != 0))
+			break;
+
+		count--;
+
+		READ_ENTER(&ipf_mutex);
+		next = next->fr_next;
+	}
+
+	if (fr != NULL) {
+		(void) fr_derefrule(&fr);
+	}
+
+	return error;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    fr_frruleiter                                               */
+/* Returns:     int - 0 = success, else error                               */
+/* Parameters:  data(I) - the token type to match                           */
+/*              uid(I)  - uid owning the token                              */
+/*              ptr(I)  - context pointer for the token                     */
+/*                                                                          */
+/* This function serves as a stepping stone between fr_ipf_ioctl and        */
+/* ipf_getnextrule.  It's role is to find the right token in the kernel for */
+/* the process doing the ioctl and use that to ask for the next rule.       */
+/* ------------------------------------------------------------------------ */
+static int ipf_frruleiter(data, uid, ctx)
+void *data, *ctx;
+int uid;
+{
+	ipftoken_t *token;
+	int error;
+
+	token = ipf_findtoken(IPFGENITER_IPF, uid, ctx);
+	if (token != NULL)
+		error = ipf_getnextrule(token, data);
+	else
+		error = EFAULT;
+	RWLOCK_EXIT(&ipf_tokens);
+
+	return error;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    fr_geniter                                                  */
+/* Returns:     int - 0 = success, else error                               */
+/* Parameters:  token(I) - pointer to ipftoken_t structure                  */
+/*              itp(I)   -                                                  */
+/*                                                                          */
+/* ------------------------------------------------------------------------ */
+static int ipf_geniter(token, itp)
+ipftoken_t *token;
+ipfgeniter_t *itp;
+{
+	int error;
+
+	switch (itp->igi_type)
+	{
+	case IPFGENITER_FRAG :
+#ifdef USE_MUTEXES
+		error = fr_nextfrag(token, itp,
+				    &ipfr_list, &ipfr_tail, &ipf_frag);
+#else
+		error = fr_nextfrag(token, itp, &ipfr_list, &ipfr_tail);
+#endif
+		break;
+	default :
+		error = EINVAL;
+		break;
+	}
+
+	return error;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    fr_genericiter                                              */
+/* Returns:     int - 0 = success, else error                               */
+/* Parameters:  data(I) - the token type to match                           */
+/*              uid(I)  - uid owning the token                              */
+/*              ptr(I)  - context pointer for the token                     */
+/*                                                                          */
+/* ------------------------------------------------------------------------ */
+int ipf_genericiter(data, uid, ctx)
+void *data, *ctx;
+int uid;
+{
+	ipftoken_t *token;
+	ipfgeniter_t iter;
+	int error;
+
+	error = fr_inobj(data, &iter, IPFOBJ_GENITER);
+	if (error != 0)
+		return error;
+
+	token = ipf_findtoken(iter.igi_type, uid, ctx);
+	if (token != NULL) {
+		token->ipt_subtype = iter.igi_type;
+		error = ipf_geniter(token, &iter);
+	} else
+		error = EFAULT;
+	RWLOCK_EXIT(&ipf_tokens);
+
+	return error;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    fr_ipf_ioctl                                                */
+/* Returns:     int - 0 = success, else error                               */
+/* Parameters:  data(I) - the token type to match                           */
+/*              cmd(I)  - the ioctl command number                          */
+/*              mode(I) - mode flags for the ioctl                          */
+/*              uid(I)  - uid owning the token                              */
+/*              ptr(I)  - context pointer for the token                     */
+/*                                                                          */
+/* This function handles all of the ioctl command that are actually isssued */
+/* to the /dev/ipl device.                                                  */
+/* ------------------------------------------------------------------------ */
+int fr_ipf_ioctl(data, cmd, mode, uid, ctx)
+caddr_t data;
+ioctlcmd_t cmd;
+int mode, uid;
+void *ctx;
+{
+	friostat_t fio;
+	int error, tmp;
+	SPL_INT(s);
+
+	switch (cmd)
+	{
+	case SIOCFRENB :
+		if (!(mode & FWRITE))
+			error = EPERM;
+		else {
+			error = BCOPYIN(data, &tmp, sizeof(tmp));
+			if (error != 0) {
+				error = EFAULT;
+				break;
+			}
+
+			RWLOCK_EXIT(&ipf_global);
+			WRITE_ENTER(&ipf_global);
+			if (tmp) {
+				if (fr_running > 0)
+					error = 0;
+				else
+					error = ipfattach();
+				if (error == 0)
+					fr_running = 1;
+				else
+					(void) ipfdetach();
+			} else {
+				error = ipfdetach();
+				if (error == 0)
+					fr_running = -1;
+			}
+		}
+		break;
+
+	case SIOCIPFSET :
+		if (!(mode & FWRITE)) {
+			error = EPERM;
+			break;
+		}
+		/* FALLTHRU */
+	case SIOCIPFGETNEXT :
+	case SIOCIPFGET :
+		error = fr_ipftune(cmd, (void *)data);
+		break;
+
+	case SIOCSETFF :
+		if (!(mode & FWRITE))
+			error = EPERM;
+		else {
+			error = BCOPYIN(data, &fr_flags, sizeof(fr_flags));
+			if (error != 0)
+				error = EFAULT;
+		}
+		break;
+
+	case SIOCGETFF :
+		error = BCOPYOUT(&fr_flags, data, sizeof(fr_flags));
+		if (error != 0)
+			error = EFAULT;
+		break;
+
+	case SIOCFUNCL :
+		error = fr_resolvefunc((void *)data);
+		break;
+
+	case SIOCINAFR :
+	case SIOCRMAFR :
+	case SIOCADAFR :
+	case SIOCZRLST :
+		if (!(mode & FWRITE))
+			error = EPERM;
+		else
+			error = frrequest(IPL_LOGIPF, cmd, data, fr_active, 1);
+		break;
+
+	case SIOCINIFR :
+	case SIOCRMIFR :
+	case SIOCADIFR :
+		if (!(mode & FWRITE))
+			error = EPERM;
+		else
+			error = frrequest(IPL_LOGIPF, cmd, data,
+					  1 - fr_active, 1);
+		break;
+
+	case SIOCSWAPA :
+		if (!(mode & FWRITE))
+			error = EPERM;
+		else {
+			WRITE_ENTER(&ipf_mutex);
+			bzero((char *)frcache, sizeof(frcache[0]) * 2);
+			error = BCOPYOUT(&fr_active, data, sizeof(fr_active));
+			if (error != 0)
+				error = EFAULT;
+			else
+				fr_active = 1 - fr_active;
+			RWLOCK_EXIT(&ipf_mutex);
+		}
+		break;
+
+	case SIOCGETFS :
+		fr_getstat(&fio);
+		error = fr_outobj((void *)data, &fio, IPFOBJ_IPFSTAT);
+		break;
+
+	case SIOCFRZST :
+		if (!(mode & FWRITE))
+			error = EPERM;
+		else
+			error = fr_zerostats(data);
+		break;
+
+	case SIOCIPFFL :
+		if (!(mode & FWRITE))
+			error = EPERM;
+		else {
+			error = BCOPYIN(data, &tmp, sizeof(tmp));
+			if (!error) {
+				tmp = frflush(IPL_LOGIPF, 4, tmp);
+				error = BCOPYOUT(&tmp, data, sizeof(tmp));
+				if (error != 0)
+					error = EFAULT;
+			} else
+				error = EFAULT;
+		}
+		break;
+
+#ifdef USE_INET6
+	case SIOCIPFL6 :
+		if (!(mode & FWRITE))
+			error = EPERM;
+		else {
+			error = BCOPYIN(data, &tmp, sizeof(tmp));
+			if (!error) {
+				tmp = frflush(IPL_LOGIPF, 6, tmp);
+				error = BCOPYOUT(&tmp, data, sizeof(tmp));
+				if (error != 0)
+					error = EFAULT;
+			} else
+				error = EFAULT;
+		}
+		break;
+#endif
+
+	case SIOCSTLCK :
+		error = BCOPYIN(data, &tmp, sizeof(tmp));
+		if (error == 0) {
+			fr_state_lock = tmp;
+			fr_nat_lock = tmp;
+			fr_frag_lock = tmp;
+			fr_auth_lock = tmp;
+		} else
+			error = EFAULT;
+		break;
+
+#ifdef	IPFILTER_LOG
+	case SIOCIPFFB :
+		if (!(mode & FWRITE))
+			error = EPERM;
+		else {
+			tmp = ipflog_clear(IPL_LOGIPF);
+			error = BCOPYOUT(&tmp, data, sizeof(tmp));
+			if (error)
+				error = EFAULT;
+		}
+		break;
+#endif /* IPFILTER_LOG */
+
+	case SIOCFRSYN :
+		if (!(mode & FWRITE))
+			error = EPERM;
+		else {
+			RWLOCK_EXIT(&ipf_global);
+			WRITE_ENTER(&ipf_global);
+#ifdef MENTAT
+			error = ipfsync();
+#else
+			frsync(NULL);
+			error = 0;
+#endif
+
+		}
+		break;
+
+	case SIOCGFRST :
+		error = fr_outobj((void *)data, fr_fragstats(),
+				  IPFOBJ_FRAGSTAT);
+		break;
+
+#ifdef	IPFILTER_LOG
+	case FIONREAD :
+		tmp = (int)iplused[IPL_LOGIPF];
+
+		error = BCOPYOUT(&tmp, data, sizeof(tmp));
+		break;
+#endif
+
+	case SIOCIPFITER :
+		SPL_SCHED(s);
+		error = ipf_frruleiter(data, uid, ctx);
+		SPL_X(s);
+		break;
+
+	case SIOCGENITER :
+		SPL_SCHED(s);
+		error = ipf_genericiter(data, uid, ctx);
+		SPL_X(s);
+		break;
+
+	case SIOCIPFDELTOK :
+		SPL_SCHED(s);
+		error = BCOPYIN(data, &tmp, sizeof(tmp));
+		if (error == 0)
+			error = ipf_deltoken(tmp, uid, ctx);
+		SPL_X(s);
+		break;
+
+	default :
+		error = EINVAL;
+		break;
+	}
+
+	return error;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_queueflush                                              */
+/* Returns:     int - number of entries flushed (0 = none)                  */
+/* Parameters:  deletefn(I) - function to call to delete entry              */
+/*              ipfqs(I)    - top of the list of ipf internal queues        */
+/*              userqs(I)   - top of the list of user defined timeouts      */
+/*                                                                          */
+/* This fucntion gets called when the state/NAT hash tables fill up and we  */
+/* need to try a bit harder to free up some space.  The algorithm used is   */
+/* to look for the oldest entries on each timeout queue and free them if    */
+/* they are within the given window we are considering.  Where the window   */
+/* starts and the steps taken to increase its size depend upon how long ipf */
+/* has been running (fr_ticks.)  Anything modified in the last 30 seconds   */
+/* is not touched.                                                          */
+/*                                              touched                     */
+/*         die     fr_ticks   30*1.5    1800*1.5   |  43200*1.5             */
+/*           |          |        |           |     |     |                  */
+/* future <--+----------+--------+-----------+-----+-----+-----------> past */
+/*                     now        \_int=30s_/ \_int=1hr_/ \_int=12hr        */
+/*                                                                          */
+/* Points to note:                                                          */
+/* - tqe_die is the time, in the future, when entries die.                  */
+/* - tqe_die - fr_ticks is how long left the connection has to live in ipf  */
+/*   ticks.                                                                 */
+/* - tqe_touched is when the entry was last used by NAT/state               */
+/* - the closer tqe_touched is to fr_ticks, the further tqe_die will be for */
+/*   any given timeout queue and vice versa.                                */
+/* - both tqe_die and tqe_touched increase over time                        */
+/* - timeout queues are sorted with the highest value of tqe_die at the     */
+/*   bottom and therefore the smallest values of each are at the top        */
+/*                                                                          */
+/* We start by setting up a maximum range to scan for things to move of     */
+/* iend (newest) to istart (oldest) in chunks of "interval".  If nothing is */
+/* found in that range, "interval" is adjusted (so long as it isn't 30) and */
+/* we start again with a new value for "iend" and "istart".  The downside   */
+/* of the current implementation is that it may return removing just 1 entry*/
+/* every time (pathological case) where it could remove more.               */
+/* ------------------------------------------------------------------------ */
+int ipf_queueflush(deletefn, ipfqs, userqs)
+ipftq_delete_fn_t deletefn;
+ipftq_t *ipfqs, *userqs;
+{
+	u_long interval, istart, iend;
+	ipftq_t *ifq, *ifqnext;
+	ipftqent_t *tqe, *tqn;
+	int removed;
+
+	/*
+	 * NOTE: Use of "* 15 / 10" is required here because if "* 1.5" is
+	 *       used then the operations are upgraded to floating point
+	 *       and kernels don't like floating point...
+	 */
+	if (fr_ticks > IPF_TTLVAL(43200 * 15 / 10)) {
+		istart = IPF_TTLVAL(86400 * 4);
+		interval = IPF_TTLVAL(43200);
+	} else if (fr_ticks > IPF_TTLVAL(1800 * 15 / 10)) {
+		istart = IPF_TTLVAL(43200);
+		interval = IPF_TTLVAL(1800);
+	} else if (fr_ticks > IPF_TTLVAL(30 * 15 / 10)) {
+		istart = IPF_TTLVAL(1800);
+		interval = IPF_TTLVAL(30);
+	} else {
+		return 0;
+	}
+	if (istart > fr_ticks) {
+		if (fr_ticks - interval < interval)
+			istart = interval;
+		else
+			istart = (fr_ticks / interval) * interval;
+	}
+
+	iend = fr_ticks - interval;
+	removed = 0;
+
+	for (;;) {
+		u_long try;
+
+		try = fr_ticks - istart; 
+
+		for (ifq = ipfqs; ifq != NULL; ifq = ifq->ifq_next) {
+			for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); ) {
+				if (try < tqe->tqe_touched)
+					break;
+				tqn = tqe->tqe_next;
+				if ((*deletefn)(tqe->tqe_parent) == 0)
+					removed++;
+			}
+		}
+
+		for (ifq = userqs; ifq != NULL; ifq = ifqnext) {
+			ifqnext = ifq->ifq_next;
+
+			for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); ) {
+				if (try < tqe->tqe_touched)
+					break;
+				tqn = tqe->tqe_next;
+				if ((*deletefn)(tqe->tqe_parent) == 0)
+					removed++;
+			}
+		}
+
+		if (try >= iend) {
+			if (removed > 0)
+				break;
+			if (interval == IPF_TTLVAL(43200)) {
+				interval = IPF_TTLVAL(1800);
+			} else if (interval == IPF_TTLVAL(1800)) {
+				interval = IPF_TTLVAL(30);
+			} else {
+				break;
+			}
+			if (interval >= fr_ticks)
+				break;
+
+			iend = fr_ticks - interval;
+		}
+		istart -= interval;
+	}
+
+	return removed;
+}
Index: ip_irc_pxy.c
===================================================================
RCS file: /home/cvs/src/sys/contrib/ipfilter/netinet/ip_irc_pxy.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/contrib/ipfilter/netinet/ip_irc_pxy.c -L sys/contrib/ipfilter/netinet/ip_irc_pxy.c -u -r1.1.1.1 -r1.2
--- sys/contrib/ipfilter/netinet/ip_irc_pxy.c
+++ sys/contrib/ipfilter/netinet/ip_irc_pxy.c
@@ -1,11 +1,9 @@
-/*	$FreeBSD: src/sys/contrib/ipfilter/netinet/ip_irc_pxy.c,v 1.1.1.1 2005/04/25 18:15:19 darrenr Exp $	*/
-
 /*
  * Copyright (C) 2000-2003 Darren Reed
  *
  * See the IPFILTER.LICENCE file for details on licencing.
  *
- * Id: ip_irc_pxy.c,v 2.39.2.4 2005/02/04 10:22:55 darrenr Exp
+ * $Id: ip_irc_pxy.c,v 2.39.2.6 2006/07/14 06:12:14 darrenr Exp $
  */
 
 #define	IPF_IRC_PROXY
@@ -50,7 +48,7 @@
 }
 
 
-char *ippr_irc_dcctypes[] = {
+const char *ippr_irc_dcctypes[] = {
 	"CHAT ",	/* CHAT chat ipnumber portnumber */
 	"SEND ",	/* SEND filename ipnumber portnumber */
 	"MOVE ",
@@ -417,7 +415,7 @@
 
 			(void) fr_addstate(&fi, NULL, SI_W_DPORT);
 			if (fi.fin_state != NULL)
-				fr_statederef(&fi, (ipstate_t **)&fi.fin_state);
+				fr_statederef((ipstate_t **)&fi.fin_state);
 		}
 		ip->ip_src = swip;
 	}
Index: ip_ipsec_pxy.c
===================================================================
RCS file: /home/cvs/src/sys/contrib/ipfilter/netinet/ip_ipsec_pxy.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/contrib/ipfilter/netinet/ip_ipsec_pxy.c -L sys/contrib/ipfilter/netinet/ip_ipsec_pxy.c -u -r1.1.1.1 -r1.2
--- sys/contrib/ipfilter/netinet/ip_ipsec_pxy.c
+++ sys/contrib/ipfilter/netinet/ip_ipsec_pxy.c
@@ -1,5 +1,3 @@
-/*	$FreeBSD: src/sys/contrib/ipfilter/netinet/ip_ipsec_pxy.c,v 1.1.1.2 2005/04/25 18:15:18 darrenr Exp $	*/
-
 /*
  * Copyright (C) 2001-2003 by Darren Reed
  *
@@ -8,7 +6,7 @@
  * Simple ISAKMP transparent proxy for in-kernel use.  For use with the NAT
  * code.
  *
- * Id: ip_ipsec_pxy.c,v 2.20.2.6 2005/03/28 10:47:53 darrenr Exp
+ * $Id: ip_ipsec_pxy.c,v 2.20.2.8 2006/07/14 06:12:14 darrenr Exp $
  *
  */
 #define	IPF_IPSEC_PROXY
@@ -96,8 +94,8 @@
 	mb_t *m;
 	ip_t *ip;
 
+	off = fin->fin_plen - fin->fin_dlen + fin->fin_ipoff;
 	bzero(ipsec_buffer, sizeof(ipsec_buffer));
-	off = fin->fin_hlen + sizeof(udphdr_t);
 	ip = fin->fin_ip;
 	m = fin->fin_m;
 
@@ -179,7 +177,7 @@
 		ipsec->ipsc_state = fr_addstate(&fi, &ipsec->ipsc_state,
 						SI_WILDP);
 		if (fi.fin_state != NULL)
-			fr_statederef(&fi, (ipstate_t **)&fi.fin_state);
+			fr_statederef((ipstate_t **)&fi.fin_state);
 	}
 	ip->ip_p = p & 0xff;
 	return 0;
@@ -258,7 +256,7 @@
 							&ipsec->ipsc_state,
 							SI_WILDP);
 			if (fi.fin_state != NULL)
-				fr_statederef(&fi, (ipstate_t **)&fi.fin_state);
+				fr_statederef((ipstate_t **)&fi.fin_state);
 		}
 		ip->ip_p = p;
 	}
@@ -287,8 +285,8 @@
 	if ((fin->fin_dlen < sizeof(cookies)) || (fin->fin_flx & FI_FRAG))
 		return -1;
 
+	off = fin->fin_plen - fin->fin_dlen + fin->fin_ipoff;
 	ipsec = aps->aps_data;
-	off = fin->fin_hlen + sizeof(udphdr_t);
 	m = fin->fin_m;
 	COPYDATA(m, off, sizeof(cookies), (char *)cookies);
 
Index: ip_auth.h
===================================================================
RCS file: /home/cvs/src/sys/contrib/ipfilter/netinet/ip_auth.h,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/contrib/ipfilter/netinet/ip_auth.h -L sys/contrib/ipfilter/netinet/ip_auth.h -u -r1.1.1.1 -r1.2
--- sys/contrib/ipfilter/netinet/ip_auth.h
+++ sys/contrib/ipfilter/netinet/ip_auth.h
@@ -1,12 +1,12 @@
-/*	$FreeBSD: src/sys/contrib/ipfilter/netinet/ip_auth.h,v 1.14 2005/04/25 18:43:13 darrenr Exp $	*/
+/*	$FreeBSD: src/sys/contrib/ipfilter/netinet/ip_auth.h,v 1.16 2007/06/04 02:54:35 darrenr Exp $	*/
 
 /*
  * Copyright (C) 1997-2001 by Darren Reed & Guido Van Rooij.
  *
  * See the IPFILTER.LICENCE file for details on licencing.
  *
- * $FreeBSD: src/sys/contrib/ipfilter/netinet/ip_auth.h,v 1.14 2005/04/25 18:43:13 darrenr Exp $
- * Id: ip_auth.h,v 2.16 2003/07/25 12:29:56 darrenr Exp
+ * $FreeBSD: src/sys/contrib/ipfilter/netinet/ip_auth.h,v 1.16 2007/06/04 02:54:35 darrenr Exp $
+ * Id: ip_auth.h,v 2.16.2.2 2006/03/16 06:45:49 darrenr Exp $
  *
  */
 #ifndef	__IP_AUTH_H__
@@ -23,13 +23,16 @@
 	char	*fra_buf;
 #ifdef	MENTAT
 	queue_t	*fra_q;
+	mb_t	*fra_m;
 #endif
 } frauth_t;
 
 typedef	struct	frauthent  {
 	struct	frentry	fae_fr;
 	struct	frauthent	*fae_next;
+	struct	frauthent	**fae_pnext;
 	u_long	fae_age;
+	int	fae_ref;
 } frauthent_t;
 
 typedef struct  fr_authstat {
@@ -62,6 +65,7 @@
 extern	mb_t	**fr_authpkts;
 extern	int	fr_newauth __P((mb_t *, fr_info_t *));
 extern	int	fr_preauthcmd __P((ioctlcmd_t, frentry_t *, frentry_t **));
-extern	int	fr_auth_ioctl __P((caddr_t, ioctlcmd_t, int));
+extern	int	fr_auth_ioctl __P((caddr_t, ioctlcmd_t, int, int, void *));
+extern	int	fr_auth_waiting __P((void));
 
 #endif	/* __IP_AUTH_H__ */
Index: ip_pptp_pxy.c
===================================================================
RCS file: /home/cvs/src/sys/contrib/ipfilter/netinet/ip_pptp_pxy.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/contrib/ipfilter/netinet/ip_pptp_pxy.c -L sys/contrib/ipfilter/netinet/ip_pptp_pxy.c -u -r1.1.1.1 -r1.2
--- sys/contrib/ipfilter/netinet/ip_pptp_pxy.c
+++ sys/contrib/ipfilter/netinet/ip_pptp_pxy.c
@@ -1,12 +1,10 @@
-/*	$FreeBSD: src/sys/contrib/ipfilter/netinet/ip_pptp_pxy.c,v 1.1.1.1 2005/04/25 18:15:30 darrenr Exp $	*/
-
 /*
  * Copyright (C) 2002-2003 by Darren Reed
  *
  * Simple PPTP transparent proxy for in-kernel use.  For use with the NAT
  * code.
  *
- * Id: ip_pptp_pxy.c,v 2.10.2.9 2005/03/16 18:17:34 darrenr Exp
+ * $Id: ip_pptp_pxy.c,v 2.10.2.15 2006/10/31 12:11:23 darrenr Exp $
  *
  */
 #define	IPF_PPTP_PROXY
@@ -80,6 +78,9 @@
 
 /*
  * Setup for a new PPTP proxy.
+ *
+ * NOTE: The printf's are broken up with %s in them to prevent them being
+ * optimised into puts statements on FreeBSD (this doesn't exist in the kernel)
  */
 int ippr_pptp_new(fin, aps, nat)
 fr_info_t *fin;
@@ -89,15 +90,14 @@
 	pptp_pxy_t *pptp;
 	ipnat_t *ipn;
 	ip_t *ip;
-	int off;
 
 	ip = fin->fin_ip;
-	off = fin->fin_hlen + sizeof(udphdr_t);
 
 	if (nat_outlookup(fin, 0, IPPROTO_GRE, nat->nat_inip,
 			  ip->ip_dst) != NULL) {
 		if (ippr_pptp_debug > 0)
-			printf("ippr_pptp_new: GRE session already exists\n");
+			printf("ippr_pptp_new: GRE session %s\n",
+			       "already exists");
 		return -1;
 	}
 
@@ -105,7 +105,8 @@
 	KMALLOCS(aps->aps_data, pptp_pxy_t *, sizeof(*pptp));
 	if (aps->aps_data == NULL) {
 		if (ippr_pptp_debug > 0)
-			printf("ippr_pptp_new: malloc for aps_data failed\n");
+			printf("ippr_pptp_new: malloc for aps_data %s\n",
+			       "failed");
 		return -1;
 	}
 
@@ -212,15 +213,17 @@
 		RWLOCK_EXIT(&ipf_state);
 	} else {
 		RWLOCK_EXIT(&ipf_state);
-		if (nat->nat_dir == NAT_INBOUND)
-			fi.fin_fi.fi_daddr = nat2->nat_inip.s_addr;
-		else
-			fi.fin_fi.fi_saddr = nat2->nat_inip.s_addr;
+		if (nat2 != NULL) {
+			if (nat->nat_dir == NAT_INBOUND)
+				fi.fin_fi.fi_daddr = nat2->nat_inip.s_addr;
+			else
+				fi.fin_fi.fi_saddr = nat2->nat_inip.s_addr;
+		}
 		fi.fin_ifp = NULL;
 		pptp->pptp_state = fr_addstate(&fi, &pptp->pptp_state,
 					       0);
 		if (fi.fin_state != NULL)
-			fr_statederef(&fi, (ipstate_t **)&fi.fin_state);
+			fr_statederef((ipstate_t **)&fi.fin_state);
 	}
 	ip->ip_p = p;
 	return;
@@ -238,7 +241,7 @@
 pptp_pxy_t *pptp;
 int rev;
 {
-	static char *funcname = "ippr_pptp_nextmessage";
+	static const char *funcname = "ippr_pptp_nextmessage";
 	pptp_side_t *pptps;
 	u_32_t start, end;
 	pptp_hdr_t *hdr;
Index: ip_sync.h
===================================================================
RCS file: /home/cvs/src/sys/contrib/ipfilter/netinet/ip_sync.h,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/contrib/ipfilter/netinet/ip_sync.h -L sys/contrib/ipfilter/netinet/ip_sync.h -u -r1.1.1.1 -r1.2
--- sys/contrib/ipfilter/netinet/ip_sync.h
+++ sys/contrib/ipfilter/netinet/ip_sync.h
@@ -1,12 +1,10 @@
-/*	$FreeBSD: src/sys/contrib/ipfilter/netinet/ip_sync.h,v 1.1.1.1 2005/04/25 18:15:41 darrenr Exp $	*/
-
 /*
  * Copyright (C) 1993-2001 by Darren Reed.
  *
  * See the IPFILTER.LICENCE file for details on licencing.
  *
  * @(#)ip_fil.h	1.35 6/5/96
- * Id: ip_sync.h,v 2.11.2.2 2004/11/04 19:29:07 darrenr Exp
+ * $Id: ip_sync.h,v 2.11.2.4 2006/07/14 06:12:20 darrenr Exp $
  */
 
 #ifndef __IP_SYNC_H__
@@ -104,14 +102,16 @@
 extern	synclogent_t	synclog[SYNCLOG_SZ];
 
 
-extern	int		fr_sync_ioctl __P((caddr_t, ioctlcmd_t, int));
-extern	synclist_t	*ipfsync_new __P((int, fr_info_t *, void *));
-extern	void		ipfsync_del __P((synclist_t *));
-extern	void		ipfsync_update __P((int, fr_info_t *, synclist_t *));
-extern	int		ipfsync_init __P((void));
-extern	int		ipfsync_nat __P((synchdr_t *sp, void *data));
-extern	int		ipfsync_state __P((synchdr_t *sp, void *data));
-extern	int		ipfsync_read __P((struct uio *uio));
-extern	int		ipfsync_write __P((struct uio *uio));
+extern	int fr_sync_ioctl __P((caddr_t, ioctlcmd_t, int, int, void *));
+extern	synclist_t *ipfsync_new __P((int, fr_info_t *, void *));
+extern	void ipfsync_del __P((synclist_t *));
+extern	void ipfsync_update __P((int, fr_info_t *, synclist_t *));
+extern	int ipfsync_init __P((void));
+extern	int ipfsync_nat __P((synchdr_t *sp, void *data));
+extern	int ipfsync_state __P((synchdr_t *sp, void *data));
+extern	int ipfsync_read __P((struct uio *uio));
+extern	int ipfsync_write __P((struct uio *uio));
+extern	int ipfsync_canread __P((void));
+extern	int ipfsync_canwrite __P((void));
 
 #endif /* IP_SYNC */
Index: ip_lookup.c
===================================================================
RCS file: /home/cvs/src/sys/contrib/ipfilter/netinet/ip_lookup.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/contrib/ipfilter/netinet/ip_lookup.c -L sys/contrib/ipfilter/netinet/ip_lookup.c -u -r1.1.1.1 -r1.2
--- sys/contrib/ipfilter/netinet/ip_lookup.c
+++ sys/contrib/ipfilter/netinet/ip_lookup.c
@@ -1,5 +1,3 @@
-/*	$FreeBSD: src/sys/contrib/ipfilter/netinet/ip_lookup.c,v 1.1.1.1 2005/04/25 18:15:23 darrenr Exp $	*/
-
 /*
  * Copyright (C) 2002-2003 by Darren Reed.
  *
@@ -35,10 +33,7 @@
 # undef _KERNEL
 #endif
 #include <sys/socket.h>
-#if (defined(__osf__) || defined(__hpux) || defined(__sgi)) && defined(_KERNEL)
-# ifdef __osf__
-#  include <net/radix.h>
-# endif
+#if (defined(__osf__) || defined(AIX) || defined(__hpux) || defined(__sgi)) && defined(_KERNEL)
 # include "radix_ipf_local.h"
 # define _RADIX_H_
 #endif
@@ -63,7 +58,7 @@
 /* END OF INCLUDES */
 
 #if !defined(lint)
-static const char rcsid[] = "@(#)Id: ip_lookup.c,v 2.35.2.5 2004/07/06 11:16:25 darrenr Exp";
+static const char rcsid[] = "@(#)$Id: ip_lookup.c,v 2.35.2.19 2007/10/11 09:05:51 darrenr Exp $";
 #endif
 
 #ifdef	IPFILTER_LOOKUP
@@ -75,6 +70,8 @@
 static int iplookup_deltable __P((caddr_t));
 static int iplookup_stats __P((caddr_t));
 static int iplookup_flush __P((caddr_t));
+static int iplookup_iterate __P((void *, int, void *));
+static int iplookup_deltok __P((void *, int, void *));
 
 
 /* ------------------------------------------------------------------------ */
@@ -131,15 +128,14 @@
 /* involves just calling another function to handle the specifics of each   */
 /* command.                                                                 */
 /* ------------------------------------------------------------------------ */
-int ip_lookup_ioctl(data, cmd, mode)
+int ip_lookup_ioctl(data, cmd, mode, uid, ctx)
 caddr_t data;
 ioctlcmd_t cmd;
-int mode;
+int mode, uid;
+void *ctx;
 {
 	int err;
-# if defined(_KERNEL) && !defined(MENTAT) && defined(USE_SPL)
-	int s;
-# endif
+	SPL_INT(s);
 
 	mode = mode;	/* LINT */
 
@@ -186,6 +182,14 @@
 		RWLOCK_EXIT(&ip_poolrw);
 		break;
 
+	case SIOCLOOKUPITER :
+		err = iplookup_iterate(data, uid, ctx);
+		break;
+
+	case SIOCIPFDELTOK :
+		err = iplookup_deltok(data, uid, ctx);
+		break;
+
 	default :
 		err = EINVAL;
 		break;
@@ -214,8 +218,13 @@
 	ip_pool_t *p;
 	int err;
 
-	err = 0;
-	BCOPYIN(data, &op, sizeof(op));
+	err = BCOPYIN(data, &op, sizeof(op));
+	if (err != 0)
+		return EFAULT;
+
+	if (op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX)
+		return EINVAL;
+
 	op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
 
 	switch (op.iplo_type)
@@ -284,8 +293,12 @@
 	ip_pool_t *p;
 	int err;
 
-	err = 0;
-	BCOPYIN(data, &op, sizeof(op));
+	err = BCOPYIN(data, &op, sizeof(op));
+	if (err != 0)
+		return EFAULT;
+
+	if (op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX)
+		return EINVAL;
 
 	op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
 
@@ -345,8 +358,12 @@
 	iplookupop_t op;
 	int err;
 
-	err = 0;
-	BCOPYIN(data, &op, sizeof(op));
+	err = BCOPYIN(data, &op, sizeof(op));
+	if (err != 0)
+		return EFAULT;
+
+	if (op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX)
+		return EINVAL;
 
 	op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
 
@@ -370,6 +387,17 @@
 		err = EINVAL;
 		break;
 	}
+
+	/*
+	 * For anonymous pools, copy back the operation struct because in the
+	 * case of success it will contain the new table's name.
+	 */
+	if ((err == 0) && ((op.iplo_arg & LOOKUP_ANON) != 0)) {
+		err = BCOPYOUT(&op, data, sizeof(op));
+		if (err != 0)
+			err = EFAULT;
+	}
+
 	return err;
 }
 
@@ -388,11 +416,14 @@
 	iplookupop_t op;
 	int err;
 
-	BCOPYIN(data, &op, sizeof(op));
-	op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
+	err = BCOPYIN(data, &op, sizeof(op));
+	if (err != 0)
+		return EFAULT;
 
-	if (op.iplo_arg & IPLT_ANON)
-		op.iplo_arg &= IPLT_ANON;
+	if (op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX)
+		return EINVAL;
+
+	op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
 
 	/*
 	 * create a new pool - fail if one already exists with
@@ -401,11 +432,11 @@
 	switch (op.iplo_type)
 	{
 	case IPLT_POOL :
-		err = ip_pool_destroy(&op);
+		err = ip_pool_destroy(op.iplo_unit, op.iplo_name);
 		break;
 
 	case IPLT_HASH :
-		err = fr_removehtable(&op);
+		err = fr_removehtable(op.iplo_unit, op.iplo_name);
 		break;
 
 	default :
@@ -429,8 +460,12 @@
 	iplookupop_t op;
 	int err;
 
-	err = 0;
-	BCOPYIN(data, &op, sizeof(op));
+	err = BCOPYIN(data, &op, sizeof(op));
+	if (err != 0)
+		return EFAULT;
+
+	if (op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX)
+		return EINVAL;
 
 	switch (op.iplo_type)
 	{
@@ -464,15 +499,16 @@
 	int err, unit, num, type;
 	iplookupflush_t flush;
 
-	err = 0;
-	BCOPYIN(data, &flush, sizeof(flush));
-
-	flush.iplf_name[sizeof(flush.iplf_name) - 1] = '\0';
+	err = BCOPYIN(data, &flush, sizeof(flush));
+	if (err != 0)
+		return EFAULT;
 
 	unit = flush.iplf_unit;
 	if ((unit < 0 || unit > IPL_LOGMAX) && (unit != IPLT_ALL))
 		return EINVAL;
 
+	flush.iplf_name[sizeof(flush.iplf_name) - 1] = '\0';
+
 	type = flush.iplf_type;
 	err = EINVAL;
 	num = 0;
@@ -489,12 +525,23 @@
 
 	if (err == 0) {
 		flush.iplf_count = num;
-		err = COPYOUT(&flush, data, sizeof(flush));
+		err = BCOPYOUT(&flush, data, sizeof(flush));
+		if (err != 0)
+			err = EFAULT;
 	}
 	return err;
 }
 
 
+/* ------------------------------------------------------------------------ */
+/* Function:    ip_lookup_delref                                            */
+/* Returns:     void                                                        */
+/* Parameters:  type(I) - table type to operate on                          */
+/*              ptr(I)  - pointer to object to remove reference for         */
+/*                                                                          */
+/* This function organises calling the correct deref function for a given   */
+/* type of object being passed into it.                                     */
+/* ------------------------------------------------------------------------ */
 void ip_lookup_deref(type, ptr)
 int type;
 void *ptr;
@@ -517,13 +564,131 @@
 }
 
 
+/* ------------------------------------------------------------------------ */
+/* Function:    iplookup_iterate                                            */
+/* Returns:     int     - 0 = success, else error                           */
+/* Parameters:  data(I) - pointer to data from ioctl call                   */
+/*              uid(I)  - uid of caller                                     */
+/*              ctx(I)  - pointer to give the uid context                   */
+/*                                                                          */
+/* Decodes ioctl request to step through either hash tables or pools.       */
+/* ------------------------------------------------------------------------ */
+static int iplookup_iterate(data, uid, ctx)
+void *data;
+int uid;
+void *ctx;
+{
+	ipflookupiter_t iter;
+	ipftoken_t *token;
+	int err;
+	SPL_INT(s);
+
+	err = fr_inobj(data, &iter, IPFOBJ_LOOKUPITER);
+	if (err != 0)
+		return err;
+
+	if (iter.ili_unit > IPL_LOGMAX)
+		return EINVAL;
+
+	if (iter.ili_ival != IPFGENITER_LOOKUP)
+		return EINVAL;
+
+	SPL_SCHED(s);
+	token = ipf_findtoken(iter.ili_key, uid, ctx);
+	if (token == NULL) {
+		RWLOCK_EXIT(&ipf_tokens);
+		SPL_X(s);
+		return ESRCH;
+	}
+
+	switch (iter.ili_type)
+	{
+	case IPLT_POOL :
+		err = ip_pool_getnext(token, &iter);
+		break;
+	case IPLT_HASH :
+		err = fr_htable_getnext(token, &iter);
+		break;
+	default :
+		err = EINVAL;
+		break;
+	}
+	RWLOCK_EXIT(&ipf_tokens);
+	SPL_X(s);
+
+	return err;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    iplookup_iterderef                                          */
+/* Returns:     int     - 0 = success, else error                           */
+/* Parameters:  data(I) - pointer to data from ioctl call                   */
+/*                                                                          */
+/* Decodes ioctl request to remove a particular hash table or pool and      */
+/* calls the relevant function to do the cleanup.                           */
+/* ------------------------------------------------------------------------ */
+void ip_lookup_iterderef(type, data)
+u_32_t type;
+void *data;
+{
+	iplookupiterkey_t	key;
+
+	key.ilik_key = type;
+
+	if (key.ilik_unstr.ilik_ival != IPFGENITER_LOOKUP)
+		return;
+
+	switch (key.ilik_unstr.ilik_type)
+	{
+	case IPLT_HASH :
+		fr_htable_iterderef((u_int)key.ilik_unstr.ilik_otype,
+				    (int)key.ilik_unstr.ilik_unit, data);
+		break;
+	case IPLT_POOL :
+		ip_pool_iterderef((u_int)key.ilik_unstr.ilik_otype,
+				  (int)key.ilik_unstr.ilik_unit, data);
+		break;
+	}
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    iplookup_deltok                                             */
+/* Returns:     int     - 0 = success, else error                           */
+/* Parameters:  data(I) - pointer to data from ioctl call                   */
+/*              uid(I)  - uid of caller                                     */
+/*              ctx(I)  - pointer to give the uid context                   */
+/*                                                                          */
+/* Deletes the token identified by the combination of (type,uid,ctx)        */
+/* "key" is a combination of the table type, iterator type and the unit for */
+/* which the token was being used.                                          */
+/* ------------------------------------------------------------------------ */
+static int iplookup_deltok(data, uid, ctx)
+void *data;
+int uid;
+void *ctx;
+{
+	int error, key;
+	SPL_INT(s);
+
+	SPL_SCHED(s);
+	error = BCOPYIN(data, &key, sizeof(key)); 
+	if (error == 0)
+		error = ipf_deltoken(key, uid, ctx);
+	SPL_X(s);
+	return error;
+}
+
+
 #else /* IPFILTER_LOOKUP */
 
 /*ARGSUSED*/
-int ip_lookup_ioctl(data, cmd, mode)
+int ip_lookup_ioctl(data, cmd, mode, uid, ctx)
 caddr_t data;
 ioctlcmd_t cmd;
-int mode;
+int mode, uid;
+void *ctx;
 {
 	return EIO;
 }
Index: ip_proxy.c
===================================================================
RCS file: /home/cvs/src/sys/contrib/ipfilter/netinet/ip_proxy.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/contrib/ipfilter/netinet/ip_proxy.c -L sys/contrib/ipfilter/netinet/ip_proxy.c -u -r1.1.1.1 -r1.2
--- sys/contrib/ipfilter/netinet/ip_proxy.c
+++ sys/contrib/ipfilter/netinet/ip_proxy.c
@@ -1,4 +1,4 @@
-/*	$FreeBSD: src/sys/contrib/ipfilter/netinet/ip_proxy.c,v 1.25 2005/04/27 05:53:12 darrenr Exp $	*/
+/*	$FreeBSD: src/sys/contrib/ipfilter/netinet/ip_proxy.c,v 1.29.2.1 2007/10/31 05:00:38 darrenr Exp $	*/
 
 /*
  * Copyright (C) 1997-2003 by Darren Reed.
@@ -16,7 +16,9 @@
 #include <sys/param.h>
 #include <sys/time.h>
 #include <sys/file.h>
-#include <sys/fcntl.h>
+#if !defined(AIX)
+# include <sys/fcntl.h>
+#endif
 #if !defined(_KERNEL) && !defined(__KERNEL__)
 # include <stdio.h>
 # include <string.h>
@@ -35,7 +37,8 @@
 #include <sys/socket.h>
 #if defined(_KERNEL)
 # if !defined(__NetBSD__) && !defined(sun) && !defined(__osf__) && \
-     !defined(__OpenBSD__) && !defined(__hpux) && !defined(__sgi)
+     !defined(__OpenBSD__) && !defined(__hpux) && !defined(__sgi) && \
+     !defined(AIX)
 #  include <sys/ctype.h>
 # endif
 # include <sys/systm.h>
@@ -93,12 +96,6 @@
 #if defined(_KERNEL)
 # include "netinet/ip_irc_pxy.c"
 # include "netinet/ip_raudio_pxy.c"
-# ifdef IPFILTER_H323
-#  include "netinet/ip_h323_pxy.c"
-# endif
-# ifdef	IPFILTER_PRO
-#  include "netinet/ip_msnrpc_pxy.c"
-# endif
 # include "netinet/ip_netbios_pxy.c"
 #endif
 #include "netinet/ip_ipsec_pxy.c"
@@ -107,7 +104,7 @@
 /* END OF INCLUDES */
 
 #if !defined(lint)
-static const char rcsid[] = "@(#)Id: ip_proxy.c,v 2.62.2.12 2005/03/03 14:28:24 darrenr Exp";
+static const char rcsid[] = "@(#)$Id: ip_proxy.c,v 2.62.2.21 2007/06/02 21:22:28 darrenr Exp $";
 #endif
 
 static int appr_fixseqack __P((fr_info_t *, ip_t *, ap_session_t *, int ));
@@ -125,7 +122,7 @@
 aproxy_t	ap_proxies[] = {
 #ifdef	IPF_FTP_PROXY
 	{ NULL, "ftp", (char)IPPROTO_TCP, 0, 0, ippr_ftp_init, ippr_ftp_fini,
-	  ippr_ftp_new, NULL, ippr_ftp_in, ippr_ftp_out, NULL },
+	  ippr_ftp_new, NULL, ippr_ftp_in, ippr_ftp_out, NULL, NULL },
 #endif
 #ifdef	IPF_IRC_PROXY
 	{ NULL, "irc", (char)IPPROTO_TCP, 0, 0, ippr_irc_init, ippr_irc_fini,
@@ -159,9 +156,9 @@
 #endif
 #ifdef  IPF_H323_PROXY
 	{ NULL, "h323", (char)IPPROTO_TCP, 0, 0, ippr_h323_init, ippr_h323_fini,
-	  ippr_h323_new, ippr_h323_del, ippr_h323_in, NULL, NULL },
+	  ippr_h323_new, ippr_h323_del, ippr_h323_in, NULL, NULL, NULL },
 	{ NULL, "h245", (char)IPPROTO_TCP, 0, 0, NULL, NULL,
-	  ippr_h245_new, NULL, NULL, ippr_h245_out, NULL },
+	  ippr_h245_new, NULL, NULL, ippr_h245_out, NULL, NULL },
 #endif
 #ifdef	IPF_RPCB_PROXY
 # if 0
@@ -173,7 +170,7 @@
 	  ippr_rpcb_init, ippr_rpcb_fini, ippr_rpcb_new, ippr_rpcb_del,
 	  ippr_rpcb_in, ippr_rpcb_out, NULL, NULL },
 #endif
-	{ NULL, "", '\0', 0, 0, NULL, NULL, NULL, NULL }
+	{ NULL, "", '\0', 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }
 };
 
 /*
@@ -195,7 +192,7 @@
 			return -1;
 		}
 
-	for (a = ap_proxylist; a->apr_p; a = a->apr_next)
+	for (a = ap_proxylist; (a != NULL); a = a->apr_next)
 		if ((a->apr_p == ap->apr_p) &&
 		    !strncmp(a->apr_label, ap->apr_label,
 			     sizeof(ap->apr_label))) {
@@ -292,13 +289,14 @@
 }
 
 
-int appr_ioctl(data, cmd, mode)
+int appr_ioctl(data, cmd, mode, ctx)
 caddr_t data;
 ioctlcmd_t cmd;
 int mode;
+void *ctx;
 {
 	ap_ctl_t ctl;
-	caddr_t ptr;
+	u_char *ptr;
 	int error;
 
 	mode = mode;	/* LINT */
@@ -306,11 +304,13 @@
 	switch (cmd)
 	{
 	case SIOCPROXY :
-		BCOPYIN(data, &ctl, sizeof(ctl));
+		error = BCOPYIN(data, &ctl, sizeof(ctl));
+		if (error != 0)
+			return EFAULT;
 		ptr = NULL;
 
 		if (ctl.apc_dsize > 0) {
-			KMALLOCS(ptr, caddr_t, ctl.apc_dsize);
+			KMALLOCS(ptr, u_char *, ctl.apc_dsize);
 			if (ptr == NULL)
 				error = ENOMEM;
 			else {
@@ -327,8 +327,7 @@
 		if (error == 0)
 			error = appr_ctl(&ctl);
 
-		if ((ctl.apc_dsize > 0) && (ptr != NULL) &&
-		    (ctl.apc_data == ptr)) {
+		if (ptr != NULL) {
 			KFREES(ptr, ctl.apc_dsize);
 		}
 		break;
@@ -567,8 +566,8 @@
 		if (err != 0) {
 			short adjlen = err & 0xffff;
 
-			s1 = LONG_SUM(ip->ip_len - adjlen);
-			s2 = LONG_SUM(ip->ip_len);
+			s1 = LONG_SUM(fin->fin_plen - adjlen);
+			s2 = LONG_SUM(fin->fin_plen);
 			CALC_SUMD(s1, s2, sd);
 			fix_outcksum(fin, &ip->ip_sum, sd);
 		}
@@ -588,19 +587,23 @@
 #if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6)
 			if (dosum)
 				tcp->th_sum = fr_cksum(fin->fin_qfm, ip,
-						       IPPROTO_TCP, tcp);
+						       IPPROTO_TCP, tcp,
+						       fin->fin_plen);
 #else
 			tcp->th_sum = fr_cksum(fin->fin_m, ip,
-					       IPPROTO_TCP, tcp);
+					       IPPROTO_TCP, tcp,
+					       fin->fin_plen);
 #endif
 		} else if ((udp != NULL) && (udp->uh_sum != 0)) {
 #if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6)
 			if (dosum)
 				udp->uh_sum = fr_cksum(fin->fin_qfm, ip,
-						       IPPROTO_UDP, udp);
+						       IPPROTO_UDP, udp,
+						       fin->fin_plen);
 #else
 			udp->uh_sum = fr_cksum(fin->fin_m, ip,
-					       IPPROTO_UDP, udp);
+					       IPPROTO_UDP, udp,
+					       fin->fin_plen);
 #endif
 		}
 		aps->aps_bytes += fin->fin_plen;
@@ -691,9 +694,9 @@
 	tcp = (tcphdr_t *)fin->fin_dp;
 	out = fin->fin_out;
 	/*
-	 * ip_len has already been adjusted by 'inc'.
+	 * fin->fin_plen has already been adjusted by 'inc'.
 	 */
-	nlen = ip->ip_len;
+	nlen = fin->fin_plen;
 	nlen -= (IP_HL(ip) << 2) + (TCP_OFF(tcp) << 2);
 
 	inc2 = inc;
@@ -814,7 +817,7 @@
 
 	if (ipf_proxy_debug > 8)
 		printf("appr_fixseqack: seq %x ack %x\n",
-			ntohl(tcp->th_seq), ntohl(tcp->th_ack));
+			(u_32_t)ntohl(tcp->th_seq), (u_32_t)ntohl(tcp->th_ack));
 	return ch ? 2 : 0;
 }
 
Index: ip_nat.c
===================================================================
RCS file: /home/cvs/src/sys/contrib/ipfilter/netinet/ip_nat.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/contrib/ipfilter/netinet/ip_nat.c -L sys/contrib/ipfilter/netinet/ip_nat.c -u -r1.1.1.1 -r1.2
--- sys/contrib/ipfilter/netinet/ip_nat.c
+++ sys/contrib/ipfilter/netinet/ip_nat.c
@@ -1,4 +1,4 @@
-/*	$FreeBSD: src/sys/contrib/ipfilter/netinet/ip_nat.c,v 1.39 2005/04/27 03:48:09 darrenr Exp $	*/
+/*	$FreeBSD: src/sys/contrib/ipfilter/netinet/ip_nat.c,v 1.42.2.1 2007/10/31 05:00:38 darrenr Exp $	*/
 
 /*
  * Copyright (C) 1995-2003 by Darren Reed.
@@ -16,9 +16,17 @@
 #include <sys/param.h>
 #include <sys/time.h>
 #include <sys/file.h>
+#if defined(_KERNEL) && defined(__NetBSD_Version__) && \
+    (__NetBSD_Version__ >= 399002000)
+# include <sys/kauth.h>
+#endif
 #if defined(__NetBSD__) && (NetBSD >= 199905) && !defined(IPFILTER_LKM) && \
     defined(_KERNEL)
-# include "opt_ipfilter_log.h"
+#if defined(__NetBSD_Version__) && (__NetBSD_Version__ < 399001400)
+#  include "opt_ipfilter_log.h"
+# else
+#  include "opt_ipfilter.h"
+# endif
 #endif
 #if !defined(_KERNEL)
 # include <stdio.h>
@@ -37,7 +45,9 @@
 #else
 # include <sys/ioctl.h>
 #endif
-#include <sys/fcntl.h>
+#if !defined(AIX)
+# include <sys/fcntl.h>
+#endif
 #if !defined(linux)
 # include <sys/protosw.h>
 #endif
@@ -107,8 +117,8 @@
 
 #if !defined(lint)
 static const char sccsid[] = "@(#)ip_nat.c	1.11 6/5/96 (C) 1995 Darren Reed";
-static const char rcsid[] = "@(#)$FreeBSD: src/sys/contrib/ipfilter/netinet/ip_nat.c,v 1.39 2005/04/27 03:48:09 darrenr Exp $";
-/* static const char rcsid[] = "@(#)Id: ip_nat.c,v 2.195.2.38 2005/03/28 11:09:54 darrenr Exp"; */
+static const char rcsid[] = "@(#)$FreeBSD: src/sys/contrib/ipfilter/netinet/ip_nat.c,v 1.42.2.1 2007/10/31 05:00:38 darrenr Exp $";
+/* static const char rcsid[] = "@(#)$Id: ip_nat.c,v 2.195.2.102 2007/10/16 10:08:10 darrenr Exp $"; */
 #endif
 
 
@@ -146,14 +156,17 @@
 	fr_nat_maxbucket_reset = 1;
 u_32_t	nat_masks = 0;
 u_32_t	rdr_masks = 0;
+u_long	nat_last_force_flush = 0;
 ipnat_t	**nat_rules = NULL;
 ipnat_t	**rdr_rules = NULL;
-hostmap_t	**maptable  = NULL;
+hostmap_t	**ipf_hm_maptable  = NULL;
+hostmap_t	*ipf_hm_maplist  = NULL;
 ipftq_t	nat_tqb[IPF_TCP_NSTATES];
 ipftq_t	nat_udptq;
 ipftq_t	nat_icmptq;
 ipftq_t	nat_iptq;
 ipftq_t	*nat_utqe = NULL;
+int	fr_nat_doflush = 0;
 #ifdef  IPFILTER_LOG
 int	nat_logging = 1;
 #else
@@ -166,36 +179,39 @@
 natstat_t nat_stats;
 int	fr_nat_lock = 0;
 int	fr_nat_init = 0;
-#if SOLARIS
+#if SOLARIS && !defined(_INET_IP_STACK_H)
 extern	int		pfil_delayed_copy;
 #endif
 
+static	int	nat_flush_entry __P((void *));
 static	int	nat_flushtable __P((void));
 static	int	nat_clearlist __P((void));
 static	void	nat_addnat __P((struct ipnat *));
 static	void	nat_addrdr __P((struct ipnat *));
-static	void	nat_delete __P((struct nat *, int));
 static	void	nat_delrdr __P((struct ipnat *));
 static	void	nat_delnat __P((struct ipnat *));
 static	int	fr_natgetent __P((caddr_t));
 static	int	fr_natgetsz __P((caddr_t));
 static	int	fr_natputent __P((caddr_t, int));
+static	int	nat_extraflush __P((int));
+static	int	nat_gettable __P((char *));
 static	void	nat_tabmove __P((nat_t *));
 static	int	nat_match __P((fr_info_t *, ipnat_t *));
 static	INLINE	int nat_newmap __P((fr_info_t *, nat_t *, natinfo_t *));
 static	INLINE	int nat_newrdr __P((fr_info_t *, nat_t *, natinfo_t *));
 static	hostmap_t *nat_hostmap __P((ipnat_t *, struct in_addr,
 				    struct in_addr, struct in_addr, u_32_t));
-static	void	nat_hostmapdel __P((struct hostmap *));
-static	INLINE	int nat_icmpquerytype4 __P((int));
+static	int	nat_icmpquerytype4 __P((int));
 static	int	nat_siocaddnat __P((ipnat_t *, ipnat_t **, int));
 static	void	nat_siocdelnat __P((ipnat_t *, ipnat_t **, int));
-static	INLINE	int nat_finalise __P((fr_info_t *, nat_t *, natinfo_t *,
+static	int	nat_finalise __P((fr_info_t *, nat_t *, natinfo_t *,
 				      tcphdr_t *, nat_t **, int));
-static	void	nat_resolverule __P((ipnat_t *));
+static	int	nat_resolverule __P((ipnat_t *));
 static	nat_t	*fr_natclone __P((fr_info_t *, nat_t *));
 static	void	nat_mssclamp __P((tcphdr_t *, u_32_t, fr_info_t *, u_short *));
-static	INLINE	int nat_wildok __P((nat_t *, int, int, int, int));
+static	int	nat_wildok __P((nat_t *, int, int, int, int));
+static	int	nat_getnext __P((ipftoken_t *, ipfgeniter_t *));
+static	int	nat_iterator __P((ipftoken_t *, ipfgeniter_t *));
 
 
 /* ------------------------------------------------------------------------ */
@@ -233,11 +249,14 @@
 	else
 		return -4;
 
-	KMALLOCS(maptable, hostmap_t **, sizeof(hostmap_t *) * ipf_hostmap_sz);
-	if (maptable != NULL)
-		bzero((char *)maptable, sizeof(hostmap_t *) * ipf_hostmap_sz);
+	KMALLOCS(ipf_hm_maptable, hostmap_t **, \
+		 sizeof(hostmap_t *) * ipf_hostmap_sz);
+	if (ipf_hm_maptable != NULL)
+		bzero((char *)ipf_hm_maptable,
+		      sizeof(hostmap_t *) * ipf_hostmap_sz);
 	else
 		return -5;
+	ipf_hm_maplist = NULL;
 
 	KMALLOCS(nat_stats.ns_bucketlen[0], u_long *,
 		 ipf_nattable_sz * sizeof(u_long));
@@ -437,7 +456,7 @@
 	hv += src.s_addr;
 	hv += dst.s_addr;
 	hv %= HOSTMAP_SIZE;
-	for (hm = maptable[hv]; hm; hm = hm->hm_next)
+	for (hm = ipf_hm_maptable[hv]; hm; hm = hm->hm_next)
 		if ((hm->hm_srcip.s_addr == src.s_addr) &&
 		    (hm->hm_dstip.s_addr == dst.s_addr) &&
 		    ((np == NULL) || (np == hm->hm_ipnat)) &&
@@ -451,11 +470,16 @@
 
 	KMALLOC(hm, hostmap_t *);
 	if (hm) {
-		hm->hm_next = maptable[hv];
-		hm->hm_pnext = maptable + hv;
-		if (maptable[hv] != NULL)
-			maptable[hv]->hm_pnext = &hm->hm_next;
-		maptable[hv] = hm;
+		hm->hm_next = ipf_hm_maplist;
+		hm->hm_pnext = &ipf_hm_maplist;
+		if (ipf_hm_maplist != NULL)
+			ipf_hm_maplist->hm_pnext = &hm->hm_next;
+		ipf_hm_maplist = hm;
+		hm->hm_hnext = ipf_hm_maptable[hv];
+		hm->hm_phnext = ipf_hm_maptable + hv;
+		if (ipf_hm_maptable[hv] != NULL)
+			ipf_hm_maptable[hv]->hm_phnext = &hm->hm_hnext;
+		ipf_hm_maptable[hv] = hm;
 		hm->hm_ipnat = np;
 		hm->hm_srcip = src;
 		hm->hm_dstip = dst;
@@ -468,19 +492,27 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    nat_hostmapdel                                              */
+/* Function:    fr_hostmapdel                                               */
 /* Returns:     Nil                                                         */
-/* Parameters:  hm(I) - pointer to hostmap structure                        */
+/* Parameters:  hmp(I) - pointer to hostmap structure pointer               */
 /* Write Locks: ipf_nat                                                     */
 /*                                                                          */
 /* Decrement the references to this hostmap structure by one.  If this      */
 /* reaches zero then remove it and free it.                                 */
 /* ------------------------------------------------------------------------ */
-static void nat_hostmapdel(hm)
-struct hostmap *hm;
+void fr_hostmapdel(hmp)
+struct hostmap **hmp;
 {
+	struct hostmap *hm;
+
+	hm = *hmp;
+	*hmp = NULL;
+
 	hm->hm_ref--;
 	if (hm->hm_ref == 0) {
+		if (hm->hm_hnext)
+			hm->hm_hnext->hm_phnext = hm->hm_phnext;
+		*hm->hm_phnext = hm->hm_hnext;
 		if (hm->hm_next)
 			hm->hm_next->hm_pnext = hm->hm_pnext;
 		*hm->hm_pnext = hm->hm_next;
@@ -610,18 +642,30 @@
 /*                                                                          */
 /* Processes an ioctl call made to operate on the IP Filter NAT device.     */
 /* ------------------------------------------------------------------------ */
-int fr_nat_ioctl(data, cmd, mode)
+int fr_nat_ioctl(data, cmd, mode, uid, ctx)
 ioctlcmd_t cmd;
 caddr_t data;
-int mode;
+int mode, uid;
+void *ctx;
 {
 	ipnat_t *nat, *nt, *n = NULL, **np = NULL;
 	int error = 0, ret, arg, getlock;
 	ipnat_t natd;
+	SPL_INT(s);
 
 #if (BSD >= 199306) && defined(_KERNEL)
-	if ((securelevel >= 3) && (mode & FWRITE))
+# if defined(__NetBSD_Version__) && (__NetBSD_Version__ >= 399002000)
+	if ((mode & FWRITE) &&
+	     kauth_authorize_network(curlwp->l_cred, KAUTH_NETWORK_FIREWALL,
+				     KAUTH_REQ_NETWORK_FIREWALL_FW,
+				     NULL, NULL, NULL)) {
 		return EPERM;
+	}
+# else
+	if ((securelevel >= 3) && (mode & FWRITE)) {
+		return EPERM;
+	}
+# endif
 #endif
 
 #if defined(__osf__) && defined(_KERNEL)
@@ -644,9 +688,6 @@
 		} else {
 			error = fr_inobj(data, &natd, IPFOBJ_IPNAT);
 		}
-
-	} else if (cmd == (ioctlcmd_t)SIOCIPFFL) { /* SIOCFLNAT & SIOCCNATL */
-		BCOPYIN(data, &arg, sizeof(arg));
 	}
 
 	if (error != 0)
@@ -668,9 +709,13 @@
 		}
 		MUTEX_ENTER(&ipf_natio);
 		for (np = &nat_list; ((n = *np) != NULL); np = &n->in_next)
-			if (!bcmp((char *)&nat->in_flags, (char *)&n->in_flags,
-					IPN_CMPSIZ))
+			if (bcmp((char *)&nat->in_flags, (char *)&n->in_flags,
+					IPN_CMPSIZ) == 0) {
+				if (nat->in_redir == NAT_REDIRECT &&
+				    nat->in_pnext != n->in_pnext)
+					continue;
 				break;
+			}
 	}
 
 	switch (cmd)
@@ -684,25 +729,37 @@
 			error = EPERM;
 		else {
 			tmp = ipflog_clear(IPL_LOGNAT);
-			BCOPYOUT((char *)&tmp, (char *)data, sizeof(tmp));
+			error = BCOPYOUT((char *)&tmp, (char *)data,
+					 sizeof(tmp));
+			if (error != 0)
+				error = EFAULT;
 		}
 		break;
 	}
+
 	case SIOCSETLG :
 		if (!(mode & FWRITE))
 			error = EPERM;
 		else {
-			BCOPYIN((char *)data, (char *)&nat_logging,
-				sizeof(nat_logging));
+			error = BCOPYIN((char *)data, (char *)&nat_logging,
+					sizeof(nat_logging));
+			if (error != 0)
+				error = EFAULT;
 		}
 		break;
+
 	case SIOCGETLG :
-		BCOPYOUT((char *)&nat_logging, (char *)data,
-			 sizeof(nat_logging));
+		error = BCOPYOUT((char *)&nat_logging, (char *)data,
+				 sizeof(nat_logging));
+		if (error != 0)
+			error = EFAULT;
 		break;
+
 	case FIONREAD :
 		arg = iplused[IPL_LOGNAT];
-		BCOPYOUT(&arg, data, sizeof(arg));
+		error = BCOPYOUT(&arg, data, sizeof(arg));
+		if (error != 0)
+			error = EFAULT;
 		break;
 #endif
 	case SIOCADNAT :
@@ -723,6 +780,7 @@
 		if (error == 0)
 			nt = NULL;
 		break;
+
 	case SIOCRMNAT :
 		if (!(mode & FWRITE)) {
 			error = EPERM;
@@ -740,11 +798,13 @@
 		MUTEX_EXIT(&ipf_natio);
 		n = NULL;
 		break;
+
 	case SIOCGNATS :
 		nat_stats.ns_table[0] = nat_table[0];
 		nat_stats.ns_table[1] = nat_table[1];
 		nat_stats.ns_list = nat_list;
-		nat_stats.ns_maptable = maptable;
+		nat_stats.ns_maptable = ipf_hm_maptable;
+		nat_stats.ns_maplist = ipf_hm_maplist;
 		nat_stats.ns_nattab_sz = ipf_nattable_sz;
 		nat_stats.ns_nattab_max = ipf_nattable_max;
 		nat_stats.ns_rultab_sz = ipf_natrules_sz;
@@ -752,8 +812,10 @@
 		nat_stats.ns_hostmap_sz = ipf_hostmap_sz;
 		nat_stats.ns_instances = nat_instances;
 		nat_stats.ns_apslist = ap_sess_list;
+		nat_stats.ns_ticks = fr_ticks;
 		error = fr_outobj(data, &nat_stats, IPFOBJ_NATSTAT);
 		break;
+
 	case SIOCGNATL :
 	    {
 		natlookup_t nl;
@@ -774,6 +836,7 @@
 		}
 		break;
 	    }
+
 	case SIOCIPFFL :	/* old SIOCFLNAT & SIOCCNATL */
 		if (!(mode & FWRITE)) {
 			error = EPERM;
@@ -782,33 +845,47 @@
 		if (getlock) {
 			WRITE_ENTER(&ipf_nat);
 		}
-		error = 0;
-		if (arg == 0)
-			ret = nat_flushtable();
-		else if (arg == 1)
-			ret = nat_clearlist();
-		else
-			error = EINVAL;
+
+		error = BCOPYIN(data, &arg, sizeof(arg));
+		if (error != 0)
+			error = EFAULT;
+		else {
+			if (arg == 0)
+				ret = nat_flushtable();
+			else if (arg == 1)
+				ret = nat_clearlist();
+			else
+				ret = nat_extraflush(arg);
+		}
+
 		if (getlock) {
 			RWLOCK_EXIT(&ipf_nat);
 		}
 		if (error == 0) {
-			BCOPYOUT(&ret, data, sizeof(ret));
+			error = BCOPYOUT(&ret, data, sizeof(ret));
 		}
 		break;
+
 	case SIOCPROXY :
-		error = appr_ioctl(data, cmd, mode);
+		error = appr_ioctl(data, cmd, mode, ctx);
 		break;
+
 	case SIOCSTLCK :
-		fr_lock(data, &fr_nat_lock);
+		if (!(mode & FWRITE)) {
+			error = EPERM;
+		} else {
+			error = fr_lock(data, &fr_nat_lock);
+		}
 		break;
+
 	case SIOCSTPUT :
-		if (fr_nat_lock) {
+		if ((mode & FWRITE) != 0) {
 			error = fr_natputent(data, getlock);
 		} else {
 			error = EACCES;
 		}
 		break;
+
 	case SIOCSTGSZ :
 		if (fr_nat_lock) {
 			if (getlock) {
@@ -821,6 +898,7 @@
 		} else
 			error = EACCES;
 		break;
+
 	case SIOCSTGET :
 		if (fr_nat_lock) {
 			if (getlock) {
@@ -833,12 +911,50 @@
 		} else
 			error = EACCES;
 		break;
+
+	case SIOCGENITER :
+	    {
+		ipfgeniter_t iter;
+		ipftoken_t *token;
+
+		SPL_SCHED(s);
+		error = fr_inobj(data, &iter, IPFOBJ_GENITER);
+		if (error == 0) {
+			token = ipf_findtoken(iter.igi_type, uid, ctx);
+			if (token != NULL) {
+				error  = nat_iterator(token, &iter);
+			}
+			RWLOCK_EXIT(&ipf_tokens);
+		}
+		SPL_X(s);
+		break;
+	    }
+
+	case SIOCIPFDELTOK :
+		error = BCOPYIN((caddr_t)data, (caddr_t)&arg, sizeof(arg));
+		if (error == 0) {
+			SPL_SCHED(s);
+			error = ipf_deltoken(arg, uid, ctx);
+			SPL_X(s);
+		} else {
+			error = EFAULT;
+		}
+		break;
+
+	case SIOCGTQTAB :
+		error = fr_outobj(data, nat_tqb, IPFOBJ_STATETQTAB);
+		break;
+
+	case SIOCGTABL :
+		error = nat_gettable(data);
+		break;
+
 	default :
 		error = EINVAL;
 		break;
 	}
 done:
-	if (nt)
+	if (nt != NULL)
 		KFREE(nt);
 	return error;
 }
@@ -862,11 +978,8 @@
 {
 	int error = 0, i, j;
 
-	nat_resolverule(n);
-	if (n->in_plabel[0] != '\0') {
-		if (n->in_apr == NULL)
-			return ENOENT;
-	}
+	if (nat_resolverule(n) != 0)
+		return ENOENT;
 
 	if ((n->in_age[0] == 0) && (n->in_age[1] != 0))
 		return EINVAL;
@@ -969,9 +1082,11 @@
 		n->in_flags &= ~IPN_NOTSRC;
 		nat_addnat(n);
 	}
+	MUTEX_INIT(&n->in_lock, "ipnat rule lock");
+
 	n = NULL;
 	nat_stats.ns_rules++;
-#if SOLARIS
+#if SOLARIS && !defined(_INET_IP_STACK_H)
 	pfil_delayed_copy = 0;
 #endif
 	if (getlock) {
@@ -991,7 +1106,7 @@
 /* from information passed to the kernel, then add it  to the appropriate   */
 /* NAT rule table(s).                                                       */
 /* ------------------------------------------------------------------------ */
-static void nat_resolverule(n)
+static int nat_resolverule(n)
 ipnat_t *n;
 {
 	n->in_ifnames[0][LIFNAMSIZ - 1] = '\0';
@@ -1002,12 +1117,15 @@
 		(void) strncpy(n->in_ifnames[1], n->in_ifnames[0], LIFNAMSIZ);
 		n->in_ifps[1] = n->in_ifps[0];
 	} else {
-		n->in_ifps[1] = fr_resolvenic(n->in_ifnames[0], 4);
+		n->in_ifps[1] = fr_resolvenic(n->in_ifnames[1], 4);
 	}
 
 	if (n->in_plabel[0] != '\0') {
 		n->in_apr = appr_lookup(n->in_p, n->in_plabel);
+		if (n->in_apr == NULL)
+			return -1;
 	}
+	return 0;
 }
 
 
@@ -1056,9 +1174,10 @@
 	if (n->in_use == 0) {
 		if (n->in_apr)
 			appr_free(n->in_apr);
+		MUTEX_DESTROY(&n->in_lock);
 		KFREE(n);
 		nat_stats.ns_rules--;
-#if SOLARIS
+#if SOLARIS && !defined(_INET_IP_STACK_H)
 		if (nat_stats.ns_rules == 0)
 			pfil_delayed_copy = 1;
 #endif
@@ -1090,7 +1209,8 @@
 	nat_t *nat, *n;
 	natget_t ng;
 
-	BCOPYIN(data, &ng, sizeof(ng));
+	if (BCOPYIN(data, &ng, sizeof(ng)) != 0)
+		return EFAULT;
 
 	nat = ng.ng_ptr;
 	if (!nat) {
@@ -1100,7 +1220,8 @@
 		 * Empty list so the size returned is 0.  Simple.
 		 */
 		if (nat == NULL) {
-			BCOPYOUT(&ng, data, sizeof(ng));
+			if (BCOPYOUT(&ng, data, sizeof(ng)) != 0)
+				return EFAULT;
 			return 0;
 		}
 	} else {
@@ -1127,7 +1248,8 @@
 			ng.ng_sz += aps->aps_psiz;
 	}
 
-	BCOPYOUT(&ng, data, sizeof(ng));
+	if (BCOPYOUT(&ng, data, sizeof(ng)) != 0)
+		return EFAULT;
 	return 0;
 }
 
@@ -1277,12 +1399,12 @@
 	aps = NULL;
 	nat = NULL;
 	ipnn = NULL;
+	fr = NULL;
 
 	/*
 	 * New entry, copy in the rest of the NAT entry if it's size is more
 	 * than just the nat_t structure.
 	 */
-	fr = NULL;
 	if (ipn.ipn_dsize > sizeof(ipn)) {
 		if (ipn.ipn_dsize > 81920) {
 			error = ENOMEM;
@@ -1335,29 +1457,51 @@
 
 		ATOMIC_INC(nat_stats.ns_rules);
 
-		nat_resolverule(in);
+		if (nat_resolverule(in) != 0) {
+			error = ESRCH;
+			goto junkput;
+		}
 	}
 
 	/*
 	 * Check that the NAT entry doesn't already exist in the kernel.
+	 *
+	 * For NAT_OUTBOUND, we're lookup for a duplicate MAP entry.  To do
+	 * this, we check to see if the inbound combination of addresses and
+	 * ports is already known.  Similar logic is applied for NAT_INBOUND.
+	 * 
 	 */
 	bzero((char *)&fin, sizeof(fin));
 	fin.fin_p = nat->nat_p;
 	if (nat->nat_dir == NAT_OUTBOUND) {
+		fin.fin_ifp = nat->nat_ifps[0];
 		fin.fin_data[0] = ntohs(nat->nat_oport);
 		fin.fin_data[1] = ntohs(nat->nat_outport);
-		fin.fin_ifp = nat->nat_ifps[1];
-		if (nat_inlookup(&fin, 0, fin.fin_p, nat->nat_oip,
-				  nat->nat_inip) != NULL) {
+		if (getlock) {
+			READ_ENTER(&ipf_nat);
+		}
+		n = nat_inlookup(&fin, nat->nat_flags, fin.fin_p,
+				 nat->nat_oip, nat->nat_inip);
+		if (getlock) {
+			RWLOCK_EXIT(&ipf_nat);
+		}
+		if (n != NULL) {
 			error = EEXIST;
 			goto junkput;
 		}
 	} else if (nat->nat_dir == NAT_INBOUND) {
+		fin.fin_ifp = nat->nat_ifps[0];
 		fin.fin_data[0] = ntohs(nat->nat_outport);
 		fin.fin_data[1] = ntohs(nat->nat_oport);
-		fin.fin_ifp = nat->nat_ifps[0];
-		if (nat_outlookup(&fin, 0, fin.fin_p, nat->nat_outip,
-				 nat->nat_oip) != NULL) {
+		if (getlock) {
+			READ_ENTER(&ipf_nat);
+		}
+		n = nat_outlookup(&fin, nat->nat_flags, fin.fin_p,
+				  nat->nat_outip, nat->nat_oip);
+		if (getlock) {
+			RWLOCK_EXIT(&ipf_nat);
+		}
+		if (n != NULL) {
 			error = EEXIST;
 			goto junkput;
 		}
@@ -1418,10 +1562,18 @@
 			fr->fr_ref = 1;
 			(void) fr_outobj(data, ipnn, IPFOBJ_NATSAVE);
 			bcopy((char *)&ipnn->ipn_fr, (char *)fr, sizeof(*fr));
+
+			fr->fr_ref = 1;
+			fr->fr_dsize = 0;
+			fr->fr_data = NULL;
+			fr->fr_type = FR_T_NONE;
+
 			MUTEX_NUKE(&fr->fr_lock);
 			MUTEX_INIT(&fr->fr_lock, "nat-filter rule lock");
 		} else {
-			READ_ENTER(&ipf_nat);
+			if (getlock) {
+				READ_ENTER(&ipf_nat);
+			}
 			for (n = nat_instances; n; n = n->nat_next)
 				if (n->nat_fr == fr)
 					break;
@@ -1431,7 +1583,9 @@
 				fr->fr_ref++;
 				MUTEX_EXIT(&fr->fr_lock);
 			}
-			RWLOCK_EXIT(&ipf_nat);
+			if (getlock) {
+				RWLOCK_EXIT(&ipf_nat);
+			}
 
 			if (!n) {
 				error = ESRCH;
@@ -1464,7 +1618,7 @@
 
 junkput:
 	if (fr != NULL)
-		fr_derefrule(&fr);
+		(void) fr_derefrule(&fr);
 
 	if ((ipnn != NULL) && (ipnn != &ipn)) {
 		KFREES(ipnn, ipn.ipn_dsize);
@@ -1497,22 +1651,23 @@
 /* Delete a nat entry from the various lists and table.  If NAT logging is  */
 /* enabled then generate a NAT log record for this event.                   */
 /* ------------------------------------------------------------------------ */
-static void nat_delete(nat, logtype)
+void nat_delete(nat, logtype)
 struct nat *nat;
 int logtype;
 {
 	struct ipnat *ipn;
+	int removed = 0;
 
 	if (logtype != 0 && nat_logging != 0)
 		nat_log(nat, logtype);
 
-	MUTEX_ENTER(&ipf_nat_new);
-
 	/*
 	 * Take it as a general indication that all the pointers are set if
 	 * nat_pnext is set.
 	 */
 	if (nat->nat_pnext != NULL) {
+		removed = 1;
+
 		nat_stats.ns_bucketlen[0][nat->nat_hv[0]]--;
 		nat_stats.ns_bucketlen[1][nat->nat_hv[1]]--;
 
@@ -1546,13 +1701,41 @@
 		nat->nat_me = NULL;
 	}
 
-	fr_deletequeueentry(&nat->nat_tqe);
+	if (nat->nat_tqe.tqe_ifq != NULL)
+		fr_deletequeueentry(&nat->nat_tqe);
 
-	nat->nat_ref--;
-	if (nat->nat_ref > 0) {
-		MUTEX_EXIT(&ipf_nat_new);
+	if (logtype == NL_EXPIRE)
+		nat_stats.ns_expire++;
+
+	MUTEX_ENTER(&nat->nat_lock);
+	/*
+	 * NL_DESTROY should only be passed in when we've got nat_ref >= 2.
+	 * This happens when a nat'd packet is blocked and we want to throw
+	 * away the NAT session.
+	 */
+	if (logtype == NL_DESTROY) {
+		if (nat->nat_ref > 2) {
+			nat->nat_ref -= 2;
+			MUTEX_EXIT(&nat->nat_lock);
+			if (removed)
+				nat_stats.ns_orphans++;
+			return;
+		}
+	} else if (nat->nat_ref > 1) {
+		nat->nat_ref--;
+		MUTEX_EXIT(&nat->nat_lock);
+		if (removed)
+			nat_stats.ns_orphans++;
 		return;
 	}
+	MUTEX_EXIT(&nat->nat_lock);
+
+	/*
+	 * At this point, nat_ref is 1, doing "--" would make it 0..
+	 */
+	nat->nat_ref = 0;
+	if (!removed)
+		nat_stats.ns_orphans--;
 
 #ifdef	IPFILTER_SYNC
 	if (nat->nat_sync)
@@ -1560,10 +1743,10 @@
 #endif
 
 	if (nat->nat_fr != NULL)
-		(void)fr_derefrule(&nat->nat_fr);
+		(void) fr_derefrule(&nat->nat_fr);
 
 	if (nat->nat_hm != NULL)
-		nat_hostmapdel(nat->nat_hm);
+		fr_hostmapdel(&nat->nat_hm);
 
 	/*
 	 * If there is an active reference from the nat entry to its parent
@@ -1572,25 +1755,13 @@
 	 */
 	ipn = nat->nat_ptr;
 	if (ipn != NULL) {
-		ipn->in_space++;
-		ipn->in_use--;
-		if (ipn->in_use == 0 && (ipn->in_flags & IPN_DELETE)) {
-			if (ipn->in_apr)
-				appr_free(ipn->in_apr);
-			KFREE(ipn);
-			nat_stats.ns_rules--;
-#if SOLARIS
-			if (nat_stats.ns_rules == 0)
-				pfil_delayed_copy = 1;
-#endif
-		}
+		fr_ipnatderef(&ipn);
 	}
 
 	MUTEX_DESTROY(&nat->nat_lock);
 
 	aps_free(nat->nat_aps);
 	nat_stats.ns_inuse--;
-	MUTEX_EXIT(&ipf_nat_new);
 
 	/*
 	 * If there's a fragment table entry too for this nat entry, then
@@ -1664,6 +1835,7 @@
 		if (n->in_use == 0) {
 			if (n->in_apr != NULL)
 				appr_free(n->in_apr);
+			MUTEX_DESTROY(&n->in_lock);
 			KFREE(n);
 			nat_stats.ns_rules--;
 		} else {
@@ -1672,7 +1844,7 @@
 		}
 		i++;
 	}
-#if SOLARIS
+#if SOLARIS && !defined(_INET_IP_STACK_H)
 	pfil_delayed_copy = 1;
 #endif
 	nat_masks = 0;
@@ -1739,8 +1911,7 @@
 			if (hm != NULL)
 				in.s_addr = hm->hm_mapip.s_addr;
 		} else if ((l == 1) && (hm != NULL)) {
-			nat_hostmapdel(hm);
-			hm = NULL;
+			fr_hostmapdel(&hm);
 		}
 		in.s_addr = ntohl(in.s_addr);
 
@@ -1961,10 +2132,12 @@
 natinfo_t *ni;
 {
 	u_short nport, dport, sport;
-	struct in_addr in;
+	struct in_addr in, inb;
+	u_short sp, dp;
 	hostmap_t *hm;
 	u_32_t flags;
 	ipnat_t *np;
+	nat_t *natl;
 	int move;
 
 	move = 1;
@@ -1982,8 +2155,8 @@
 	 * packet might match a different one to the previous connection but
 	 * we want the same destination to be used.
 	 */
-	if ((np->in_flags & (IPN_ROUNDR|IPN_STICKY)) ==
-	    (IPN_ROUNDR|IPN_STICKY)) {
+	if (((np->in_flags & (IPN_ROUNDR|IPN_SPLIT)) != 0) &&
+	    ((np->in_flags & IPN_STICKY) != 0)) {
 		hm = nat_hostmap(NULL, fin->fin_src, fin->fin_dst, in,
 				 (u_32_t)dport);
 		if (hm != NULL) {
@@ -2004,7 +2177,7 @@
 		in.s_addr = np->in_nip;
 
 		if ((np->in_flags & (IPN_ROUNDR|IPN_STICKY)) == IPN_STICKY) {
-			hm = nat_hostmap(np, fin->fin_src, fin->fin_dst,
+			hm = nat_hostmap(NULL, fin->fin_src, fin->fin_dst,
 					 in, (u_32_t)dport);
 			if (hm != NULL) {
 				in.s_addr = hm->hm_mapip.s_addr;
@@ -2074,9 +2247,29 @@
 		in.s_addr = ntohl(fin->fin_daddr);
 	}
 
+	/*
+	 * Check to see if this redirect mapping already exists and if
+	 * it does, return "failure" (allowing it to be created will just
+	 * cause one or both of these "connections" to stop working.)
+	 */
+	inb.s_addr = htonl(in.s_addr);
+	sp = fin->fin_data[0];
+	dp = fin->fin_data[1];
+	fin->fin_data[1] = fin->fin_data[0];
+	fin->fin_data[0] = ntohs(nport);
+	natl = nat_outlookup(fin, flags & ~(SI_WILDP|NAT_SEARCH),
+			     (u_int)fin->fin_p, inb, fin->fin_src);
+	fin->fin_data[0] = sp;
+	fin->fin_data[1] = dp;
+	if (natl != NULL)
+		return -1;
+
 	nat->nat_inip.s_addr = htonl(in.s_addr);
 	nat->nat_outip = fin->fin_dst;
 	nat->nat_oip = fin->fin_src;
+	if ((nat->nat_hm == NULL) && ((np->in_flags & IPN_STICKY) != 0))
+		nat->nat_hm = nat_hostmap(np, fin->fin_src, fin->fin_dst, in,
+					  (u_32_t)dport);
 
 	ni->nai_sum1 = LONG_SUM(ntohl(fin->fin_daddr)) + ntohs(dport);
 	ni->nai_sum2 = LONG_SUM(in.s_addr) + ntohs(nport);
@@ -2128,6 +2321,9 @@
 /* structure for a "MAP" rule (outgoing NAT translation); (2) deal with     */
 /* creating a new NAT structure for a "RDR" rule (incoming NAT translation) */
 /* and (3) building that structure and putting it into the NAT table(s).    */
+/*                                                                          */
+/* NOTE: natsave should NOT be used top point back to an ipstate_t struct   */
+/*       as it can result in memory being corrupted.                        */
 /* ------------------------------------------------------------------------ */
 nat_t *nat_new(fin, np, natsave, flags, direction)
 fr_info_t *fin;
@@ -2151,6 +2347,7 @@
 
 	if (nat_stats.ns_inuse >= ipf_nattable_max) {
 		nat_stats.ns_memfail++;
+		fr_nat_doflush = 1;
 		return NULL;
 	}
 
@@ -2161,6 +2358,8 @@
 	ni.nai_np = np;
 	ni.nai_nflags = nflags;
 	ni.nai_flags = flags;
+	ni.nai_dport = 0;
+	ni.nai_sport = 0;
 
 	/* Give me a new nat */
 	KMALLOC(nat, nat_t *);
@@ -2204,6 +2403,7 @@
 
 	bzero((char *)nat, sizeof(*nat));
 	nat->nat_flags = flags;
+	nat->nat_redir = np->in_redir;
 
 	if ((flags & NAT_SLAVE) == 0) {
 		MUTEX_ENTER(&ipf_nat_new);
@@ -2221,6 +2421,7 @@
 		natl = nat_outlookup(fin, nflags, (u_int)fin->fin_p,
 				     fin->fin_src, fin->fin_dst);
 		if (natl != NULL) {
+			KFREE(nat);
 			nat = natl;
 			goto done;
 		}
@@ -2238,6 +2439,7 @@
 		natl = nat_inlookup(fin, nflags, (u_int)fin->fin_p,
 				    fin->fin_src, fin->fin_dst);
 		if (natl != NULL) {
+			KFREE(nat);
 			nat = natl;
 			goto done;
 		}
@@ -2306,15 +2508,17 @@
 	}
 
 	if (nat_finalise(fin, nat, &ni, tcp, natsave, direction) == -1) {
+		fr_nat_doflush = 1;
 		goto badnat;
 	}
 	if (flags & SI_WILDP)
 		nat_stats.ns_wilds++;
+	fin->fin_flx |= FI_NEWNAT;
 	goto done;
 badnat:
 	nat_stats.ns_badnat++;
 	if ((hm = nat->nat_hm) != NULL)
-		nat_hostmapdel(hm);
+		fr_hostmapdel(&hm);
 	KFREE(nat);
 	nat = NULL;
 done:
@@ -2338,7 +2542,7 @@
 /* for both IPv4 and IPv6.                                                  */
 /* ------------------------------------------------------------------------ */
 /*ARGSUSED*/
-static INLINE int nat_finalise(fin, nat, ni, tcp, natsave, direction)
+static int nat_finalise(fin, nat, ni, tcp, natsave, direction)
 fr_info_t *fin;
 nat_t *nat;
 natinfo_t *ni;
@@ -2351,7 +2555,12 @@
 
 	np = ni->nai_np;
 
-	COPYIFNAME(fin->fin_ifp, nat->nat_ifnames[0]);
+	if (np->in_ifps[0] != NULL) {
+		COPYIFNAME(4, np->in_ifps[0], nat->nat_ifnames[0]);
+	}
+	if (np->in_ifps[1] != NULL) {
+		COPYIFNAME(4, np->in_ifps[1], nat->nat_ifnames[1]);
+	}
 #ifdef	IPFILTER_SYNC
 	if ((nat->nat_flags & SI_CLONE) == 0)
 		nat->nat_sync = ipfsync_new(SMC_NAT, fin, nat);
@@ -2359,12 +2568,13 @@
 
 	nat->nat_me = natsave;
 	nat->nat_dir = direction;
-	nat->nat_ifps[0] = fin->fin_ifp;
+	nat->nat_ifps[0] = np->in_ifps[0];
+	nat->nat_ifps[1] = np->in_ifps[1];
 	nat->nat_ptr = np;
 	nat->nat_p = fin->fin_p;
 	nat->nat_mssclamp = np->in_mssclamp;
-	fr = fin->fin_fr;
-	nat->nat_fr = fr;
+	if (nat->nat_p == IPPROTO_TCP)
+		nat->nat_seqnext[0] = ntohl(tcp->th_seq);
 
 	if ((np->in_apr != NULL) && ((ni->nai_flags & NAT_SLAVE) == 0))
 		if (appr_new(fin, nat) == -1)
@@ -2374,6 +2584,8 @@
 		if (nat_logging)
 			nat_log(nat, (u_int)np->in_redir);
 		np->in_use++;
+		fr = fin->fin_fr;
+		nat->nat_fr = fr;
 		if (fr != NULL) {
 			MUTEX_ENTER(&fr->fr_lock);
 			fr->fr_ref++;
@@ -2446,7 +2658,7 @@
 	nat->nat_ifnames[0][LIFNAMSIZ - 1] = '\0';
 	nat->nat_ifps[0] = fr_resolvenic(nat->nat_ifnames[0], 4);
 
-	if (nat->nat_ifnames[1][0] !='\0') {
+	if (nat->nat_ifnames[1][0] != '\0') {
 		nat->nat_ifnames[1][LIFNAMSIZ - 1] = '\0';
 		nat->nat_ifps[1] = fr_resolvenic(nat->nat_ifnames[1], 4);
 	} else {
@@ -2515,8 +2727,7 @@
 	 * Only a basic IP header (no options) should be with an ICMP error
 	 * header.  Also, if it's not an error type, then return.
 	 */
-	if ((fin->fin_hlen != sizeof(ip_t)) ||
-	    !fr_icmp4errortype(type))
+	if ((fin->fin_hlen != sizeof(ip_t)) || !(fin->fin_flx & FI_ICMPERR))
 		return NULL;
 
 	/*
@@ -2636,9 +2847,9 @@
 int dir;
 {
 	u_32_t sum1, sum2, sumd, sumd2;
-	struct in_addr in;
+	struct in_addr a1, a2;
+	int flags, dlen, odst;
 	icmphdr_t *icmp;
-	int flags, dlen;
 	u_short *csump;
 	tcphdr_t *tcp;
 	nat_t *nat;
@@ -2689,33 +2900,7 @@
 	/*
 	 * Step 1
 	 * Fix the IP addresses in the offending IP packet. You also need
-	 * to adjust the IP header checksum of that offending IP packet
-	 * and the ICMP checksum of the ICMP error message itself.
-	 *
-	 * Unfortunately, for UDP and TCP, the IP addresses are also contained
-	 * in the pseudo header that is used to compute the UDP resp. TCP
-	 * checksum. So, we must compensate that as well. Even worse, the
-	 * change in the UDP and TCP checksums require yet another
-	 * adjustment of the ICMP checksum of the ICMP error message.
-	 */
-
-	if (oip->ip_dst.s_addr == nat->nat_oip.s_addr) {
-		sum1 = LONG_SUM(ntohl(oip->ip_src.s_addr));
-		in = nat->nat_inip;
-		oip->ip_src = in;
-	} else {
-		sum1 = LONG_SUM(ntohl(oip->ip_dst.s_addr));
-		in = nat->nat_outip;
-		oip->ip_dst = in;
-	}
-
-	sum2 = LONG_SUM(ntohl(in.s_addr));
-
-	CALC_SUMD(sum1, sum2, sumd);
-
-	/*
-	 * Fix IP checksum of the offending IP packet to adjust for
-	 * the change in the IP address.
+	 * to adjust the IP header checksum of that offending IP packet.
 	 *
 	 * Normally, you would expect that the ICMP checksum of the
 	 * ICMP error message needs to be adjusted as well for the
@@ -2727,217 +2912,134 @@
 	 * the IP address is x, then the delta for ip_sum is minus x),
 	 * so no change in the icmp_cksum is necessary.
 	 *
-	 * Be careful that nat_dir refers to the direction of the
-	 * offending IP packet (oip), not to its ICMP response (icmp)
-	 */
-	fix_datacksum(&oip->ip_sum, sumd);
-	/* Fix icmp cksum : IP Addr + Cksum */
-	sumd2 = (sumd >> 16);
-
-	/*
-	 * Fix UDP pseudo header checksum to compensate for the
-	 * IP address change.
+	 * Inbound ICMP
+	 * ------------
+	 * MAP rule, SRC=a,DST=b -> SRC=c,DST=b
+	 * - response to outgoing packet (a,b)=>(c,b) (OIP_SRC=c,OIP_DST=b)
+	 * - OIP_SRC(c)=nat_outip, OIP_DST(b)=nat_oip
+	 *
+	 * RDR rule, SRC=a,DST=b -> SRC=a,DST=c
+	 * - response to outgoing packet (c,a)=>(b,a) (OIP_SRC=b,OIP_DST=a)
+	 * - OIP_SRC(b)=nat_outip, OIP_DST(a)=nat_oip
+	 *
+	 * Outbound ICMP
+	 * -------------
+	 * MAP rule, SRC=a,DST=b -> SRC=c,DST=b
+	 * - response to incoming packet (b,c)=>(b,a) (OIP_SRC=b,OIP_DST=a)
+	 * - OIP_SRC(a)=nat_oip, OIP_DST(c)=nat_inip
+	 *
+	 * RDR rule, SRC=a,DST=b -> SRC=a,DST=c
+	 * - response to incoming packet (a,b)=>(a,c) (OIP_SRC=a,OIP_DST=c)
+	 * - OIP_SRC(a)=nat_oip, OIP_DST(c)=nat_inip
+	 *
 	 */
-	if ((oip->ip_p == IPPROTO_UDP) && (dlen >= 8) && (*csump != 0)) {
-		/*
-		 * The UDP checksum is optional, only adjust it
-		 * if it has been set.
-		 */
-		sum1 = ntohs(*csump);
-		fix_datacksum(csump, sumd);
-		sum2 = ntohs(*csump);
-
-		/*
-		 * Fix ICMP checksum to compensate the UDP
-		 * checksum adjustment.
-		 */
-		sumd2 = sumd << 1;
-		CALC_SUMD(sum1, sum2, sumd);
-		sumd2 += sumd;
+	odst = (oip->ip_dst.s_addr == nat->nat_oip.s_addr) ? 1 : 0;
+	if (odst == 1) {
+		a1.s_addr = ntohl(nat->nat_inip.s_addr);
+		a2.s_addr = ntohl(oip->ip_src.s_addr);
+		oip->ip_src.s_addr = htonl(a1.s_addr);
+	} else {
+		a1.s_addr = ntohl(nat->nat_outip.s_addr);
+		a2.s_addr = ntohl(oip->ip_dst.s_addr);
+		oip->ip_dst.s_addr = htonl(a1.s_addr);
 	}
 
-	/*
-	 * 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!).
-	 * 18 = offsetof(tcphdr_t, th_sum) + 2
-	 */
-	else if (oip->ip_p == IPPROTO_TCP && dlen >= 18) {
-		sum1 = ntohs(*csump);
-		fix_datacksum(csump, sumd);
-		sum2 = ntohs(*csump);
+	sumd = a2.s_addr - a1.s_addr;
+	if (sumd != 0) {
+		if (a1.s_addr > a2.s_addr)
+			sumd--;
+		sumd = ~sumd;
 
-		/*
-		 * Fix ICMP checksum to compensate the TCP
-		 * checksum adjustment.
-		 */
-		sumd2 = sumd << 1;
-		CALC_SUMD(sum1, sum2, sumd);
-		sumd2 += sumd;
-	} else {
-		if (nat->nat_dir == NAT_OUTBOUND)
-			sumd2 = ~sumd2;
-		else
-			sumd2 = ~sumd2 + 1;
+		fix_datacksum(&oip->ip_sum, sumd);
 	}
 
-	if (((flags & IPN_TCPUDP) != 0) && (dlen >= 4)) {
-		int mode = 0;
+	sumd2 = sumd;
+	sum1 = 0;
+	sum2 = 0;
 
+	/*
+	 * Fix UDP pseudo header checksum to compensate for the
+	 * IP address change.
+	 */
+	if (((flags & IPN_TCPUDP) != 0) && (dlen >= 4)) {
 		/*
 		 * Step 2 :
 		 * For offending TCP/UDP IP packets, translate the ports as
 		 * well, based on the NAT specification. Of course such
-		 * a change must be reflected in the ICMP checksum as well.
-		 *
-		 * Advance notice : Now it becomes complicated :-)
+		 * a change may be reflected in the ICMP checksum as well.
 		 *
 		 * Since the port fields are part of the TCP/UDP checksum
 		 * of the offending IP packet, you need to adjust that checksum
-		 * as well... but, if you change, you must change the icmp
-		 * checksum *again*, to reflect that change.
-		 *
-		 * 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. 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!
+		 * as well... except that the change in the port numbers should 
+		 * be offset by the checksum change.  However, the TCP/UDP
+		 * checksum will also need to change if there has been an
+		 * IP address change.
 		 */
+		if (odst == 1) {
+			sum1 = ntohs(nat->nat_inport);
+			sum2 = ntohs(tcp->th_sport);
 
-		if (nat->nat_oport == tcp->th_dport) { 
-			if (tcp->th_sport != nat->nat_inport) {
-				mode = 1;
-				sum1 = ntohs(nat->nat_inport);
-				sum2 = ntohs(tcp->th_sport);
-			}
-		} else if (tcp->th_sport == nat->nat_oport) {
-			mode = 2;
+			tcp->th_sport = htons(sum1);
+		} else {
 			sum1 = ntohs(nat->nat_outport);
 			sum2 = ntohs(tcp->th_dport);
-		}
 
-		if (mode == 1) {
-			/*
-			 * Fix ICMP checksum to compensate port adjustment.
-			 */
-			tcp->th_sport = htons(sum1);
+			tcp->th_dport = htons(sum1);
+		}
 
+		sumd += sum1 - sum2;
+		if (sumd != 0 || sumd2 != 0) {
 			/*
-			 * Fix udp checksum to compensate port adjustment.
-			 * NOTE : the offending IP packet flows the other
-			 * direction compared to the ICMP message.
+			 * At this point, sumd is the delta to apply to the
+			 * TCP/UDP header, given the changes in both the IP
+			 * address and the ports and sumd2 is the delta to
+			 * apply to the ICMP header, given the IP address
+			 * change delta that may need to be applied to the
+			 * TCP/UDP checksum instead.
 			 *
-			 * The UDP checksum is optional, only adjust it if
-			 * it has been set.
+			 * If we will both the IP and TCP/UDP checksums
+			 * then the ICMP checksum changes by the address
+			 * delta applied to the TCP/UDP checksum.  If we
+			 * do not change the TCP/UDP checksum them we
+			 * apply the delta in ports to the ICMP checksum.
 			 */
-			if ((oip->ip_p == IPPROTO_UDP) &&
-			    (dlen >= 8) && (*csump != 0)) {
-				sumd = sum1 - sum2;
-				sumd2 += sumd;
-
-				sum1 = ntohs(*csump);
-				fix_datacksum(csump, sumd);
-				sum2 = ntohs(*csump);
-
-				/*
-				 * Fix ICMP checksum to compenstate
-				 * UDP checksum adjustment.
-				 */
-				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) {
+			if (oip->ip_p == IPPROTO_UDP) {
+				if ((dlen >= 8) && (*csump != 0)) {
+					fix_datacksum(csump, sumd);
+				} else {
+					sumd2 = sum1 - sum2;
+					if (sum2 > sum1)
+						sumd2--;
+				}
+			} else if (oip->ip_p == IPPROTO_TCP) {
 				if (dlen >= 18) {
-					sumd = sum1 - sum2;
-					sumd2 += sumd;
-
-					sum1 = ntohs(*csump);
 					fix_datacksum(csump, sumd);
-					sum2 = ntohs(*csump);
-
-					/*
-					 * Fix ICMP checksum to compensate
-					 * TCP checksum adjustment.
-					 */
-					CALC_SUMD(sum1, sum2, sumd);
-					sumd2 += sumd;
 				} else {
-					sumd = sum2 - sum1 + 1;
-					sumd2 += sumd;
+					sumd2 = sum2 - sum1;
+					if (sum1 > sum2)
+						sumd2--;
 				}
 			}
-		} else if (mode == 2) {
-			/*
-			 * Fix ICMP checksum to compensate port adjustment.
-			 */
-			tcp->th_dport = htons(sum1);
-
-			/*
-			 * Fix UDP checksum to compensate port adjustment.
-			 * NOTE : the offending IP packet flows the other
-			 * direction compared to the ICMP message.
-			 *
-			 * The UDP checksum is optional, only adjust
-			 * it if it has been set.
-			 */
-			if ((oip->ip_p == IPPROTO_UDP) &&
-			    (dlen >= 8) && (*csump != 0)) {
-				sumd = sum1 - sum2;
-				sumd2 += sumd;
-
-				sum1 = ntohs(*csump);
-				fix_datacksum(csump, sumd);
-				sum2 = ntohs(*csump);
-
-				/*
-				 * Fix ICMP checksum to compensate
-				 * UDP checksum adjustment.
-				 */
-				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) {
-				if (dlen >= 18) {
-					sumd = sum1 - sum2;
-					sumd2 += sumd;
+			if (sumd2 != 0) {
+				ipnat_t *np;
 
-					sum1 = ntohs(*csump);
-					fix_datacksum(csump, sumd);
-					sum2 = ntohs(*csump);
-
-					/*
-					 * Fix ICMP checksum to compensate
-					 * TCP checksum adjustment.
-					 */
-					CALC_SUMD(sum1, sum2, sumd);
-					sumd2 += sumd;
+				np = nat->nat_ptr;
+				sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16);
+				sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16);
+				sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16);
+
+				if ((odst == 0) && (dir == NAT_OUTBOUND) &&
+				    (fin->fin_rev == 0) && (np != NULL) &&
+				    (np->in_redir & NAT_REDIRECT)) {
+					fix_outcksum(fin, &icmp->icmp_cksum,
+						     sumd2);
 				} else {
-					if (nat->nat_dir == NAT_INBOUND)
-						sumd = sum2 - sum1;
-					else
-						sumd = sum2 - sum1 + 1;
-					sumd2 += sumd;
+					fix_incksum(fin, &icmp->icmp_cksum,
+						    sumd2);
 				}
 			}
 		}
-		if (sumd2 != 0) {
-			sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16);
-			sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16);
-			fix_incksum(fin, &icmp->icmp_cksum, sumd2);
-		}
 	} else if (((flags & IPN_ICMPQUERY) != 0) && (dlen >= 8)) {
 		icmphdr_t *orgicmp;
 
@@ -2947,7 +3049,7 @@
 		 */
 		orgicmp = (icmphdr_t *)dp;
 
-		if (nat->nat_dir == NAT_OUTBOUND) {
+		if (odst == 1) {
 			if (orgicmp->icmp_id != nat->nat_inport) {
 
 				/*
@@ -3016,10 +3118,7 @@
 	void *ifp;
 	u_int hv;
 
-	if (fin != NULL)
-		ifp = fin->fin_ifp;
-	else
-		ifp = NULL;
+	ifp = fin->fin_ifp;
 	sport = 0;
 	dport = 0;
 	gre = NULL;
@@ -3051,17 +3150,13 @@
 	hv = NAT_HASH_FN(src.s_addr, hv + sport, ipf_nattable_sz);
 	nat = nat_table[1][hv];
 	for (; nat; nat = nat->nat_hnext[1]) {
-		nflags = nat->nat_flags;
+		if (nat->nat_ifps[0] != NULL) {
+			if ((ifp != NULL) && (ifp != nat->nat_ifps[0]))
+				continue;
+		} else if (ifp != NULL)
+			nat->nat_ifps[0] = ifp;
 
-		if (ifp != NULL) {
-			if (nat->nat_dir == NAT_REDIRECT) {
-				if (ifp != nat->nat_ifps[0])
-					continue;
-			} else {
-				if (ifp != nat->nat_ifps[1])
-					continue;
-			}
-		}
+		nflags = nat->nat_flags;
 
 		if (nat->nat_oip.s_addr == src.s_addr &&
 		    nat->nat_outip.s_addr == dst &&
@@ -3126,15 +3221,11 @@
 
 	nat = nat_table[1][hv];
 	for (; nat; nat = nat->nat_hnext[1]) {
-		if (ifp != NULL) {
-			if (nat->nat_dir == NAT_REDIRECT) {
-				if (ifp != nat->nat_ifps[0])
-					continue;
-			} else {
-				if (ifp != nat->nat_ifps[1])
-					continue;
-			}
-		}
+		if (nat->nat_ifps[0] != NULL) {
+			if ((ifp != NULL) && (ifp != nat->nat_ifps[0]))
+				continue;
+		} else if (ifp != NULL)
+			nat->nat_ifps[0] = ifp;
 
 		if (nat->nat_p != fin->fin_p)
 			continue;
@@ -3301,17 +3392,13 @@
 	hv = NAT_HASH_FN(dst.s_addr, hv + dport, ipf_nattable_sz);
 	nat = nat_table[0][hv];
 	for (; nat; nat = nat->nat_hnext[0]) {
-		nflags = nat->nat_flags;
+		if (nat->nat_ifps[1] != NULL) {
+			if ((ifp != NULL) && (ifp != nat->nat_ifps[1]))
+				continue;
+		} else if (ifp != NULL)
+			nat->nat_ifps[1] = ifp;
 
-		if (ifp != NULL) {
-			if (nat->nat_dir == NAT_REDIRECT) {
-				if (ifp != nat->nat_ifps[1])
-					continue;
-			} else {
-				if (ifp != nat->nat_ifps[0])
-					continue;
-			}
-		}
+		nflags = nat->nat_flags;
 
 		if (nat->nat_inip.s_addr == srcip &&
 		    nat->nat_oip.s_addr == dst.s_addr &&
@@ -3366,15 +3453,11 @@
 
 	nat = nat_table[0][hv];
 	for (; nat; nat = nat->nat_hnext[0]) {
-		if (ifp != NULL) {
-			if (nat->nat_dir == NAT_REDIRECT) {
-				if (ifp != nat->nat_ifps[1])
-					continue;
-			} else {
-				if (ifp != nat->nat_ifps[0])
-					continue;
-			}
-		}
+		if (nat->nat_ifps[1] != NULL) {
+			if ((ifp != NULL) && (ifp != nat->nat_ifps[1]))
+				continue;
+		} else if (ifp != NULL)
+			nat->nat_ifps[1] = ifp;
 
 		if (nat->nat_p != fin->fin_p)
 			continue;
@@ -3423,6 +3506,16 @@
 /*                      entry for.                                          */
 /*                                                                          */
 /* Lookup the NAT tables to search for a matching redirect                  */
+/* The contents of natlookup_t should imitate those found in a packet that  */
+/* would be translated - ie a packet coming in for RDR or going out for MAP.*/
+/* We can do the lookup in one of two ways, imitating an inbound or         */
+/* outbound  packet.  By default we assume outbound, unless IPN_IN is set.  */
+/* For IN, the fields are set as follows:                                   */
+/*     nl_real* = source information                                        */
+/*     nl_out* = destination information (translated)                       */
+/* For an out packet, the fields are set like this:                         */
+/*     nl_in* = source information (untranslated)                           */
+/*     nl_out* = destination information (translated)                       */
 /* ------------------------------------------------------------------------ */
 nat_t *nat_lookupredir(np)
 natlookup_t *np;
@@ -3571,6 +3664,26 @@
 		ifq2 = NULL;
 
 	if (nat->nat_p == IPPROTO_TCP && ifq2 == NULL) {
+		u_32_t end, ack;
+		u_char tcpflags;
+		tcphdr_t *tcp;
+		int dsize;
+
+		tcp = fin->fin_dp;
+		tcpflags = tcp->th_flags;
+		dsize = fin->fin_dlen - (TCP_OFF(tcp) << 2) +
+			((tcpflags & TH_SYN) ? 1 : 0) +
+			((tcpflags & TH_FIN) ? 1 : 0);
+
+		ack = ntohl(tcp->th_ack);
+		end = ntohl(tcp->th_seq) + dsize;
+
+		if (SEQ_GT(ack, nat->nat_seqnext[1 - fin->fin_rev]))
+			nat->nat_seqnext[1 - fin->fin_rev] = ack;
+
+		if (nat->nat_seqnext[fin->fin_rev] == 0)
+			nat->nat_seqnext[fin->fin_rev] = end;
+
 		(void) fr_tcp_age(&nat->nat_tqe, fin, nat_tqb, 0);
 	} else {
 		if (ifq2 == NULL) {
@@ -3624,9 +3737,11 @@
 	natfailed = 0;
 	fr = fin->fin_fr;
 	sifp = fin->fin_ifp;
-	if ((fr != NULL) && !(fr->fr_flags & FR_DUP) &&
-	    fr->fr_tif.fd_ifp && fr->fr_tif.fd_ifp != (void *)-1)
-		fin->fin_ifp = fr->fr_tif.fd_ifp;
+	if (fr != NULL) {
+		ifp = fr->fr_tifs[fin->fin_rev].fd_ifp;
+		if ((ifp != NULL) && (ifp != (void *)-1))
+			fin->fin_ifp = ifp;
+	}
 	ifp = fin->fin_ifp;
 
 	if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) {
@@ -3684,7 +3799,7 @@
 		hv = NAT_HASH_FN(iph, 0, ipf_natrules_sz);
 		for (np = nat_rules[hv]; np; np = np->in_mnext)
 		{
-			if ((np->in_ifps[0] && (np->in_ifps[0] != ifp)))
+			if ((np->in_ifps[1] && (np->in_ifps[1] != ifp)))
 				continue;
 			if (np->in_v != fin->fin_v)
 				continue;
@@ -3738,6 +3853,7 @@
 			MUTEX_ENTER(&nat->nat_lock);
 			nat->nat_ref++;
 			MUTEX_EXIT(&nat->nat_lock);
+			nat->nat_touched = fr_ticks;
 			fin->fin_nat = nat;
 		}
 	} else
@@ -3806,8 +3922,15 @@
 			CALC_SUMD(s1, s2, sumd);
 			fix_outcksum(fin, &fin->fin_ip->ip_sum, sumd);
 		}
-#if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) || defined(linux)
+#if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) || \
+    defined(linux) || defined(BRIDGE_IPF)
 		else {
+			/*
+			 * Strictly speaking, this isn't necessary on BSD
+			 * kernels because they do checksum calculation after
+			 * this code has run BUT if ipfilter is being used
+			 * to do NAT as a bridge, that code doesn't exist.
+			 */
 			if (nat->nat_dir == NAT_OUTBOUND)
 				fix_outcksum(fin, &fin->fin_ip->ip_sum,
 					     nat->nat_ipsumd);
@@ -4024,8 +4147,8 @@
 			MUTEX_ENTER(&nat->nat_lock);
 			nat->nat_ref++;
 			MUTEX_EXIT(&nat->nat_lock);
+			nat->nat_touched = fr_ticks;
 			fin->fin_nat = nat;
-			fin->fin_state = nat->nat_state;
 		}
 	} else
 		rval = natfailed;
@@ -4269,9 +4392,9 @@
 		KFREES(rdr_rules, sizeof(ipnat_t *) * ipf_rdrrules_sz);
 		rdr_rules = NULL;
 	}
-	if (maptable != NULL) {
-		KFREES(maptable, sizeof(hostmap_t *) * ipf_hostmap_sz);
-		maptable = NULL;
+	if (ipf_hm_maptable != NULL) {
+		KFREES(ipf_hm_maptable, sizeof(hostmap_t *) * ipf_hostmap_sz);
+		ipf_hm_maptable = NULL;
 	}
 	if (nat_stats.ns_bucketlen[0] != NULL) {
 		KFREES(nat_stats.ns_bucketlen[0],
@@ -4316,10 +4439,8 @@
 {
 	ipftq_t *ifq, *ifqnext;
 	ipftqent_t *tqe, *tqn;
-#if defined(_KERNEL) && !defined(MENTAT) && defined(USE_SPL)
-	int s;
-#endif
 	int i;
+	SPL_INT(s);
 
 	SPL_NET(s);
 	WRITE_ENTER(&ipf_nat);
@@ -4352,6 +4473,11 @@
 		}
 	}
 
+	if (fr_nat_doflush != 0) {
+		nat_extraflush(2);
+		fr_nat_doflush = 0;
+	}
+
 	RWLOCK_EXIT(&ipf_nat);
 	SPL_X(s);
 }
@@ -4373,9 +4499,7 @@
 	ipnat_t *n;
 	nat_t *nat;
 	void *ifp2;
-#if defined(_KERNEL) && !defined(MENTAT) && defined(USE_SPL)
-	int s;
-#endif
+	SPL_INT(s);
 
 	if (fr_running <= 0)
 		return;
@@ -4457,7 +4581,7 @@
 /* Tests to see if the ICMP type number passed is a query/response type or  */
 /* not.                                                                     */
 /* ------------------------------------------------------------------------ */
-static INLINE int nat_icmpquerytype4(icmptype)
+static int nat_icmpquerytype4(icmptype)
 int icmptype;
 {
 
@@ -4563,12 +4687,50 @@
 
 
 /* ------------------------------------------------------------------------ */
+/* Function:    fr_ipnatderef                                               */
+/* Returns:     Nil                                                         */
+/* Parameters:  isp(I) - pointer to pointer to NAT rule                     */
+/* Write Locks: ipf_nat                                                     */
+/*                                                                          */
+/* ------------------------------------------------------------------------ */
+void fr_ipnatderef(inp)
+ipnat_t **inp;
+{
+	ipnat_t *in;
+
+	in = *inp;
+	*inp = NULL;
+	in->in_space++;
+	in->in_use--;
+	if (in->in_use == 0 && (in->in_flags & IPN_DELETE)) {
+		if (in->in_apr)
+			appr_free(in->in_apr);
+		MUTEX_DESTROY(&in->in_lock);
+		KFREE(in);
+		nat_stats.ns_rules--;
+#if SOLARIS && !defined(_INET_IP_STACK_H)
+		if (nat_stats.ns_rules == 0)
+			pfil_delayed_copy = 1;
+#endif
+	}
+}
+
+
+/* ------------------------------------------------------------------------ */
 /* Function:    fr_natderef                                                 */
 /* Returns:     Nil                                                         */
 /* Parameters:  isp(I) - pointer to pointer to NAT table entry              */
 /*                                                                          */
 /* Decrement the reference counter for this NAT table entry and free it if  */
 /* there are no more things using it.                                       */
+/*                                                                          */
+/* IF nat_ref == 1 when this function is called, then we have an orphan nat */
+/* structure *because* it only gets called on paths _after_ nat_ref has been*/
+/* incremented.  If nat_ref == 1 then we shouldn't decrement it here        */
+/* because nat_delete() will do that and send nat_ref to -1.                */
+/*                                                                          */
+/* Holding the lock on nat_lock is required to serialise nat_delete() being */
+/* called from a NAT flush ioctl with a deref happening because of a packet.*/
 /* ------------------------------------------------------------------------ */
 void fr_natderef(natp)
 nat_t **natp;
@@ -4577,10 +4739,17 @@
 
 	nat = *natp;
 	*natp = NULL;
+
+	MUTEX_ENTER(&nat->nat_lock);
+	if (nat->nat_ref > 1) {
+		nat->nat_ref--;
+		MUTEX_EXIT(&nat->nat_lock);
+		return;
+	}
+	MUTEX_EXIT(&nat->nat_lock);
+
 	WRITE_ENTER(&ipf_nat);
-	nat->nat_ref--;
-	if (nat->nat_ref == 0)
-		nat_delete(nat, NL_EXPIRE);
+	nat_delete(nat, NL_EXPIRE);
 	RWLOCK_EXIT(&ipf_nat);
 }
 
@@ -4610,9 +4779,20 @@
 
 	MUTEX_NUKE(&clone->nat_lock);
 
+	clone->nat_aps = NULL;
+	/*
+	 * Initialize all these so that nat_delete() doesn't cause a crash.
+	 */
+	clone->nat_tqe.tqe_pnext = NULL;
+	clone->nat_tqe.tqe_next = NULL;
+	clone->nat_tqe.tqe_ifq = NULL;
+	clone->nat_tqe.tqe_parent = clone;
+
 	clone->nat_flags &= ~SI_CLONE;
 	clone->nat_flags |= SI_CLONED;
 
+	if (clone->nat_hm)
+		clone->nat_hm->hm_ref++;
 
 	if (nat_insert(clone, fin->fin_rev) == -1) {
 		KFREE(clone);
@@ -4631,14 +4811,13 @@
 		MUTEX_EXIT(&fr->fr_lock);
 	}
 
-
 	/*
 	 * Because the clone is created outside the normal loop of things and
 	 * TCP has special needs in terms of state, initialise the timeout
 	 * state of the new NAT from here.
 	 */
 	if (clone->nat_p == IPPROTO_TCP) {
-		(void) fr_tcp_age(&clone->nat_tqe, fin, nat_tqb, \
+		(void) fr_tcp_age(&clone->nat_tqe, fin, nat_tqb,
 				  clone->nat_flags);
 	}
 #ifdef	IPFILTER_SYNC
@@ -4663,7 +4842,7 @@
 /* Use NAT entry and packet direction to determine which combination of     */
 /* wildcard flags should be used.                                           */
 /* ------------------------------------------------------------------------ */
-static INLINE int nat_wildok(nat, sport, dport, flags, dir)
+static int nat_wildok(nat, sport, dport, flags, dir)
 nat_t *nat;
 int sport;
 int dport;
@@ -4833,3 +5012,449 @@
 		fr_queueappend(&nat->nat_tqe, nifq, nat);
 	return;
 }
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    nat_getnext                                                 */
+/* Returns:     int - 0 == ok, else error                                   */
+/* Parameters:  t(I)   - pointer to ipftoken structure                      */
+/*              itp(I) - pointer to ipfgeniter_t structure                  */
+/*                                                                          */
+/* Fetch the next nat/ipnat structure pointer from the linked list and      */
+/* copy it out to the storage space pointed to by itp_data.  The next item  */
+/* in the list to look at is put back in the ipftoken struture.             */
+/* If we call ipf_freetoken, the accompanying pointer is set to NULL because*/
+/* ipf_freetoken will call a deref function for us and we dont want to call */
+/* that twice (second time would be in the second switch statement below.   */
+/* ------------------------------------------------------------------------ */
+static int nat_getnext(t, itp)
+ipftoken_t *t;
+ipfgeniter_t *itp;
+{
+	hostmap_t *hm, *nexthm = NULL, zerohm;
+	ipnat_t *ipn, *nextipnat = NULL, zeroipn;
+	nat_t *nat, *nextnat = NULL, zeronat;
+	int error = 0, count;
+	char *dst;
+
+	count = itp->igi_nitems;
+	if (count < 1)
+		return ENOSPC;
+
+	READ_ENTER(&ipf_nat);
+
+	switch (itp->igi_type)
+	{
+	case IPFGENITER_HOSTMAP :
+		hm = t->ipt_data;
+		if (hm == NULL) {
+			nexthm = ipf_hm_maplist;
+		} else {
+			nexthm = hm->hm_next;
+		}
+		break;
+
+	case IPFGENITER_IPNAT :
+		ipn = t->ipt_data;
+		if (ipn == NULL) {
+			nextipnat = nat_list;
+		} else {
+			nextipnat = ipn->in_next;
+		}
+		break;
+
+	case IPFGENITER_NAT :
+		nat = t->ipt_data;
+		if (nat == NULL) {
+			nextnat = nat_instances;
+		} else {
+			nextnat = nat->nat_next;
+		}
+		break;
+	default :
+		RWLOCK_EXIT(&ipf_nat);
+		return EINVAL;
+	}
+
+	dst = itp->igi_data;
+	for (;;) {
+		switch (itp->igi_type)
+		{
+		case IPFGENITER_HOSTMAP :
+			if (nexthm != NULL) {
+				if (count == 1) {
+					ATOMIC_INC32(nexthm->hm_ref);
+					t->ipt_data = nexthm;
+				}
+			} else {
+				bzero(&zerohm, sizeof(zerohm));
+				nexthm = &zerohm;
+				count = 1;
+				t->ipt_data = NULL;
+			}
+			break;
+
+		case IPFGENITER_IPNAT :
+			if (nextipnat != NULL) {
+				if (count == 1) {
+					MUTEX_ENTER(&nextipnat->in_lock);
+					nextipnat->in_use++;
+					MUTEX_EXIT(&nextipnat->in_lock);
+					t->ipt_data = nextipnat;
+				}
+			} else {
+				bzero(&zeroipn, sizeof(zeroipn));
+				nextipnat = &zeroipn;
+				count = 1;
+				t->ipt_data = NULL;
+			}
+			break;
+
+		case IPFGENITER_NAT :
+			if (nextnat != NULL) {
+				if (count == 1) {
+					MUTEX_ENTER(&nextnat->nat_lock);
+					nextnat->nat_ref++;
+					MUTEX_EXIT(&nextnat->nat_lock);
+					t->ipt_data = nextnat;
+				}
+			} else {
+				bzero(&zeronat, sizeof(zeronat));
+				nextnat = &zeronat;
+				count = 1;
+				t->ipt_data = NULL;
+			}
+			break;
+		default :
+			break;
+		}
+		RWLOCK_EXIT(&ipf_nat);
+
+		/*
+		 * Copying out to user space needs to be done without the lock.
+		 */
+		switch (itp->igi_type)
+		{
+		case IPFGENITER_HOSTMAP :
+			error = COPYOUT(nexthm, dst, sizeof(*nexthm));
+			if (error != 0)
+				error = EFAULT;
+			else
+				dst += sizeof(*nexthm);
+			break;
+
+		case IPFGENITER_IPNAT :
+			error = COPYOUT(nextipnat, dst, sizeof(*nextipnat));
+			if (error != 0)
+				error = EFAULT;
+			else
+				dst += sizeof(*nextipnat);
+			break;
+
+		case IPFGENITER_NAT :
+			error = COPYOUT(nextnat, dst, sizeof(*nextnat));
+			if (error != 0)
+				error = EFAULT;
+			else
+				dst += sizeof(*nextnat);
+			break;
+		}
+
+		if ((count == 1) || (error != 0))
+			break;
+
+		count--;
+
+		READ_ENTER(&ipf_nat);
+
+		/*
+		 * We need to have the lock again here to make sure that
+		 * using _next is consistent.
+		 */
+		switch (itp->igi_type)
+		{
+		case IPFGENITER_HOSTMAP :
+			nexthm = nexthm->hm_next;
+			break;
+		case IPFGENITER_IPNAT :
+			nextipnat = nextipnat->in_next;
+			break;
+		case IPFGENITER_NAT :
+			nextnat = nextnat->nat_next;
+			break;
+		}
+	}
+
+
+	switch (itp->igi_type)
+	{
+	case IPFGENITER_HOSTMAP :
+		if (hm != NULL) {
+			WRITE_ENTER(&ipf_nat);
+			fr_hostmapdel(&hm);
+			RWLOCK_EXIT(&ipf_nat);
+		}
+		break;
+	case IPFGENITER_IPNAT :
+		if (ipn != NULL) {
+			fr_ipnatderef(&ipn);
+		}
+		break;
+	case IPFGENITER_NAT :
+		if (nat != NULL) {
+			fr_natderef(&nat);
+		}
+		break;
+	default :
+		break;
+	}
+
+	return error;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    nat_iterator                                                */
+/* Returns:     int - 0 == ok, else error                                   */
+/* Parameters:  token(I) - pointer to ipftoken structure                    */
+/*              itp(I) - pointer to ipfgeniter_t structure                  */
+/*                                                                          */
+/* This function acts as a handler for the SIOCGENITER ioctls that use a    */
+/* generic structure to iterate through a list.  There are three different  */
+/* linked lists of NAT related information to go through: NAT rules, active */
+/* NAT mappings and the NAT fragment cache.                                 */
+/* ------------------------------------------------------------------------ */
+static int nat_iterator(token, itp)
+ipftoken_t *token;
+ipfgeniter_t *itp;
+{
+	int error;
+
+	if (itp->igi_data == NULL)
+		return EFAULT;
+
+	token->ipt_subtype = itp->igi_type;
+
+	switch (itp->igi_type)
+	{
+	case IPFGENITER_HOSTMAP :
+	case IPFGENITER_IPNAT :
+	case IPFGENITER_NAT :
+		error = nat_getnext(token, itp);
+		break;
+
+	case IPFGENITER_NATFRAG :
+#ifdef USE_MUTEXES
+		error = fr_nextfrag(token, itp, &ipfr_natlist,
+				    &ipfr_nattail, &ipf_natfrag);
+#else
+		error = fr_nextfrag(token, itp, &ipfr_natlist, &ipfr_nattail);
+#endif
+		break;
+	default :
+		error = EINVAL;
+		break;
+	}
+
+	return error;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    nat_extraflush                                              */
+/* Returns:     int - 0 == success, -1 == failure                           */
+/* Parameters:  which(I) - how to flush the active NAT table                */
+/* Write Locks: ipf_nat                                                     */
+/*                                                                          */
+/* Flush nat tables.  Three actions currently defined:                      */
+/* which == 0 : flush all nat table entries                                 */
+/* which == 1 : flush TCP connections which have started to close but are   */
+/*	      stuck for some reason.                                        */
+/* which == 2 : flush TCP connections which have been idle for a long time, */
+/*	      starting at > 4 days idle and working back in successive half-*/
+/*	      days to at most 12 hours old.  If this fails to free enough   */
+/*            slots then work backwards in half hour slots to 30 minutes.   */
+/*            If that too fails, then work backwards in 30 second intervals */
+/*            for the last 30 minutes to at worst 30 seconds idle.          */
+/* ------------------------------------------------------------------------ */
+static int nat_extraflush(which)
+int which;
+{
+	ipftq_t *ifq, *ifqnext;
+	nat_t *nat, **natp;
+	ipftqent_t *tqn;
+	int removed;
+	SPL_INT(s);
+
+	removed = 0;
+
+	SPL_NET(s);
+
+	switch (which)
+	{
+	case 0 :
+		/*
+		 * Style 0 flush removes everything...
+		 */
+		for (natp = &nat_instances; ((nat = *natp) != NULL); ) {
+			nat_delete(nat, NL_FLUSH);
+			removed++;
+		}
+		break;
+
+	case 1 :
+		/*
+		 * Since we're only interested in things that are closing,
+		 * we can start with the appropriate timeout queue.
+		 */
+		for (ifq = nat_tqb + IPF_TCPS_CLOSE_WAIT; ifq != NULL;
+		     ifq = ifq->ifq_next) {
+
+			for (tqn = ifq->ifq_head; tqn != NULL; ) {
+				nat = tqn->tqe_parent;
+				tqn = tqn->tqe_next;
+				if (nat->nat_p != IPPROTO_TCP)
+					break;
+				nat_delete(nat, NL_EXPIRE);
+				removed++;
+			}
+		}
+
+		/*
+		 * Also need to look through the user defined queues.
+		 */
+		for (ifq = nat_utqe; ifq != NULL; ifq = ifqnext) {
+			ifqnext = ifq->ifq_next;
+			for (tqn = ifq->ifq_head; tqn != NULL; ) {
+				nat = tqn->tqe_parent;
+				tqn = tqn->tqe_next;
+				if (nat->nat_p != IPPROTO_TCP)
+					continue;
+
+				if ((nat->nat_tcpstate[0] >
+				     IPF_TCPS_ESTABLISHED) &&
+				    (nat->nat_tcpstate[1] >
+				     IPF_TCPS_ESTABLISHED)) {
+					nat_delete(nat, NL_EXPIRE);
+					removed++;
+				}
+			}
+		}
+		break;
+
+		/*
+		 * Args 5-11 correspond to flushing those particular states
+		 * for TCP connections.
+		 */
+	case IPF_TCPS_CLOSE_WAIT :
+	case IPF_TCPS_FIN_WAIT_1 :
+	case IPF_TCPS_CLOSING :
+	case IPF_TCPS_LAST_ACK :
+	case IPF_TCPS_FIN_WAIT_2 :
+	case IPF_TCPS_TIME_WAIT :
+	case IPF_TCPS_CLOSED :
+		tqn = nat_tqb[which].ifq_head;
+		while (tqn != NULL) {
+			nat = tqn->tqe_parent;
+			tqn = tqn->tqe_next;
+			nat_delete(nat, NL_FLUSH);
+			removed++;
+		}
+		break;
+	 
+	default :
+		if (which < 30)
+			break;
+	   
+		/*
+		 * Take a large arbitrary number to mean the number of seconds
+		 * for which which consider to be the maximum value we'll allow
+		 * the expiration to be.
+		 */
+		which = IPF_TTLVAL(which);
+		for (natp = &nat_instances; ((nat = *natp) != NULL); ) {
+			if (fr_ticks - nat->nat_touched > which) {
+				nat_delete(nat, NL_FLUSH);
+				removed++;
+			} else
+				natp = &nat->nat_next;
+		}
+		break;
+	}
+
+	if (which != 2) {
+		SPL_X(s);
+		return removed;
+	}
+
+	/*
+	 * Asked to remove inactive entries because the table is full.
+	 */
+	if (fr_ticks - nat_last_force_flush > IPF_TTLVAL(5)) {
+		nat_last_force_flush = fr_ticks;
+		removed = ipf_queueflush(nat_flush_entry, nat_tqb, nat_utqe);
+	}
+
+	SPL_X(s);
+	return removed;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    nat_flush_entry                                             */
+/* Returns:     0 - always succeeds                                         */
+/* Parameters:  entry(I) - pointer to NAT entry                             */
+/* Write Locks: ipf_nat                                                     */
+/*                                                                          */
+/* This function is a stepping stone between ipf_queueflush() and           */
+/* nat_dlete().  It is used so we can provide a uniform interface via the   */
+/* ipf_queueflush() function.  Since the nat_delete() function returns void */
+/* we translate that to mean it always succeeds in deleting something.      */
+/* ------------------------------------------------------------------------ */
+static int nat_flush_entry(entry)
+void *entry;
+{
+	nat_delete(entry, NL_FLUSH);
+	return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    nat_gettable                                                */
+/* Returns:     int     - 0 = success, else error                           */
+/* Parameters:  data(I) - pointer to ioctl data                             */
+/*                                                                          */
+/* This function handles ioctl requests for tables of nat information.      */
+/* At present the only table it deals with is the hash bucket statistics.   */
+/* ------------------------------------------------------------------------ */
+static int nat_gettable(data)
+char *data;
+{
+	ipftable_t table;
+	int error;
+
+	error = fr_inobj(data, &table, IPFOBJ_GTABLE);
+	if (error != 0)
+		return error;
+
+	switch (table.ita_type)
+	{
+	case IPFTABLE_BUCKETS_NATIN :
+		error = COPYOUT(nat_stats.ns_bucketlen[0], table.ita_table, 
+				ipf_nattable_sz * sizeof(u_long));
+		break;
+
+	case IPFTABLE_BUCKETS_NATOUT :
+		error = COPYOUT(nat_stats.ns_bucketlen[1], table.ita_table, 
+				ipf_nattable_sz * sizeof(u_long));
+		break;
+
+	default :
+		return EINVAL;
+	}
+
+	if (error != 0) {
+		error = EFAULT;
+	}
+	return error;
+}
Index: ip_ftp_pxy.c
===================================================================
RCS file: /home/cvs/src/sys/contrib/ipfilter/netinet/ip_ftp_pxy.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/contrib/ipfilter/netinet/ip_ftp_pxy.c -L sys/contrib/ipfilter/netinet/ip_ftp_pxy.c -u -r1.1.1.1 -r1.2
--- sys/contrib/ipfilter/netinet/ip_ftp_pxy.c
+++ sys/contrib/ipfilter/netinet/ip_ftp_pxy.c
@@ -1,4 +1,4 @@
-/*	$FreeBSD: src/sys/contrib/ipfilter/netinet/ip_ftp_pxy.c,v 1.25 2005/04/25 18:43:14 darrenr Exp $	*/
+/*	$FreeBSD: src/sys/contrib/ipfilter/netinet/ip_ftp_pxy.c,v 1.28 2007/06/04 02:54:35 darrenr Exp $	*/
 
 /*
  * Copyright (C) 1997-2003 by Darren Reed
@@ -8,8 +8,8 @@
  * Simple FTP transparent proxy for in-kernel use.  For use with the NAT
  * code.
  *
- * $FreeBSD: src/sys/contrib/ipfilter/netinet/ip_ftp_pxy.c,v 1.25 2005/04/25 18:43:14 darrenr Exp $
- * Id: ip_ftp_pxy.c,v 2.88.2.15 2005/03/19 19:38:10 darrenr Exp
+ * $FreeBSD: src/sys/contrib/ipfilter/netinet/ip_ftp_pxy.c,v 1.28 2007/06/04 02:54:35 darrenr Exp $
+ * Id: ip_ftp_pxy.c,v 2.88.2.19 2006/04/01 10:14:53 darrenr Exp $
  */
 
 #define	IPF_FTP_PROXY
@@ -369,26 +369,13 @@
 				fi.fin_fi.fi_daddr = nat->nat_inip.s_addr;
 				ip->ip_dst = nat->nat_inip;
 			}
-			(void) fr_addstate(&fi, &nat2->nat_state, SI_W_DPORT);
+			(void) fr_addstate(&fi, NULL, SI_W_DPORT);
 			if (fi.fin_state != NULL)
-				fr_statederef(&fi, (ipstate_t **)&fi.fin_state);
+				fr_statederef((ipstate_t **)&fi.fin_state);
 		}
 		ip->ip_len = slen;
 		ip->ip_src = swip;
 		ip->ip_dst = swip2;
-	} else {
-		ipstate_t *is;
-
-		nat_update(&fi, nat2, nat->nat_ptr);
-		READ_ENTER(&ipf_state);
-		is = nat2->nat_state;
-		if (is != NULL) {
-			MUTEX_ENTER(&is->is_lock);
-			(void)fr_tcp_age(&is->is_sti, &fi, ips_tqtqb,
-					 is->is_flags);
-			MUTEX_EXIT(&is->is_lock);
-		}
-		RWLOCK_EXIT(&ipf_state);
 	}
 	return APR_INC(inc);
 }
@@ -474,9 +461,10 @@
 {
 	u_int a1, a2, a3, a4, data_ip;
 	char newbuf[IPF_FTPBUFSZ];
-	char *s, *brackets[2];
+	const char *brackets[2];
 	u_short a5, a6;
 	ftpside_t *f;
+	char *s;
 
 	if (ippr_ftp_forcepasv != 0 &&
 	    ftp->ftp_side[0].ftps_cmds != FTPXY_C_PASV) {
@@ -730,27 +718,14 @@
 				fi.fin_fi.fi_daddr = nat->nat_inip.s_addr;
 				ip->ip_dst = nat->nat_inip;
 			}
-			(void) fr_addstate(&fi, &nat2->nat_state, sflags);
+			(void) fr_addstate(&fi, NULL, sflags);
 			if (fi.fin_state != NULL)
-				fr_statederef(&fi, (ipstate_t **)&fi.fin_state);
+				fr_statederef((ipstate_t **)&fi.fin_state);
 		}
 
 		ip->ip_len = slen;
 		ip->ip_src = swip;
 		ip->ip_dst = swip2;
-	} else {
-		ipstate_t *is;
-
-		nat_update(&fi, nat2, nat->nat_ptr);
-		READ_ENTER(&ipf_state);
-		is = nat2->nat_state;
-		if (is != NULL) {
-			MUTEX_ENTER(&is->is_lock);
-			(void)fr_tcp_age(&is->is_sti, &fi, ips_tqtqb,
-					 is->is_flags);
-			MUTEX_EXIT(&is->is_lock);
-		}
-		RWLOCK_EXIT(&ipf_state);
 	}
 	return inc;
 }
@@ -1029,13 +1004,14 @@
 	if (ippr_ftp_debug > 4)
 		printf("ippr_ftp_process: mlen %d\n", mlen);
 
-	if (mlen <= 0) {
-		if ((tcp->th_flags & TH_OPENING) == TH_OPENING) {
-			f->ftps_seq[0] = thseq + 1;
-			t->ftps_seq[0] = thack;
-		}
+	if ((mlen == 0) && ((tcp->th_flags & TH_OPENING) == TH_OPENING)) {
+		f->ftps_seq[0] = thseq + 1;
+		t->ftps_seq[0] = thack;
+		return 0;
+	} else if (mlen < 0) {
 		return 0;
 	}
+
 	aps = nat->nat_aps;
 
 	sel = aps->aps_sel[1 - rv];
@@ -1142,8 +1118,8 @@
 				f->ftps_seq[1] = thseq + 1 - seqoff;
 			} else {
 				if (ippr_ftp_debug > 1) {
-					printf("FIN: thseq %x seqoff %d ftps_seq %x\n",
-					       thseq, seqoff, f->ftps_seq[0]);
+					printf("FIN: thseq %x seqoff %d ftps_seq %x %x\n",
+					       thseq, seqoff, f->ftps_seq[0], f->ftps_seq[1]);
 				}
 				return APR_ERR(1);
 			}
@@ -1425,7 +1401,7 @@
 		ap += *s++ - '0';
 	}
 
-	if (!s)
+	if (!*s)
 		return 0;
 
 	if (*s == '|')
Index: mlfk_ipl.c
===================================================================
RCS file: /home/cvs/src/sys/contrib/ipfilter/netinet/mlfk_ipl.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/contrib/ipfilter/netinet/mlfk_ipl.c -L sys/contrib/ipfilter/netinet/mlfk_ipl.c -u -r1.1.1.1 -r1.2
--- sys/contrib/ipfilter/netinet/mlfk_ipl.c
+++ sys/contrib/ipfilter/netinet/mlfk_ipl.c
@@ -1,9 +1,9 @@
-/*	$FreeBSD: src/sys/contrib/ipfilter/netinet/mlfk_ipl.c,v 1.16 2005/04/25 18:43:14 darrenr Exp $	*/
+/*	$FreeBSD: src/sys/contrib/ipfilter/netinet/mlfk_ipl.c,v 1.19.2.1 2007/10/31 05:00:38 darrenr Exp $	*/
 
 /*
  * Copyright (C) 2000 by Darren Reed.
  *
- * $FreeBSD: src/sys/contrib/ipfilter/netinet/mlfk_ipl.c,v 1.16 2005/04/25 18:43:14 darrenr Exp $
+ * $FreeBSD: src/sys/contrib/ipfilter/netinet/mlfk_ipl.c,v 1.19.2.1 2007/10/31 05:00:38 darrenr Exp $
  * See the IPFILTER.LICENCE file for details on licencing.
  */
 
@@ -15,6 +15,10 @@
 #include <sys/conf.h>
 #include <sys/socket.h>
 #include <sys/sysctl.h>
+#include <sys/select.h>
+#if __FreeBSD_version >= 500000
+# include <sys/selinfo.h>
+#endif                  
 #include <net/if.h>
 #include <netinet/in_systm.h>
 #include <netinet/in.h>
@@ -27,6 +31,7 @@
 #include <netinet/ip_nat.h>
 #include <netinet/ip_auth.h>
 #include <netinet/ip_frag.h>
+#include <netinet/ip_sync.h>
 
 #if __FreeBSD_version >= 502116
 static struct cdev *ipf_devs[IPL_LOGSIZE];
@@ -94,7 +99,11 @@
 SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_minttl, CTLFLAG_RW, &fr_minttl, 0, "");
 
 #define CDEV_MAJOR 79
-#if __FreeBSD_version >= 501000
+#include <sys/poll.h>
+#if __FreeBSD_version >= 500043
+# include <sys/select.h>
+static int iplpoll(struct cdev *dev, int events, struct thread *td);
+
 static struct cdevsw ipl_cdevsw = {
 # if __FreeBSD_version >= 502103
 	.d_version =	D_VERSION,
@@ -103,20 +112,26 @@
 	.d_open =	iplopen,
 	.d_close =	iplclose,
 	.d_read =	iplread,
+	.d_write =	iplwrite,
 	.d_ioctl =	iplioctl,
 	.d_name =	"ipl",
+# if __FreeBSD_version >= 500043
+	.d_poll =	iplpoll,
+# endif
 # if __FreeBSD_version < 600000
 	.d_maj =	CDEV_MAJOR,
 # endif
 };
 #else
+static int iplpoll(dev_t dev, int events, struct proc *p);
+
 static struct cdevsw ipl_cdevsw = {
 	/* open */	iplopen,
 	/* close */	iplclose,
 	/* read */	iplread,
 	/* write */	iplwrite,
 	/* ioctl */	iplioctl,
-	/* poll */	nopoll,
+	/* poll */	iplpoll,
 	/* mmap */	nommap,
 	/* strategy */	nostrategy,
 	/* name */	"ipl",
@@ -127,7 +142,9 @@
 # if (__FreeBSD_version < 500043)
 	/* bmaj */	-1,
 # endif
+# if (__FreeBSD_version > 430000)
 	/* kqfilter */	NULL
+# endif
 };
 #endif
 
@@ -163,9 +180,17 @@
 	char *defpass, *c, *str;
 	int i, j, error;
 
-	error = iplattach();
-	if (error)
+	RWLOCK_INIT(&ipf_global, "ipf filter load/unload mutex");
+	RWLOCK_INIT(&ipf_mutex, "ipf filter rwlock");
+	RWLOCK_INIT(&ipf_frcache, "ipf cache rwlock");
+
+	error = ipfattach();
+	if (error) {
+		RW_DESTROY(&ipf_global);
+		RW_DESTROY(&ipf_mutex);
+		RW_DESTROY(&ipf_frcache);
 		return error;
+	}
 
 	for (i = 0; i < IPL_LOGSIZE; i++)
 		ipf_devs[i] = NULL;
@@ -182,6 +207,11 @@
 		ipf_devs[i] = make_dev(&ipl_cdevsw, i, 0, 0, 0600, c);
 	}
 
+	error = ipf_pfil_hook();
+	if (error != 0)
+		return error;
+	ipf_event_reg();
+
 	if (FR_ISPASS(fr_pass))
 		defpass = "pass";
 	else if (FR_ISBLOCK(fr_pass))
@@ -215,12 +245,20 @@
 		return EBUSY;
 
 	if (fr_running >= 0) {
-		error = ipldetach();
+		ipf_pfil_unhook();
+		ipf_event_dereg();
+		WRITE_ENTER(&ipf_global);
+		error = ipfdetach();
+		RWLOCK_EXIT(&ipf_global);
 		if (error != 0)
 			return error;
 	} else
 		error = 0;
 
+	RW_DESTROY(&ipf_global);
+	RW_DESTROY(&ipf_mutex);
+	RW_DESTROY(&ipf_frcache);
+
 	fr_running = -2;
 
 	for (i = 0; ipf_devfiles[i]; i++) {
@@ -272,3 +310,53 @@
 	return (error);
 }
 #endif
+
+
+static int
+#if __FreeBSD_version >= 500043
+iplpoll(struct cdev *dev, int events, struct thread *td)
+#else
+iplpoll(dev_t dev, int events, struct proc *td)
+#endif
+{
+	u_int xmin = GET_MINOR(dev);
+	int revents;
+
+	if (xmin < 0 || xmin > IPL_LOGMAX)
+		return 0;
+
+	revents = 0;
+
+	switch (xmin) 
+	{
+	case IPL_LOGIPF :
+	case IPL_LOGNAT :
+	case IPL_LOGSTATE :
+#ifdef IPFILTER_LOG
+		if ((events & (POLLIN | POLLRDNORM)) && ipflog_canread(xmin))
+			revents |= events & (POLLIN | POLLRDNORM);
+#endif  
+		break;
+	case IPL_LOGAUTH :
+		if ((events & (POLLIN | POLLRDNORM)) && fr_auth_waiting())
+			revents |= events & (POLLIN | POLLRDNORM);
+		break; 
+	case IPL_LOGSYNC :
+#ifdef IPFILTER_SYNC
+		if ((events & (POLLIN | POLLRDNORM)) && ipfsync_canread())
+			revents |= events & (POLLIN | POLLRDNORM);
+		if ((events & (POLLOUT | POLLWRNORM)) && ipfsync_canwrite())
+			revents |= events & (POLLOUT | POLLWRNORM);
+#endif
+		break;
+	case IPL_LOGSCAN :
+	case IPL_LOGLOOKUP :
+	default :
+		break;
+	}
+
+	if ((revents == 0) && ((events & (POLLIN|POLLRDNORM)) != 0))
+		selrecord(td, &ipfselwait[xmin]);
+
+	return revents;
+}
Index: ip_pool.h
===================================================================
RCS file: /home/cvs/src/sys/contrib/ipfilter/netinet/ip_pool.h,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/contrib/ipfilter/netinet/ip_pool.h -L sys/contrib/ipfilter/netinet/ip_pool.h -u -r1.1.1.1 -r1.2
--- sys/contrib/ipfilter/netinet/ip_pool.h
+++ sys/contrib/ipfilter/netinet/ip_pool.h
@@ -1,24 +1,22 @@
-/*	$FreeBSD: src/sys/contrib/ipfilter/netinet/ip_pool.h,v 1.1.1.1 2005/04/25 18:15:28 darrenr Exp $	*/
-
 /*
  * Copyright (C) 1993-2001, 2003 by Darren Reed.
  *
  * See the IPFILTER.LICENCE file for details on licencing.
  *
- * Id: ip_pool.h,v 2.26.2.2 2004/03/23 12:44:34 darrenr Exp
+ * $Id: ip_pool.h,v 2.26.2.6 2007/10/10 09:51:43 darrenr Exp $
  */
 
 #ifndef	__IP_POOL_H__
 #define	__IP_POOL_H__
 
 #if defined(_KERNEL) && !defined(__osf__) && !defined(__hpux) && \
-    !defined(linux) && !defined(sun)
+    !defined(linux) && !defined(sun) && !defined(AIX)
 # include <net/radix.h>
 extern void rn_freehead __P((struct radix_node_head *));
 # define FreeS(p, z)		KFREES(p, z)
 extern int max_keylen;
 #else
-# if defined(__osf__) || defined(__hpux)
+# if defined(__osf__) || defined(__hpux) || defined(sun)
 #  include "radix_ipf_local.h"
 #  define radix_mask ipf_radix_mask
 #  define radix_node ipf_radix_node
@@ -37,8 +35,9 @@
 	addrfamily_t		ipn_addr;
 	addrfamily_t		ipn_mask;
 	int			ipn_info;
-	char			ipn_name[FR_GROUPLEN];
-	u_long			ipn_hits;
+	int			ipn_ref;
+char			ipn_name[FR_GROUPLEN];
+u_long			ipn_hits;
 	struct ip_pool_node	*ipn_next, **ipn_pnext;
 } ip_pool_node_t;
 
@@ -55,7 +54,8 @@
 	char		ipo_name[FR_GROUPLEN];
 } ip_pool_t;
 
-#define	IPOOL_ANON	0x80000000
+#define	IPOOL_DELETE	0x01
+#define	IPOOL_ANON	0x02
 
 
 typedef	struct	ip_pool_stat	{
@@ -75,13 +75,16 @@
 extern	int	ip_pool_create __P((iplookupop_t *));
 extern	int	ip_pool_insert __P((ip_pool_t *, i6addr_t *, i6addr_t *, int));
 extern	int	ip_pool_remove __P((ip_pool_t *, ip_pool_node_t *));
-extern	int	ip_pool_destroy __P((iplookupop_t *));
+extern	int	ip_pool_destroy __P((int, char *));
 extern	void	ip_pool_free __P((ip_pool_t *));
 extern	void	ip_pool_deref __P((ip_pool_t *));
+extern	void	ip_pool_node_deref __P((ip_pool_node_t *));
 extern	void	*ip_pool_find __P((int, char *));
 extern	ip_pool_node_t *ip_pool_findeq __P((ip_pool_t *,
 					  addrfamily_t *, addrfamily_t *));
 extern	int	ip_pool_flush __P((iplookupflush_t *));
 extern	int	ip_pool_statistics __P((iplookupop_t *));
+extern	int	ip_pool_getnext __P((ipftoken_t *, ipflookupiter_t *));
+extern	void	ip_pool_iterderef __P((u_int, int, void *));
 
 #endif /* __IP_POOL_H__ */
Index: ip_fil_freebsd.c
===================================================================
RCS file: /home/cvs/src/sys/contrib/ipfilter/netinet/ip_fil_freebsd.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/contrib/ipfilter/netinet/ip_fil_freebsd.c -L sys/contrib/ipfilter/netinet/ip_fil_freebsd.c -u -r1.1.1.1 -r1.2
--- sys/contrib/ipfilter/netinet/ip_fil_freebsd.c
+++ sys/contrib/ipfilter/netinet/ip_fil_freebsd.c
@@ -1,4 +1,4 @@
-/*	$FreeBSD: src/sys/contrib/ipfilter/netinet/ip_fil_freebsd.c,v 1.1.1.1 2005/04/25 18:15:15 darrenr Exp $	*/
+/*	$FreeBSD: src/sys/contrib/ipfilter/netinet/ip_fil_freebsd.c,v 1.6.2.2 2007/12/01 00:53:41 darrenr Exp $	*/
 
 /*
  * Copyright (C) 1993-2003 by Darren Reed.
@@ -7,7 +7,7 @@
  */
 #if !defined(lint)
 static const char sccsid[] = "@(#)ip_fil.c	2.41 6/5/96 (C) 1993-2000 Darren Reed";
-static const char rcsid[] = "@(#)Id: ip_fil_freebsd.c,v 2.53.2.25 2005/02/01 03:15:56 darrenr Exp";
+static const char rcsid[] = "@(#)$Id: ip_fil_freebsd.c,v 2.53.2.50 2007/09/20 12:51:50 darrenr Exp $";
 #endif
 
 #if defined(KERNEL) || defined(_KERNEL)
@@ -57,10 +57,18 @@
 #endif
 #include <sys/protosw.h>
 #include <sys/socket.h>
+#if __FreeBSD_version >= 500043
+# include <sys/selinfo.h>
+#else
+# include <sys/select.h>
+#endif
 
 #include <net/if.h>
 #if __FreeBSD_version >= 300000
 # include <net/if_var.h>
+# if __FreeBSD_version >= 500043
+#  include <net/netisr.h>
+# endif
 # if !defined(IPFILTER_LKM)
 #  include "opt_ipfilter.h"
 # endif
@@ -112,7 +120,7 @@
 #endif
 
 # ifdef IPFILTER_M_IPFILTER
-MALLOC_DEFINE(M_IPFILTER, "IP Filter", "IP Filter packet filter data structures");
+MALLOC_DEFINE(M_IPFILTER, "ipfilter", "IP Filter packet filter data structures");
 # endif
 
 
@@ -125,7 +133,7 @@
 # ifdef USE_MUTEXES
 ipfmutex_t	ipl_mutex, ipf_authmx, ipf_rw, ipf_stinsert;
 ipfmutex_t	ipf_nat_new, ipf_natio, ipf_timeoutlock;
-ipfrwlock_t	ipf_mutex, ipf_global, ipf_ipidfrag;
+ipfrwlock_t	ipf_mutex, ipf_global, ipf_ipidfrag, ipf_frcache, ipf_tokens;
 ipfrwlock_t	ipf_frag, ipf_state, ipf_nat, ipf_natfrag, ipf_auth;
 # endif
 int		ipf_locks_done = 0;
@@ -133,6 +141,7 @@
 #if (__FreeBSD_version >= 300000)
 struct callout_handle fr_slowtimer_ch;
 #endif
+struct	selinfo	ipfselwait[IPL_LOGSIZE];
 
 #if (__FreeBSD_version >= 500011)
 # include <sys/conf.h>
@@ -147,6 +156,19 @@
 #endif /* __FreeBSD_version >= 500011 */
 
 
+#if (__FreeBSD_version >= 502103)
+static eventhandler_tag ipf_arrivetag, ipf_departtag, ipf_clonetag;
+
+static void ipf_ifevent(void *arg);
+
+static void ipf_ifevent(arg)
+void *arg;
+{
+        frsync(NULL);
+}
+#endif
+
+
 #if (__FreeBSD_version >= 501108) && defined(_KERNEL)
 
 static int
@@ -178,20 +200,11 @@
 #endif /* IPFILTER_LKM */
 
 
-int iplattach()
+int ipfattach()
 {
 #ifdef USE_SPL
 	int s;
 #endif
-#if defined(NETBSD_PF) && (__FreeBSD_version >= 500011)
-	int error = 0;
-# if __FreeBSD_version >= 501108
-	struct pfil_head *ph_inet;
-#  ifdef USE_INET6
-	struct pfil_head *ph_inet6;
-#  endif
-# endif
-#endif
 
 	SPL_NET(s);
 	if (fr_running > 0) {
@@ -200,10 +213,9 @@
 	}
 
 	MUTEX_INIT(&ipf_rw, "ipf rw mutex");
-	RWLOCK_INIT(&ipf_global, "ipf filter load/unload mutex");
 	MUTEX_INIT(&ipf_timeoutlock, "ipf timeout queue mutex");
-	RWLOCK_INIT(&ipf_mutex, "ipf filter rwlock");
 	RWLOCK_INIT(&ipf_ipidfrag, "ipf IP NAT-Frag rwlock");
+	RWLOCK_INIT(&ipf_tokens, "ipf token rwlock");
 	ipf_locks_done = 1;
 
 	if (fr_initialise() < 0) {
@@ -212,70 +224,12 @@
 	}
 
 
-# ifdef NETBSD_PF
-#  if __FreeBSD_version >= 500011
-#   if __FreeBSD_version >= 501108
-	ph_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
-#    ifdef USE_INET6
-	ph_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6);
-#    endif
-	if (ph_inet == NULL
-#    ifdef USE_INET6
-	    && ph_inet6 == NULL
-#    endif
-	   )
-		return ENODEV;
-
-	if (ph_inet != NULL)
-		error = pfil_add_hook((void *)fr_check_wrapper, NULL,
-				      PFIL_IN|PFIL_OUT, ph_inet);
-	else
-		error = 0;
-#  else
-	error = pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT,
-			      &inetsw[ip_protox[IPPROTO_IP]].pr_pfh);
-#  endif
-	if (error) {
-#   ifdef USE_INET6
-		goto pfil_error;
-#   else
-		fr_deinitialise();
-		SPL_X(s);
-		return error;
-#   endif
-	}
-#  else
-	pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT);
-#  endif
-#  ifdef USE_INET6
-#   if __FreeBSD_version >= 501108
-	if (ph_inet6 != NULL)
-		error = pfil_add_hook((void *)fr_check_wrapper6, NULL,
-				      PFIL_IN|PFIL_OUT, ph_inet6);
-	else
-		error = 0;
-	if (error) {
-		pfil_remove_hook((void *)fr_check_wrapper6, NULL,
-				 PFIL_IN|PFIL_OUT, ph_inet6);
-#   else
-	error = pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT,
-			      &inet6sw[ip6_protox[IPPROTO_IPV6]].pr_pfh);
-	if (error) {
-		pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT,
-				 &inetsw[ip_protox[IPPROTO_IP]].pr_pfh);
-#   endif
-pfil_error:
-		fr_deinitialise();
-		SPL_X(s);
-		return error;
-	}
-#  endif
-# endif
 	if (fr_checkp != fr_check) {
 		fr_savep = fr_checkp;
 		fr_checkp = fr_check;
 	}
 
+	bzero((char *)ipfselwait, sizeof(ipfselwait));
 	bzero((char *)frcache, sizeof(frcache));
 	fr_running = 1;
 
@@ -297,21 +251,11 @@
  * Disable the filter by removing the hooks from the IP input/output
  * stream.
  */
-int ipldetach()
+int ipfdetach()
 {
 #ifdef USE_SPL
 	int s;
 #endif
-#if defined(NETBSD_PF) && (__FreeBSD_version >= 500011)
-	int error = 0;
-# if __FreeBSD_version >= 501108
-	struct pfil_head *ph_inet;
-#  ifdef USE_INET6
-	struct pfil_head *ph_inet6;
-#  endif
-# endif
-#endif
-
 	if (fr_control_forwarding & 2)
 		ipforwarding = 0;
 
@@ -331,44 +275,6 @@
 	fr_savep = NULL;
 #endif
 
-#ifdef NETBSD_PF
-# if (__FreeBSD_version >= 500011)
-#  if (__FreeBSD_version >= 501108)
-	ph_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
-	if (ph_inet != NULL)
-		error = pfil_remove_hook((void *)fr_check_wrapper, NULL,
-					 PFIL_IN|PFIL_OUT, ph_inet);
-	else
-		error = 0;
-#  else
-	error = pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT,
-				 &inetsw[ip_protox[IPPROTO_IP]].pr_pfh);
-#  endif
-	if (error) {
-		SPL_X(s);
-		return error;
-	}
-# else
-	pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT);
-# endif
-# ifdef USE_INET6
-#  if (__FreeBSD_version >= 501108)
-	ph_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6);
-	if (ph_inet6 != NULL)
-		error = pfil_remove_hook((void *)fr_check_wrapper6, NULL,
-					 PFIL_IN|PFIL_OUT, ph_inet6);
-	else
-		error = 0;
-#  else
-	error = pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT,
-				 &inet6sw[ip6_protox[IPPROTO_IPV6]].pr_pfh);
-#  endif
-	if (error) {
-		SPL_X(s);
-		return error;
-	}
-# endif
-#endif
 	fr_deinitialise();
 
 	fr_running = -2;
@@ -379,9 +285,8 @@
 	if (ipf_locks_done == 1) {
 		MUTEX_DESTROY(&ipf_timeoutlock);
 		MUTEX_DESTROY(&ipf_rw);
-		RW_DESTROY(&ipf_mutex);
 		RW_DESTROY(&ipf_ipidfrag);
-		RW_DESTROY(&ipf_global);
+		RW_DESTROY(&ipf_tokens);
 		ipf_locks_done = 0;
 	}
 
@@ -399,8 +304,14 @@
 , p)
 #  if (__FreeBSD_version >= 500024)
 struct thread *p;
+#   if (__FreeBSD_version >= 500043)
+#    define	p_uid	td_ucred->cr_ruid
+#   else
+#    define	p_uid	t_proc->p_cred->p_ruid
+#   endif
 #  else
 struct proc *p;
+#   define	p_uid	p_cred->p_ruid
 #  endif /* __FreeBSD_version >= 500024 */
 # else
 )
@@ -414,14 +325,11 @@
 caddr_t data;
 int mode;
 {
-#ifdef USE_SPL
-	int s;
-#endif
-	int error = 0, unit = 0, tmp;
-	friostat_t fio;
+	int error = 0, unit = 0;
+	SPL_INT(s);
 
 #if (BSD >= 199306) && defined(_KERNEL)
-	if ((securelevel >= 2) && (mode & FWRITE))
+	if ((securelevel >= 3) && (mode & FWRITE))
 		return EPERM;
 #endif
 
@@ -439,150 +347,18 @@
 	}
 
 	SPL_NET(s);
+	READ_ENTER(&ipf_global);
 
-	error = fr_ioctlswitch(unit, data, cmd, mode);
+	error = fr_ioctlswitch(unit, data, cmd, mode, p->p_uid, p);
 	if (error != -1) {
+		RWLOCK_EXIT(&ipf_global);
 		SPL_X(s);
 		return error;
 	}
-	error = 0;
 
-	switch (cmd)
-	{
-	case FIONREAD :
-#ifdef IPFILTER_LOG
-		BCOPYOUT(&iplused[IPL_LOGIPF], (caddr_t)data,
-			 sizeof(iplused[IPL_LOGIPF]));
-#endif
-		break;
-	case SIOCFRENB :
-		if (!(mode & FWRITE))
-			error = EPERM;
-		else {
-			BCOPYIN(data, &tmp, sizeof(tmp));
-			if (tmp) {
-				if (fr_running > 0)
-					error = 0;
-				else
-					error = iplattach();
-				if (error == 0)
-					fr_running = 1;
-				else
-					(void) ipldetach();
-			} else {
-				error = ipldetach();
-				if (error == 0)
-					fr_running = -1;
-			}
-		}
-		break;
-	case SIOCIPFSET :
-		if (!(mode & FWRITE)) {
-			error = EPERM;
-			break;
-		}
-	case SIOCIPFGETNEXT :
-	case SIOCIPFGET :
-		error = fr_ipftune(cmd, data);
-		break;
-	case SIOCSETFF :
-		if (!(mode & FWRITE))
-			error = EPERM;
-		else
-			BCOPYIN(data, &fr_flags, sizeof(fr_flags));
-		break;
-	case SIOCGETFF :
-		BCOPYOUT(&fr_flags, data, sizeof(fr_flags));
-		break;
-	case SIOCFUNCL :
-		error = fr_resolvefunc(data);
-		break;
-	case SIOCINAFR :
-	case SIOCRMAFR :
-	case SIOCADAFR :
-	case SIOCZRLST :
-		if (!(mode & FWRITE))
-			error = EPERM;
-		else
-			error = frrequest(unit, cmd, data, fr_active, 1);
-		break;
-	case SIOCINIFR :
-	case SIOCRMIFR :
-	case SIOCADIFR :
-		if (!(mode & FWRITE))
-			error = EPERM;
-		else
-			error = frrequest(unit, cmd, data, 1 - fr_active, 1);
-		break;
-	case SIOCSWAPA :
-		if (!(mode & FWRITE))
-			error = EPERM;
-		else {
-			bzero((char *)frcache, sizeof(frcache[0]) * 2);
-			*(u_int *)data = fr_active;
-			fr_active = 1 - fr_active;
-		}
-		break;
-	case SIOCGETFS :
-		fr_getstat(&fio);
-		error = fr_outobj(data, &fio, IPFOBJ_IPFSTAT);
-		break;
-	case SIOCFRZST :
-		if (!(mode & FWRITE))
-			error = EPERM;
-		else
-			error = fr_zerostats(data);
-		break;
-	case SIOCIPFFL :
-		if (!(mode & FWRITE))
-			error = EPERM;
-		else {
-			BCOPYIN(data, &tmp, sizeof(tmp));
-			tmp = frflush(unit, 4, tmp);
-			BCOPYOUT(&tmp, data, sizeof(tmp));
-		}
-		break;
-#ifdef USE_INET6
-	case SIOCIPFL6 :
-		if (!(mode & FWRITE))
-			error = EPERM;
-		else {
-			BCOPYIN(data, &tmp, sizeof(tmp));
-			tmp = frflush(unit, 6, tmp);
-			BCOPYOUT(&tmp, data, sizeof(tmp));
-		}
-		break;
-#endif
-	case SIOCSTLCK :
-		BCOPYIN(data, &tmp, sizeof(tmp));
-		fr_state_lock = tmp;
-		fr_nat_lock = tmp;
-		fr_frag_lock = tmp;
-		fr_auth_lock = tmp;
-		break;
-#ifdef IPFILTER_LOG
-	case SIOCIPFFB :
-		if (!(mode & FWRITE))
-			error = EPERM;
-		else
-			*(int *)data = ipflog_clear(unit);
-		break;
-#endif /* IPFILTER_LOG */
-	case SIOCGFRST :
-		error = fr_outobj(data, fr_fragstats(), IPFOBJ_FRAGSTAT);
-		break;
-	case SIOCFRSYN :
-		if (!(mode & FWRITE))
-			error = EPERM;
-		else {
-			frsync(NULL);
-		}
-		break;
-	default :
-		error = EINVAL;
-		break;
-	}
+	RWLOCK_EXIT(&ipf_global);
 	SPL_X(s);
+
 	return error;
 }
 
@@ -705,14 +481,21 @@
 #endif
 register struct uio *uio;
 {
+	u_int	xmin = GET_MINOR(dev);
+
+	if (fr_running < 1)
+		return EIO;
+
+	if (xmin < 0)
+		return ENXIO;
 
 # ifdef	IPFILTER_SYNC
-	if (GET_MINOR(dev) == IPL_LOGSYNC)
+	if (xmin == IPL_LOGSYNC)
 		return ipfsync_read(uio);
 # endif
 
 #ifdef IPFILTER_LOG
-	return ipflog_read(GET_MINOR(dev), uio);
+	return ipflog_read(xmin, uio);
 #else
 	return ENXIO;
 #endif
@@ -739,6 +522,9 @@
 register struct uio *uio;
 {
 
+	if (fr_running < 1)
+		return EIO;
+
 #ifdef	IPFILTER_SYNC
 	if (GET_MINOR(dev) == IPL_LOGSYNC)
 		return ipfsync_write(uio);
@@ -766,10 +552,8 @@
 	if (tcp->th_flags & TH_RST)
 		return -1;		/* feedback loop */
 
-#ifndef	IPFILTER_CKSUM
 	if (fr_checkl4sum(fin) == -1)
 		return -1;
-#endif
 
 	tlen = fin->fin_dlen - (TCP_OFF(tcp) << 2) +
 			((tcp->th_flags & TH_SYN) ? 1 : 0) +
@@ -928,7 +712,7 @@
 #endif
 	ip_t *ip, *ip2;
 
-	if ((type < 0) || (type > ICMP_MAXTYPE))
+	if ((type < 0) || (type >= ICMP_MAXTYPE))
 		return -1;
 
 	code = fin->fin_icode;
@@ -937,10 +721,8 @@
 		return -1;
 #endif
 
-#ifndef	IPFILTER_CKSUM
 	if (fr_checkl4sum(fin) == -1)
 		return -1;
-#endif
 #ifdef MGETHDR
 	MGETHDR(m, M_DONTWAIT, MT_HEADER);
 #else
@@ -1096,7 +878,7 @@
 # endif
 iplinit()
 {
-	if (iplattach() != 0)
+	if (ipfattach() != 0)
 		printf("IP Filter failed to attach\n");
 	ip_init();
 }
@@ -1118,6 +900,8 @@
 	u_short ip_off;
 	frentry_t *fr;
 
+	ro = NULL;
+
 #ifdef M_WRITABLE
 	/*
 	* HOT FIX/KLUDGE:
@@ -1131,15 +915,15 @@
 	* problem.
 	*/
 	if (M_WRITABLE(m) == 0) {
-		if ((m0 = m_dup(m, M_DONTWAIT)) != 0) {
+		m0 = m_dup(m, M_DONTWAIT);
+		if (m0 != 0) {
 			FREE_MB_T(m);
 			m = m0;
 			*mpp = m;
 		} else {
 			error = ENOBUFS;
 			FREE_MB_T(m);
-			*mpp = NULL;
-			fr_frouteok[1]++;
+			goto done;
 		}
 	}
 #endif
@@ -1181,18 +965,8 @@
 		goto bad;
 	}
 
-	/*
-	 * In case we're here due to "to <if>" being used with "keep state",
-	 * check that we're going in the correct direction.
-	 */
-	if ((fr != NULL) && (fin->fin_rev != 0)) {
-		if ((ifp != NULL) && (fdp == &fr->fr_tif))
-			return -1;
-	}
-	if (fdp != NULL) {
-		if (fdp->fd_ip.s_addr != 0)
-			dst->sin_addr = fdp->fd_ip;
-	}
+	if ((fdp != NULL) && (fdp->fd_ip.s_addr != 0))
+		dst->sin_addr = fdp->fd_ip;
 
 	dst->sin_len = sizeof(*dst);
 	rtalloc(ro);
@@ -1215,9 +989,11 @@
 	/*
 	 * For input packets which are being "fastrouted", they won't
 	 * go back through output filtering and miss their chance to get
-	 * NAT'd and counted.
+	 * NAT'd and counted.  Duplicated packets aren't considered to be
+	 * part of the normal packet stream, so do not NAT them or pass
+	 * them through stateful checking, etc.
 	 */
-	if (fin->fin_out == 0) {
+	if ((fdp != &fr->fr_dif) && (fin->fin_out == 0)) {
 		sifp = fin->fin_ifp;
 		fin->fin_ifp = ifp;
 		fin->fin_out = 1;
@@ -1226,7 +1002,8 @@
 		if (!fr || !(fr->fr_flags & FR_RETMASK)) {
 			u_32_t pass;
 
-			(void) fr_checkstate(fin, &pass);
+			if (fr_checkstate(fin, &pass) != NULL)
+				fr_statederef((ipstate_t **)&fin->fin_state);
 		}
 
 		switch (fr_checknatout(fin, NULL))
@@ -1234,6 +1011,7 @@
 		case 0 :
 			break;
 		case 1 :
+			fr_natderef((nat_t **)&fin->fin_nat);
 			ip->ip_sum = 0;
 			break;
 		case -1 :
@@ -1309,6 +1087,7 @@
 		else
 			mhip->ip_off |= IP_MF;
 		mhip->ip_len = htons((u_short)(len + mhlen));
+		*mnext = m;
 		m->m_next = m_copy(m0, off, len);
 		if (m->m_next == 0) {
 			error = ENOBUFS;	/* ??? */
@@ -1319,7 +1098,6 @@
 		mhip->ip_off = htons((u_short)mhip->ip_off);
 		mhip->ip_sum = 0;
 		mhip->ip_sum = in_cksum(m, mhlen);
-		*mnext = m;
 		mnext = &m->m_act;
 	}
 	/*
@@ -1348,7 +1126,7 @@
 	else
 		fr_frouteok[1]++;
 
-	if (ro->ro_rt) {
+	if ((ro != NULL) && (ro->ro_rt != NULL)) {
 		RTFREE(ro->ro_rt);
 	}
 	*mpp = NULL;
@@ -1451,6 +1229,9 @@
 	else if (atype == FRI_PEERADDR)
 		sock = ifa->ifa_dstaddr;
 
+	if (sock == NULL)
+		return -1;
+
 #ifdef USE_INET6
 	if (v == 6) {
 		return fr_ifpfillv6addr(atype, (struct sockaddr_in6 *)sock,
@@ -1545,6 +1326,9 @@
 	if ((fin->fin_flx & FI_NOCKSUM) != 0)
 		return;
 
+	if (fin->fin_cksum != 0)
+		return;
+
 	m = fin->fin_m;
 	if (m == NULL) {
 		manual = 1;
@@ -1560,8 +1344,12 @@
 					htonl(m->m_pkthdr.csum_data +
 					fin->fin_ip->ip_len + fin->fin_p));
 		sum ^= 0xffff;
-		if (sum != 0)
+		if (sum != 0) {
 			fin->fin_flx |= FI_BAD;
+			fin->fin_cksum = -1;
+		} else {
+			fin->fin_cksum = 1;
+		}
 	} else
 		manual = 1;
 skipauto:
@@ -1673,11 +1461,16 @@
 			m = m_pullup(m, len);
 		}
 		*fin->fin_mp = m;
-		fin->fin_m = m;
 		if (m == NULL) {
+			fin->fin_m = NULL;
 			ATOMIC_INCL(frstats[out].fr_pull[1]);
 			return NULL;
 		}
+
+		while (M_LEN(m) == 0) {
+			m = m->m_next;
+		}
+		fin->fin_m = m;
 		ip = MTOD(m, char *) + ipoff;
 	}
 
@@ -1690,3 +1483,167 @@
 		fin->fin_flx |= FI_COALESCE;
 	return ip;
 }
+
+
+int ipf_inject(fin, m)
+fr_info_t *fin;
+mb_t *m;
+{
+	int error = 0;
+
+	if (fin->fin_out == 0) {
+#if (__FreeBSD_version >= 501000)
+		netisr_dispatch(NETISR_IP, m);
+#else
+		struct ifqueue *ifq;
+
+		ifq = &ipintrq;
+
+# ifdef _IF_QFULL
+		if (_IF_QFULL(ifq))
+# else
+		if (IF_QFULL(ifq))
+# endif
+		{
+# ifdef _IF_DROP
+			_IF_DROP(ifq);
+# else
+			IF_DROP(ifq);
+# endif
+			FREE_MB_T(m);
+			error = ENOBUFS;
+		} else {
+			IF_ENQUEUE(ifq, m);
+		}
+#endif
+	} else {
+		fin->fin_ip->ip_len = ntohs(fin->fin_ip->ip_len);
+		fin->fin_ip->ip_off = ntohs(fin->fin_ip->ip_off);
+#if (__FreeBSD_version >= 470102)
+		error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL, NULL);
+#else
+		error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL);
+#endif
+	}
+
+	return error;
+}
+
+int ipf_pfil_unhook(void) {
+#if defined(NETBSD_PF) && (__FreeBSD_version >= 500011)
+# if __FreeBSD_version >= 501108
+	struct pfil_head *ph_inet;
+#  ifdef USE_INET6
+	struct pfil_head *ph_inet6;
+#  endif
+# endif
+#endif
+
+#ifdef NETBSD_PF
+# if (__FreeBSD_version >= 500011)
+#  if (__FreeBSD_version >= 501108)
+	ph_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
+	if (ph_inet != NULL)
+		pfil_remove_hook((void *)fr_check_wrapper, NULL,
+		    PFIL_IN|PFIL_OUT|PFIL_WAITOK, ph_inet);
+#  else
+	pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT|PFIL_WAITOK,
+	    &inetsw[ip_protox[IPPROTO_IP]].pr_pfh);
+#  endif
+# else
+	pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT|PFIL_WAITOK);
+# endif
+# ifdef USE_INET6
+#  if (__FreeBSD_version >= 501108)
+	ph_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6);
+	if (ph_inet6 != NULL)
+		pfil_remove_hook((void *)fr_check_wrapper6, NULL,
+		    PFIL_IN|PFIL_OUT|PFIL_WAITOK, ph_inet6);
+#  else
+	pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT|PFIL_WAITOK,
+				 &inet6sw[ip6_protox[IPPROTO_IPV6]].pr_pfh);
+#  endif
+# endif
+#endif
+
+	return (0);
+}
+
+int ipf_pfil_hook(void) {
+#if defined(NETBSD_PF) && (__FreeBSD_version >= 500011)
+# if __FreeBSD_version >= 501108
+	struct pfil_head *ph_inet;
+#  ifdef USE_INET6
+	struct pfil_head *ph_inet6;
+#  endif
+# endif
+#endif
+
+# ifdef NETBSD_PF
+#  if __FreeBSD_version >= 500011
+#   if __FreeBSD_version >= 501108
+	ph_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
+#    ifdef USE_INET6
+	ph_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6);
+#    endif
+	if (ph_inet == NULL
+#    ifdef USE_INET6
+	    && ph_inet6 == NULL
+#    endif
+	   )
+		return ENODEV;
+
+	if (ph_inet != NULL)
+		pfil_add_hook((void *)fr_check_wrapper, NULL,
+		    PFIL_IN|PFIL_OUT|PFIL_WAITOK, ph_inet);
+#  else
+	pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT|PFIL_WAITOK,
+			      &inetsw[ip_protox[IPPROTO_IP]].pr_pfh);
+#  endif
+#  else
+	pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT|PFIL_WAITOK);
+#  endif
+#  ifdef USE_INET6
+#   if __FreeBSD_version >= 501108
+	if (ph_inet6 != NULL)
+		pfil_add_hook((void *)fr_check_wrapper6, NULL,
+				      PFIL_IN|PFIL_OUT|PFIL_WAITOK, ph_inet6);
+#   else
+	pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT|PFIL_WAITOK,
+			      &inet6sw[ip6_protox[IPPROTO_IPV6]].pr_pfh);
+#   endif
+#  endif
+# endif
+	return (0);
+}
+
+void
+ipf_event_reg(void)
+{
+#if (__FreeBSD_version >= 502103)
+	ipf_arrivetag =  EVENTHANDLER_REGISTER(ifnet_arrival_event, \
+					       ipf_ifevent, NULL, \
+					       EVENTHANDLER_PRI_ANY);
+	ipf_departtag =  EVENTHANDLER_REGISTER(ifnet_departure_event, \
+					       ipf_ifevent, NULL, \
+					       EVENTHANDLER_PRI_ANY);
+	ipf_clonetag =  EVENTHANDLER_REGISTER(if_clone_event, ipf_ifevent, \
+					      NULL, EVENTHANDLER_PRI_ANY);
+#endif
+}
+
+void
+ipf_event_dereg(void)
+{
+#if (__FreeBSD_version >= 502103)
+	if (ipf_arrivetag != NULL) {
+		EVENTHANDLER_DEREGISTER(ifnet_arrival_event, ipf_arrivetag);
+	}
+	if (ipf_departtag != NULL) {
+		EVENTHANDLER_DEREGISTER(ifnet_departure_event, ipf_departtag);
+	}
+	if (ipf_clonetag != NULL) {
+		EVENTHANDLER_DEREGISTER(if_clone_event, ipf_clonetag);
+	}
+#endif
+}
Index: ip_auth.c
===================================================================
RCS file: /home/cvs/src/sys/contrib/ipfilter/netinet/ip_auth.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/contrib/ipfilter/netinet/ip_auth.c -L sys/contrib/ipfilter/netinet/ip_auth.c -u -r1.1.1.1 -r1.2
--- sys/contrib/ipfilter/netinet/ip_auth.c
+++ sys/contrib/ipfilter/netinet/ip_auth.c
@@ -1,4 +1,4 @@
-/*	$FreeBSD: src/sys/contrib/ipfilter/netinet/ip_auth.c,v 1.40 2005/04/27 03:48:09 darrenr Exp $	*/
+/*	$FreeBSD: src/sys/contrib/ipfilter/netinet/ip_auth.c,v 1.44.2.2 2007/12/01 00:53:41 darrenr Exp $	*/
 
 /*
  * Copyright (C) 1998-2003 by Darren Reed & Guido van Rooij.
@@ -52,7 +52,8 @@
 # include <sys/stream.h>
 # include <sys/kmem.h>
 #endif
-#if (_BSDI_VERSION >= 199802) || (__FreeBSD_version >= 400000)
+#if (defined(_BSDI_VERSION) && _BSDI_VERSION >= 199802) || \
+    (__FreeBSD_version >= 400000)
 # include <sys/queue.h>
 #endif
 #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(bsdi)
@@ -119,13 +120,14 @@
 /* END OF INCLUDES */
 
 #if !defined(lint)
-static const char rcsid[] = "@(#)$FreeBSD: src/sys/contrib/ipfilter/netinet/ip_auth.c,v 1.40 2005/04/27 03:48:09 darrenr Exp $";
-/* static const char rcsid[] = "@(#)Id: ip_auth.c,v 2.73.2.3 2004/08/26 11:25:21 darrenr Exp"; */
+static const char rcsid[] = "@(#)$FreeBSD: src/sys/contrib/ipfilter/netinet/ip_auth.c,v 1.44.2.2 2007/12/01 00:53:41 darrenr Exp $";
+/* static const char rcsid[] = "@(#)$Id: ip_auth.c,v 2.73.2.24 2007/09/09 11:32:04 darrenr Exp $"; */
 #endif
 
 
-#if SOLARIS
+#if SOLARIS && defined(_KERNEL)
 extern kcondvar_t ipfauthwait;
+extern struct pollhead iplpollhead[IPL_LOGSIZE];
 #endif /* SOLARIS */
 #if defined(linux) && defined(_KERNEL)
 wait_queue_head_t     fr_authnext_linux;
@@ -144,7 +146,19 @@
 frentry_t	*ipauth = NULL,
 		*fr_authlist = NULL;
 
-
+void fr_authderef __P((frauthent_t **));
+int fr_authgeniter __P((ipftoken_t *, ipfgeniter_t *));
+int fr_authreply __P((char *));
+int fr_authwait __P((char *));
+
+/* ------------------------------------------------------------------------ */
+/* Function:    fr_authinit                                                 */
+/* Returns:     int - 0 == success, else error                              */
+/* Parameters:  None                                                        */
+/*                                                                          */
+/* Allocate memory and initialise data structures used in handling auth     */
+/* rules.                                                                   */
+/* ------------------------------------------------------------------------ */
 int fr_authinit()
 {
 	KMALLOCS(fr_auth, frauth_t *, fr_authsize * sizeof(*fr_auth));
@@ -174,11 +188,16 @@
 }
 
 
-/*
- * Check if a packet has authorization.  If the packet is found to match an
- * authorization result and that would result in a feedback loop (i.e. it
- * will end up returning FR_AUTH) then return FR_BLOCK instead.
- */
+/* ------------------------------------------------------------------------ */
+/* Function:    fr_checkauth                                                */
+/* Returns:     frentry_t* - pointer to ipf rule if match found, else NULL  */
+/* Parameters:  fin(I)   - pointer to ipftoken structure                    */
+/*              passp(I) - pointer to ipfgeniter structure                  */
+/*                                                                          */
+/* Check if a packet has authorization.  If the packet is found to match an */
+/* authorization result and that would result in a feedback loop (i.e. it   */
+/* will end up returning FR_AUTH) then return FR_BLOCK instead.             */
+/* ------------------------------------------------------------------------ */
 frentry_t *fr_checkauth(fin, passp)
 fr_info_t *fin;
 u_32_t *passp;
@@ -235,7 +254,12 @@
 				fr = fra->fra_info.fin_fr;
 			fin->fin_fr = fr;
 			RWLOCK_EXIT(&ipf_auth);
+
 			WRITE_ENTER(&ipf_auth);
+			/*
+			 * fr_authlist is populated with the rules malloc'd
+			 * above and only those.
+			 */
 			if ((fr != NULL) && (fr != fra->fra_info.fin_fr)) {
 				fr->fr_next = fr_authlist;
 				fr_authlist = fr;
@@ -277,11 +301,16 @@
 }
 
 
-/*
- * Check if we have room in the auth array to hold details for another packet.
- * If we do, store it and wake up any user programs which are waiting to
- * hear about these events.
- */
+/* ------------------------------------------------------------------------ */
+/* Function:    fr_newauth                                                  */
+/* Returns:     int - 1 == success, 0 = did not put packet on auth queue    */
+/* Parameters:  m(I)   - pointer to mb_t with packet in it                  */
+/*              fin(I) - pointer to packet information                      */
+/*                                                                          */
+/* Check if we have room in the auth array to hold details for another      */
+/* packet. If we do, store it and wake up any user programs which are       */
+/* waiting to hear about these events.                                      */
+/* ------------------------------------------------------------------------ */
 int fr_newauth(m, fin)
 mb_t *m;
 fr_info_t *fin;
@@ -299,16 +328,10 @@
 		return 0;
 
 	WRITE_ENTER(&ipf_auth);
-	if (fr_authstart > fr_authend) {
+	if (((fr_authend + 1) % fr_authsize) == fr_authstart) {
 		fr_authstats.fas_nospace++;
 		RWLOCK_EXIT(&ipf_auth);
 		return 0;
-	} else {
-		if (fr_authused == fr_authsize) {
-			fr_authstats.fas_nospace++;
-			RWLOCK_EXIT(&ipf_auth);
-			return 0;
-		}
 	}
 
 	fr_authstats.fas_added++;
@@ -316,11 +339,14 @@
 	i = fr_authend++;
 	if (fr_authend == fr_authsize)
 		fr_authend = 0;
-	RWLOCK_EXIT(&ipf_auth);
-
 	fra = fr_auth + i;
 	fra->fra_index = i;
-	fra->fra_pass = 0;
+	RWLOCK_EXIT(&ipf_auth);
+
+	if (fin->fin_fr != NULL)
+		fra->fra_pass = fin->fin_fr->fr_flags;
+	else
+		fra->fra_pass = 0;
 	fra->fra_age = fr_defaultauthage;
 	bcopy((char *)fin, (char *)&fra->fra_info, sizeof(*fin));
 #if !defined(sparc) && !defined(m68k)
@@ -342,17 +368,17 @@
 	}
 #endif
 #if SOLARIS && defined(_KERNEL)
+	COPYIFNAME(fin->fin_v, fin->fin_ifp, fra->fra_info.fin_ifname);
 	m->b_rptr -= qpi->qpi_off;
 	fr_authpkts[i] = *(mblk_t **)fin->fin_mp;
+# if !defined(_INET_IP_STACK_H)
 	fra->fra_q = qpi->qpi_q;	/* The queue can disappear! */
+# endif
+	fra->fra_m = *fin->fin_mp;
+	fra->fra_info.fin_mp = &fra->fra_m;
 	cv_signal(&ipfauthwait);
+	pollwakeup(&iplpollhead[IPL_LOGAUTH], POLLIN|POLLRDNORM);
 #else
-# if defined(BSD) && !defined(sparc) && (BSD >= 199306)
-	if (!fin->fin_out) {
-		ip->ip_len = htons(ip->ip_len);
-		ip->ip_off = htons(ip->ip_off);
-	}
-# endif
 	fr_authpkts[i] = m;
 	WAKEUP(&fr_authnext,0);
 #endif
@@ -360,31 +386,65 @@
 }
 
 
-int fr_auth_ioctl(data, cmd, mode)
+/* ------------------------------------------------------------------------ */
+/* Function:    fr_auth_ioctl                                               */
+/* Returns:     int - 0 == success, else error                              */
+/* Parameters:  data(IO) - pointer to ioctl data                            */
+/*              cmd(I)   - ioctl command                                    */
+/*              mode(I)  - mode flags associated with open descriptor       */
+/*              uid(I)   - uid associatd with application making the call   */
+/*              ctx(I)   - pointer for context                              */
+/*                                                                          */
+/* This function handles all of the ioctls recognised by the auth component */
+/* in IPFilter - ie ioctls called on an open fd for /dev/ipauth             */
+/* ------------------------------------------------------------------------ */
+int fr_auth_ioctl(data, cmd, mode, uid, ctx)
 caddr_t data;
 ioctlcmd_t cmd;
-int mode;
+int mode, uid;
+void *ctx;
 {
-	mb_t *m;
-#if defined(_KERNEL) && !defined(MENTAT) && !defined(linux) && \
-    (!defined(__FreeBSD_version) || (__FreeBSD_version < 501000))
-	struct ifqueue *ifq;
-# ifdef USE_SPL
-	int s;
-# endif /* USE_SPL */
-#endif
-	frauth_t auth, *au = &auth, *fra;
-	int i, error = 0, len;
-	char *t;
+	int error = 0, i;
+	SPL_INT(s);
 
 	switch (cmd)
 	{
+	case SIOCGENITER :
+	    {
+		ipftoken_t *token;
+		ipfgeniter_t iter;
+
+		error = fr_inobj(data, &iter, IPFOBJ_GENITER);
+		if (error != 0)
+			break;
+
+		SPL_SCHED(s);
+		token = ipf_findtoken(IPFGENITER_AUTH, uid, ctx);
+		if (token != NULL)
+			error = fr_authgeniter(token, &iter);
+		else
+			error = ESRCH;
+		RWLOCK_EXIT(&ipf_tokens);
+		SPL_X(s);
+
+		break;
+	    }
+
+	case SIOCADAFR :
+	case SIOCRMAFR :
+		if (!(mode & FWRITE))
+			error = EPERM;
+		else
+			error = frrequest(IPL_LOGAUTH, cmd, data,
+					  fr_active, 1);
+		break;
+
 	case SIOCSTLCK :
 		if (!(mode & FWRITE)) {
 			error = EPERM;
 			break;
 		}
-		fr_lock(data, &fr_auth_lock);
+		error = fr_lock(data, &fr_auth_lock);
 		break;
 
 	case SIOCATHST:
@@ -398,195 +458,17 @@
 		i = fr_authflush();
 		RWLOCK_EXIT(&ipf_auth);
 		SPL_X(s);
-		error = copyoutptr((char *)&i, data, sizeof(i));
+		error = BCOPYOUT((char *)&i, data, sizeof(i));
+		if (error != 0)
+			error = EFAULT;
 		break;
 
 	case SIOCAUTHW:
-fr_authioctlloop:
-		error = fr_inobj(data, au, IPFOBJ_FRAUTH);
-		READ_ENTER(&ipf_auth);
-		if ((fr_authnext != fr_authend) && fr_authpkts[fr_authnext]) {
-			error = fr_outobj(data, &fr_auth[fr_authnext],
-					  IPFOBJ_FRAUTH);
-			if (auth.fra_len != 0 && auth.fra_buf != NULL) {
-				/*
-				 * Copy packet contents out to user space if
-				 * requested.  Bail on an error.
-				 */
-				m = fr_authpkts[fr_authnext];
-				len = MSGDSIZE(m);
-				if (len > auth.fra_len)
-					len = auth.fra_len;
-				auth.fra_len = len;
-				for (t = auth.fra_buf; m && (len > 0); ) {
-					i = MIN(M_LEN(m), len);
-					error = copyoutptr(MTOD(m, char *),
-							  t, i);
-					len -= i;
-					t += i;
-					if (error != 0)
-						break;
-				}
-			}
-			RWLOCK_EXIT(&ipf_auth);
-			if (error != 0)
-				break;
-			SPL_NET(s);
-			WRITE_ENTER(&ipf_auth);
-			fr_authnext++;
-			if (fr_authnext == fr_authsize)
-				fr_authnext = 0;
-			RWLOCK_EXIT(&ipf_auth);
-			SPL_X(s);
-			return 0;
-		}
-		RWLOCK_EXIT(&ipf_auth);
-		/*
-		 * We exit ipf_global here because a program that enters in
-		 * here will have a lock on it and goto sleep having this lock.
-		 * If someone were to do an 'ipf -D' the system would then
-		 * deadlock.  The catch with releasing it here is that the
-		 * caller of this function expects it to be held when we
-		 * return so we have to reacquire it in here.
-		 */
-		RWLOCK_EXIT(&ipf_global);
-
-		MUTEX_ENTER(&ipf_authmx);
-#ifdef	_KERNEL
-# if	SOLARIS
-		error = 0;
-		if (!cv_wait_sig(&ipfauthwait, &ipf_authmx.ipf_lk))
-			error = EINTR;
-# else /* SOLARIS */
-#  ifdef __hpux
-		{
-		lock_t *l;
-
-		l = get_sleep_lock(&fr_authnext);
-		error = sleep(&fr_authnext, PZERO+1);
-		spinunlock(l);
-		}
-#  else
-#   ifdef __osf__
-		error = mpsleep(&fr_authnext, PSUSP|PCATCH, "fr_authnext", 0,
-				&ipf_authmx, MS_LOCK_SIMPLE);
-#   else
-		error = SLEEP(&fr_authnext, "fr_authnext");
-#   endif /* __osf__ */
-#  endif /* __hpux */
-# endif /* SOLARIS */
-#endif
-		MUTEX_EXIT(&ipf_authmx);
-		READ_ENTER(&ipf_global);
-		if (error == 0) {
-			READ_ENTER(&ipf_auth);
-			goto fr_authioctlloop;
-		}
+		error = fr_authwait(data);
 		break;
 
 	case SIOCAUTHR:
-		error = fr_inobj(data, &auth, IPFOBJ_FRAUTH);
-		if (error != 0)
-			return error;
-		SPL_NET(s);
-		WRITE_ENTER(&ipf_auth);
-		i = au->fra_index;
-		fra = fr_auth + i;
-		if ((i < 0) || (i >= fr_authsize) ||
-		    (fra->fra_info.fin_id != au->fra_info.fin_id)) {
-			RWLOCK_EXIT(&ipf_auth);
-			SPL_X(s);
-			return ESRCH;
-		}
-		m = fr_authpkts[i];
-		fra->fra_index = -2;
-		fra->fra_pass = au->fra_pass;
-		fr_authpkts[i] = NULL;
-		RWLOCK_EXIT(&ipf_auth);
-#ifdef	_KERNEL
-		if ((m != NULL) && (au->fra_info.fin_out != 0)) {
-# ifdef MENTAT
-			error = !putq(fra->fra_q, m);
-# else /* MENTAT */
-#  ifdef linux
-#  else
-#   if (_BSDI_VERSION >= 199802) || defined(__OpenBSD__) || \
-       (defined(__sgi) && (IRIX >= 60500) || \
-       (defined(__FreeBSD__) && (__FreeBSD_version >= 470102)))
-			error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL,
-					  NULL);
-#   else
-			error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL);
-#   endif
-#  endif /* Linux */
-# endif /* MENTAT */
-			if (error != 0)
-				fr_authstats.fas_sendfail++;
-			else
-				fr_authstats.fas_sendok++;
-		} else if (m) {
-# ifdef MENTAT
-			error = !putq(fra->fra_q, m);
-# else /* MENTAT */
-#  ifdef linux
-#  else
-#   if __FreeBSD_version >= 501000
-			netisr_dispatch(NETISR_IP, m);
-#   else
-#    if IRIX >= 60516
-			ifq = &((struct ifnet *)fra->fra_info.fin_ifp)->if_snd;
-#    else
-			ifq = &ipintrq;
-#    endif
-			if (IF_QFULL(ifq)) {
-				IF_DROP(ifq);
-				FREE_MB_T(m);
-				error = ENOBUFS;
-			} else {
-				IF_ENQUEUE(ifq, m);
-#    if IRIX < 60500
-				schednetisr(NETISR_IP);
-#    endif
-			}
-#   endif
-#  endif /* Linux */
-# endif /* MENTAT */
-			if (error != 0)
-				fr_authstats.fas_quefail++;
-			else
-				fr_authstats.fas_queok++;
-		} else
-			error = EINVAL;
-# ifdef MENTAT
-		if (error != 0)
-			error = EINVAL;
-# else /* MENTAT */
-		/*
-		 * If we experience an error which will result in the packet
-		 * not being processed, make sure we advance to the next one.
-		 */
-		if (error == ENOBUFS) {
-			fr_authused--;
-			fra->fra_index = -1;
-			fra->fra_pass = 0;
-			if (i == fr_authstart) {
-				while (fra->fra_index == -1) {
-					i++;
-					if (i == fr_authsize)
-						i = 0;
-					fr_authstart = i;
-					if (i == fr_authend)
-						break;
-				}
-				if (fr_authstart == fr_authend) {
-					fr_authnext = 0;
-					fr_authstart = fr_authend = 0;
-				}
-			}
-		}
-# endif /* MENTAT */
-#endif /* _KERNEL */
-		SPL_X(s);
+		error = fr_authreply(data);
 		break;
 
 	default :
@@ -597,9 +479,13 @@
 }
 
 
-/*
- * Free all network buffer memory used to keep saved packets.
- */
+/* ------------------------------------------------------------------------ */
+/* Function:    fr_authunload                                               */
+/* Returns:     None                                                        */
+/* Parameters:  None                                                        */
+/*                                                                          */
+/* Free all network buffer memory used to keep saved packets.               */
+/* ------------------------------------------------------------------------ */
 void fr_authunload()
 {
 	register int i;
@@ -653,20 +539,22 @@
 }
 
 
-/*
- * Slowly expire held auth records.  Timeouts are set
- * in expectation of this being called twice per second.
- */
+/* ------------------------------------------------------------------------ */
+/* Function:    fr_authexpire                                               */
+/* Returns:     None                                                        */
+/* Parameters:  None                                                        */
+/*                                                                          */
+/* Slowly expire held auth records.  Timeouts are set in expectation of     */
+/* this being called twice per second.                                      */
+/* ------------------------------------------------------------------------ */
 void fr_authexpire()
 {
-	register int i;
-	register frauth_t *fra;
-	register frauthent_t *fae, **faep;
-	register frentry_t *fr, **frp;
+	frauthent_t *fae, **faep;
+	frentry_t *fr, **frp;
+	frauth_t *fra;
 	mb_t *m;
-# if !defined(MENAT) && defined(_KERNEL) && defined(USE_SPL)
-	int s;
-# endif
+	int i;
+	SPL_INT(s);
 
 	if (fr_auth_lock)
 		return;
@@ -684,11 +572,13 @@
 		}
 	}
 
+	/*
+	 * Expire pre-auth rules
+	 */
 	for (faep = &fae_list; ((fae = *faep) != NULL); ) {
 		fae->fae_age--;
 		if (fae->fae_age == 0) {
-			*faep = fae->fae_next;
-			KFREE(fae);
+			fr_authderef(&fae);
 			fr_authstats.fas_expire++;
 		} else
 			faep = &fae->fae_next;
@@ -709,19 +599,26 @@
 	SPL_X(s);
 }
 
+
+/* ------------------------------------------------------------------------ */
+/* Function:    fr_preauthcmd                                               */
+/* Returns:     int - 0 == success, else error                              */
+/* Parameters:  cmd(I)  - ioctl command for rule                            */
+/*              fr(I)   - pointer to ipf rule                               */
+/*              fptr(I) - pointer to caller's 'fr'                          */
+/*                                                                          */
+/* ------------------------------------------------------------------------ */
 int fr_preauthcmd(cmd, fr, frptr)
 ioctlcmd_t cmd;
 frentry_t *fr, **frptr;
 {
 	frauthent_t *fae, **faep;
 	int error = 0;
-# if !defined(MENAT) && defined(_KERNEL) && defined(USE_SPL)
-	int s;
-#endif
+	SPL_INT(s);
 
 	if ((cmd != SIOCADAFR) && (cmd != SIOCRMAFR))
 		return EIO;
-	
+
 	for (faep = &fae_list; ((fae = *faep) != NULL); ) {
 		if (&fae->fae_fr == fr)
 			break;
@@ -755,6 +652,7 @@
 			fae->fae_age = fr_defaultauthage;
 			fae->fae_fr.fr_hits = 0;
 			fae->fae_fr.fr_next = *frptr;
+			fae->fae_ref = 1;
 			*frptr = &fae->fae_fr;
 			fae->fae_next = *faep;
 			*faep = fae;
@@ -769,11 +667,18 @@
 }
 
 
-/*
- * Flush held packets.
- * Must already be properly SPL'ed and Locked on &ipf_auth.
- *
- */
+/* ------------------------------------------------------------------------ */
+/* Function:    fr_authflush                                                */
+/* Returns:     int - number of auth entries flushed                        */
+/* Parameters:  None                                                        */
+/* Locks:       WRITE(ipf_auth)                                             */
+/*                                                                          */
+/* This function flushs the fr_authpkts array of any packet data with       */
+/* references still there.                                                  */
+/* It is expected that the caller has already acquired the correct locks or */
+/* set the priority level correctly for this to block out other code paths  */
+/* into these data structures.                                              */
+/* ------------------------------------------------------------------------ */
 int fr_authflush()
 {
 	register int i, num_flushed;
@@ -803,3 +708,336 @@
 
 	return num_flushed;
 }
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    fr_auth_waiting                                             */
+/* Returns:     int - 0 = no pakcets wiating, 1 = packets waiting.          */
+/* Parameters:  None                                                        */
+/*                                                                          */
+/* Simple truth check to see if there are any packets waiting in the auth   */
+/* queue.                                                                   */
+/* ------------------------------------------------------------------------ */
+int fr_auth_waiting()
+{
+	return (fr_authused != 0);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    fr_authgeniter                                              */
+/* Returns:     int - 0 == success, else error                              */
+/* Parameters:  token(I) - pointer to ipftoken structure                    */
+/*              itp(I)   - pointer to ipfgeniter structure                  */
+/*                                                                          */
+/* ------------------------------------------------------------------------ */
+int fr_authgeniter(token, itp)
+ipftoken_t *token;
+ipfgeniter_t *itp;
+{
+	frauthent_t *fae, *next, zero;
+	int error;
+
+	if (itp->igi_data == NULL)
+		return EFAULT;
+
+	if (itp->igi_type != IPFGENITER_AUTH)
+		return EINVAL;
+
+	fae = token->ipt_data;
+	READ_ENTER(&ipf_auth);
+	if (fae == NULL) {
+		next = fae_list;
+	} else {
+		next = fae->fae_next;
+	}
+
+	if (next != NULL) {
+		/*
+		 * If we find an auth entry to use, bump its reference count
+		 * so that it can be used for is_next when we come back.
+		 */
+		ATOMIC_INC(next->fae_ref);
+		if (next->fae_next == NULL) {
+			ipf_freetoken(token);
+			token = NULL;
+		} else {
+			token->ipt_data = next;
+		}
+	} else {
+		bzero(&zero, sizeof(zero));
+		next = &zero;
+	}
+	RWLOCK_EXIT(&ipf_auth);
+
+	/*
+	 * If we had a prior pointer to an auth entry, release it.
+	 */
+	if (fae != NULL) {
+		WRITE_ENTER(&ipf_auth);
+		fr_authderef(&fae);
+		RWLOCK_EXIT(&ipf_auth);
+	}
+
+	/*
+	 * This should arguably be via fr_outobj() so that the auth
+	 * structure can (if required) be massaged going out.
+	 */
+	error = COPYOUT(next, itp->igi_data, sizeof(*next));
+	if (error != 0)
+		error = EFAULT;
+
+	return error;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    fr_authderef                                                */
+/* Returns:     None                                                        */
+/* Parameters:  faep(IO) - pointer to caller's frauthent_t pointer          */
+/* Locks:       WRITE(ipf_auth)                                             */
+/*                                                                          */
+/* This function unconditionally sets the pointer in the caller to NULL,    */
+/* to make it clear that it should no longer use that pointer, and drops    */
+/* the reference count on the structure by 1.  If it reaches 0, free it up. */
+/* ------------------------------------------------------------------------ */
+void fr_authderef(faep)
+frauthent_t **faep;
+{
+	frauthent_t *fae;
+
+	fae = *faep;
+	*faep = NULL;
+
+	fae->fae_ref--;
+	if (fae->fae_ref == 0) {
+		KFREE(fae);
+	}
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    fr_authwait                                                 */
+/* Returns:     int - 0 == success, else error                              */
+/* Parameters:  data(I) - pointer to data from ioctl call                   */
+/*                                                                          */
+/* This function is called when an application is waiting for a packet to   */
+/* match an "auth" rule by issuing an SIOCAUTHW ioctl.  If there is already */
+/* a packet waiting on the queue then we will return that _one_ immediately.*/
+/* If there are no packets present in the queue (fr_authpkts) then we go to */
+/* sleep.                                                                   */
+/* ------------------------------------------------------------------------ */
+int fr_authwait(data)
+char *data;
+{
+	frauth_t auth, *au = &auth;
+	int error, len, i;
+	mb_t *m;
+	char *t;
+#if defined(_KERNEL) && !defined(MENTAT) && !defined(linux) && \
+    (!defined(__FreeBSD_version) || (__FreeBSD_version < 501000))
+	SPL_INT(s);
+#endif
+
+fr_authioctlloop:
+	error = fr_inobj(data, au, IPFOBJ_FRAUTH);
+	if (error != 0)
+		return error;
+
+	/*
+	 * XXX Locks are held below over calls to copyout...a better
+	 * solution needs to be found so this isn't necessary.  The situation
+	 * we are trying to guard against here is an error in the copyout
+	 * steps should not cause the packet to "disappear" from the queue.
+	 */
+	READ_ENTER(&ipf_auth);
+
+	/*
+	 * If fr_authnext is not equal to fr_authend it will be because there
+	 * is a packet waiting to be delt with in the fr_authpkts array.  We
+	 * copy as much of that out to user space as requested.
+	 */
+	if (fr_authused > 0) {
+		while (fr_authpkts[fr_authnext] == NULL) {
+			fr_authnext++;
+			if (fr_authnext == fr_authsize)
+				fr_authnext = 0;
+		}
+
+		error = fr_outobj(data, &fr_auth[fr_authnext], IPFOBJ_FRAUTH);
+		if (error != 0)
+			return error;
+
+		if (auth.fra_len != 0 && auth.fra_buf != NULL) {
+			/*
+			 * Copy packet contents out to user space if
+			 * requested.  Bail on an error.
+			 */
+			m = fr_authpkts[fr_authnext];
+			len = MSGDSIZE(m);
+			if (len > auth.fra_len)
+				len = auth.fra_len;
+			auth.fra_len = len;
+
+			for (t = auth.fra_buf; m && (len > 0); ) {
+				i = MIN(M_LEN(m), len);
+				error = copyoutptr(MTOD(m, char *), &t, i);
+				len -= i;
+				t += i;
+				if (error != 0)
+					return error;
+				m = m->m_next;
+			}
+		}
+		RWLOCK_EXIT(&ipf_auth);
+
+		SPL_NET(s);
+		WRITE_ENTER(&ipf_auth);
+		fr_authnext++;
+		if (fr_authnext == fr_authsize)
+			fr_authnext = 0;
+		RWLOCK_EXIT(&ipf_auth);
+		SPL_X(s);
+
+		return 0;
+	}
+	RWLOCK_EXIT(&ipf_auth);
+
+	MUTEX_ENTER(&ipf_authmx);
+#ifdef	_KERNEL
+# if	SOLARIS
+	error = 0;
+	if (!cv_wait_sig(&ipfauthwait, &ipf_authmx.ipf_lk))
+		error = EINTR;
+# else /* SOLARIS */
+#  ifdef __hpux
+	{
+	lock_t *l;
+
+	l = get_sleep_lock(&fr_authnext);
+	error = sleep(&fr_authnext, PZERO+1);
+	spinunlock(l);
+	}
+#  else
+#   ifdef __osf__
+	error = mpsleep(&fr_authnext, PSUSP|PCATCH, "fr_authnext", 0,
+			&ipf_authmx, MS_LOCK_SIMPLE);
+#   else
+	error = SLEEP(&fr_authnext, "fr_authnext");
+#   endif /* __osf__ */
+#  endif /* __hpux */
+# endif /* SOLARIS */
+#endif
+	MUTEX_EXIT(&ipf_authmx);
+	if (error == 0)
+		goto fr_authioctlloop;
+	return error;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    fr_authreply                                                */
+/* Returns:     int - 0 == success, else error                              */
+/* Parameters:  data(I) - pointer to data from ioctl call                   */
+/*                                                                          */
+/* This function is called by an application when it wants to return a      */
+/* decision on a packet using the SIOCAUTHR ioctl.  This is after it has    */
+/* received information using an SIOCAUTHW.  The decision returned in the   */
+/* form of flags, the same as those used in each rule.                      */
+/* ------------------------------------------------------------------------ */
+int fr_authreply(data)
+char *data;
+{
+	frauth_t auth, *au = &auth, *fra;
+	int error, i;
+	mb_t *m;
+	SPL_INT(s);
+
+	error = fr_inobj(data, &auth, IPFOBJ_FRAUTH);
+	if (error != 0)
+		return error;
+
+	SPL_NET(s);
+	WRITE_ENTER(&ipf_auth);
+
+	i = au->fra_index;
+	fra = fr_auth + i;
+	error = 0;
+
+	/*
+	 * Check the validity of the information being returned with two simple
+	 * checks.  First, the auth index value should be within the size of
+	 * the array and second the packet id being returned should also match.
+	 */
+	if ((i < 0) || (i >= fr_authsize) ||
+	    (fra->fra_info.fin_id != au->fra_info.fin_id)) {
+		RWLOCK_EXIT(&ipf_auth);
+		SPL_X(s);
+		return ESRCH;
+	}
+
+	m = fr_authpkts[i];
+	fra->fra_index = -2;
+	fra->fra_pass = au->fra_pass;
+	fr_authpkts[i] = NULL;
+
+	RWLOCK_EXIT(&ipf_auth);
+
+	/*
+	 * Re-insert the packet back into the packet stream flowing through
+	 * the kernel in a manner that will mean IPFilter sees the packet
+	 * again.  This is not the same as is done with fastroute,
+	 * deliberately, as we want to resume the normal packet processing
+	 * path for it.
+	 */
+#ifdef	_KERNEL
+	if ((m != NULL) && (au->fra_info.fin_out != 0)) {
+		error = ipf_inject(&fra->fra_info, m);
+		if (error != 0) {
+			error = ENOBUFS;
+			fr_authstats.fas_sendfail++;
+		} else {
+			fr_authstats.fas_sendok++;
+		}
+	} else if (m) {
+		error = ipf_inject(&fra->fra_info, m);
+		if (error != 0) {
+			error = ENOBUFS;
+			fr_authstats.fas_quefail++;
+		} else {
+			fr_authstats.fas_queok++;
+		}
+	} else {
+		error = EINVAL;
+	}
+
+	/*
+	 * If we experience an error which will result in the packet
+	 * not being processed, make sure we advance to the next one.
+	 */
+	if (error == ENOBUFS) {
+		WRITE_ENTER(&ipf_auth);
+		fr_authused--;
+		fra->fra_index = -1;
+		fra->fra_pass = 0;
+		if (i == fr_authstart) {
+			while (fra->fra_index == -1) {
+				i++;
+				if (i == fr_authsize)
+					i = 0;
+				fr_authstart = i;
+				if (i == fr_authend)
+					break;
+			}
+			if (fr_authstart == fr_authend) {
+				fr_authnext = 0;
+				fr_authstart = fr_authend = 0;
+			}
+		}
+		RWLOCK_EXIT(&ipf_auth);
+	}
+#endif /* _KERNEL */
+	SPL_X(s);
+
+	return 0;
+}
Index: ip_fil.h
===================================================================
RCS file: /home/cvs/src/sys/contrib/ipfilter/netinet/ip_fil.h,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/contrib/ipfilter/netinet/ip_fil.h -L sys/contrib/ipfilter/netinet/ip_fil.h -u -r1.1.1.1 -r1.2
--- sys/contrib/ipfilter/netinet/ip_fil.h
+++ sys/contrib/ipfilter/netinet/ip_fil.h
@@ -1,13 +1,11 @@
-/*	$FreeBSD: src/sys/contrib/ipfilter/netinet/ip_fil.h,v 1.31 2005/04/26 17:58:05 darrenr Exp $	*/
-
 /*
  * Copyright (C) 1993-2001, 2003 by Darren Reed.
  *
  * See the IPFILTER.LICENCE file for details on licencing.
  *
  * @(#)ip_fil.h	1.35 6/5/96
- * $FreeBSD: src/sys/contrib/ipfilter/netinet/ip_fil.h,v 1.31 2005/04/26 17:58:05 darrenr Exp $
- * Id: ip_fil.h,v 2.170.2.18 2005/03/28 10:47:52 darrenr Exp
+ * $FreeBSD: src/sys/contrib/ipfilter/netinet/ip_fil.h,v 1.35.2.1 2007/10/31 05:00:37 darrenr Exp $
+ * Id: ip_fil.h,v 2.170.2.51 2007/10/10 09:48:03 darrenr Exp $
  */
 
 #ifndef	__IP_FIL_H__
@@ -27,7 +25,7 @@
 # endif
 #endif
 
-#if defined(__STDC__) || defined(__GNUC__)
+#if defined(__STDC__) || defined(__GNUC__) || defined(_AIX51)
 # define	SIOCADAFR	_IOW('r', 60, struct ipfobj)
 # define	SIOCRMAFR	_IOW('r', 61, struct ipfobj)
 # define	SIOCSETFF	_IOW('r', 62, u_int)
@@ -46,12 +44,12 @@
 # define	SIOCZRLST	_IOWR('r', 75, struct ipfobj)
 # define	SIOCAUTHW	_IOWR('r', 76, struct ipfobj)
 # define	SIOCAUTHR	_IOWR('r', 77, struct ipfobj)
-# define	SIOCATHST	_IOWR('r', 78, struct ipfobj)
+# define	SIOCSTAT1	_IOWR('r', 78, struct ipfobj)
 # define	SIOCSTLCK	_IOWR('r', 79, u_int)
 # define	SIOCSTPUT	_IOWR('r', 80, struct ipfobj)
 # define	SIOCSTGET	_IOWR('r', 81, struct ipfobj)
 # define	SIOCSTGSZ	_IOWR('r', 82, struct ipfobj)
-# define	SIOCGFRST	_IOWR('r', 83, struct ipfobj)
+# define	SIOCSTAT2	_IOWR('r', 83, struct ipfobj)
 # define	SIOCSETLG	_IOWR('r', 84, int)
 # define	SIOCGETLG	_IOWR('r', 85, int)
 # define	SIOCFUNCL	_IOWR('r', 86, struct ipfunc_resolve)
@@ -59,6 +57,12 @@
 # define	SIOCIPFGET	_IOWR('r', 88, struct ipfobj)
 # define	SIOCIPFSET	_IOWR('r', 89, struct ipfobj)
 # define	SIOCIPFL6	_IOWR('r', 90, int)
+# define	SIOCIPFITER	_IOWR('r', 91, struct ipfobj)
+# define	SIOCGENITER	_IOWR('r', 92, struct ipfobj)
+# define	SIOCGTABL	_IOWR('r', 93, struct ipfobj)
+# define	SIOCIPFDELTOK	_IOWR('r', 94, int)
+# define	SIOCLOOKUPITER	_IOWR('r', 95, struct ipfobj)
+# define	SIOCGTQTAB	_IOWR('r', 96, struct ipfobj)
 #else
 # define	SIOCADAFR	_IOW(r, 60, struct ipfobj)
 # define	SIOCRMAFR	_IOW(r, 61, struct ipfobj)
@@ -78,12 +82,12 @@
 # define	SIOCZRLST	_IOWR(r, 75, struct ipfobj)
 # define	SIOCAUTHW	_IOWR(r, 76, struct ipfobj)
 # define	SIOCAUTHR	_IOWR(r, 77, struct ipfobj)
-# define	SIOCATHST	_IOWR(r, 78, struct ipfobj)
+# define	SIOCSTAT1	_IOWR(r, 78, struct ipfobj)
 # define	SIOCSTLCK	_IOWR(r, 79, u_int)
 # define	SIOCSTPUT	_IOWR(r, 80, struct ipfobj)
 # define	SIOCSTGET	_IOWR(r, 81, struct ipfobj)
 # define	SIOCSTGSZ	_IOWR(r, 82, struct ipfobj)
-# define	SIOCGFRST	_IOWR(r, 83, struct ipfobj)
+# define	SIOCSTAT2	_IOWR(r, 83, struct ipfobj)
 # define	SIOCSETLG	_IOWR(r, 84, int)
 # define	SIOCGETLG	_IOWR(r, 85, int)
 # define	SIOCFUNCL	_IOWR(r, 86, struct ipfunc_resolve)
@@ -91,10 +95,18 @@
 # define	SIOCIPFGET	_IOWR(r, 88, struct ipfobj)
 # define	SIOCIPFSET	_IOWR(r, 89, struct ipfobj)
 # define	SIOCIPFL6	_IOWR(r, 90, int)
+# define	SIOCIPFITER	_IOWR(r, 91, struct ipfobj)
+# define	SIOCGENITER	_IOWR(r, 92, struct ipfobj)
+# define	SIOCGTABL	_IOWR(r, 93, struct ipfobj)
+# define	SIOCIPFDELTOK	_IOWR(r, 94, int)
+# define	SIOCLOOKUPITER	_IOWR(r, 95, struct ipfobj)
+# define	SIOCGTQTAB	_IOWR(r, 96, struct ipfobj)
 #endif
 #define	SIOCADDFR	SIOCADAFR
 #define	SIOCDELFR	SIOCRMAFR
 #define	SIOCINSFR	SIOCINAFR
+#define	SIOCATHST	SIOCSTAT1
+#define	SIOCGFRST	SIOCSTAT2
 
 
 struct ipscan;
@@ -114,6 +126,11 @@
 	struct	in6_addr in6;
 	void	*vptr[2];
 	lookupfunc_t	lptr[2];
+	struct {
+		u_short	type;
+		u_short	subtype;
+		char	label[12];
+	} i6un;
 } i6addr_t;
 #else
 typedef	union	i6addr	{
@@ -121,26 +138,33 @@
 	struct	in_addr	in4;
 	void	*vptr[2];
 	lookupfunc_t	lptr[2];
+	struct {
+		u_short	type;
+		u_short	subtype;
+		char	label[12];
+	} i6un;
 } i6addr_t;
 #endif
 
 #define in4_addr	in4.s_addr
-#define	iplookupnum	i6[0]
-#define	iplookuptype	i6[1]
+#define	iplookupnum	i6[1]
+#define	iplookupname	i6un.label
+#define	iplookuptype	i6un.type
+#define	iplookupsubtype	i6un.subtype
 /*
  * NOTE: These DO overlap the above on 64bit systems and this IS recognised.
  */
 #define	iplookupptr	vptr[0]
 #define	iplookupfunc	lptr[1]
 
-#define	I60(x)	(((i6addr_t *)(x))->i6[0])
-#define	I61(x)	(((i6addr_t *)(x))->i6[1])
-#define	I62(x)	(((i6addr_t *)(x))->i6[2])
-#define	I63(x)	(((i6addr_t *)(x))->i6[3])
-#define	HI60(x)	ntohl(((i6addr_t *)(x))->i6[0])
-#define	HI61(x)	ntohl(((i6addr_t *)(x))->i6[1])
-#define	HI62(x)	ntohl(((i6addr_t *)(x))->i6[2])
-#define	HI63(x)	ntohl(((i6addr_t *)(x))->i6[3])
+#define	I60(x)	(((u_32_t *)(x))[0])
+#define	I61(x)	(((u_32_t *)(x))[1])
+#define	I62(x)	(((u_32_t *)(x))[2])
+#define	I63(x)	(((u_32_t *)(x))[3])
+#define	HI60(x)	ntohl(((u_32_t *)(x))[0])
+#define	HI61(x)	ntohl(((u_32_t *)(x))[1])
+#define	HI62(x)	ntohl(((u_32_t *)(x))[2])
+#define	HI63(x)	ntohl(((u_32_t *)(x))[3])
 
 #define	IP6_EQ(a,b)	((I63(a) == I63(b)) && (I62(a) == I62(b)) && \
 			 (I61(a) == I61(b)) && (I60(a) == I60(b)))
@@ -158,14 +182,14 @@
 			      HI63(a) < HI63(b)))))))
 #define	NLADD(n,x)	htonl(ntohl(n) + (x))
 #define	IP6_INC(a)	\
-		{ i6addr_t *_i6 = (i6addr_t *)(a); \
-		  _i6->i6[0] = NLADD(_i6->i6[0], 1); \
-		  if (_i6->i6[0] == 0) { \
-			_i6->i6[0] = NLADD(_i6->i6[1], 1); \
-			if (_i6->i6[1] == 0) { \
-				_i6->i6[0] = NLADD(_i6->i6[2], 1); \
-				if (_i6->i6[2] == 0) { \
-					_i6->i6[0] = NLADD(_i6->i6[3], 1); \
+		{ u_32_t *_i6 = (u_32_t *)(a); \
+		  _i6[3] = NLADD(_i6[3], 1); \
+		  if (_i6[3] == 0) { \
+			_i6[2] = NLADD(_i6[2], 1); \
+			if (_i6[2] == 0) { \
+				_i6[1] = NLADD(_i6[1], 1); \
+				if (_i6[1] == 0) { \
+					_i6[0] = NLADD(_i6[0], 1); \
 				} \
 			} \
 		  } \
@@ -239,11 +263,12 @@
 #define	FI_FRAGBODY	0x2000
 #define	FI_BADSRC	0x4000
 #define	FI_LOWTTL	0x8000
-#define	FI_CMP		0xcfe3	/* Not FI_FRAG,FI_NATED,FI_FRAGTAIL */
+#define	FI_CMP		0xcf03	/* Not FI_FRAG,FI_NATED,FI_FRAGTAIL,broadcast */
 #define	FI_ICMPCMP	0x0003	/* Flags we can check for ICMP error packets */
 #define	FI_WITH		0xeffe	/* Not FI_TCPUDP */
 #define	FI_V6EXTHDR	0x10000
 #define	FI_COALESCE	0x20000
+#define	FI_NEWNAT	0x40000
 #define	FI_NOCKSUM	0x20000000	/* don't do a L4 checksum validation */
 #define	FI_DONTCACHE	0x40000000	/* don't cache the result */
 #define	FI_IGNORE	0x80000000
@@ -252,8 +277,12 @@
 #define	fi_daddr	fi_dst.in4.s_addr
 #define	fi_srcnum	fi_src.iplookupnum
 #define	fi_dstnum	fi_dst.iplookupnum
+#define	fi_srcname	fi_src.iplookupname
+#define	fi_dstname	fi_dst.iplookupname
 #define	fi_srctype	fi_src.iplookuptype
 #define	fi_dsttype	fi_dst.iplookuptype
+#define	fi_srcsubtype	fi_src.iplookupsubtype
+#define	fi_dstsubtype	fi_dst.iplookupsubtype
 #define	fi_srcptr	fi_src.iplookupptr
 #define	fi_dstptr	fi_dst.iplookupptr
 #define	fi_srcfunc	fi_src.iplookupfunc
@@ -299,15 +328,18 @@
 	u_short	fin_off;
 	int	fin_depth;		/* Group nesting depth */
 	int	fin_error;		/* Error code to return */
+	int	fin_cksum;		/* -1 bad, 1 good, 0 not done */
 	void	*fin_nat;
 	void	*fin_state;
 	void	*fin_nattag;
+	void	*fin_exthdr;
 	ip_t	*fin_ip;
 	mb_t	**fin_mp;		/* pointer to pointer to mbuf */
 	mb_t	*fin_m;			/* pointer to mbuf */
 #ifdef	MENTAT
 	mb_t	*fin_qfm;		/* pointer to mblk where pkt starts */
 	void	*fin_qpi;
+	char	fin_ifname[LIFNAMSIZ];
 #endif
 #ifdef	__sgi
 	void	*fin_hbuf;
@@ -331,8 +363,8 @@
 #define	fin_dport	fin_dat.fid_16[1]
 #define	fin_ports	fin_dat.fid_32
 
-#define	IPF_IN	0
-#define	IPF_OUT	1
+#define	IPF_IN		0
+#define	IPF_OUT		1
 
 typedef	struct frentry	*(*ipfunc_t) __P((fr_info_t *, u_32_t *));
 typedef	int		(*ipfuncinit_t) __P((struct frentry *));
@@ -442,9 +474,13 @@
 	int	fri_difpidx;		/* index into fr_ifps[] to use when */
 } fripf_t;
 
-#define	fri_dstnum	fri_ip.fi_dstnum
+#define	fri_dlookup	fri_mip.fi_dst
+#define	fri_slookup	fri_mip.fi_src
+#define	fri_dstnum	fri_mip.fi_dstnum
 #define	fri_srcnum	fri_mip.fi_srcnum
-#define	fri_dstptr	fri_ip.fi_dstptr
+#define	fri_dstname	fri_mip.fi_dstname
+#define	fri_srcname	fri_mip.fi_srcname
+#define	fri_dstptr	fri_mip.fi_dstptr
 #define	fri_srcptr	fri_mip.fi_srcptr
 
 #define	FRI_NORMAL	0	/* Normal address */
@@ -470,6 +506,13 @@
 	int	fr_ref;		/* reference count - for grouping */
 	int	fr_statecnt;	/* state count - for limit rules */
 	/*
+	 * The line number from a file is here because we need to be able to
+	 * match the rule generated with ``grep rule ipf.conf | ipf -rf -''
+	 * with the rule loaded using ``ipf -f ipf.conf'' - thus it can't be
+	 * on the other side of fr_func.
+	 */
+	int	fr_flineno;	/* line number from conf file */
+	/*
 	 * These are only incremented when a packet  matches this rule and
 	 * it is the last match
 	 */
@@ -496,7 +539,6 @@
 	int	fr_dsize;
 	int	fr_pps;
 	int	fr_statemax;	/* max reference count */
-	int	fr_flineno;	/* line number from conf file */
 	u_32_t	fr_type;
 	u_32_t	fr_flags;	/* per-rule flags && options (see below) */
 	u_32_t	fr_logtag;	/* user defined log tag # */
@@ -556,8 +598,14 @@
 #define	fr_smask	fr_mip.fi_src.in4.s_addr
 #define	fr_dstnum	fr_ip.fi_dstnum
 #define	fr_srcnum	fr_ip.fi_srcnum
+#define	fr_dlookup	fr_ip.fi_dst
+#define	fr_slookup	fr_ip.fi_src
+#define	fr_dstname	fr_ip.fi_dstname
+#define	fr_srcname	fr_ip.fi_srcname
 #define	fr_dsttype	fr_ip.fi_dsttype
 #define	fr_srctype	fr_ip.fi_srctype
+#define	fr_dstsubtype	fr_ip.fi_dstsubtype
+#define	fr_srcsubtype	fr_ip.fi_srcsubtype
 #define	fr_dstptr	fr_mip.fi_dstptr
 #define	fr_srcptr	fr_mip.fi_srcptr
 #define	fr_dstfunc	fr_mip.fi_dstfunc
@@ -907,6 +955,7 @@
 
 #define	TCP_WSCALE_SEEN		0x00000001
 #define	TCP_WSCALE_FIRST	0x00000002
+#define	TCP_SACK_PERMIT		0x00000004
 
 
 typedef	struct tcpinfo {
@@ -916,6 +965,9 @@
 } tcpinfo_t;
 
 
+/*
+ * Structures to define a GRE header as seen in a packet.
+ */
 struct	grebits	{
 	u_32_t	grb_C:1;
 	u_32_t	grb_R:1;
@@ -950,7 +1002,9 @@
 #define	gr_A		gr_bits.grb_A
 #define	gr_ver		gr_bits.grb_ver
 
-
+/*
+ * GRE information tracked by "keep state"
+ */
 typedef	struct	greinfo	{
 	u_short	gs_call[2];
 	u_short	gs_flags;
@@ -961,6 +1015,20 @@
 
 
 /*
+ * Format of an Authentication header
+ */
+typedef	struct	authhdr	{
+	u_char	ah_next;
+	u_char	ah_plen;
+	u_short	ah_reserved;
+	u_32_t	ah_spi;
+	u_32_t	ah_seq;
+	/* Following the sequence number field is 0 or more bytes of */
+	/* authentication data, as specified by ah_plen - RFC 2402.  */
+} authhdr_t;
+
+
+/*
  * Timeout tail queue list member
  */
 typedef	struct	ipftqent	{
@@ -1000,6 +1068,8 @@
 					/* checks its timeout queues.       */
 #define	IPF_TTLVAL(x)	(((x) / IPF_HZ_MULT) * IPF_HZ_DIVIDE)
 
+typedef	int	(*ipftq_delete_fn_t)(void *);       
+
 /*
  * Structure to define address for pool lookups.
  */
@@ -1035,6 +1105,13 @@
 #define	IPFOBJ_STATESTAT	11	/* struct ips_stat */
 #define	IPFOBJ_FRAUTH		12	/* struct frauth */
 #define	IPFOBJ_TUNEABLE		13	/* struct ipftune */
+#define	IPFOBJ_NAT		14	/* struct nat */
+#define	IPFOBJ_IPFITER		15	/* struct ipfruleiter */
+#define	IPFOBJ_GENITER		16	/* struct ipfgeniter */
+#define	IPFOBJ_GTABLE		17	/* struct ipftable */
+#define	IPFOBJ_LOOKUPITER	18	/* struct ipflookupiter */
+#define	IPFOBJ_STATETQTAB	19	/* struct ipftq [NSTATES] */
+#define	IPFOBJ_COUNT		20	/* How many #defines are above this? */
 
 
 typedef	union	ipftunevalptr	{
@@ -1047,7 +1124,7 @@
 
 typedef	struct	ipftuneable	{
 	ipftunevalptr_t	ipft_una;
-	char		*ipft_name;
+	const char	*ipft_name;
 	u_long		ipft_min;
 	u_long		ipft_max;
 	int		ipft_sz;
@@ -1086,6 +1163,68 @@
 #define	ipft_vshort	ipft_un.ipftu_short
 #define	ipft_vchar	ipft_un.ipftu_char
 
+/*
+ *
+ */
+typedef	struct	ipfruleiter {
+	int		iri_inout;
+	char		iri_group[FR_GROUPLEN];
+	int		iri_active;
+	int		iri_nrules;
+	int		iri_v;
+	frentry_t	*iri_rule;
+} ipfruleiter_t;
+
+/*
+ * Values for iri_inout
+ */
+#define	F_IN	0
+#define	F_OUT	1
+#define	F_ACIN	2
+#define	F_ACOUT	3
+
+
+typedef	struct	ipfgeniter {
+	int	igi_type;
+	int	igi_nitems;
+	void	*igi_data;
+} ipfgeniter_t;
+
+#define	IPFGENITER_IPF		0
+#define	IPFGENITER_NAT		1
+#define	IPFGENITER_IPNAT	2
+#define	IPFGENITER_FRAG		3
+#define	IPFGENITER_AUTH		4
+#define	IPFGENITER_STATE	5
+#define	IPFGENITER_NATFRAG	6
+#define	IPFGENITER_HOSTMAP	7
+#define	IPFGENITER_LOOKUP	8
+
+typedef	struct	ipftable {
+	int	ita_type;
+	void	*ita_table;
+} ipftable_t;
+
+#define	IPFTABLE_BUCKETS	1
+#define	IPFTABLE_BUCKETS_NATIN	2
+#define	IPFTABLE_BUCKETS_NATOUT	3
+
+
+/*
+ *
+ */
+typedef struct ipftoken {
+	struct ipftoken	*ipt_next;
+	struct ipftoken	**ipt_pnext;
+	void		*ipt_ctx;
+	void		*ipt_data;
+	u_long		ipt_die;
+	int		ipt_type;
+	int		ipt_uid;
+	int		ipt_subtype;
+	int		ipt_alive;
+} ipftoken_t;
+
 
 /*
 ** HPUX Port
@@ -1108,7 +1247,7 @@
 #if (defined(NetBSD) && (NetBSD > 199609) && (NetBSD <= 1991011)) || \
     (defined(NetBSD1_2) && NetBSD1_2 > 1) || \
     (defined(__FreeBSD__) && (__FreeBSD_version >= 500043))
-# if (NetBSD >= 199905)
+# if defined(NetBSD) && (NetBSD >= 199905)
 #  define PFIL_HOOKS
 # endif
 # ifdef PFIL_HOOKS
@@ -1116,6 +1255,17 @@
 # endif
 #endif
 
+#ifdef _KERNEL
+# define	FR_VERBOSE(verb_pr)
+# define	FR_DEBUG(verb_pr)
+#else
+extern	void	debug __P((char *, ...));
+extern	void	verbose __P((char *, ...));
+# define	FR_VERBOSE(verb_pr)	verbose verb_pr
+# define	FR_DEBUG(verb_pr)	debug verb_pr
+#endif
+
+
 #ifndef	_KERNEL
 extern	int	fr_check __P((struct ip *, int, void *, int, mb_t **));
 extern	int	(*fr_checkp) __P((ip_t *, int, void *, int, mb_t **));
@@ -1131,12 +1281,24 @@
 extern	int	iplopen __P((dev_t, int));
 extern	int	iplclose __P((dev_t, int));
 extern	void	m_freem __P((mb_t *));
+extern	int	bcopywrap __P((void *, void *, size_t));
 #else /* #ifndef _KERNEL */
+# ifdef BSD
+#  if (defined(__NetBSD__) && (__NetBSD_Version__ < 399000000)) || \
+      defined(__osf__) || \
+      (defined(__FreeBSD_version) && (__FreeBSD_version < 500043))
+#   include <sys/select.h>
+#  else
+#   include <sys/selinfo.h>
+#  endif
+extern struct selinfo ipfselwait[IPL_LOGSIZE];
+# endif
 # if defined(__NetBSD__) && defined(PFIL_HOOKS)
 extern	void	ipfilterattach __P((int));
 # endif
 extern	int	ipl_enable __P((void));
 extern	int	ipl_disable __P((void));
+extern	int	ipf_inject __P((fr_info_t *, mb_t *));
 # ifdef MENTAT
 extern	int	fr_check __P((struct ip *, int, void *, int, void *,
 			      mblk_t **));
@@ -1159,7 +1321,6 @@
 extern	int	iplwrite __P((dev_t, uio_t *));
 extern	int	iplselect __P((dev_t, int));
 #  endif
-extern	int	ipfsync __P((void));
 extern	int	fr_qout __P((queue_t *, mblk_t *));
 # else /* MENTAT */
 extern	int	fr_check __P((struct ip *, int, void *, int, mb_t **));
@@ -1172,7 +1333,6 @@
 extern	int	iplclose __P((dev_t, int, int, cred_t *));
 extern	int	iplread __P((dev_t, uio_t *, cred_t *));
 extern	int	iplwrite __P((dev_t, uio_t *, cred_t *));
-extern	int	ipfsync __P((void));
 extern	int	ipfilter_sgi_attach __P((void));
 extern	void	ipfilter_sgi_detach __P((void));
 extern	void	ipfilter_sgi_intfsync __P((void));
@@ -1180,9 +1340,11 @@
 #   ifdef	IPFILTER_LKM
 extern	int	iplidentify __P((char *));
 #   endif
-#   if (_BSDI_VERSION >= 199510) || (__FreeBSD_version >= 220000) || \
+#   if (defined(_BSDI_VERSION) && _BSDI_VERSION >= 199510) || \
+      (__FreeBSD_version >= 220000) || \
       (NetBSD >= 199511) || defined(__OpenBSD__)
-#    if defined(__NetBSD__) || (_BSDI_VERSION >= 199701) || \
+#    if defined(__NetBSD__) || \
+       (defined(_BSDI_VERSION) && _BSDI_VERSION >= 199701) || \
        defined(__OpenBSD__) || (__FreeBSD_version >= 300000)
 #     if (__FreeBSD_version >= 500024)
 #      if (__FreeBSD_version >= 502116)
@@ -1191,7 +1353,15 @@
 extern	int	iplioctl __P((dev_t, u_long, caddr_t, int, struct thread *));
 #      endif /* __FreeBSD_version >= 502116 */
 #     else
+#      if  (__NetBSD_Version__ >= 499001000)
+extern	int	iplioctl __P((dev_t, u_long, void *, int, struct lwp *));
+#       else
+#       if  (__NetBSD_Version__ >= 399001400)
+extern	int	iplioctl __P((dev_t, u_long, caddr_t, int, struct lwp *));
+#       else
 extern	int	iplioctl __P((dev_t, u_long, caddr_t, int, struct proc *));
+#       endif
+#      endif
 #     endif /* __FreeBSD_version >= 500024 */
 #    else
 extern	int	iplioctl __P((dev_t, int, caddr_t, int, struct thread *));
@@ -1205,8 +1375,13 @@
 extern	int	iplclose __P((dev_t, int, int, struct thread *));
 #      endif /* __FreeBSD_version >= 502116 */
 #    else
+#     if  (__NetBSD_Version__ >= 399001400)
+extern	int	iplopen __P((dev_t, int, int, struct lwp *));
+extern	int	iplclose __P((dev_t, int, int, struct lwp *));
+#     else
 extern	int	iplopen __P((dev_t, int, int, struct proc *));
 extern	int	iplclose __P((dev_t, int, int, struct proc *));
+#     endif /* __NetBSD_Version__ >= 399001400 */
 #    endif /* __FreeBSD_version >= 500024 */
 #   else
 #    ifdef linux
@@ -1234,26 +1409,35 @@
 #  endif /* __ sgi */
 # endif /* MENTAT */
 
+# if defined(__FreeBSD_version)
+extern	int	ipf_pfil_hook __P((void));
+extern	int	ipf_pfil_unhook __P((void));
+extern	void	ipf_event_reg __P((void));
+extern	void	ipf_event_dereg __P((void));
+# endif
+
 #endif /* #ifndef _KERNEL */
 
 extern	ipfmutex_t	ipl_mutex, ipf_authmx, ipf_rw, ipf_hostmap;
 extern	ipfmutex_t	ipf_timeoutlock, ipf_stinsert, ipf_natio, ipf_nat_new;
 extern	ipfrwlock_t	ipf_mutex, ipf_global, ip_poolrw, ipf_ipidfrag;
 extern	ipfrwlock_t	ipf_frag, ipf_state, ipf_nat, ipf_natfrag, ipf_auth;
+extern	ipfrwlock_t	ipf_frcache, ipf_tokens;
 
-extern	char	*memstr __P((char *, char *, int, int));
+extern	char	*memstr __P((const char *, char *, size_t, size_t));
 extern	int	count4bits __P((u_32_t));
 extern	int	frrequest __P((int, ioctlcmd_t, caddr_t, int, int));
 extern	char	*getifname __P((struct ifnet *));
-extern	int	iplattach __P((void));
-extern	int	ipldetach __P((void));
+extern	int	ipfattach __P((void));
+extern	int	ipfdetach __P((void));
 extern	u_short	ipf_cksum __P((u_short *, int));
 extern	int	copyinptr __P((void *, void *, size_t));
 extern	int	copyoutptr __P((void *, void *, size_t));
 extern	int	fr_fastroute __P((mb_t *, mb_t **, fr_info_t *, frdest_t *));
 extern	int	fr_inobj __P((void *, void *, int));
 extern	int	fr_inobjsz __P((void *, void *, int, int));
-extern	int	fr_ioctlswitch __P((int, void *, ioctlcmd_t, int));
+extern	int	fr_ioctlswitch __P((int, void *, ioctlcmd_t, int, int, void *));
+extern	int	fr_ipf_ioctl __P((caddr_t, ioctlcmd_t, int, int, void *));
 extern	int	fr_ipftune __P((ioctlcmd_t, void *));
 extern	int	fr_outobj __P((void *, void *, int));
 extern	int	fr_outobjsz __P((void *, void *, int, int));
@@ -1263,7 +1447,7 @@
 extern	void	*fr_resolvenic __P((char *, int));
 extern	int	fr_send_icmp_err __P((int, fr_info_t *, int));
 extern	int	fr_send_reset __P((fr_info_t *));
-#if  (__FreeBSD_version < 490000) || !defined(_KERNEL)
+#if  (__FreeBSD_version < 501000) || !defined(_KERNEL)
 extern	int	ppsratecheck __P((struct timeval *, int *, int));
 #endif
 extern	ipftq_t	*fr_addtimeoutqueue __P((ipftq_t **, u_int));
@@ -1298,6 +1482,7 @@
 extern	frgroup_t *fr_findgroup __P((char *, minor_t, int, frgroup_t ***));
 
 extern	int	fr_loginit __P((void));
+extern	int	ipflog_canread __P((int));
 extern	int	ipflog_clear __P((minor_t));
 extern	int	ipflog_read __P((minor_t, uio_t *));
 extern	int	ipflog __P((fr_info_t *, u_int));
@@ -1306,7 +1491,7 @@
 
 extern	frentry_t	*fr_acctpkt __P((fr_info_t *, u_32_t *));
 extern	int		fr_copytolog __P((int, char *, int));
-extern	u_short		fr_cksum __P((mb_t *, ip_t *, int, void *));
+extern	u_short		fr_cksum __P((mb_t *, ip_t *, int, void *, int));
 extern	void		fr_deinitialise __P((void));
 extern	frentry_t 	*fr_dolog __P((fr_info_t *, u_32_t *));
 extern	frentry_t 	*fr_dstgrpmap __P((fr_info_t *, u_32_t *));
@@ -1314,23 +1499,30 @@
 extern	void		fr_forgetifp __P((void *));
 extern	frentry_t 	*fr_getrulen __P((int, char *, u_32_t));
 extern	void		fr_getstat __P((struct friostat *));
-extern	int		fr_icmp4errortype __P((int));
 extern	int		fr_ifpaddr __P((int, int, void *,
 				struct in_addr *, struct in_addr *));
 extern	int		fr_initialise __P((void));
-extern	void		fr_lock __P((caddr_t, int *));
+extern	int		fr_lock __P((caddr_t, int *));
 extern  int		fr_makefrip __P((int, ip_t *, fr_info_t *));
 extern	int		fr_matchtag __P((ipftag_t *, ipftag_t *));
 extern	int		fr_matchicmpqueryreply __P((int, icmpinfo_t *,
 					    struct icmp *, int));
 extern	u_32_t		fr_newisn __P((fr_info_t *));
 extern	u_short		fr_nextipid __P((fr_info_t *));
+extern	int	ipf_queueflush __P((ipftq_delete_fn_t, ipftq_t *, ipftq_t *));
 extern	int		fr_rulen __P((int, frentry_t *));
 extern	int		fr_scanlist __P((fr_info_t *, u_32_t));
 extern	frentry_t 	*fr_srcgrpmap __P((fr_info_t *, u_32_t *));
 extern	int		fr_tcpudpchk __P((fr_info_t *, frtuc_t *));
 extern	int		fr_verifysrc __P((fr_info_t *fin));
-extern	int		fr_zerostats __P((char *));
+extern	int		fr_zerostats __P((void *));
+extern	ipftoken_t	*ipf_findtoken __P((int, int, void *));
+extern	int		ipf_getnextrule __P((ipftoken_t *, void *));
+extern	void		ipf_expiretokens __P((void));
+extern	void		ipf_freetoken __P((ipftoken_t *));
+extern	int		ipf_deltoken __P((int,int, void *));
+extern	int		ipfsync __P((void));
+extern	int		ipf_genericiter __P((void *, int, void *));
 
 extern	int	fr_running;
 extern	u_long	fr_frouteok[2];
@@ -1345,7 +1537,6 @@
 extern	int	nat_logging;
 extern	int	ipstate_logging;
 extern	int	ipl_suppress;
-extern	int	ipl_buffer_sz;
 extern	int	ipl_logmax;
 extern	int	ipl_logall;
 extern	int	ipl_logsize;
Index: ip_frag.h
===================================================================
RCS file: /home/cvs/src/sys/contrib/ipfilter/netinet/ip_frag.h,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/contrib/ipfilter/netinet/ip_frag.h -L sys/contrib/ipfilter/netinet/ip_frag.h -u -r1.1.1.1 -r1.2
--- sys/contrib/ipfilter/netinet/ip_frag.h
+++ sys/contrib/ipfilter/netinet/ip_frag.h
@@ -1,4 +1,4 @@
-/*	$FreeBSD: src/sys/contrib/ipfilter/netinet/ip_frag.h,v 1.17 2005/04/25 18:43:14 darrenr Exp $	*/
+/*	$FreeBSD: src/sys/contrib/ipfilter/netinet/ip_frag.h,v 1.19 2007/06/04 02:54:35 darrenr Exp $	*/
 
 /*
  * Copyright (C) 1993-2001 by Darren Reed.
@@ -6,7 +6,7 @@
  * See the IPFILTER.LICENCE file for details on licencing.
  *
  * @(#)ip_frag.h	1.5 3/24/96
- * $FreeBSD: src/sys/contrib/ipfilter/netinet/ip_frag.h,v 1.17 2005/04/25 18:43:14 darrenr Exp $
+ * $FreeBSD: src/sys/contrib/ipfilter/netinet/ip_frag.h,v 1.19 2007/06/04 02:54:35 darrenr Exp $
  * Id: ip_frag.h,v 2.23.2.1 2004/03/29 16:21:56 darrenr Exp
  */
 
@@ -19,6 +19,16 @@
 	struct	ipfr	*ipfr_hnext, **ipfr_hprev;
 	struct	ipfr	*ipfr_next, **ipfr_prev;
 	void	*ipfr_data;
+	frentry_t *ipfr_rule;
+	u_long	ipfr_ttl;
+	int	ipfr_ref;
+	u_short	ipfr_off;
+	u_short	ipfr_seen0;
+	/*
+	 * All of the fields, from ipfr_ifp to ipfr_pass, are compared
+	 * using bcmp to see if an identical entry is present.  It is
+	 * therefore important for this set to remain together.
+	 */
 	void	*ipfr_ifp;
 	struct	in_addr	ipfr_src;
 	struct	in_addr	ipfr_dst;
@@ -29,10 +39,6 @@
 	u_char	ipfr_p;
 	u_char	ipfr_tos;
 	u_32_t	ipfr_pass;
-	u_short	ipfr_off;
-	u_char	ipfr_ttl;
-	u_char	ipfr_seen0;
-	frentry_t *ipfr_rule;
 } ipfr_t;
 
 
@@ -52,6 +58,8 @@
 #define	IPFR_CMPSZ	(offsetof(ipfr_t, ipfr_pass) - \
 			 offsetof(ipfr_t, ipfr_ifp))
 
+extern	ipfr_t	*ipfr_list, **ipfr_tail;
+extern	ipfr_t	*ipfr_natlist, **ipfr_nattail;
 extern	int	ipfr_size;
 extern	int	fr_ipfrttl;
 extern	int	fr_frag_lock;
@@ -67,6 +75,15 @@
 
 extern	int	fr_ipid_newfrag __P((fr_info_t *, u_32_t));
 extern	u_32_t	fr_ipid_knownfrag __P((fr_info_t *));
+#ifdef USE_MUTEXES
+extern	void	fr_fragderef __P((ipfr_t **, ipfrwlock_t *));
+extern	int	fr_nextfrag __P((ipftoken_t *, ipfgeniter_t *, ipfr_t **, \
+				 ipfr_t ***, ipfrwlock_t *));
+#else
+extern	void	fr_fragderef __P((ipfr_t **));
+extern	int	fr_nextfrag __P((ipftoken_t *, ipfgeniter_t *, ipfr_t **, \
+				 ipfr_t ***));
+#endif
 
 extern	void	fr_forget __P((void *));
 extern	void	fr_forgetnat __P((void *));
@@ -81,7 +98,11 @@
 extern	void	fr_slowtimer __P((void *));
 # endif
 #else
+# if defined(linux) && defined(_KERNEL)
+extern	void	fr_slowtimer __P((long));
+# else
 extern	int	fr_slowtimer __P((void));
+# endif
 #endif
 
 #endif	/* __IP_FRAG_H__ */
Index: ip_sync.c
===================================================================
RCS file: /home/cvs/src/sys/contrib/ipfilter/netinet/ip_sync.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/contrib/ipfilter/netinet/ip_sync.c -L sys/contrib/ipfilter/netinet/ip_sync.c -u -r1.1.1.1 -r1.2
--- sys/contrib/ipfilter/netinet/ip_sync.c
+++ sys/contrib/ipfilter/netinet/ip_sync.c
@@ -1,4 +1,4 @@
-/*	$FreeBSD: src/sys/contrib/ipfilter/netinet/ip_sync.c,v 1.2 2005/06/14 09:18:26 darrenr Exp $	*/
+/*	$FreeBSD: src/sys/contrib/ipfilter/netinet/ip_sync.c,v 1.5.2.1 2007/10/31 05:00:38 darrenr Exp $	*/
 
 /*
  * Copyright (C) 1995-1998 by Darren Reed.
@@ -98,7 +98,7 @@
 /* END OF INCLUDES */
 
 #if !defined(lint)
-static const char rcsid[] = "@(#)Id: ip_sync.c,v 2.40.2.3 2005/02/18 13:06:29 darrenr Exp";
+static const char rcsid[] = "@(#)$Id: ip_sync.c,v 2.40.2.9 2007/06/02 21:22:28 darrenr Exp $";
 #endif
 
 #define	SYNC_STATETABSZ	256
@@ -231,8 +231,10 @@
 		ips->is_die = htonl(ips->is_die);
 		ips->is_pass = htonl(ips->is_pass);
 		ips->is_flags = htonl(ips->is_flags);
-		ips->is_opt = htonl(ips->is_opt);
-		ips->is_optmsk = htonl(ips->is_optmsk);
+		ips->is_opt[0] = htonl(ips->is_opt[0]);
+		ips->is_opt[1] = htonl(ips->is_opt[1]);
+		ips->is_optmsk[0] = htonl(ips->is_optmsk[0]);
+		ips->is_optmsk[1] = htonl(ips->is_optmsk[1]);
 		ips->is_sec = htons(ips->is_sec);
 		ips->is_secmsk = htons(ips->is_secmsk);
 		ips->is_auth = htons(ips->is_auth);
@@ -246,8 +248,10 @@
 		ips->is_die = ntohl(ips->is_die);
 		ips->is_pass = ntohl(ips->is_pass);
 		ips->is_flags = ntohl(ips->is_flags);
-		ips->is_opt = ntohl(ips->is_opt);
-		ips->is_optmsk = ntohl(ips->is_optmsk);
+		ips->is_opt[0] = ntohl(ips->is_opt[0]);
+		ips->is_opt[1] = ntohl(ips->is_opt[1]);
+		ips->is_optmsk[0] = ntohl(ips->is_optmsk[0]);
+		ips->is_optmsk[1] = ntohl(ips->is_optmsk[1]);
 		ips->is_sec = ntohs(ips->is_sec);
 		ips->is_secmsk = ntohs(ips->is_secmsk);
 		ips->is_auth = ntohs(ips->is_auth);
@@ -297,7 +301,7 @@
 
 		if (uio->uio_resid >= sizeof(sh)) {
 
-			err = UIOMOVE((caddr_t)&sh, sizeof(sh), UIO_WRITE, uio);
+			err = UIOMOVE(&sh, sizeof(sh), UIO_WRITE, uio);
 
 			if (err) {
 				if (ipf_sync_debug > 2)
@@ -369,7 +373,7 @@
 
 		if (uio->uio_resid >= sh.sm_len) {
 
-			err = UIOMOVE((caddr_t)data, sh.sm_len, UIO_WRITE, uio);
+			err = UIOMOVE(data, sh.sm_len, UIO_WRITE, uio);
 
 			if (err) {
 				if (ipf_sync_debug > 2)
@@ -469,7 +473,7 @@
 	READ_ENTER(&ipf_syncstate);
 	while ((sl_tail < sl_idx)  && (uio->uio_resid > sizeof(*sl))) {
 		sl = synclog + sl_tail++;
-		err = UIOMOVE((caddr_t)sl, sizeof(*sl), UIO_READ, uio);
+		err = UIOMOVE(sl, sizeof(*sl), UIO_READ, uio);
 		if (err != 0)
 			break;
 	}
@@ -477,7 +481,7 @@
 	while ((su_tail < su_idx)  && (uio->uio_resid > sizeof(*su))) {
 		su = syncupd + su_tail;
 		su_tail++;
-		err = UIOMOVE((caddr_t)su, sizeof(*su), UIO_READ, uio);
+		err = UIOMOVE(su, sizeof(*su), UIO_READ, uio);
 		if (err != 0)
 			break;
 		if (su->sup_hdr.sm_sl != NULL)
@@ -700,7 +704,6 @@
 synchdr_t *sp;
 void *data;
 {
-	synclogent_t sle;
 	syncupdent_t su;
 	nat_t *n, *nat;
 	synclist_t *sl;
@@ -712,8 +715,6 @@
 	switch (sp->sm_cmd)
 	{
 	case SMC_CREATE :
-		bcopy(data, &sle, sizeof(sle));
-
 		KMALLOC(n, nat_t *);
 		if (n == NULL) {
 			err = ENOMEM;
@@ -727,9 +728,7 @@
 			break;
 		}
 
-		WRITE_ENTER(&ipf_nat);
-
-		nat = &sle.sle_un.sleu_ipn;
+		nat = (nat_t *)data;
 		bzero((char *)n, offsetof(nat_t, nat_age));
 		bcopy((char *)&nat->nat_age, (char *)&n->nat_age,
 		      sizeof(*n) - offsetof(nat_t, nat_age));
@@ -739,6 +738,8 @@
 		sl->sl_idx = -1;
 		sl->sl_ipn = n;
 		sl->sl_num = ntohl(sp->sm_num);
+
+		WRITE_ENTER(&ipf_nat);
 		sl->sl_pnext = syncstatetab + hv;
 		sl->sl_next = syncstatetab[hv];
 		if (syncstatetab[hv] != NULL)
@@ -996,11 +997,24 @@
 /* This function currently does not handle any ioctls and so just returns   */
 /* EINVAL on all occasions.                                                 */
 /* ------------------------------------------------------------------------ */
-int fr_sync_ioctl(data, cmd, mode)
+int fr_sync_ioctl(data, cmd, mode, uid, ctx)
 caddr_t data;
 ioctlcmd_t cmd;
-int mode;
+int mode, uid;
+void *ctx;
 {
 	return EINVAL;
 }
+
+
+int ipfsync_canread()
+{
+	return !((sl_tail == sl_idx) && (su_tail == su_idx));
+}
+
+
+int ipfsync_canwrite()
+{
+	return 1;
+}
 #endif /* IPFILTER_SYNC */
Index: ip_state.h
===================================================================
RCS file: /home/cvs/src/sys/contrib/ipfilter/netinet/ip_state.h,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/contrib/ipfilter/netinet/ip_state.h -L sys/contrib/ipfilter/netinet/ip_state.h -u -r1.1.1.1 -r1.2
--- sys/contrib/ipfilter/netinet/ip_state.h
+++ sys/contrib/ipfilter/netinet/ip_state.h
@@ -1,4 +1,4 @@
-/*	$FreeBSD: src/sys/contrib/ipfilter/netinet/ip_state.h,v 1.17 2005/04/25 18:43:14 darrenr Exp $	*/
+/*	$FreeBSD: src/sys/contrib/ipfilter/netinet/ip_state.h,v 1.19.2.1 2007/10/31 05:00:38 darrenr Exp $	*/
 
 /*
  * Copyright (C) 1995-2001 by Darren Reed.
@@ -6,13 +6,13 @@
  * See the IPFILTER.LICENCE file for details on licencing.
  *
  * @(#)ip_state.h	1.3 1/12/96 (C) 1995 Darren Reed
- * $FreeBSD: src/sys/contrib/ipfilter/netinet/ip_state.h,v 1.17 2005/04/25 18:43:14 darrenr Exp $
- * Id: ip_state.h,v 2.68.2.3 2005/03/03 14:24:11 darrenr Exp
+ * $FreeBSD: src/sys/contrib/ipfilter/netinet/ip_state.h,v 1.19.2.1 2007/10/31 05:00:38 darrenr Exp $
+ * Id: ip_state.h,v 2.68.2.10 2007/10/16 09:33:24 darrenr Exp $
  */
 #ifndef	__IP_STATE_H__
 #define	__IP_STATE_H__
 
-#if defined(__STDC__) || defined(__GNUC__)
+#if defined(__STDC__) || defined(__GNUC__) || defined(_AIX51)
 # define	SIOCDELST	_IOW('r', 61, struct ipfobj)
 #else
 # define	SIOCDELST	_IOW(r, 61, struct ipfobj)
@@ -27,10 +27,8 @@
 # define	IPSTATE_MAX	4013	/* Maximum number of states held */
 #endif
 
-#define	PAIRS(s1,d1,s2,d2)	((((s1) == (s2)) && ((d1) == (d2))) ||\
-				 (((s1) == (d2)) && ((d1) == (s2))))
-#define	IPPAIR(s1,d1,s2,d2)	PAIRS((s1).s_addr, (d1).s_addr, \
-				      (s2).s_addr, (d2).s_addr)
+#define	SEQ_GE(a,b)	((int)((a) - (b)) >= 0)
+#define	SEQ_GT(a,b)	((int)((a) - (b)) > 0)
 
 
 typedef struct ipstate {
@@ -42,7 +40,6 @@
 	struct	ipstate	**is_me;
 	void		*is_ifp[4];
 	void		*is_sync;
-	struct nat	*is_nat[2];
 	frentry_t	*is_rule;
 	struct	ipftq	*is_tqehead[2];
 	struct	ipscan	*is_isc;
@@ -61,8 +58,8 @@
 	u_char	is_v;
 	u_32_t	is_hv;
 	u_32_t	is_tag;
-	u_32_t	is_opt;			/* packet options set */
-	u_32_t	is_optmsk;		/*    "      "    mask */
+	u_32_t	is_opt[2];		/* packet options set */
+	u_32_t	is_optmsk[2];		/*    "      "    mask */
 	u_short	is_sec;			/* security options set */
 	u_short	is_secmsk;		/*    "        "    mask */
 	u_short	is_auth;		/* authentication options set */
@@ -190,6 +187,7 @@
 #define	ISL_INTERMEDIATE	0xfffc
 #define	ISL_KILLED		0xfffb
 #define	ISL_ORPHAN		0xfffa
+#define	ISL_UNLOAD		0xfff9
 
 
 typedef	struct	ips_stat {
@@ -216,6 +214,7 @@
 	ipstate_t **iss_table;
 	ipstate_t *iss_list;
 	u_long	*iss_bucketlen;
+	ipftq_t	*iss_tcptab;
 } ips_stat_t;
 
 
@@ -251,12 +250,12 @@
 				    struct tcpdata *, tcphdr_t *, int));
 extern	void	fr_stateunload __P((void));
 extern	void	ipstate_log __P((struct ipstate *, u_int));
-extern	int	fr_state_ioctl __P((caddr_t, ioctlcmd_t, int));
+extern	int	fr_state_ioctl __P((caddr_t, ioctlcmd_t, int, int, void *));
 extern	void	fr_stinsert __P((struct ipstate *, int));
 extern	void	fr_sttab_init __P((struct ipftq *));
 extern	void	fr_sttab_destroy __P((struct ipftq *));
 extern	void	fr_updatestate __P((fr_info_t *, ipstate_t *, ipftq_t *));
-extern	void	fr_statederef __P((fr_info_t *, ipstate_t **));
+extern	void	fr_statederef __P((ipstate_t **));
 extern	void	fr_setstatequeue __P((ipstate_t *, int));
 
 #endif /* __IP_STATE_H__ */
Index: ip_lookup.h
===================================================================
RCS file: /home/cvs/src/sys/contrib/ipfilter/netinet/ip_lookup.h,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/contrib/ipfilter/netinet/ip_lookup.h -L sys/contrib/ipfilter/netinet/ip_lookup.h -u -r1.1.1.1 -r1.2
--- sys/contrib/ipfilter/netinet/ip_lookup.h
+++ sys/contrib/ipfilter/netinet/ip_lookup.h
@@ -1,10 +1,8 @@
-/*	$FreeBSD: src/sys/contrib/ipfilter/netinet/ip_lookup.h,v 1.1.1.1 2005/04/25 18:15:23 darrenr Exp $	*/
-
 
 #ifndef __IP_LOOKUP_H__
 #define __IP_LOOKUP_H__
 
-#if defined(__STDC__) || defined(__GNUC__)
+#if defined(__STDC__) || defined(__GNUC__) || defined(_AIX51)
 # define	SIOCLOOKUPADDTABLE	_IOWR('r', 60, struct iplookupop)
 # define	SIOCLOOKUPDELTABLE	_IOWR('r', 61, struct iplookupop)
 # define	SIOCLOOKUPSTAT		_IOWR('r', 64, struct iplookupop)
@@ -35,6 +33,9 @@
 	void	*iplo_struct;
 } iplookupop_t;
 
+#define	LOOKUP_ANON	0x80000000
+
+
 typedef	struct	iplookupflush	{
 	int	iplf_type;	/* IPLT_* */
 	int	iplf_unit;	/* IPL_LOG* */
@@ -57,9 +58,38 @@
 
 #define	IPLT_ANON	0x80000000
 
+
+typedef	union	{
+	struct	iplookupiterkey {
+		char	ilik_ival;
+		u_char	ilik_type;	/* IPLT_* */
+		u_char	ilik_otype;
+		u_char	ilik_unit;	/* IPL_LOG* */
+	} ilik_unstr;
+	u_32_t	ilik_key;
+} iplookupiterkey_t;
+
+typedef	struct	ipflookupiter	{
+	int			ili_nitems;
+	iplookupiterkey_t	ili_lkey;
+	char			ili_name[FR_GROUPLEN];
+	void			*ili_data;
+} ipflookupiter_t;
+
+#define	ili_key		ili_lkey.ilik_key
+#define	ili_ival	ili_lkey.ilik_unstr.ilik_ival
+#define	ili_unit	ili_lkey.ilik_unstr.ilik_unit
+#define	ili_type	ili_lkey.ilik_unstr.ilik_type
+#define	ili_otype	ili_lkey.ilik_unstr.ilik_otype
+
+#define	IPFLOOKUPITER_LIST	0
+#define	IPFLOOKUPITER_NODE	1
+
+
 extern int ip_lookup_init __P((void));
-extern int ip_lookup_ioctl __P((caddr_t, ioctlcmd_t, int));
+extern int ip_lookup_ioctl __P((caddr_t, ioctlcmd_t, int, int, void *));
 extern void ip_lookup_unload __P((void));
 extern void ip_lookup_deref __P((int, void *));
+extern void ip_lookup_iterderef __P((u_32_t, void *));
 
 #endif /* __IP_LOOKUP_H__ */
Index: ip_state.c
===================================================================
RCS file: /home/cvs/src/sys/contrib/ipfilter/netinet/ip_state.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/contrib/ipfilter/netinet/ip_state.c -L sys/contrib/ipfilter/netinet/ip_state.c -u -r1.1.1.1 -r1.2
--- sys/contrib/ipfilter/netinet/ip_state.c
+++ sys/contrib/ipfilter/netinet/ip_state.c
@@ -1,4 +1,4 @@
-/*	$FreeBSD: src/sys/contrib/ipfilter/netinet/ip_state.c,v 1.35 2005/04/25 18:43:14 darrenr Exp $	*/
+/*	$FreeBSD: src/sys/contrib/ipfilter/netinet/ip_state.c,v 1.39.2.1 2007/10/31 05:00:38 darrenr Exp $	*/
 
 /*
  * Copyright (C) 1995-2003 by Darren Reed.
@@ -17,7 +17,11 @@
 #include <sys/file.h>
 #if defined(__NetBSD__) && (NetBSD >= 199905) && !defined(IPFILTER_LKM) && \
     defined(_KERNEL)
-# include "opt_ipfilter_log.h"
+# if (__NetBSD_Version__ < 399001400)
+#  include "opt_ipfilter_log.h"
+# else
+#  include "opt_ipfilter.h"
+# endif
 #endif
 #if defined(_KERNEL) && defined(__FreeBSD_version) && \
     (__FreeBSD_version >= 400000) && !defined(KLD_MODULE)
@@ -109,7 +113,7 @@
 
 #if !defined(lint)
 static const char sccsid[] = "@(#)ip_state.c	1.8 6/5/96 (C) 1993-2000 Darren Reed";
-static const char rcsid[] = "@(#)Id: ip_state.c,v 2.186.2.29 2005/03/28 10:47:54 darrenr Exp";
+static const char rcsid[] = "@(#)$Id: ip_state.c,v 2.186.2.80 2007/10/16 09:33:23 darrenr Exp $";
 #endif
 
 static	ipstate_t **ips_table = NULL;
@@ -125,8 +129,9 @@
 				      i6addr_t *, tcphdr_t *, u_32_t));
 static ipstate_t *fr_checkicmpmatchingstate __P((fr_info_t *));
 static int fr_state_flush __P((int, int));
+static int fr_state_flush_entry __P((void *));
 static ips_stat_t *fr_statetstats __P((void));
-static void fr_delstate __P((ipstate_t *, int));
+static int fr_delstate __P((ipstate_t *, int));
 static int fr_state_remove __P((caddr_t));
 static void fr_ipsmove __P((ipstate_t *, u_int));
 static int fr_tcpstate __P((fr_info_t *, tcphdr_t *, ipstate_t *));
@@ -135,6 +140,8 @@
 static void fr_fixinisn __P((fr_info_t *, ipstate_t *));
 static void fr_fixoutisn __P((fr_info_t *, ipstate_t *));
 static void fr_checknewisn __P((fr_info_t *, ipstate_t *));
+static int fr_stateiter __P((ipftoken_t *, ipfgeniter_t *));
+static int fr_stgettable __P((char *));
 
 int fr_stputent __P((caddr_t));
 int fr_stgetent __P((caddr_t));
@@ -145,9 +152,10 @@
 
 u_long	fr_tcpidletimeout = FIVE_DAYS,
 	fr_tcpclosewait = IPF_TTLVAL(2 * TCP_MSL),
-	fr_tcplastack = IPF_TTLVAL(2 * TCP_MSL),
+	fr_tcplastack = IPF_TTLVAL(30),
 	fr_tcptimeout = IPF_TTLVAL(2 * TCP_MSL),
-	fr_tcpclosed = IPF_TTLVAL(60),
+	fr_tcptimewait = IPF_TTLVAL(2 * TCP_MSL),
+	fr_tcpclosed = IPF_TTLVAL(30),
 	fr_tcphalfclosed = IPF_TTLVAL(2 * 3600),	/* 2 hours */
 	fr_udptimeout = IPF_TTLVAL(120),
 	fr_udpacktimeout = IPF_TTLVAL(12),
@@ -167,6 +175,7 @@
 	ips_iptq,
 	ips_icmptq,
 	ips_icmpacktq,
+	ips_deletetq,
 	*ips_utqe = NULL;
 #ifdef	IPFILTER_LOG
 int	ipstate_logging = 1;
@@ -241,6 +250,7 @@
 		fr_state_maxbucket *= 2;
 	}
 
+	ips_stats.iss_tcptab = ips_tqtqb;
 	fr_sttab_init(ips_tqtqb);
 	ips_tqtqb[IPF_TCP_NSTATES - 1].ifq_next = &ips_udptq;
 	ips_udptq.ifq_ttl = (u_long)fr_udptimeout;
@@ -272,7 +282,13 @@
 	ips_iptq.ifq_head = NULL;
 	ips_iptq.ifq_tail = &ips_iptq.ifq_head;
 	MUTEX_INIT(&ips_iptq.ifq_lock, "ipftq ip tab");
-	ips_iptq.ifq_next = NULL;
+	ips_iptq.ifq_next = &ips_deletetq;
+	ips_deletetq.ifq_ttl = (u_long)1;
+	ips_deletetq.ifq_ref = 1;
+	ips_deletetq.ifq_head = NULL;
+	ips_deletetq.ifq_tail = &ips_deletetq.ifq_head;
+	MUTEX_INIT(&ips_deletetq.ifq_lock, "state delete queue");
+	ips_deletetq.ifq_next = NULL;
 
 	RWLOCK_INIT(&ipf_state, "ipf IP state rwlock");
 	MUTEX_INIT(&ipf_stinsert, "ipf state insert mutex");
@@ -297,7 +313,7 @@
 	ipstate_t *is;
 
 	while ((is = ips_list) != NULL)
-		fr_delstate(is, 0);
+		fr_delstate(is, ISL_UNLOAD);
 
 	/*
 	 * Proxy timeout queues are not cleaned here because although they
@@ -323,6 +339,7 @@
 		MUTEX_DESTROY(&ips_udpacktq.ifq_lock);
 		MUTEX_DESTROY(&ips_icmpacktq.ifq_lock);
 		MUTEX_DESTROY(&ips_iptq.ifq_lock);
+		MUTEX_DESTROY(&ips_deletetq.ifq_lock);
 	}
 
 	if (ips_table != NULL) {
@@ -416,12 +433,14 @@
 /*                                                                          */
 /* Processes an ioctl call made to operate on the IP Filter state device.   */
 /* ------------------------------------------------------------------------ */
-int fr_state_ioctl(data, cmd, mode)
+int fr_state_ioctl(data, cmd, mode, uid, ctx)
 caddr_t data;
 ioctlcmd_t cmd;
-int mode;
+int mode, uid;
+void *ctx;
 {
 	int arg, ret, error = 0;
+	SPL_INT(s);
 
 	switch (cmd)
 	{
@@ -431,29 +450,37 @@
 	case SIOCDELST :
 		error = fr_state_remove(data);
 		break;
+
 	/*
 	 * Flush the state table
 	 */
 	case SIOCIPFFL :
-		BCOPYIN(data, (char *)&arg, sizeof(arg));
-		if (arg == 0 || arg == 1) {
+		error = BCOPYIN(data, (char *)&arg, sizeof(arg));
+		if (error != 0) {
+			error = EFAULT;
+		} else {
 			WRITE_ENTER(&ipf_state);
 			ret = fr_state_flush(arg, 4);
 			RWLOCK_EXIT(&ipf_state);
-			BCOPYOUT((char *)&ret, data, sizeof(ret));
-		} else
-			error = EINVAL;
+			error = BCOPYOUT((char *)&ret, data, sizeof(ret));
+			if (error != 0)
+				error = EFAULT;
+		}
 		break;
+
 #ifdef	USE_INET6
 	case SIOCIPFL6 :
-		BCOPYIN(data, (char *)&arg, sizeof(arg));
-		if (arg == 0 || arg == 1) {
+		error = BCOPYIN(data, (char *)&arg, sizeof(arg));
+		if (error != 0) {
+			error = EFAULT;
+		} else {
 			WRITE_ENTER(&ipf_state);
 			ret = fr_state_flush(arg, 6);
 			RWLOCK_EXIT(&ipf_state);
-			BCOPYOUT((char *)&ret, data, sizeof(ret));
-		} else
-			error = EINVAL;
+			error = BCOPYOUT((char *)&ret, data, sizeof(ret));
+			if (error != 0)
+				error = EFAULT;
+		}
 		break;
 #endif
 #ifdef	IPFILTER_LOG
@@ -467,9 +494,12 @@
 			int tmp;
 
 			tmp = ipflog_clear(IPL_LOGSTATE);
-			BCOPYOUT((char *)&tmp, data, sizeof(tmp));
+			error = BCOPYOUT((char *)&tmp, data, sizeof(tmp));
+			if (error != 0)
+				error = EFAULT;
 		}
 		break;
+
 	/*
 	 * Turn logging of state information on/off.
 	 */
@@ -477,48 +507,64 @@
 		if (!(mode & FWRITE))
 			error = EPERM;
 		else {
-			BCOPYIN((char *)data, (char *)&ipstate_logging,
-				sizeof(ipstate_logging));
+			error = BCOPYIN((char *)data, (char *)&ipstate_logging,
+					sizeof(ipstate_logging));
+			if (error != 0)
+				error = EFAULT;
 		}
 		break;
+
 	/*
 	 * Return the current state of logging.
 	 */
 	case SIOCGETLG :
-		BCOPYOUT((char *)&ipstate_logging, (char *)data,
-			 sizeof(ipstate_logging));
+		error = BCOPYOUT((char *)&ipstate_logging, (char *)data,
+				 sizeof(ipstate_logging));
+		if (error != 0)
+			error = EFAULT;
 		break;
+
 	/*
 	 * Return the number of bytes currently waiting to be read.
 	 */
 	case FIONREAD :
 		arg = iplused[IPL_LOGSTATE];	/* returned in an int */
-		BCOPYOUT((char *)&arg, data, sizeof(arg));
+		error = BCOPYOUT((char *)&arg, data, sizeof(arg));
+		if (error != 0)
+			error = EFAULT;
 		break;
 #endif
+
 	/*
 	 * Get the current state statistics.
 	 */
 	case SIOCGETFS :
 		error = fr_outobj(data, fr_statetstats(), IPFOBJ_STATESTAT);
 		break;
+
 	/*
 	 * Lock/Unlock the state table.  (Locking prevents any changes, which
 	 * means no packets match).
 	 */
 	case SIOCSTLCK :
-		fr_lock(data, &fr_state_lock);
+		if (!(mode & FWRITE)) {
+			error = EPERM;
+		} else {
+			error = fr_lock(data, &fr_state_lock);
+		}
 		break;
+
 	/*
 	 * Add an entry to the current state table.
 	 */
 	case SIOCSTPUT :
-		if (!fr_state_lock) {
+		if (!fr_state_lock || !(mode &FWRITE)) {
 			error = EACCES;
 			break;
 		}
 		error = fr_stputent(data);
 		break;
+
 	/*
 	 * Get a state table entry.
 	 */
@@ -529,6 +575,56 @@
 		}
 		error = fr_stgetent(data);
 		break;
+
+	/*
+	 * Return a copy of the hash table bucket lengths
+	 */
+	case SIOCSTAT1 :
+		error = BCOPYOUT(ips_stats.iss_bucketlen, data,
+				 fr_statesize * sizeof(u_long));
+		if (error != 0)
+			error = EFAULT;
+		break;
+
+	case SIOCGENITER :
+	    {
+		ipftoken_t *token;
+		ipfgeniter_t iter;
+
+		error = fr_inobj(data, &iter, IPFOBJ_GENITER);
+		if (error != 0)
+			break;
+
+		SPL_SCHED(s);
+		token = ipf_findtoken(IPFGENITER_STATE, uid, ctx);
+		if (token != NULL)
+			error = fr_stateiter(token, &iter);
+		else
+			error = ESRCH;
+		RWLOCK_EXIT(&ipf_tokens);
+		SPL_X(s);
+		break;
+	    }
+
+	case SIOCGTABL :
+		error = fr_stgettable(data);
+		break;
+
+	case SIOCIPFDELTOK :
+		error = BCOPYIN(data, (char *)&arg, sizeof(arg));
+		if (error != 0) {
+			error = EFAULT;
+		} else {
+			SPL_SCHED(s);
+			error = ipf_deltoken(arg, uid, ctx);
+			SPL_X(s);
+		}
+		break;
+
+	case SIOCGTQTAB :
+		error = fr_outobj(data, ips_tqtqb, IPFOBJ_STATETQTAB);
+		break;
+
 	default :
 		error = EINVAL;
 		break;
@@ -556,8 +652,8 @@
 	int error;
 
 	error = fr_inobj(data, &ips, IPFOBJ_STATESAVE);
-	if (error)
-		return EFAULT;
+	if (error != 0)
+		return error;
 
 	isn = ips.ips_next;
 	if (isn == NULL) {
@@ -586,9 +682,7 @@
 		bcopy((char *)isn->is_rule, (char *)&ips.ips_fr,
 		      sizeof(ips.ips_fr));
 	error = fr_outobj(data, &ips, IPFOBJ_STATESAVE);
-	if (error)
-		return EFAULT;
-	return 0;
+	return error;
 }
 
 
@@ -635,6 +729,7 @@
 	if (fr == NULL) {
 		READ_ENTER(&ipf_state);
 		fr_stinsert(isn, 0);
+		MUTEX_EXIT(&isn->is_lock);
 		RWLOCK_EXIT(&ipf_state);
 		return 0;
 	}
@@ -665,8 +760,10 @@
 		fr->fr_ref = 0;
 		fr->fr_dsize = 0;
 		fr->fr_data = NULL;
+		fr->fr_type = FR_T_NONE;
 
-		fr_resolvedest(&fr->fr_tif, fr->fr_v);
+		fr_resolvedest(&fr->fr_tifs[0], fr->fr_v);
+		fr_resolvedest(&fr->fr_tifs[1], fr->fr_v);
 		fr_resolvedest(&fr->fr_dif, fr->fr_v);
 
 		/*
@@ -682,6 +779,7 @@
 		}
 		READ_ENTER(&ipf_state);
 		fr_stinsert(isn, 0);
+		MUTEX_EXIT(&isn->is_lock);
 		RWLOCK_EXIT(&ipf_state);
 
 	} else {
@@ -689,6 +787,7 @@
 		for (is = ips_list; is; is = is->is_next)
 			if (is->is_rule == fr) {
 				fr_stinsert(isn, 0);
+				MUTEX_EXIT(&isn->is_lock);
 				break;
 			}
 
@@ -716,6 +815,7 @@
 /* to pointers and adjusts running stats for the hash table as appropriate. */
 /*                                                                          */
 /* Locking: it is assumed that some kind of lock on ipf_state is held.      */
+/*          Exits with is_lock initialised and held.                        */
 /* ------------------------------------------------------------------------ */
 void fr_stinsert(is, rev)
 ipstate_t *is;
@@ -780,7 +880,6 @@
 	MUTEX_EXIT(&ipf_stinsert);
 
 	fr_setstatequeue(is, rev);
-	MUTEX_EXIT(&is->is_lock);
 }
 
 
@@ -796,6 +895,11 @@
 /* Inserts it into the state table and appends to the bottom of the active  */
 /* list.  If the capacity of the table has reached the maximum allowed then */
 /* the call will fail and a flush is scheduled for the next timeout call.   */
+/*                                                                          */
+/* NOTE: The use of stsave to point to nat_state will result in memory      */
+/*       corruption.  It should only be used to point to objects that will  */
+/*       either outlive this (not expired) or will deref the ip_state_t     */
+/*       when they are deleted.                                             */
 /* ------------------------------------------------------------------------ */
 ipstate_t *fr_addstate(fin, stsave, flags)
 fr_info_t *fin;
@@ -808,7 +912,6 @@
 	frentry_t *fr;
 	tcphdr_t *tcp;
 	grehdr_t *gre;
-	void *ifp;
 	int out;
 
 	if (fr_state_lock ||
@@ -818,24 +921,28 @@
 	if ((fin->fin_flx & FI_OOW) && !(fin->fin_tcpf & TH_SYN))
 		return NULL;
 
-	fr = fin->fin_fr;
-	if ((fr->fr_statemax == 0) && (ips_num == fr_statemax)) {
-		ATOMIC_INCL(ips_stats.iss_max);
-		fr_state_doflush = 1;
-		return NULL;
-	}
-
 	/*
 	 * If a "keep state" rule has reached the maximum number of references
 	 * to it, then schedule an automatic flush in case we can clear out
-	 * some "dead old wood".
+	 * some "dead old wood".  Note that because the lock isn't held on
+	 * fr it is possible that we could overflow.  The cost of overflowing
+	 * is being ignored here as the number by which it can overflow is
+	 * a product of the number of simultaneous threads that could be
+	 * executing in here, so a limit of 100 won't result in 200, but could
+	 * result in 101 or 102.
 	 */
-	if ((fr != NULL) && (fr->fr_statemax != 0) &&
-	    (fr->fr_statecnt >= fr->fr_statemax)) {
-		MUTEX_EXIT(&fr->fr_lock);
-		ATOMIC_INCL(ips_stats.iss_maxref);
-		fr_state_doflush = 1;
-		return NULL;
+	fr = fin->fin_fr;
+	if (fr != NULL) {
+		if ((ips_num >= fr_statemax) && (fr->fr_statemax == 0)) {
+			ATOMIC_INCL(ips_stats.iss_max);
+			fr_state_doflush = 1;
+			return NULL;
+		}
+		if ((fr->fr_statemax != 0) &&
+		    (fr->fr_statecnt >= fr->fr_statemax)) {
+			ATOMIC_INCL(ips_stats.iss_maxref);
+			return NULL;
+		}
 	}
 
 	pass = (fr == NULL) ? 0 : fr->fr_flags;
@@ -884,6 +991,16 @@
 		hv += is->is_src.i6[3];
 	}
 #endif
+	if ((fin->fin_v == 4) &&
+	    (fin->fin_flx & (FI_MULTICAST|FI_BROADCAST|FI_MBCAST))) {
+		if (fin->fin_out == 0) {
+			flags |= SI_W_DADDR|SI_CLONE;
+			hv -= is->is_daddr;
+		} else {
+			flags |= SI_W_SADDR|SI_CLONE;
+			hv -= is->is_saddr;
+		}
+	}
 
 	switch (is->is_p)
 	{
@@ -979,9 +1096,9 @@
 			    TH_SYN &&
 			    (TCP_OFF(tcp) > (sizeof(tcphdr_t) >> 2))) {
 				if (fr_tcpoptions(fin, tcp,
-					      &is->is_tcp.ts_data[0]))
-					is->is_swinflags = TCP_WSCALE_SEEN|
-							   TCP_WSCALE_FIRST;
+					      &is->is_tcp.ts_data[0]) == -1) {
+					fin->fin_flx |= FI_BAD;
+				}
 			}
 
 			if ((fin->fin_out != 0) && (pass & FR_NEWISN) != 0) {
@@ -1068,30 +1185,43 @@
 
 		is->is_tag = fr->fr_logtag;
 
+		/*
+		 * The name '-' is special for network interfaces and causes
+		 * a NULL name to be present, always, allowing packets to
+		 * match it, regardless of their interface.
+		 */
+		if ((fin->fin_ifp == NULL) ||
+		    (fr->fr_ifnames[out << 1][0] == '-' &&
+		     fr->fr_ifnames[out << 1][1] == '\0')) {
+			is->is_ifp[out << 1] = fr->fr_ifas[0];
+			strncpy(is->is_ifname[out << 1], fr->fr_ifnames[0],
+				sizeof(fr->fr_ifnames[0]));
+		} else {
+			is->is_ifp[out << 1] = fin->fin_ifp;
+			COPYIFNAME(is->is_v, fin->fin_ifp,
+				   is->is_ifname[out << 1]);
+		}
+
 		is->is_ifp[(out << 1) + 1] = fr->fr_ifas[1];
+		strncpy(is->is_ifname[(out << 1) + 1], fr->fr_ifnames[1],
+			sizeof(fr->fr_ifnames[1]));
+
 		is->is_ifp[(1 - out) << 1] = fr->fr_ifas[2];
-		is->is_ifp[((1 - out) << 1) + 1] = fr->fr_ifas[3];
+		strncpy(is->is_ifname[((1 - out) << 1)], fr->fr_ifnames[2],
+			sizeof(fr->fr_ifnames[2]));
 
-		if (((ifp = fr->fr_ifas[1]) != NULL) &&
-		    (ifp != (void *)-1)) {
-			COPYIFNAME(ifp, is->is_ifname[(out << 1) + 1]);
-		}
-		if (((ifp = fr->fr_ifas[2]) != NULL) &&
-		    (ifp != (void *)-1)) {
-			COPYIFNAME(ifp, is->is_ifname[(1 - out) << 1]);
-		}
-		if (((ifp = fr->fr_ifas[3]) != NULL) &&
-		    (ifp != (void *)-1)) {
-			COPYIFNAME(ifp, is->is_ifname[((1 - out) << 1) + 1]);
-		}
+		is->is_ifp[((1 - out) << 1) + 1] = fr->fr_ifas[3];
+		strncpy(is->is_ifname[((1 - out) << 1) + 1], fr->fr_ifnames[3],
+			sizeof(fr->fr_ifnames[3]));
 	} else {
 		pass = fr_flags;
 		is->is_tag = FR_NOLOGTAG;
-	}
 
-	is->is_ifp[out << 1] = fin->fin_ifp;
-	if (fin->fin_ifp != NULL) {
-		COPYIFNAME(fin->fin_ifp, is->is_ifname[out << 1]);
+		if (fin->fin_ifp != NULL) {
+			is->is_ifp[out << 1] = fin->fin_ifp;
+			COPYIFNAME(is->is_v, fin->fin_ifp,
+				   is->is_ifname[out << 1]);
+		}
 	}
 
 	/*
@@ -1124,8 +1254,15 @@
 	 * this may change.
 	 */
 	is->is_v = fin->fin_v;
-	is->is_opt = fin->fin_optmsk;
-	is->is_optmsk = 0xffffffff;
+	is->is_opt[0] = fin->fin_optmsk;
+	is->is_optmsk[0] = 0xffffffff;
+	is->is_optmsk[1] = 0xffffffff;
+	if (is->is_v == 6) {
+		is->is_opt[0] &= ~0x8;
+		is->is_optmsk[0] &= ~0x8;
+		is->is_optmsk[1] &= ~0x8;
+	}
+	is->is_me = stsave;
 	is->is_sec = fin->fin_secmsk;
 	is->is_secmsk = 0xffff;
 	is->is_auth = fin->fin_auth;
@@ -1140,7 +1277,6 @@
 		is->is_pass &= ~(FR_LOGFIRST|FR_LOG);
 
 	READ_ENTER(&ipf_state);
-	is->is_me = stsave;
 
 	fr_stinsert(is, fin->fin_rev);
 
@@ -1150,13 +1286,14 @@
 		* timer on it as we'll never see an error if it fails to
 		* connect.
 		*/
-		MUTEX_ENTER(&is->is_lock);
 		(void) fr_tcp_age(&is->is_sti, fin, ips_tqtqb, is->is_flags);
 		MUTEX_EXIT(&is->is_lock);
 #ifdef	IPFILTER_SCAN
 		if ((is->is_flags & SI_CLONE) == 0)
 			(void) ipsc_attachis(is);
 #endif
+	} else {
+		MUTEX_EXIT(&is->is_lock);
 	}
 #ifdef	IPFILTER_SYNC
 	if ((is->is_flags & IS_STATESYNC) && ((is->is_flags & SI_CLONE) == 0))
@@ -1178,7 +1315,8 @@
 
 /* ------------------------------------------------------------------------ */
 /* Function:    fr_tcpoptions                                               */
-/* Returns:     int - 1 == packet matches state entry, 0 == it does not     */
+/* Returns:     int - 1 == packet matches state entry, 0 == it does not,    */
+/*                   -1 == packet has bad TCP options data                  */
 /* Parameters:  fin(I) - pointer to packet information                      */
 /*              tcp(I) - pointer to TCP packet header                       */
 /*              td(I)  - pointer to TCP data held as part of the state      */
@@ -1195,13 +1333,14 @@
 	char buf[64], *s, opt;
 	mb_t *m = NULL;
 
-	off = fin->fin_hlen + sizeof(*tcp);
-	len = (TCP_OFF(tcp) << 2) - sizeof(*tcp);
-	if (fin->fin_plen < off + len)
+	len = (TCP_OFF(tcp) << 2);
+	if (fin->fin_dlen < len)
 		return 0;
+	len -= sizeof(*tcp);
+
+	off = fin->fin_plen - fin->fin_dlen + sizeof(*tcp) + fin->fin_ipoff;
 
 	m = fin->fin_m;
-	off += fin->fin_ipoff;
 	mlen = MSGDSIZE(m) - off;
 	if (len > mlen) {
 		len = mlen;
@@ -1239,7 +1378,10 @@
 					else if (i < 0)
 						i = 0;
 					td->td_winscale = i;
-				}
+					td->td_winflags |= TCP_WSCALE_SEEN|
+							   TCP_WSCALE_FIRST;
+				} else
+					retval = -1;
 				break;
 			case TCPOPT_MAXSEG :
 				/*
@@ -1251,7 +1393,14 @@
 					i <<= 8;
 					i += (int)*(s + 3);
 					td->td_maxseg = i;
-				}
+				} else
+					retval = -1;
+				break;
+			case TCPOPT_SACK_PERMITTED :
+				if (ol == TCPOLEN_SACK_PERMITTED)
+					td->td_winflags |= TCP_SACK_PERMIT;
+				else
+					retval = -1;
 				break;
 			}
 		}
@@ -1289,7 +1438,24 @@
 	tdata = &is->is_tcp.ts_data[source];
 
 	MUTEX_ENTER(&is->is_lock);
-	if (fr_tcpinwindow(fin, fdata, tdata, tcp, is->is_flags)) {
+
+	/*
+	 * If a SYN packet is received for a connection that is on the way out
+	 * but hasn't yet departed then advance this session along the way.
+	 */
+	if ((tcp->th_flags & TH_OPENING) == TH_SYN) {
+		if ((is->is_state[0] > IPF_TCPS_ESTABLISHED) &&
+		    (is->is_state[1] > IPF_TCPS_ESTABLISHED)) {
+			is->is_state[!source] = IPF_TCPS_CLOSED;
+			fr_movequeue(&is->is_sti, is->is_sti.tqe_ifq,
+				     &ips_deletetq);
+			MUTEX_EXIT(&is->is_lock);
+			return 0;
+		}
+	}
+
+	ret = fr_tcpinwindow(fin, fdata, tdata, tcp, is->is_flags);
+	if (ret > 0) {
 #ifdef	IPFILTER_SCAN
 		if (is->is_flags & (IS_SC_CLIENT|IS_SC_SERVER)) {
 			ipsc_packet(fin, is);
@@ -1321,33 +1487,27 @@
 		if (flags == (TH_SYN|TH_ACK)) {
 			is->is_s0[source] = ntohl(tcp->th_ack);
 			is->is_s0[!source] = ntohl(tcp->th_seq) + 1;
-			if ((TCP_OFF(tcp) > (sizeof(tcphdr_t) >> 2)) &&
-			    tdata->td_winscale) {
-				if (fr_tcpoptions(fin, tcp, fdata)) {
-					fdata->td_winflags = TCP_WSCALE_SEEN|
-							     TCP_WSCALE_FIRST;
-				} else {
-					if (!fdata->td_winscale)
-						tdata->td_winscale = 0;
-				}
+			if ((TCP_OFF(tcp) > (sizeof(tcphdr_t) >> 2))) {
+				if (fr_tcpoptions(fin, tcp, fdata) == -1)
+					fin->fin_flx |= FI_BAD;
 			}
 			if ((fin->fin_out != 0) && (is->is_pass & FR_NEWISN))
 				fr_checknewisn(fin, is);
 		} else if (flags == TH_SYN) {
 			is->is_s0[source] = ntohl(tcp->th_seq) + 1;
-			if ((TCP_OFF(tcp) > (sizeof(tcphdr_t) >> 2)))
-				if (fr_tcpoptions(fin, tcp, tdata)) {
-					tdata->td_winflags = TCP_WSCALE_SEEN|
-							     TCP_WSCALE_FIRST;
-				}
+			if ((TCP_OFF(tcp) > (sizeof(tcphdr_t) >> 2))) {
+				if (fr_tcpoptions(fin, tcp, fdata) == -1)
+					fin->fin_flx |= FI_BAD;
+			}
 
 			if ((fin->fin_out != 0) && (is->is_pass & FR_NEWISN))
 				fr_checknewisn(fin, is);
 
 		}
 		ret = 1;
-	} else
+	} else {
 		fin->fin_flx |= FI_OOW;
+	}
 	MUTEX_EXIT(&is->is_lock);
 	return ret;
 }
@@ -1391,7 +1551,8 @@
 
 /* ------------------------------------------------------------------------ */
 /* Function:    fr_tcpinwindow                                              */
-/* Returns:     int - 1 == packet inside TCP "window", 0 == not inside.     */
+/* Returns:     int - 1 == packet inside TCP "window", 0 == not inside,     */
+/*                    2 == packet seq number matches next expected          */
 /* Parameters:  fin(I)   - pointer to packet information                    */
 /*              fdata(I) - pointer to tcp state informatio (forward)        */
 /*              tdata(I) - pointer to tcp state informatio (reverse)        */
@@ -1410,6 +1571,7 @@
 	tcp_seq seq, ack, end;
 	int ackskew, tcpflags;
 	u_32_t win, maxwin;
+	int dsize, inseq;
 
 	/*
 	 * Find difference between last checked packet and this packet.
@@ -1421,9 +1583,16 @@
 		win = ntohs(tcp->th_win);
 	else
 		win = ntohs(tcp->th_win) << fdata->td_winscale;
+
+	/*
+	 * A window of 0 produces undesirable behaviour from this function.
+	 */
 	if (win == 0)
 		win = 1;
 
+	dsize = fin->fin_dlen - (TCP_OFF(tcp) << 2) +
+	        ((tcpflags & TH_SYN) ? 1 : 0) + ((tcpflags & TH_FIN) ? 1 : 0);
+
 	/*
 	 * if window scaling is present, the scaling is only allowed
 	 * for windows not in the first SYN packet. In that packet the
@@ -1436,19 +1605,11 @@
 	 * the receiver also does window scaling)
 	 */
 	if (!(tcpflags & TH_SYN) && (fdata->td_winflags & TCP_WSCALE_FIRST)) {
-		if (tdata->td_winflags & TCP_WSCALE_SEEN) {
-			fdata->td_winflags &= ~TCP_WSCALE_FIRST;
-			fdata->td_maxwin = win;
-		} else {
-			fdata->td_winscale = 0;
-			fdata->td_winflags = 0;
-			tdata->td_winscale = 0;
-			tdata->td_winflags = 0;
-		  }
+		fdata->td_winflags &= ~TCP_WSCALE_FIRST;
+		fdata->td_maxwin = win;
 	}
 
-	end = seq + fin->fin_dlen - (TCP_OFF(tcp) << 2) +
-	      ((tcpflags & TH_SYN) ? 1 : 0) + ((tcpflags & TH_FIN) ? 1 : 0);
+	end = seq + dsize;
 
 	if ((fdata->td_end == 0) &&
 	    (!(flags & IS_TCPFSM) ||
@@ -1456,7 +1617,7 @@
 		/*
 		 * Must be a (outgoing) SYN-ACK in reply to a SYN.
 		 */
-		fdata->td_end = end;
+		fdata->td_end = end - 1;
 		fdata->td_maxwin = 1;
 		fdata->td_maxend = end + win;
 	}
@@ -1469,33 +1630,72 @@
 		ack = tdata->td_end;
 	}
 
-	if (seq == end)
-		seq = end = fdata->td_end;
-
 	maxwin = tdata->td_maxwin;
 	ackskew = tdata->td_end - ack;
 
 	/*
 	 * Strict sequencing only allows in-order delivery.
 	 */
-	if ((flags & IS_STRICT) != 0) {
-		if (seq != fdata->td_end) {
+	if (seq != fdata->td_end) {
+		if ((flags & IS_STRICT) != 0) {
 			return 0;
 		}
 	}
 
-#define	SEQ_GE(a,b)	((int)((a) - (b)) >= 0)
-#define	SEQ_GT(a,b)	((int)((a) - (b)) > 0)
-	if (
-#if defined(_KERNEL)
-	    (SEQ_GE(fdata->td_maxend, end)) &&
+	inseq = 0;
+	if ((SEQ_GE(fdata->td_maxend, end)) &&
 	    (SEQ_GE(seq, fdata->td_end - maxwin)) &&
-#endif
 /* XXX what about big packets */
 #define MAXACKWINDOW 66000
-	    (-ackskew <= (MAXACKWINDOW << fdata->td_winscale)) &&
+	    (-ackskew <= (MAXACKWINDOW)) &&
 	    ( ackskew <= (MAXACKWINDOW << fdata->td_winscale))) {
+		inseq = 1;
+	/*
+	 * Microsoft Windows will send the next packet to the right of the
+	 * window if SACK is in use.
+	 */
+	} else if ((seq == fdata->td_maxend) && (ackskew == 0) &&
+	    (fdata->td_winflags & TCP_SACK_PERMIT) &&
+	    (tdata->td_winflags & TCP_SACK_PERMIT)) {
+		inseq = 1;
+	/*
+	 * Sometimes a TCP RST will be generated with only the ACK field
+	 * set to non-zero.
+	 */
+	} else if ((seq == 0) && (tcpflags == (TH_RST|TH_ACK)) &&
+		   (ackskew >= -1) && (ackskew <= 1)) {
+		inseq = 1;
+	} else if (!(flags & IS_TCPFSM)) {
+		int i;
 
+		i = (fin->fin_rev << 1) + fin->fin_out;
+
+#if 0
+		if (is_pkts[i]0 == 0) {
+			/*
+			 * Picking up a connection in the middle, the "next"
+			 * packet seen from a direction that is new should be
+			 * accepted, even if it appears out of sequence.
+			 */
+			inseq = 1;
+		} else 
+#endif
+		if (!(fdata->td_winflags &
+			    (TCP_WSCALE_SEEN|TCP_WSCALE_FIRST))) {
+			/*
+			 * No TCPFSM and no window scaling, so make some
+			 * extra guesses.
+			 */
+			if ((seq == fdata->td_maxend) && (ackskew == 0))
+				inseq = 1;
+			else if (SEQ_GE(seq + maxwin, fdata->td_end - maxwin))
+				inseq = 1;
+		}
+	}
+
+	/* TRACE(inseq, fdata, tdata, seq, end, ack, ackskew, win, maxwin) */
+
+	if (inseq) {
 		/* if ackskew < 0 then this should be due to fragmented
 		 * packets. There is no way to know the length of the
 		 * total packet in advance.
@@ -1584,8 +1784,7 @@
 	clone->is_flags &= ~SI_CLONE;
 	clone->is_flags |= SI_CLONED;
 	fr_stinsert(clone, fin->fin_rev);
-	MUTEX_ENTER(&clone->is_lock);
-	clone->is_ref = 1;
+	clone->is_ref = 2;
 	if (clone->is_p == IPPROTO_TCP) {
 		(void) fr_tcp_age(&clone->is_sti, fin, ips_tqtqb,
 				  clone->is_flags);
@@ -1653,9 +1852,9 @@
 	 * If the interface for this 'direction' is set, make sure it matches.
 	 * An interface name that is not set matches any, as does a name of *.
 	 */
-	if ((is->is_ifp[idx] == NULL &&
-	    (*is->is_ifname[idx] == '\0' || *is->is_ifname[idx] == '*')) ||
-	    is->is_ifp[idx] == ifp)
+	if ((is->is_ifp[idx] == ifp) || (is->is_ifp[idx] == NULL &&
+	    (*is->is_ifname[idx] == '\0' || *is->is_ifname[idx] == '-' ||
+	     *is->is_ifname[idx] == '*')))
 		ret = 1;
 
 	if (ret == 0)
@@ -1770,7 +1969,7 @@
 	 * Match up any flags set from IP options.
 	 */
 	if ((cflx && (flx != (cflx & cmask))) ||
-	    ((fin->fin_optmsk & is->is_optmsk) != is->is_opt) ||
+	    ((fin->fin_optmsk & is->is_optmsk[rev]) != is->is_opt[rev]) ||
 	    ((fin->fin_secmsk & is->is_secmsk) != is->is_sec) ||
 	    ((fin->fin_auth & is->is_authmsk) != is->is_auth))
 		return NULL;
@@ -1787,9 +1986,12 @@
 
 	if ((flags & (SI_W_SPORT|SI_W_DPORT))) {
 		if ((flags & SI_CLONE) != 0) {
-			is = fr_stclone(fin, tcp, is);
-			if (is == NULL)
+			ipstate_t *clone;
+
+			clone = fr_stclone(fin, tcp, is);
+			if (clone == NULL)
 				return NULL;
+			is = clone;
 		} else {
 			ATOMIC_DECL(ips_stats.iss_wild);
 		}
@@ -1820,8 +2022,14 @@
 
 	ret = -1;
 
-	if (is->is_flx[out][rev] == 0)
+	if (is->is_flx[out][rev] == 0) {
 		is->is_flx[out][rev] = flx;
+		is->is_opt[rev] = fin->fin_optmsk;
+		if (is->is_v == 6) {
+			is->is_opt[rev] &= ~0x8;
+			is->is_optmsk[rev] &= ~0x8;
+		}
+	}
 
 	/*
 	 * Check if the interface name for this "direction" is set and if not,
@@ -1830,7 +2038,7 @@
 	if (is->is_ifp[idx] == NULL &&
 	    (*is->is_ifname[idx] == '\0' || *is->is_ifname[idx] == '*')) {
 		is->is_ifp[idx] = ifp;
-		COPYIFNAME(ifp, is->is_ifname[idx]);
+		COPYIFNAME(is->is_v, ifp, is->is_ifname[idx]);
 	}
 	fin->fin_rev = rev;
 	return is;
@@ -1867,21 +2075,16 @@
 
 	/*
 	 * Does it at least have the return (basic) IP header ?
+	 * Is it an actual recognised ICMP error type?
 	 * Only a basic IP header (no options) should be with
 	 * an ICMP error header.
 	 */
 	if ((fin->fin_v != 4) || (fin->fin_hlen != sizeof(ip_t)) ||
-	    (fin->fin_plen < ICMPERR_MINPKTLEN))
+	    (fin->fin_plen < ICMPERR_MINPKTLEN) ||
+	    !(fin->fin_flx & FI_ICMPERR))
 		return NULL;
 	ic = fin->fin_dp;
 	type = ic->icmp_type;
-	/*
-	 * If it's not an error type, then return
-	 */
-	if ((type != ICMP_UNREACH) && (type != ICMP_SOURCEQUENCH) &&
-    	    (type != ICMP_REDIRECT) && (type != ICMP_TIMXCEED) &&
-    	    (type != ICMP_PARAMPROB))
-		return NULL;
 
 	oip = (ip_t *)((char *)ic + ICMPERR_ICMPHLEN);
 	/*
@@ -1921,7 +2124,7 @@
 # endif
 	}
 #endif
-	bcopy((char *)fin, (char *)&ofin, sizeof(fin));
+	bcopy((char *)fin, (char *)&ofin, sizeof(*fin));
 
 	/*
 	 * in the IPv4 case we must zero the i6addr union otherwise
@@ -1944,14 +2147,13 @@
 	 */
 	savelen = oip->ip_len;
 	oip->ip_len = len;
-	oip->ip_off = htons(oip->ip_off);
+	oip->ip_off = ntohs(oip->ip_off);
 
 	ofin.fin_flx = FI_NOCKSUM;
 	ofin.fin_v = 4;
 	ofin.fin_ip = oip;
 	ofin.fin_m = NULL;	/* if dereferenced, panic XXX */
 	ofin.fin_mp = NULL;	/* if dereferenced, panic XXX */
-	ofin.fin_plen = fin->fin_dlen - ICMPERR_ICMPHLEN;
 	(void) fr_makefrip(IP_HL(oip) << 2, oip, &ofin);
 	ofin.fin_ifp = fin->fin_ifp;
 	ofin.fin_out = !fin->fin_out;
@@ -1972,8 +2174,6 @@
 	switch (oip->ip_p)
 	{
 	case IPPROTO_ICMP :
-		icmp = (icmphdr_t *)((char *)oip + (IP_HL(oip) << 2));
-
 		/*
 		 * an ICMP error can only be generated as a result of an
 		 * ICMP query, not as the response on an ICMP error
@@ -1981,15 +2181,13 @@
 		 * XXX theoretically ICMP_ECHOREP and the other reply's are
 		 * ICMP query's as well, but adding them here seems strange XXX
 		 */
-		if ((icmp->icmp_type != ICMP_ECHO) &&
-		    (icmp->icmp_type != ICMP_TSTAMP) &&
-		    (icmp->icmp_type != ICMP_IREQ) &&
-		    (icmp->icmp_type != ICMP_MASKREQ))
+		if ((ofin.fin_flx & FI_ICMPERR) != 0)
 		    	return NULL;
 
 		/*
 		 * perform a lookup of the ICMP packet in the state table
 		 */
+		icmp = (icmphdr_t *)((char *)oip + (IP_HL(oip) << 2));
 		hv = (pr = oip->ip_p);
 		src.in4 = oip->ip_src;
 		hv += src.in4.s_addr;
@@ -2008,10 +2206,6 @@
 			is = fr_matchsrcdst(&ofin, is, &src, &dst,
 					    NULL, FI_ICMPCMP);
 			if (is != NULL) {
-				if ((is->is_pass & FR_NOICMPERR) != 0) {
-					RWLOCK_EXIT(&ipf_state);
-					return NULL;
-				}
 				/*
 				 * i  : the index of this packet (the icmp
 				 *      unreachable)
@@ -2115,8 +2309,6 @@
 	ipstate_t **isp;
 	u_int hvm;
 
-	ASSERT(rw_read_locked(&ipf_state.ipf_lk) == 0);
-
 	hvm = is->is_hv;
 	/*
 	 * Remove the hash from the old location...
@@ -2199,6 +2391,14 @@
 		}
 	}
 #endif
+	if ((v == 4) &&
+	    (fin->fin_flx & (FI_MULTICAST|FI_BROADCAST|FI_MBCAST))) {
+		if (fin->fin_out == 0) {
+			hv -= src.in4.s_addr;
+		} else {
+			hv -= dst.in4.s_addr;
+		}
+	}
 
 	/*
 	 * Search the hash table for matching packet header info.
@@ -2219,6 +2419,13 @@
 		hvm = DOUBLE_HASH(hv);
 		for (isp = &ips_table[hvm]; ((is = *isp) != NULL); ) {
 			isp = &is->is_hnext;
+			/*
+			 * If a connection is about to be deleted, no packets
+			 * are allowed to match it.
+			 */
+			if (is->is_sti.tqe_ifq == &ips_deletetq)
+				continue;
+
 			if ((is->is_p != pr) || (is->is_v != v))
 				continue;
 			is = fr_matchsrcdst(fin, is, &src, &dst, NULL, FI_CMP);
@@ -2284,7 +2491,8 @@
 			if ((is->is_p != pr) || (is->is_v != v))
 				continue;
 			is = fr_matchsrcdst(fin, is, &src, &dst, NULL, FI_CMP);
-			if (is != NULL &&
+			if ((is != NULL) &&
+			    (ic->icmp_id == is->is_icmp.ici_id) &&
 			    fr_matchicmpqueryreply(v, &is->is_icmp,
 						   ic, fin->fin_rev)) {
 				if (fin->fin_rev)
@@ -2339,12 +2547,31 @@
 		}
 		RWLOCK_EXIT(&ipf_state);
 
-		if (!tryagain && ips_stats.iss_wild) {
-			hv -= dport;
-			hv -= sport;
-			tryagain = 1;
-			WRITE_ENTER(&ipf_state);
-			goto retry_tcpudp;
+		if (ips_stats.iss_wild) {
+			if (tryagain == 0) {
+				hv -= dport;
+				hv -= sport;
+			} else if (tryagain == 1) {
+				hv = fin->fin_fi.fi_p;
+				/*
+				 * If we try to pretend this is a reply to a
+				 * multicast/broadcast packet then we need to
+				 * exclude part of the address from the hash
+				 * calculation.
+				 */
+				if (fin->fin_out == 0) {
+					hv += src.in4.s_addr;
+				} else {
+					hv += dst.in4.s_addr;
+				}
+				hv += dport;
+				hv += sport;
+			}
+			tryagain++;
+			if (tryagain <= 2) {
+				WRITE_ENTER(&ipf_state);
+				goto retry_tcpudp;
+			}
 		}
 		fin->fin_flx |= oow;
 		break;
@@ -2377,11 +2604,13 @@
 		break;
 	}
 
-	if ((is != NULL) && ((is->is_sti.tqe_flags & TQE_RULEBASED) != 0) &&
-	    (is->is_tqehead[fin->fin_rev] != NULL))
-		ifq = is->is_tqehead[fin->fin_rev];
-	if (ifq != NULL && ifqp != NULL)
-		*ifqp = ifq;
+	if (is != NULL) {
+		if (((is->is_sti.tqe_flags & TQE_RULEBASED) != 0) &&
+		    (is->is_tqehead[fin->fin_rev] != NULL))
+			ifq = is->is_tqehead[fin->fin_rev];
+		if (ifq != NULL && ifqp != NULL)
+			*ifqp = ifq;
+	}
 	return is;
 }
 
@@ -2545,8 +2774,6 @@
 	fin->fin_rule = is->is_rulen;
 	pass = is->is_pass;
 	fr_updatestate(fin, is, ifq);
-	if (fin->fin_out == 1)
-		fin->fin_nat = is->is_nat[fin->fin_rev];
 
 	fin->fin_state = is;
 	is->is_touched = fr_ticks;
@@ -2682,7 +2909,7 @@
 
 /* ------------------------------------------------------------------------ */
 /* Function:    fr_delstate                                                 */
-/* Returns:     Nil                                                         */
+/* Returns:     int - 0 = entry deleted, else reference count on struct     */
 /* Parameters:  is(I)  - pointer to state structure to delete               */
 /*              why(I) - if not 0, log reason why it was deleted            */
 /* Write Locks: ipf_state                                                   */
@@ -2691,27 +2918,15 @@
 /* and timeout queue lists.  Make adjustments to hash table statistics and  */
 /* global counters as required.                                             */
 /* ------------------------------------------------------------------------ */
-static void fr_delstate(is, why)
+static int fr_delstate(is, why)
 ipstate_t *is;
 int why;
 {
 
-	ASSERT(rw_read_locked(&ipf_state.ipf_lk) == 0);
-
 	/*
 	 * Since we want to delete this, remove it from the state table,
 	 * where it can be found & used, first.
 	 */
-	if (is->is_pnext != NULL) {
-		*is->is_pnext = is->is_next;
-
-		if (is->is_next != NULL)
-			is->is_next->is_pnext = is->is_pnext;
-
-		is->is_pnext = NULL;
-		is->is_next = NULL;
-	}
-
 	if (is->is_phnext != NULL) {
 		*is->is_phnext = is->is_hnext;
 		if (is->is_hnext != NULL)
@@ -2739,7 +2954,8 @@
 	/*
 	 * Next, remove it from the timeout queue it is in.
 	 */
-	fr_deletequeueentry(&is->is_sti);
+	if (is->is_sti.tqe_ifq != NULL)
+		fr_deletequeueentry(&is->is_sti);
 
 	if (is->is_me != NULL) {
 		*is->is_me = NULL;
@@ -2748,11 +2964,21 @@
 
 	/*
 	 * If it is still in use by something else, do not go any further,
-	 * but note that at this point it is now an orphan.
+	 * but note that at this point it is now an orphan.  How can this
+	 * be?  fr_state_flush() calls fr_delete() directly because it wants
+	 * to empty the table out and if something has a hold on a state
+	 * entry (such as ipfstat), it'll do the deref path that'll bring
+	 * us back here to do the real delete & free.
 	 */
-	is->is_ref--;
-	if (is->is_ref > 0)
-		return;
+	MUTEX_ENTER(&is->is_lock);
+	if (is->is_ref > 1) {
+		is->is_ref--;
+		MUTEX_EXIT(&is->is_lock);
+		return is->is_ref;
+	}
+	MUTEX_EXIT(&is->is_lock);
+
+	is->is_ref = 0;
 
 	if (is->is_tqehead[0] != NULL) {
 		if (fr_deletetimeoutqueue(is->is_tqehead[0]) == 0)
@@ -2771,17 +2997,37 @@
 	(void) ipsc_detachis(is);
 #endif
 
+	/*
+	 * Now remove it from the linked list of known states
+	 */
+	if (is->is_pnext != NULL) {
+		*is->is_pnext = is->is_next;
+
+		if (is->is_next != NULL)
+			is->is_next->is_pnext = is->is_pnext;
+
+		is->is_pnext = NULL;
+		is->is_next = NULL;
+	}
+
 	if (ipstate_logging != 0 && why != 0)
 		ipstate_log(is, why);
 
+	if (is->is_p == IPPROTO_TCP)
+		ips_stats.iss_fin++;
+	else
+		ips_stats.iss_expire++;
+
 	if (is->is_rule != NULL) {
 		is->is_rule->fr_statecnt--;
-		(void)fr_derefrule(&is->is_rule);
+		(void) fr_derefrule(&is->is_rule);
 	}
 
 	MUTEX_DESTROY(&is->is_lock);
 	KFREE(is);
 	ips_num--;
+
+	return 0;
 }
 
 
@@ -2800,9 +3046,7 @@
 	ipftq_t *ifq, *ifqnext;
 	ipftqent_t *tqe, *tqn;
 	ipstate_t *is;
-#if defined(USE_SPL) && defined(_KERNEL)
-	int s;
-#endif
+	SPL_INT(s);
 
 	SPL_NET(s);
 	WRITE_ENTER(&ipf_state);
@@ -2869,48 +3113,115 @@
 	ipftq_t *ifq, *ifqnext;
 	ipftqent_t *tqe, *tqn;
 	ipstate_t *is, **isp;
-	int delete, removed;
-	long try, maxtick;
-	u_long interval;
-#if defined(_KERNEL) && !defined(MENTAT) && defined(USE_SPL)
-	int s;
-#endif
+	int removed;
+	SPL_INT(s);
 
 	removed = 0;
 
 	SPL_NET(s);
-	for (isp = &ips_list; ((is = *isp) != NULL); ) {
-		delete = 0;
 
-		if ((proto != 0) && (is->is_v != proto)) {
-			isp = &is->is_next;
-			continue;
+	switch (which)
+	{
+	case 0 :
+		/*
+		 * Style 0 flush removes everything...
+		 */
+		for (isp = &ips_list; ((is = *isp) != NULL); ) {
+			if ((proto != 0) && (is->is_v != proto)) {
+				isp = &is->is_next;
+				continue;
+			}
+			if (fr_delstate(is, ISL_FLUSH) == 0)
+				removed++;
+			else
+				isp = &is->is_next;
 		}
+		break;
 
-		switch (which)
-		{
-		case 0 :
-			delete = 1;
-			break;
-		case 1 :
-		case 2 :
-			if (is->is_p != IPPROTO_TCP)
-				break;
-			if ((is->is_state[0] != IPF_TCPS_ESTABLISHED) ||
-			    (is->is_state[1] != IPF_TCPS_ESTABLISHED))
-				delete = 1;
-			break;
+	case 1 :
+		/*
+		 * Since we're only interested in things that are closing,
+		 * we can start with the appropriate timeout queue.
+		 */
+		for (ifq = ips_tqtqb + IPF_TCPS_CLOSE_WAIT; ifq != NULL;
+		     ifq = ifq->ifq_next) {
+
+			for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); ) {
+				tqn = tqe->tqe_next;
+				is = tqe->tqe_parent;
+				if (is->is_p != IPPROTO_TCP)
+					break;
+				if (fr_delstate(is, ISL_EXPIRE) == 0)
+					removed++;
+			}
 		}
 
-		if (delete) {
-			if (is->is_p == IPPROTO_TCP)
-				ips_stats.iss_fin++;
-			else
-				ips_stats.iss_expire++;
-			fr_delstate(is, ISL_FLUSH);
-			removed++;
-		} else
+		/*
+		 * Also need to look through the user defined queues.
+		 */
+		for (ifq = ips_utqe; ifq != NULL; ifq = ifqnext) {
+			ifqnext = ifq->ifq_next;
+			for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); ) {
+				tqn = tqe->tqe_next;
+				is = tqe->tqe_parent;
+				if (is->is_p != IPPROTO_TCP)
+					continue;
+
+				if ((is->is_state[0] > IPF_TCPS_ESTABLISHED) &&
+				    (is->is_state[1] > IPF_TCPS_ESTABLISHED)) {
+					if (fr_delstate(is, ISL_EXPIRE) == 0)
+						removed++;
+				}
+			}
+		}
+		break;
+
+	case 2 :
+		break;
+
+		/*  
+		 * Args 5-11 correspond to flushing those particular states
+		 * for TCP connections.
+		 */
+	case IPF_TCPS_CLOSE_WAIT :
+	case IPF_TCPS_FIN_WAIT_1 :
+	case IPF_TCPS_CLOSING :
+	case IPF_TCPS_LAST_ACK :
+	case IPF_TCPS_FIN_WAIT_2 :
+	case IPF_TCPS_TIME_WAIT :
+	case IPF_TCPS_CLOSED :
+		tqn = ips_tqtqb[which].ifq_head;
+		while (tqn != NULL) {
+			tqe = tqn;
+			tqn = tqe->tqe_next;
+			is = tqe->tqe_parent;
+			if (fr_delstate(is, ISL_FLUSH) == 0)
+				removed++;
+		}
+		break;
+
+	default :
+		if (which < 30)
+			break;
+
+		/* 
+		 * Take a large arbitrary number to mean the number of seconds
+		 * for which which consider to be the maximum value we'll allow
+		 * the expiration to be.
+		 */
+		which = IPF_TTLVAL(which);
+		for (isp = &ips_list; ((is = *isp) != NULL); ) {
+			if ((proto == 0) || (is->is_v == proto)) {
+				if (fr_ticks - is->is_touched > which) {
+					if (fr_delstate(is, ISL_FLUSH) == 0) {
+						removed++;
+						continue;
+					}
+				}
+			}
 			isp = &is->is_next;
+		}
+		break;
 	}
 
 	if (which != 2) {
@@ -2919,83 +3230,35 @@
 	}
 
 	/*
-	 * Asked to remove inactive entries because the table is full, try
-	 * again, 3 times, if first attempt failed with a different criteria
-	 * each time.  The order tried in must be in decreasing age.
-	 * Another alternative is to implement random drop and drop N entries
-	 * at random until N have been freed up.
+	 * Asked to remove inactive entries because the table is full.
 	 */
-	if (fr_ticks - ips_last_force_flush < IPF_TTLVAL(5))
-		goto force_flush_skipped;
-	ips_last_force_flush = fr_ticks;
-
-	if (fr_ticks > IPF_TTLVAL(43200))
-		interval = IPF_TTLVAL(43200);
-	else if (fr_ticks > IPF_TTLVAL(1800))
-		interval = IPF_TTLVAL(1800);
-	else if (fr_ticks > IPF_TTLVAL(30))
-		interval = IPF_TTLVAL(30);
-	else
-		interval = IPF_TTLVAL(10);
-	try = fr_ticks - (fr_ticks - interval);
-	if (try < 0)
-		goto force_flush_skipped;
-
-	while (removed == 0) {
-		maxtick = fr_ticks - interval;
-		if (maxtick < 0)
-			break;
-
-		while (try < maxtick) {
-			for (ifq = ips_tqtqb; ifq != NULL;
-			     ifq = ifq->ifq_next) {
-				for (tqn = ifq->ifq_head;
-				     ((tqe = tqn) != NULL); ) {
-					if (tqe->tqe_die > try)
-						break;
-					tqn = tqe->tqe_next;
-					is = tqe->tqe_parent;
-					fr_delstate(is, ISL_EXPIRE);
-					removed++;
-				}
-			}
-
-			for (ifq = ips_utqe; ifq != NULL; ifq = ifqnext) {
-				ifqnext = ifq->ifq_next;
-
-				for (tqn = ifq->ifq_head;
-				     ((tqe = tqn) != NULL); ) {
-					if (tqe->tqe_die > try)
-						break;
-					tqn = tqe->tqe_next;
-					is = tqe->tqe_parent;
-					fr_delstate(is, ISL_EXPIRE);
-					removed++;
-				}
-			}
-			if (try + interval > maxtick)
-				break;
-			try += interval;
-		}
-
-		if (removed == 0) {
-			if (interval == IPF_TTLVAL(43200)) {
-				interval = IPF_TTLVAL(1800);
-			} else if (interval == IPF_TTLVAL(1800)) {
-				interval = IPF_TTLVAL(30);
-			} else if (interval == IPF_TTLVAL(30)) {
-				interval = IPF_TTLVAL(10);
-			} else {
-				break;
-			}
-		}
+	if (fr_ticks - ips_last_force_flush > IPF_TTLVAL(5)) {
+		ips_last_force_flush = fr_ticks;
+                removed = ipf_queueflush(fr_state_flush_entry, ips_tqtqb,
+					 ips_utqe);
 	}
-force_flush_skipped:
+
 	SPL_X(s);
 	return removed;
 }
 
 
+/* ------------------------------------------------------------------------ */
+/* Function:    fr_state_flush_entry                                        */
+/* Returns:     int - 0 = entry deleted, else not deleted                   */
+/* Parameters:  entry(I)  - pointer to state structure to delete            */
+/* Write Locks: ipf_state                                                   */
+/*                                                                          */
+/* This function is a stepping stone between ipf_queueflush() and           */
+/* fr_delstate().  It is used so we can provide a uniform interface via the */
+/* ipf_queueflush() function.                                               */
+/* ------------------------------------------------------------------------ */
+static int fr_state_flush_entry(entry)
+void *entry;
+{
+	return fr_delstate(entry, ISL_FLUSH);
+}     
+
 
 /* ------------------------------------------------------------------------ */
 /* Function:    fr_tcp_age                                                  */
@@ -3025,6 +3288,25 @@
 /*    dir == 0 : a packet from source to dest                               */
 /*    dir == 1 : a packet from dest to source                               */
 /*                                                                          */
+/* A typical procession for a connection is as follows:                     */
+/*                                                                          */
+/* +--------------+-------------------+                                     */
+/* | Side '0'     | Side '1'          |                                     */
+/* +--------------+-------------------+                                     */
+/* | 0 -> 1 (SYN) |                   |                                     */
+/* |              | 0 -> 2 (SYN-ACK)  |                                     */
+/* | 1 -> 3 (ACK) |                   |                                     */
+/* |              | 2 -> 4 (ACK-PUSH) |                                     */
+/* | 3 -> 4 (ACK) |                   |                                     */
+/* |   ...        |   ...             |                                     */
+/* |              | 4 -> 6 (FIN-ACK)  |                                     */
+/* | 4 -> 5 (ACK) |                   |                                     */
+/* |              | 6 -> 6 (ACK-PUSH) |                                     */
+/* | 5 -> 5 (ACK) |                   |                                     */
+/* | 5 -> 8 (FIN) |                   |                                     */
+/* |              | 6 -> 10 (ACK)     |                                     */
+/* +--------------+-------------------+                                     */
+/*                                                                          */
 /* Locking: it is assumed that the parent of the tqe structure is locked.   */
 /* ------------------------------------------------------------------------ */
 int fr_tcp_age(tqe, fin, tqtab, flags)
@@ -3042,7 +3324,7 @@
 	rval = 0;
 	dir = fin->fin_rev;
 	tcpflags = tcp->th_flags;
-	dlen = fin->fin_plen - fin->fin_hlen - (TCP_OFF(tcp) << 2);
+	dlen = fin->fin_dlen - (TCP_OFF(tcp) << 2);
 
 	if (tcpflags & TH_RST) {
 		if (!(tcpflags & TH_PUSH) && !dlen)
@@ -3056,16 +3338,16 @@
 
 		switch (nstate)
 		{
-		case IPF_TCPS_CLOSED: /* 0 */
+		case IPF_TCPS_LISTEN: /* 0 */
 			if ((tcpflags & TH_OPENING) == TH_OPENING) {
 				/*
 				 * 'dir' received an S and sends SA in
-				 * response, CLOSED -> SYN_RECEIVED
+				 * response, LISTEN -> SYN_RECEIVED
 				 */
 				nstate = IPF_TCPS_SYN_RECEIVED;
 				rval = 1;
 			} else if ((tcpflags & TH_OPENING) == TH_SYN) {
-				/* 'dir' sent S, CLOSED -> SYN_SENT */
+				/* 'dir' sent S, LISTEN -> SYN_SENT */
 				nstate = IPF_TCPS_SYN_SENT;
 				rval = 1;
 			}
@@ -3084,7 +3366,7 @@
 				 */
 				switch (ostate)
 				{
-				case IPF_TCPS_CLOSED :
+				case IPF_TCPS_LISTEN :
 				case IPF_TCPS_SYN_RECEIVED :
 					nstate = IPF_TCPS_HALF_ESTAB;
 					rval = 1;
@@ -3105,11 +3387,7 @@
 			 */
 			break;
 
-		case IPF_TCPS_LISTEN: /* 1 */
-			/* NOT USED */
-			break;
-
-		case IPF_TCPS_SYN_SENT: /* 2 */
+		case IPF_TCPS_SYN_SENT: /* 1 */
 			if ((tcpflags & ~(TH_ECN|TH_CWR)) == TH_SYN) {
 				/*
 				 * A retransmitted SYN packet.  We do not reset
@@ -3150,7 +3428,7 @@
 			}
 			break;
 
-		case IPF_TCPS_SYN_RECEIVED: /* 3 */
+		case IPF_TCPS_SYN_RECEIVED: /* 2 */
 			if ((tcpflags & (TH_SYN|TH_FIN|TH_ACK)) == TH_ACK) {
 				/*
 				 * we see an A from 'dir' which was in
@@ -3179,17 +3457,38 @@
 			}
 			break;
 
-		case IPF_TCPS_HALF_ESTAB: /* 4 */
-			if (ostate >= IPF_TCPS_HALF_ESTAB) {
-				if ((tcpflags & TH_ACKMASK) == TH_ACK) {
+		case IPF_TCPS_HALF_ESTAB: /* 3 */
+			if (tcpflags & TH_FIN) {
+				nstate = IPF_TCPS_FIN_WAIT_1;
+				rval = 1;
+			} else if ((tcpflags & TH_ACKMASK) == TH_ACK) {
+				/*
+				 * If we've picked up a connection in mid
+				 * flight, we could be looking at a follow on
+				 * packet from the same direction as the one
+				 * that created this state.  Recognise it but
+				 * do not advance the entire connection's
+				 * state.
+				 */
+				switch (ostate)
+				{
+				case IPF_TCPS_LISTEN :
+				case IPF_TCPS_SYN_SENT :
+				case IPF_TCPS_SYN_RECEIVED :
+					rval = 1;
+					break;
+				case IPF_TCPS_HALF_ESTAB :
+				case IPF_TCPS_ESTABLISHED :
 					nstate = IPF_TCPS_ESTABLISHED;
 					rval = 1;
+					break;
+				default :
+					break;
 				}
 			}
-				
 			break;
 
-		case IPF_TCPS_ESTABLISHED: /* 5 */
+		case IPF_TCPS_ESTABLISHED: /* 4 */
 			rval = 1;
 			if (tcpflags & TH_FIN) {
 				/*
@@ -3197,7 +3496,11 @@
 				 * this gives us a half-closed connection;
 				 * ESTABLISHED -> FIN_WAIT_1
 				 */
-				nstate = IPF_TCPS_FIN_WAIT_1;
+				if (ostate == IPF_TCPS_FIN_WAIT_1) {
+					nstate = IPF_TCPS_CLOSING;
+				} else {
+					nstate = IPF_TCPS_FIN_WAIT_1;
+				}
 			} else if (tcpflags & TH_ACK) {
 				/*
 				 * an ACK, should we exclude other flags here?
@@ -3222,7 +3525,7 @@
 			}
 			break;
 
-		case IPF_TCPS_CLOSE_WAIT: /* 6 */
+		case IPF_TCPS_CLOSE_WAIT: /* 5 */
 			rval = 1;
 			if (tcpflags & TH_FIN) {
 				/*
@@ -3240,7 +3543,7 @@
 			}
 			break;
 
-		case IPF_TCPS_FIN_WAIT_1: /* 7 */
+		case IPF_TCPS_FIN_WAIT_1: /* 6 */
 			rval = 1;
 			if ((tcpflags & TH_ACK) &&
 			    ostate > IPF_TCPS_CLOSE_WAIT) {
@@ -3268,11 +3571,14 @@
 			}
 			break;
 
-		case IPF_TCPS_CLOSING: /* 8 */
-			/* NOT USED */
+		case IPF_TCPS_CLOSING: /* 7 */
+			if ((tcpflags & (TH_FIN|TH_ACK)) == TH_ACK) {
+				nstate = IPF_TCPS_TIME_WAIT;
+			}
+			rval = 2;
 			break;
 
-		case IPF_TCPS_LAST_ACK: /* 9 */
+		case IPF_TCPS_LAST_ACK: /* 8 */
 			if (tcpflags & TH_ACK) {
 				if ((tcpflags & TH_PUSH) || dlen)
 					/*
@@ -3291,19 +3597,22 @@
 			 */
 			break;
 
-		case IPF_TCPS_FIN_WAIT_2: /* 10 */
-			rval = 1;
-			if ((tcpflags & TH_OPENING) == TH_OPENING)
-				nstate = IPF_TCPS_SYN_RECEIVED;
-			else if (tcpflags & TH_SYN)
-				nstate = IPF_TCPS_SYN_SENT;
+		case IPF_TCPS_FIN_WAIT_2: /* 9 */
+			/* NOT USED */
 			break;
 
-		case IPF_TCPS_TIME_WAIT: /* 11 */
+		case IPF_TCPS_TIME_WAIT: /* 10 */
 			/* we're in 2MSL timeout now */
+			if (ostate == IPF_TCPS_LAST_ACK) {
+				nstate = IPF_TCPS_CLOSED;
+			}
 			rval = 1;
 			break;
 
+		case IPF_TCPS_CLOSED: /* 11 */
+			rval = 2;
+			break;
+
 		default :
 #if defined(_KERNEL)
 # if SOLARIS
@@ -3316,9 +3625,6 @@
 				(u_long)tcp, tcpflags, (u_long)tqe,
 				nstate, ostate);
 # endif
-# ifdef DIAGNOSTIC
-			panic("invalid TCP state");
-# endif
 #else
 			abort();
 #endif
@@ -3442,26 +3748,22 @@
 
 	/*
 	 * Does it at least have the return (basic) IP header ?
+	 * Is it an actual recognised ICMP error type?
 	 * Only a basic IP header (no options) should be with
 	 * an ICMP error header.
 	 */
-	if ((fin->fin_v != 6) || (fin->fin_plen < ICMP6ERR_MINPKTLEN))
+	if ((fin->fin_v != 6) || (fin->fin_plen < ICMP6ERR_MINPKTLEN) ||
+	    !(fin->fin_flx & FI_ICMPERR))
 		return NULL;
 
 	ic6 = fin->fin_dp;
 	type = ic6->icmp6_type;
-	/*
-	 * If it's not an error type, then return
-	 */
-	if ((type != ICMP6_DST_UNREACH) && (type != ICMP6_PACKET_TOO_BIG) &&
-	    (type != ICMP6_TIME_EXCEEDED) && (type != ICMP6_PARAM_PROB))
-		return NULL;
 
 	oip6 = (ip6_t *)((char *)ic6 + ICMPERR_ICMPHLEN);
 	if (fin->fin_plen < sizeof(*oip6))
 		return NULL;
 
-	bcopy((char *)fin, (char *)&ofin, sizeof(fin));
+	bcopy((char *)fin, (char *)&ofin, sizeof(*fin));
 	ofin.fin_v = 6;
 	ofin.fin_ifp = fin->fin_ifp;
 	ofin.fin_out = !fin->fin_out;
@@ -3482,7 +3784,6 @@
 	oip6->ip6_plen = fin->fin_dlen - ICMPERR_ICMPHLEN;
 	ofin.fin_flx = FI_NOCKSUM;
 	ofin.fin_ip = (ip_t *)oip6;
-	ofin.fin_plen = oip6->ip6_plen;
 	(void) fr_makefrip(sizeof(*oip6), (ip_t *)oip6, &ofin);
 	ofin.fin_flx &= ~(FI_BAD|FI_SHORT);
 	oip6->ip6_plen = savelen;
@@ -3629,7 +3930,7 @@
 	tqp[IPF_TCPS_CLOSING].ifq_ttl = fr_tcptimeout;
 	tqp[IPF_TCPS_LAST_ACK].ifq_ttl = fr_tcplastack;
 	tqp[IPF_TCPS_FIN_WAIT_2].ifq_ttl = fr_tcpclosewait;
-	tqp[IPF_TCPS_TIME_WAIT].ifq_ttl = fr_tcptimeout;
+	tqp[IPF_TCPS_TIME_WAIT].ifq_ttl = fr_tcptimewait;
 	tqp[IPF_TCPS_HALF_ESTAB].ifq_ttl = fr_tcptimeout;
 }
 
@@ -3660,6 +3961,14 @@
 /* Decrement the reference counter for this state table entry and free it   */
 /* if there are no more things using it.                                    */
 /*                                                                          */
+/* This function is only called when cleaning up after increasing is_ref by */
+/* one earlier in the 'code path' so if is_ref is 1 when entering, we do    */
+/* have an orphan, otherwise not.  However there is a possible race between */
+/* the entry being deleted via flushing with an ioctl call (that calls the  */
+/* delete function directly) and the tail end of packet processing so we    */
+/* need to grab is_lock before doing the check to synchronise the two code  */
+/* paths.                                                                   */
+/*                                                                          */
 /* When operating in userland (ipftest), we have no timers to clear a state */
 /* entry.  Therefore, we make a few simple tests before deleting an entry   */
 /* outright.  We compare states on each side looking for a combination of   */
@@ -3675,60 +3984,30 @@
 /*    dir == 0 : a packet from source to dest                               */
 /*    dir == 1 : a packet from dest to source                               */
 /* ------------------------------------------------------------------------ */
-void fr_statederef(fin, isp)
-fr_info_t *fin;
+void fr_statederef(isp)
 ipstate_t **isp;
 {
-	ipstate_t *is = *isp;
-#if 0
-	int nstate, ostate, dir, eol;
-
-	eol = 0; /* End-of-the-line flag. */
-	dir = fin->fin_rev;
-	ostate = is->is_state[1 - dir];
-	nstate = is->is_state[dir];
-	/*
-	 * Determine whether this packet is local or routed.  State entries
-	 * with us as the destination will have an interface list of
-	 * int1,-,-,int1.  Entries with us as the origin run as -,int1,int1,-.
-	 */
-	if ((fin->fin_p == IPPROTO_TCP) && (fin->fin_out == 0)) {
-		if ((strcmp(is->is_ifname[0], is->is_ifname[3]) == 0) &&
-		    (strcmp(is->is_ifname[1], is->is_ifname[2]) == 0)) {
-			if ((dir == 0) &&
-			    (strcmp(is->is_ifname[1], "-") == 0) &&
-			    (strcmp(is->is_ifname[0], "-") != 0)) {
-				eol = 1;
-			} else if ((dir == 1) &&
-				   (strcmp(is->is_ifname[0], "-") == 0) &&
-				   (strcmp(is->is_ifname[1], "-") != 0)) {
-				eol = 1;
-			}
-		}
-	}
-#endif
+	ipstate_t *is;
 
-	fin = fin;	/* LINT */
 	is = *isp;
 	*isp = NULL;
-	WRITE_ENTER(&ipf_state);
-	is->is_ref--;
-	if (is->is_ref == 0) {
-		is->is_ref++;		/* To counter ref-- in fr_delstate() */
-		fr_delstate(is, ISL_EXPIRE);
+
+	MUTEX_ENTER(&is->is_lock);
+	if (is->is_ref > 1) {
+		is->is_ref--;
+		MUTEX_EXIT(&is->is_lock);
 #ifndef	_KERNEL
-#if 0
-	} else if (((fin->fin_out == 1) || (eol == 1)) &&
-		   ((ostate == IPF_TCPS_LAST_ACK) &&
-		   (nstate == IPF_TCPS_TIME_WAIT))) {
-		;
-#else
-	} else if ((is->is_sti.tqe_state[0] > IPF_TCPS_ESTABLISHED) ||
+		if ((is->is_sti.tqe_state[0] > IPF_TCPS_ESTABLISHED) ||
 		   (is->is_sti.tqe_state[1] > IPF_TCPS_ESTABLISHED)) {
+			fr_delstate(is, ISL_ORPHAN);
+		}
 #endif
-		fr_delstate(is, ISL_ORPHAN);
-#endif
+		return;
 	}
+	MUTEX_EXIT(&is->is_lock);
+
+	WRITE_ENTER(&ipf_state);
+	fr_delstate(is, ISL_EXPIRE);
 	RWLOCK_EXIT(&ipf_state);
 }
 
@@ -3800,3 +4079,121 @@
 		fr_queueappend(&is->is_sti, nifq, is);
 	return;
 }
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    fr_stateiter                                                */
+/* Returns:     int - 0 == success, else error                              */
+/* Parameters:  token(I) - pointer to ipftoken structure                    */
+/*              itp(I)   - pointer to ipfgeniter structure                  */
+/*                                                                          */
+/* This function handles the SIOCGENITER ioctl for the state tables and     */
+/* walks through the list of entries in the state table list (ips_list.)    */
+/* ------------------------------------------------------------------------ */
+static int fr_stateiter(token, itp)
+ipftoken_t *token;
+ipfgeniter_t *itp;
+{
+	ipstate_t *is, *next, zero;
+	int error, count;
+	char *dst;
+
+	if (itp->igi_data == NULL)
+		return EFAULT;
+
+	if (itp->igi_nitems < 1)
+		return ENOSPC;
+
+	if (itp->igi_type != IPFGENITER_STATE)
+		return EINVAL;
+
+	is = token->ipt_data;
+	if (is == (void *)-1) {
+		ipf_freetoken(token);
+		return ESRCH;
+	}
+
+	error = 0;
+	dst = itp->igi_data;
+
+	READ_ENTER(&ipf_state);
+	if (is == NULL) {
+		next = ips_list;
+	} else {
+		next = is->is_next;
+	}
+
+	count = itp->igi_nitems;
+	for (;;) {
+		if (next != NULL) {
+			/*
+			 * If we find a state entry to use, bump its
+			 * reference count so that it can be used for
+			 * is_next when we come back.
+			 */
+			if (count == 1) {
+				MUTEX_ENTER(&next->is_lock);
+				next->is_ref++;
+				MUTEX_EXIT(&next->is_lock);
+				token->ipt_data = next;
+			}
+		} else {
+			bzero(&zero, sizeof(zero));
+			next = &zero;
+			count = 1;
+			token->ipt_data = NULL;
+		}
+		RWLOCK_EXIT(&ipf_state);
+
+		/*
+		 * This should arguably be via fr_outobj() so that the state
+		 * structure can (if required) be massaged going out.
+		 */
+		error = COPYOUT(next, dst, sizeof(*next));
+		if (error != 0)
+			error = EFAULT;
+		if ((count == 1) || (error != 0))
+			break;
+
+		dst += sizeof(*next);
+		count--;
+
+		READ_ENTER(&ipf_state);
+		next = next->is_next;
+	}
+
+	if (is != NULL) {
+		fr_statederef(&is);
+	}
+
+	return error;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    fr_stgettable                                               */
+/* Returns:     int     - 0 = success, else error                           */
+/* Parameters:  data(I) - pointer to ioctl data                             */
+/*                                                                          */
+/* This function handles ioctl requests for tables of state information.    */
+/* At present the only table it deals with is the hash bucket statistics.   */
+/* ------------------------------------------------------------------------ */
+static int fr_stgettable(data)
+char *data;
+{
+	ipftable_t table;
+	int error;
+
+	error = fr_inobj(data, &table, IPFOBJ_GTABLE);
+	if (error != 0)
+		return error;
+
+	if (table.ita_type != IPFTABLE_BUCKETS)
+		return EINVAL;
+
+	error = COPYOUT(ips_stats.iss_bucketlen, table.ita_table, 
+			fr_statesize * sizeof(u_long));
+	if (error != 0)
+		error = EFAULT;
+	return error;
+}
Index: ip_scan.h
===================================================================
RCS file: /home/cvs/src/sys/contrib/ipfilter/netinet/ip_scan.h,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/contrib/ipfilter/netinet/ip_scan.h -L sys/contrib/ipfilter/netinet/ip_scan.h -u -r1.1.1.1 -r1.2
--- sys/contrib/ipfilter/netinet/ip_scan.h
+++ sys/contrib/ipfilter/netinet/ip_scan.h
@@ -1,12 +1,10 @@
-/*	$FreeBSD: src/sys/contrib/ipfilter/netinet/ip_scan.h,v 1.1.1.1 2005/04/25 18:15:35 darrenr Exp $	*/
-
 /*
  * Copyright (C) 1993-2001 by Darren Reed.
  *
  * See the IPFILTER.LICENCE file for details on licencing.
  *
  * @(#)ip_fil.h	1.35 6/5/96
- * Id: ip_scan.h,v 2.9 2003/07/25 22:05:01 darrenr Exp
+ * $Id: ip_scan.h,v 2.9.2.2 2006/07/14 06:12:19 darrenr Exp $
  */
 
 #ifndef __IP_SCAN_H__
@@ -27,7 +25,7 @@
 struct ipstate;
 
 
-#if defined(__STDC__) || defined(__GNUC__)
+#if defined(__STDC__) || defined(__GNUC__) || defined(_AIX51)
 # define	SIOCADSCA	_IOWR('r', 60, struct ipscan *)
 # define	SIOCRMSCA	_IOWR('r', 61, struct ipscan *)
 # define	SIOCGSCST	_IOWR('r', 62, struct ipscan *)
@@ -96,7 +94,7 @@
 } ipscanstat_t;
 
 
-extern	int fr_scan_ioctl __P((caddr_t, ioctlcmd_t, int));
+extern	int fr_scan_ioctl __P((caddr_t, ioctlcmd_t, int, int, void *));
 extern	int ipsc_init __P((void));
 extern	int ipsc_attachis __P((struct ipstate *));
 extern	int ipsc_attachfr __P((struct frentry *));
Index: ip_nat.h
===================================================================
RCS file: /home/cvs/src/sys/contrib/ipfilter/netinet/ip_nat.h,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/contrib/ipfilter/netinet/ip_nat.h -L sys/contrib/ipfilter/netinet/ip_nat.h -u -r1.1.1.1 -r1.2
--- sys/contrib/ipfilter/netinet/ip_nat.h
+++ sys/contrib/ipfilter/netinet/ip_nat.h
@@ -1,4 +1,4 @@
-/*	$FreeBSD: src/sys/contrib/ipfilter/netinet/ip_nat.h,v 1.24 2005/04/27 03:48:10 darrenr Exp $	*/
+/*	$FreeBSD: src/sys/contrib/ipfilter/netinet/ip_nat.h,v 1.26.2.1 2007/10/31 05:00:38 darrenr Exp $	*/
 
 /*
  * Copyright (C) 1995-2001, 2003 by Darren Reed.
@@ -6,8 +6,8 @@
  * See the IPFILTER.LICENCE file for details on licencing.
  *
  * @(#)ip_nat.h	1.5 2/4/96
- * $FreeBSD: src/sys/contrib/ipfilter/netinet/ip_nat.h,v 1.24 2005/04/27 03:48:10 darrenr Exp $
- * Id: ip_nat.h,v 2.90.2.9 2005/03/28 11:09:55 darrenr Exp
+ * $FreeBSD: src/sys/contrib/ipfilter/netinet/ip_nat.h,v 1.26.2.1 2007/10/31 05:00:38 darrenr Exp $
+ * Id: ip_nat.h,v 2.90.2.20 2007/09/25 08:27:32 darrenr Exp $
  */
 
 #ifndef	__IP_NAT_H__
@@ -17,18 +17,16 @@
 #define	SOLARIS	(defined(sun) && (defined(__svr4__) || defined(__SVR4)))
 #endif
 
-#if defined(__STDC__) || defined(__GNUC__)
+#if defined(__STDC__) || defined(__GNUC__) || defined(_AIX51)
 #define	SIOCADNAT	_IOW('r', 60, struct ipfobj)
 #define	SIOCRMNAT	_IOW('r', 61, struct ipfobj)
 #define	SIOCGNATS	_IOWR('r', 62, struct ipfobj)
 #define	SIOCGNATL	_IOWR('r', 63, struct ipfobj)
-/*	SIOCPROXY	_IOWR('r', 64, struct ap_control) */
 #else
 #define	SIOCADNAT	_IOW(r, 60, struct ipfobj)
 #define	SIOCRMNAT	_IOW(r, 61, struct ipfobj)
 #define	SIOCGNATS	_IOWR(r, 62, struct ipfobj)
 #define	SIOCGNATL	_IOWR(r, 63, struct ipfobj)
-/*	SIOCPROXY	_IOWR(r, 64, struct ap_control) */
 #endif
 
 #undef	LARGE_NAT	/* define	this if you're setting up a system to NAT
@@ -126,6 +124,8 @@
 	int		nat_hv[2];
 	char		nat_ifnames[2][LIFNAMSIZ];
 	int		nat_rev;		/* 0 = forward, 1 = reverse */
+	int		nat_redir;		/* copy of in_redir */
+	u_32_t		nat_seqnext[2];
 } nat_t;
 
 #define	nat_inip	nat_inip6.in4
@@ -138,6 +138,8 @@
 #define	nat_seq		nat_un.nat_uni.ici_seq
 #define	nat_id		nat_un.nat_uni.ici_id
 #define	nat_tcpstate	nat_tqe.tqe_state
+#define	nat_die		nat_tqe.tqe_die
+#define	nat_touched	nat_tqe.tqe_touched
 
 /*
  * Values for nat_dir
@@ -154,7 +156,7 @@
 #define	NAT_ICMPQUERY	0x0008	/* IPN_ICMPQUERY */
 #define	NAT_SEARCH	0x0010
 #define	NAT_SLAVE	0x0020	/* Slave connection for a proxy */
-#define	NAT_NOTRULEPORT	0x0040
+#define	NAT_NOTRULEPORT	0x0040	/* Don't use the port # in the NAT rule */
 
 #define	NAT_TCPUDP	(NAT_TCP|NAT_UDP)
 #define	NAT_TCPUDPICMP	(NAT_TCP|NAT_UDP|NAT_ICMPERR)
@@ -173,6 +175,7 @@
 #define	NAT_DEBUG	0x800000
 
 typedef	struct	ipnat	{
+	ipfmutex_t	in_lock;
 	struct	ipnat	*in_next;		/* NAT rule list next */
 	struct	ipnat	*in_rnext;		/* rdr rule hash next */
 	struct	ipnat	**in_prnext;		/* prior rdr next ptr */
@@ -298,24 +301,6 @@
 } natget_t;
 
 
-typedef	struct	nattrpnt	{
-	struct	in_addr	tr_dstip;	/* real destination IP# */
-	struct	in_addr	tr_srcip;	/* real source IP# */
-	struct	in_addr	tr_locip;	/* local source IP# */
-	u_int	tr_flags;
-	int	tr_expire;
-	u_short	tr_dstport;	/* real destination port# */
-	u_short	tr_srcport;	/* real source port# */
-	u_short	tr_locport;	/* local source port# */
-	struct	nattrpnt	*tr_hnext;
-	struct	nattrpnt	**tr_phnext;
-	struct	nattrpnt	*tr_next;
-	struct	nattrpnt	**tr_pnext;	/* previous next */
-} nattrpnt_t;
-
-#define	TN_CMPSIZ	offsetof(nattrpnt_t, tr_hnext)
-
-
 /*
  * This structure gets used to help NAT sessions keep the same NAT rule (and
  * thus translation for IP address) when:
@@ -323,6 +308,8 @@
  * (b) different IP add
  */
 typedef	struct	hostmap	{
+	struct	hostmap	*hm_hnext;
+	struct	hostmap	**hm_phnext;
 	struct	hostmap	*hm_next;
 	struct	hostmap	**hm_pnext;
 	struct	ipnat	*hm_ipnat;
@@ -374,8 +361,10 @@
 	u_int	ns_trpntab_sz;
 	u_int	ns_hostmap_sz;
 	nat_t	*ns_instances;
-	nattrpnt_t *ns_trpntlist;
+	hostmap_t *ns_maplist;
 	u_long	*ns_bucketlen[2];
+	u_long	ns_ticks;
+	u_int	ns_orphans;
 } natstat_t;
 
 typedef	struct	natlog {
@@ -397,6 +386,7 @@
 #define	NL_NEWRDR	NAT_REDIRECT
 #define	NL_NEWBIMAP	NAT_BIMAP
 #define	NL_NEWBLOCK	NAT_MAPBLK
+#define	NL_DESTROY	0xfffc
 #define	NL_CLONE	0xfffd
 #define	NL_FLUSH	0xfffe
 #define	NL_EXPIRE	0xffff
@@ -428,6 +418,7 @@
 extern	u_int	fr_nat_maxbucket;
 extern	u_int	fr_nat_maxbucket_reset;
 extern	int	fr_nat_lock;
+extern	int	fr_nat_doflush;
 extern	void	fr_natsync __P((void *));
 extern	u_long	fr_defnatage;
 extern	u_long	fr_defnaticmpage;
@@ -445,7 +436,7 @@
 #if defined(__OpenBSD__)
 extern	void	nat_ifdetach __P((void *));
 #endif
-extern	int	fr_nat_ioctl __P((caddr_t, ioctlcmd_t, int));
+extern	int	fr_nat_ioctl __P((caddr_t, ioctlcmd_t, int, int, void *));
 extern	int	fr_natinit __P((void));
 extern	nat_t	*nat_new __P((fr_info_t *, ipnat_t *, nat_t **, u_int, int));
 extern	nat_t	*nat_outlookup __P((fr_info_t *, u_int, u_int, struct in_addr,
@@ -459,6 +450,7 @@
 extern	nat_t	*nat_lookupredir __P((natlookup_t *));
 extern	nat_t	*nat_icmperrorlookup __P((fr_info_t *, int));
 extern	nat_t	*nat_icmperror __P((fr_info_t *, u_int *, int));
+extern	void	nat_delete __P((struct nat *, int));
 extern	int	nat_insert __P((nat_t *, int));
 
 extern	int	fr_checknatout __P((fr_info_t *, u_32_t *));
@@ -470,9 +462,11 @@
 extern	void	nat_log __P((struct nat *, u_int));
 extern	void	fix_incksum __P((fr_info_t *, u_short *, u_32_t));
 extern	void	fix_outcksum __P((fr_info_t *, u_short *, u_32_t));
+extern	void	fr_ipnatderef __P((ipnat_t **));
 extern	void	fr_natderef __P((nat_t **));
 extern	u_short	*nat_proto __P((fr_info_t *, nat_t *, u_int));
 extern	void	nat_update __P((fr_info_t *, nat_t *, ipnat_t *));
 extern	void	fr_setnatqueue __P((nat_t *, int));
+extern	void	fr_hostmapdel __P((hostmap_t **));
 
 #endif /* __IP_NAT_H__ */
Index: ip_pool.c
===================================================================
RCS file: /home/cvs/src/sys/contrib/ipfilter/netinet/ip_pool.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/contrib/ipfilter/netinet/ip_pool.c -L sys/contrib/ipfilter/netinet/ip_pool.c -u -r1.1.1.1 -r1.2
--- sys/contrib/ipfilter/netinet/ip_pool.c
+++ sys/contrib/ipfilter/netinet/ip_pool.c
@@ -1,5 +1,3 @@
-/*	$FreeBSD: src/sys/contrib/ipfilter/netinet/ip_pool.c,v 1.1.1.1 2005/04/25 18:15:28 darrenr Exp $	*/
-
 /*
  * Copyright (C) 1993-2001, 2003 by Darren Reed.
  *
@@ -55,10 +53,11 @@
 # include <sys/malloc.h>
 #endif
 
-#if (defined(__osf__) || defined(__hpux) || defined(__sgi)) && defined(_KERNEL)
-# ifdef __osf__
-#  include <net/radix.h>
-# endif
+#if defined(SOLARIS2) && !defined(_KERNEL)
+# include "radix_ipf.h"
+#endif
+#if defined(_KERNEL) && (defined(__osf__) || defined(AIX) || \
+     defined(__hpux) || defined(__sgi))
 # include "radix_ipf_local.h"
 # define _RADIX_H_
 #endif
@@ -79,18 +78,22 @@
 
 #if !defined(lint)
 static const char sccsid[] = "@(#)ip_fil.c	2.41 6/5/96 (C) 1993-2000 Darren Reed";
-static const char rcsid[] = "@(#)Id: ip_pool.c,v 2.55.2.12 2005/02/01 04:04:46 darrenr Exp";
+static const char rcsid[] = "@(#)$Id: ip_pool.c,v 2.55.2.24 2007/10/10 09:45:37 darrenr Exp $";
 #endif
 
 #ifdef IPFILTER_LOOKUP
 
-# ifndef RADIX_NODE_HEAD_LOCK
+# if !defined(RADIX_NODE_HEAD_LOCK) || !defined(RADIX_NODE_HEAD_UNLOCK) || \
+     !defined(_KERNEL)
+#  undef RADIX_NODE_HEAD_LOCK
+#  undef RADIX_NODE_HEAD_UNLOCK
 #  define RADIX_NODE_HEAD_LOCK(x)	;
-# endif
-# ifndef RADIX_NODE_HEAD_UNLOCK
 #  define RADIX_NODE_HEAD_UNLOCK(x)	;
 # endif
 
+static void ip_pool_clearnodes __P((ip_pool_t *));
+static void *ip_pool_exists __P((int, char *));
+
 ip_pool_stat_t ipoolstat;
 ipfrwlock_t ip_poolrw;
 
@@ -138,7 +141,7 @@
 	strcpy(op.iplo_name, "0");
 
 	if (ip_pool_create(&op) == 0)
-		ipo = ip_pool_find(0, "0");
+		ipo = ip_pool_exists(0, "0");
 
 	a.adf_addr.in4.s_addr = 0x0a010203;
 	b.adf_addr.in4.s_addr = 0xffffffff;
@@ -263,18 +266,12 @@
 void ip_pool_fini()
 {
 	ip_pool_t *p, *q;
-	iplookupop_t op;
 	int i;
 
-	ASSERT(rw_read_locked(&ipf_global.ipf_lk) == 0);
-
 	for (i = 0; i <= IPL_LOGMAX; i++) {
 		for (q = ip_pool_list[i]; (p = q) != NULL; ) {
-			op.iplo_unit = i;
-			(void)strncpy(op.iplo_name, p->ipo_name,
-				sizeof(op.iplo_name));
 			q = p->ipo_next;
-			(void) ip_pool_destroy(&op);
+			(void) ip_pool_destroy(i, p->ipo_name);
 		}
 	}
 
@@ -308,8 +305,8 @@
 			stats.ipls_list[i] = ip_pool_list[i];
 	} else if (unit >= 0 && unit < IPL_LOGSIZE) {
 		if (op->iplo_name[0] != '\0')
-			stats.ipls_list[unit] = ip_pool_find(unit,
-							     op->iplo_name);
+			stats.ipls_list[unit] = ip_pool_exists(unit,
+							       op->iplo_name);
 		else
 			stats.ipls_list[unit] = ip_pool_list[unit];
 	} else
@@ -320,16 +317,15 @@
 }
 
 
-
 /* ------------------------------------------------------------------------ */
-/* Function:    ip_pool_find                                                */
+/* Function:    ip_pool_exists                                              */
 /* Returns:     int     - 0 = success, else error                           */
 /* Parameters:  ipo(I)  - pointer to the pool getting the new node.         */
 /*                                                                          */
 /* Find a matching pool inside the collection of pools for a particular     */
 /* device, indicated by the unit number.                                    */
 /* ------------------------------------------------------------------------ */
-void *ip_pool_find(unit, name)
+static void *ip_pool_exists(unit, name)
 int unit;
 char *name;
 {
@@ -343,6 +339,29 @@
 
 
 /* ------------------------------------------------------------------------ */
+/* Function:    ip_pool_find                                                */
+/* Returns:     int     - 0 = success, else error                           */
+/* Parameters:  ipo(I)  - pointer to the pool getting the new node.         */
+/*                                                                          */
+/* Find a matching pool inside the collection of pools for a particular     */
+/* device, indicated by the unit number.  If it is marked for deletion then */
+/* pretend it does not exist.                                               */
+/* ------------------------------------------------------------------------ */
+void *ip_pool_find(unit, name)
+int unit;
+char *name;
+{
+	ip_pool_t *p;
+
+	p = ip_pool_exists(unit, name);
+	if ((p != NULL) && (p->ipo_flags & IPOOL_DELETE))
+		return NULL;
+
+	return p;
+}
+
+
+/* ------------------------------------------------------------------------ */
 /* Function:    ip_pool_findeq                                              */
 /* Returns:     int     - 0 = success, else error                           */
 /* Parameters:  ipo(I)  - pointer to the pool getting the new node.         */
@@ -356,11 +375,9 @@
 addrfamily_t *addr, *mask;
 {
 	struct radix_node *n;
-#ifdef USE_SPL
-	int s;
+	SPL_INT(s);
 
 	SPL_NET(s);
-#endif
 	RADIX_NODE_HEAD_LOCK(ipo->ipo_head);
 	n = ipo->ipo_head->rnh_lookup(addr, mask, ipo->ipo_head);
 	RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head);
@@ -378,9 +395,9 @@
 /*                                                                          */
 /* Search the pool for a given address and return a search result.          */
 /* ------------------------------------------------------------------------ */
-int ip_pool_search(tptr, version, dptr)
+int ip_pool_search(tptr, ipversion, dptr)
 void *tptr;
-int version;
+int ipversion;
 void *dptr;
 {
 	struct radix_node *rn;
@@ -400,11 +417,11 @@
 	bzero(&v, sizeof(v));
 	v.adf_len = offsetof(addrfamily_t, adf_addr);
 
-	if (version == 4) {
+	if (ipversion == 4) {
 		v.adf_len += sizeof(addr->in4);
 		v.adf_addr.in4 = addr->in4;
 #ifdef USE_INET6
-	} else if (version == 6) {
+	} else if (ipversion == 6) {
 		v.adf_len += sizeof(addr->in6);
 		v.adf_addr.in6 = addr->in6;
 #endif
@@ -448,8 +465,6 @@
 	struct radix_node *rn;
 	ip_pool_node_t *x;
 
-	ASSERT(rw_read_locked(&ip_poolrw.ipf_lk) == 0);
-
 	KMALLOC(x, ip_pool_node_t *);
 	if (x == NULL) {
 		return ENOMEM;
@@ -478,6 +493,7 @@
 		return ENOMEM;
 	}
 
+	x->ipn_ref = 1;
 	x->ipn_next = ipo->ipo_list;
 	x->ipn_pnext = &ipo->ipo_list;
 	if (ipo->ipo_list != NULL)
@@ -501,6 +517,10 @@
 /* when being inserted - assume this has already been done.  If the pool is */
 /* marked as being anonymous, give it a new, unique, identifier.  Call any  */
 /* other functions required to initialise the structure.                    */
+/*                                                                          */
+/* If the structure is flagged for deletion then reset the flag and return, */
+/* as this likely means we've tried to free a pool that is in use (flush)   */
+/* and now want to repopulate it with "new" data.                           */
 /* ------------------------------------------------------------------------ */
 int ip_pool_create(op)
 iplookupop_t *op;
@@ -509,7 +529,17 @@
 	int poolnum, unit;
 	ip_pool_t *h;
 
-	ASSERT(rw_read_locked(&ip_poolrw.ipf_lk) == 0);
+	unit = op->iplo_unit;
+
+	if ((op->iplo_arg & LOOKUP_ANON) == 0) {
+		h = ip_pool_exists(unit, op->iplo_name);
+		if (h != NULL) {
+			if ((h->ipo_flags & IPOOL_DELETE) == 0)
+				return EEXIST;
+			h->ipo_flags &= ~IPOOL_DELETE;
+			return 0;
+		}
+	}
 
 	KMALLOC(h, ip_pool_t *);
 	if (h == NULL)
@@ -522,12 +552,11 @@
 		return ENOMEM;
 	}
 
-	unit = op->iplo_unit;
-
-	if ((op->iplo_arg & IPOOL_ANON) != 0) {
+	if ((op->iplo_arg & LOOKUP_ANON) != 0) {
 		ip_pool_t *p;
 
-		poolnum = IPOOL_ANON;
+		h->ipo_flags |= IPOOL_ANON;
+		poolnum = LOOKUP_ANON;
 
 #if defined(SNPRINTF) && defined(_KERNEL)
 		SNPRINTF(name, sizeof(name), "%x", poolnum);
@@ -550,8 +579,9 @@
 		}
 
 		(void)strncpy(h->ipo_name, name, sizeof(h->ipo_name));
+		(void)strncpy(op->iplo_name, name, sizeof(op->iplo_name));
 	} else {
-		(void) strncpy(h->ipo_name, op->iplo_name, sizeof(h->ipo_name));
+		(void)strncpy(h->ipo_name, op->iplo_name, sizeof(h->ipo_name));
 	}
 
 	h->ipo_ref = 1;
@@ -576,36 +606,24 @@
 /*              ipe(I) - address being deleted as a node                    */
 /* Locks:       WRITE(ip_poolrw)                                            */
 /*                                                                          */
-/* Add another node to the pool given by ipo.  The three parameters passed  */
-/* in (addr, mask, info) shold all be stored in the node.                   */
+/* Remove a node from the pool given by ipo.                                */
 /* ------------------------------------------------------------------------ */
 int ip_pool_remove(ipo, ipe)
 ip_pool_t *ipo;
 ip_pool_node_t *ipe;
 {
-	ip_pool_node_t **ipp, *n;
 
-	ASSERT(rw_read_locked(&ip_poolrw.ipf_lk) == 0);
-
-	for (ipp = &ipo->ipo_list; (n = *ipp) != NULL; ipp = &n->ipn_next) {
-		if (ipe == n) {
-			*n->ipn_pnext = n->ipn_next;
-			if (n->ipn_next)
-				n->ipn_next->ipn_pnext = n->ipn_pnext;
-			break;
-		}
-	}
-
-	if (n == NULL)
-		return ENOENT;
+	if (ipe->ipn_pnext != NULL)
+		*ipe->ipn_pnext = ipe->ipn_next;
+	if (ipe->ipn_next != NULL)
+		ipe->ipn_next->ipn_pnext = ipe->ipn_pnext;
 
 	RADIX_NODE_HEAD_LOCK(ipo->ipo_head);
-	ipo->ipo_head->rnh_deladdr(&n->ipn_addr, &n->ipn_mask,
+	ipo->ipo_head->rnh_deladdr(&ipe->ipn_addr, &ipe->ipn_mask,
 				   ipo->ipo_head);
 	RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head);
-	KFREE(n);
 
-	ipoolstat.ipls_nodes--;
+	ip_pool_node_deref(ipe);
 
 	return 0;
 }
@@ -618,23 +636,28 @@
 /* Locks:       WRITE(ip_poolrw) or WRITE(ipf_global)                       */
 /*                                                                          */
 /* Search for a pool using paramters passed in and if it's not otherwise    */
-/* busy, free it.                                                           */
+/* busy, free it.  If it is busy, clear all of its nodes, mark it for being */
+/* deleted and return an error saying it is busy.                           */
 /*                                                                          */
-/* NOTE: Because this function is called out of ipldetach() where ip_poolrw */
+/* NOTE: Because this function is called out of ipfdetach() where ip_poolrw */
 /* may not be initialised, we can't use an ASSERT to enforce the locking    */
 /* assertion that one of the two (ip_poolrw,ipf_global) is held.            */
 /* ------------------------------------------------------------------------ */
-int ip_pool_destroy(op)
-iplookupop_t *op;
+int ip_pool_destroy(unit, name)
+int unit;
+char *name;
 {
 	ip_pool_t *ipo;
 
-	ipo = ip_pool_find(op->iplo_unit, op->iplo_name);
+	ipo = ip_pool_exists(unit, name);
 	if (ipo == NULL)
 		return ESRCH;
 
-	if (ipo->ipo_ref != 1)
-		return EBUSY;
+	if (ipo->ipo_ref != 1) {
+		ip_pool_clearnodes(ipo);
+		ipo->ipo_flags |= IPOOL_DELETE;
+		return 0;
+	}
 
 	ip_pool_free(ipo);
 	return 0;
@@ -650,7 +673,7 @@
 /* Free all pools associated with the device that matches the unit number   */
 /* passed in with operation.                                                */
 /*                                                                          */
-/* NOTE: Because this function is called out of ipldetach() where ip_poolrw */
+/* NOTE: Because this function is called out of ipfdetach() where ip_poolrw */
 /* may not be initialised, we can't use an ASSERT to enforce the locking    */
 /* assertion that one of the two (ip_poolrw,ipf_global) is held.            */
 /* ------------------------------------------------------------------------ */
@@ -671,7 +694,7 @@
 			(void)strncpy(op.iplo_name, p->ipo_name,
 				sizeof(op.iplo_name));
 			q = p->ipo_next;
-			err = ip_pool_destroy(&op);
+			err = ip_pool_destroy(op.iplo_unit, op.iplo_name);
 			if (err == 0)
 				num++;
 			else
@@ -692,13 +715,37 @@
 /* all of the address information stored in it, including any tree data     */
 /* structures also allocated.                                               */
 /*                                                                          */
-/* NOTE: Because this function is called out of ipldetach() where ip_poolrw */
+/* NOTE: Because this function is called out of ipfdetach() where ip_poolrw */
 /* may not be initialised, we can't use an ASSERT to enforce the locking    */
 /* assertion that one of the two (ip_poolrw,ipf_global) is held.            */
 /* ------------------------------------------------------------------------ */
 void ip_pool_free(ipo)
 ip_pool_t *ipo;
 {
+
+	ip_pool_clearnodes(ipo);
+
+	if (ipo->ipo_next != NULL)
+		ipo->ipo_next->ipo_pnext = ipo->ipo_pnext;
+	*ipo->ipo_pnext = ipo->ipo_next;
+	rn_freehead(ipo->ipo_head);
+	KFREE(ipo);
+
+	ipoolstat.ipls_pools--;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ip_pool_clearnodes                                          */
+/* Returns:     void                                                        */
+/* Parameters:  ipo(I) -  pointer to pool structure                         */
+/* Locks:       WRITE(ip_poolrw) or WRITE(ipf_global)                       */
+/*                                                                          */
+/* Deletes all nodes stored in a pool structure.                            */
+/* ------------------------------------------------------------------------ */
+static void ip_pool_clearnodes(ipo)
+ip_pool_t *ipo;
+{
 	ip_pool_node_t *n;
 
 	RADIX_NODE_HEAD_LOCK(ipo->ipo_head);
@@ -717,13 +764,6 @@
 	RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head);
 
 	ipo->ipo_list = NULL;
-	if (ipo->ipo_next != NULL)
-		ipo->ipo_next->ipo_pnext = ipo->ipo_pnext;
-	*ipo->ipo_pnext = ipo->ipo_next;
-	rn_freehead(ipo->ipo_head);
-	KFREE(ipo);
-
-	ipoolstat.ipls_pools--;
 }
 
 
@@ -740,11 +780,178 @@
 ip_pool_t *ipo;
 {
 
-	ASSERT(rw_read_locked(&ip_poolrw.ipf_lk) == 0);
-
 	ipo->ipo_ref--;
+
 	if (ipo->ipo_ref == 0)
 		ip_pool_free(ipo);
+
+	else if ((ipo->ipo_ref == 1) && (ipo->ipo_flags & IPOOL_DELETE))
+		ip_pool_destroy(ipo->ipo_unit, ipo->ipo_name);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ip_pool_node_deref                                          */
+/* Returns:     void                                                        */
+/* Parameters:  ipn(I) - pointer to pool structure                          */
+/* Locks:       WRITE(ip_poolrw)                                            */
+/*                                                                          */
+/* Drop a reference to the pool node passed in and if we're the last, free  */
+/* it all up and adjust the stats accordingly.                              */
+/* ------------------------------------------------------------------------ */
+void ip_pool_node_deref(ipn)
+ip_pool_node_t *ipn;
+{
+
+	ipn->ipn_ref--;
+
+	if (ipn->ipn_ref == 0) {
+		KFREE(ipn);
+		ipoolstat.ipls_nodes--;
+	}
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ip_pool_getnext                                             */
+/* Returns:     void                                                        */
+/* Parameters:  token(I) - pointer to pool structure                        */
+/* Parameters:  ilp(IO)   - pointer to pool iterating structure             */
+/*                                                                          */
+/* ------------------------------------------------------------------------ */
+int ip_pool_getnext(token, ilp)
+ipftoken_t *token;
+ipflookupiter_t *ilp;
+{
+	ip_pool_node_t *node, zn, *nextnode;
+	ip_pool_t *ipo, zp, *nextipo;
+	int err;
+
+	err = 0;
+	node = NULL;
+	nextnode = NULL;
+	ipo = NULL;
+	nextipo = NULL;
+
+	READ_ENTER(&ip_poolrw);
+
+	switch (ilp->ili_otype)
+	{
+	case IPFLOOKUPITER_LIST :
+		ipo = token->ipt_data;
+		if (ipo == NULL) {
+			nextipo = ip_pool_list[(int)ilp->ili_unit];
+		} else {
+			nextipo = ipo->ipo_next;
+		}
+
+		if (nextipo != NULL) {
+			ATOMIC_INC(nextipo->ipo_ref);
+			token->ipt_data = nextipo;
+		} else {
+			bzero((char *)&zp, sizeof(zp));
+			nextipo = &zp;
+			token->ipt_data = NULL;
+		}
+		break;
+
+	case IPFLOOKUPITER_NODE :
+		node = token->ipt_data;
+		if (node == NULL) {
+			ipo = ip_pool_exists(ilp->ili_unit, ilp->ili_name);
+			if (ipo == NULL)
+				err = ESRCH;
+			else {
+				nextnode = ipo->ipo_list;
+				ipo = NULL;
+			}
+		} else {
+			nextnode = node->ipn_next;
+		}
+
+		if (nextnode != NULL) {
+			ATOMIC_INC(nextnode->ipn_ref);
+			token->ipt_data = nextnode;
+		} else {
+			bzero((char *)&zn, sizeof(zn));
+			nextnode = &zn;
+			token->ipt_data = NULL;
+		}
+		break;
+	default :
+		err = EINVAL;
+		break;
+	}
+
+	RWLOCK_EXIT(&ip_poolrw);
+
+	if (err != 0)
+		return err;
+
+	switch (ilp->ili_otype)
+	{
+	case IPFLOOKUPITER_LIST :
+		if (ipo != NULL) {
+			WRITE_ENTER(&ip_poolrw);
+			ip_pool_deref(ipo);
+			RWLOCK_EXIT(&ip_poolrw);
+		}
+		err = COPYOUT(nextipo, ilp->ili_data, sizeof(*nextipo));
+		if (err != 0)
+			err = EFAULT;
+		break;
+
+	case IPFLOOKUPITER_NODE :
+		if (node != NULL) {
+			WRITE_ENTER(&ip_poolrw);
+			ip_pool_node_deref(node);
+			RWLOCK_EXIT(&ip_poolrw);
+		}
+		err = COPYOUT(nextnode, ilp->ili_data, sizeof(*nextnode));
+		if (err != 0)
+			err = EFAULT;
+		break;
+	}
+
+	return err;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ip_pool_iterderef                                           */
+/* Returns:     void                                                        */
+/* Parameters:  ipn(I) - pointer to pool structure                          */
+/* Locks:       WRITE(ip_poolrw)                                            */
+/*                                                                          */
+/* ------------------------------------------------------------------------ */
+void ip_pool_iterderef(otype, unit, data)
+u_int otype;
+int unit;
+void *data;
+{
+
+	if (data == NULL)
+		return;
+
+	if (unit < 0 || unit > IPL_LOGMAX)
+		return;
+
+	switch (otype)
+	{
+	case IPFLOOKUPITER_LIST :
+		WRITE_ENTER(&ip_poolrw);
+		ip_pool_deref((ip_pool_t *)data);
+		RWLOCK_EXIT(&ip_poolrw);
+		break;
+
+	case IPFLOOKUPITER_NODE :
+		WRITE_ENTER(&ip_poolrw);
+		ip_pool_node_deref((ip_pool_node_t *)data);
+		RWLOCK_EXIT(&ip_poolrw);
+		break;
+	default :
+		break;
+	}
 }
 
 
@@ -782,5 +989,4 @@
 	Free(rnh);
 }
 # endif
-
 #endif /* IPFILTER_LOOKUP */
Index: ip_netbios_pxy.c
===================================================================
RCS file: /home/cvs/src/sys/contrib/ipfilter/netinet/ip_netbios_pxy.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/contrib/ipfilter/netinet/ip_netbios_pxy.c -L sys/contrib/ipfilter/netinet/ip_netbios_pxy.c -u -r1.1.1.1 -r1.2
--- sys/contrib/ipfilter/netinet/ip_netbios_pxy.c
+++ sys/contrib/ipfilter/netinet/ip_netbios_pxy.c
@@ -1,9 +1,7 @@
-/*	$FreeBSD: src/sys/contrib/ipfilter/netinet/ip_netbios_pxy.c,v 1.1.1.2 2005/04/25 18:15:27 darrenr Exp $	*/
-
 /*
  * Simple netbios-dgm transparent proxy for in-kernel use.
  * For use with the NAT code.
- * Id: ip_netbios_pxy.c,v 2.8 2003/12/01 02:52:16 darrenr Exp
+ * $Id: ip_netbios_pxy.c,v 2.8.2.1 2005/08/20 13:48:23 darrenr Exp $
  */
 
 /*-
@@ -31,7 +29,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * Id: ip_netbios_pxy.c,v 2.8 2003/12/01 02:52:16 darrenr Exp
+ * $Id: ip_netbios_pxy.c,v 2.8.2.1 2005/08/20 13:48:23 darrenr Exp $
  */
 
 #define	IPF_NETBIOS_PROXY
@@ -82,19 +80,17 @@
 	aps = aps;	/* LINT */
 	nat = nat;	/* LINT */
 
-	ip = fin->fin_ip;
-	m = *(mb_t **)fin->fin_mp;
-	off = fin->fin_hlen + sizeof(udphdr_t);
-	dlen = M_LEN(m);
-	dlen -= off;
-
+	m = fin->fin_m;
+	dlen = fin->fin_dlen - sizeof(*udp);
 	/*
 	 * no net bios datagram could possibly be shorter than this
 	 */
 	if (dlen < 11)
 		return 0;
 
+	ip = fin->fin_ip;
 	udp = (udphdr_t *)fin->fin_dp;
+	off = (char *)udp - (char *)ip + sizeof(*udp) + fin->fin_ipoff;
 
 	/*
 	 * move past the
Index: ip_frag.c
===================================================================
RCS file: /home/cvs/src/sys/contrib/ipfilter/netinet/ip_frag.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/contrib/ipfilter/netinet/ip_frag.c -L sys/contrib/ipfilter/netinet/ip_frag.c -u -r1.1.1.1 -r1.2
--- sys/contrib/ipfilter/netinet/ip_frag.c
+++ sys/contrib/ipfilter/netinet/ip_frag.c
@@ -1,4 +1,4 @@
-/*	$FreeBSD: src/sys/contrib/ipfilter/netinet/ip_frag.c,v 1.29 2005/04/29 05:57:17 ru Exp $	*/
+/*	$FreeBSD: src/sys/contrib/ipfilter/netinet/ip_frag.c,v 1.32.2.1 2007/10/31 05:00:37 darrenr Exp $	*/
 
 /*
  * Copyright (C) 1993-2003 by Darren Reed.
@@ -47,7 +47,7 @@
 # endif
 #endif
 #if !defined(__SVR4) && !defined(__svr4__)
-# if defined(_KERNEL) && !defined(__sgi)
+# if defined(_KERNEL) && !defined(__sgi) && !defined(AIX)
 #  include <sys/kernel.h>
 # endif
 #else
@@ -102,21 +102,22 @@
 
 #if !defined(lint)
 static const char sccsid[] = "@(#)ip_frag.c	1.11 3/24/96 (C) 1993-2000 Darren Reed";
-static const char rcsid[] = "@(#)$FreeBSD: src/sys/contrib/ipfilter/netinet/ip_frag.c,v 1.29 2005/04/29 05:57:17 ru Exp $";
-/* static const char rcsid[] = "@(#)Id: ip_frag.c,v 2.77 2004/01/27 00:24:54 darrenr Exp"; */
+static const char rcsid[] = "@(#)$FreeBSD: src/sys/contrib/ipfilter/netinet/ip_frag.c,v 1.32.2.1 2007/10/31 05:00:37 darrenr Exp $";
+/* static const char rcsid[] = "@(#)$Id: ip_frag.c,v 2.77.2.12 2007/09/20 12:51:51 darrenr Exp $"; */
 #endif
 
 
-static ipfr_t   *ipfr_list = NULL;
-static ipfr_t   **ipfr_tail = &ipfr_list;
-static ipfr_t	**ipfr_heads;
+ipfr_t   *ipfr_list = NULL;
+ipfr_t   **ipfr_tail = &ipfr_list;
 
-static ipfr_t   *ipfr_natlist = NULL;
-static ipfr_t   **ipfr_nattail = &ipfr_natlist;
-static ipfr_t	**ipfr_nattab;
+ipfr_t   *ipfr_natlist = NULL;
+ipfr_t   **ipfr_nattail = &ipfr_natlist;
 
-static ipfr_t   *ipfr_ipidlist = NULL;
-static ipfr_t   **ipfr_ipidtail = &ipfr_ipidlist;
+ipfr_t   *ipfr_ipidlist = NULL;
+ipfr_t   **ipfr_ipidtail = &ipfr_ipidlist;
+
+static ipfr_t	**ipfr_heads;
+static ipfr_t	**ipfr_nattab;
 static ipfr_t	**ipfr_ipidtab;
 
 static ipfrstat_t ipfr_stats;
@@ -132,6 +133,7 @@
 static ipfr_t *ipfr_newfrag __P((fr_info_t *, u_32_t, ipfr_t **));
 static ipfr_t *fr_fraglookup __P((fr_info_t *, ipfr_t **));
 static void fr_fragdelete __P((ipfr_t *, ipfr_t ***));
+static void fr_fragfree __P((ipfr_t *));
 
 
 /* ------------------------------------------------------------------------ */
@@ -227,6 +229,7 @@
 {
 	ipfr_t *fra, frag;
 	u_int idx, off;
+	frentry_t *fr;
 	ip_t *ip;
 
 	if (ipfr_inuse >= IPFT_SIZE)
@@ -238,7 +241,7 @@
 	ip = fin->fin_ip;
 
 	if (pass & FR_FRSTRICT)
-		if ((ip->ip_off & IP_OFFMASK) != 0)
+		if (fin->fin_off != 0)
 			return NULL;
 
 	frag.ipfr_p = ip->ip_p;
@@ -278,8 +281,13 @@
 		return NULL;
 	}
 
-	if ((fra->ipfr_rule = fin->fin_fr) != NULL)
-		fin->fin_fr->fr_ref++;
+	fr = fin->fin_fr;
+	fra->ipfr_rule = fr;
+	if (fr != NULL) {
+		MUTEX_ENTER(&fr->fr_lock);
+		fr->fr_ref++;
+		MUTEX_EXIT(&fr->fr_lock);
+	}
 
 	/*
 	 * Insert the fragment into the fragment table, copy the struct used
@@ -302,6 +310,7 @@
 		fra->ipfr_seen0 = 1;
 	fra->ipfr_off = off + (fin->fin_dlen >> 3);
 	fra->ipfr_pass = pass;
+	fra->ipfr_ref = 1;
 	ipfr_stats.ifs_new++;
 	ipfr_inuse++;
 	return fra;
@@ -682,11 +691,6 @@
 static void fr_fragdelete(fra, tail)
 ipfr_t *fra, ***tail;
 {
-	frentry_t *fr;
-
-	fr = fra->ipfr_rule;
-	if (fr != NULL)
-		(void)fr_derefrule(&fr);
 
 	if (fra->ipfr_next)
 		fra->ipfr_next->ipfr_prev = fra->ipfr_prev;
@@ -697,7 +701,30 @@
 	if (fra->ipfr_hnext)
 		fra->ipfr_hnext->ipfr_hprev = fra->ipfr_hprev;
 	*fra->ipfr_hprev = fra->ipfr_hnext;
+
+	if (fra->ipfr_rule != NULL) {
+		(void) fr_derefrule(&fra->ipfr_rule);
+	}
+
+	if (fra->ipfr_ref <= 0)
+		fr_fragfree(fra);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    fr_fragfree                                                 */
+/* Returns:     Nil                                                         */
+/* Parameters:  fra - pointer to frag structure to free                     */
+/*                                                                          */
+/* Take care of the details associated with deleting an entry from the frag */
+/* cache.  Currently this just means bumping stats correctly after freeing  */
+/* ------------------------------------------------------------------------ */
+static void fr_fragfree(fra)
+ipfr_t *fra;
+{
 	KFREE(fra);
+	ipfr_stats.ifs_expire++;
+	ipfr_inuse--;
 }
 
 
@@ -715,8 +742,10 @@
 	nat_t	*nat;
 
 	WRITE_ENTER(&ipf_frag);
-	while ((fra = ipfr_list) != NULL)
+	while ((fra = ipfr_list) != NULL) {
+		fra->ipfr_ref--;
 		fr_fragdelete(fra, &ipfr_tail);
+	}
 	ipfr_tail = &ipfr_list;
 	RWLOCK_EXIT(&ipf_frag);
 
@@ -728,6 +757,7 @@
 			if (nat->nat_data == fra)
 				nat->nat_data = NULL;
 		}
+		fra->ipfr_ref--;
 		fr_fragdelete(fra, &ipfr_nattail);
 	}
 	ipfr_nattail = &ipfr_natlist;
@@ -747,9 +777,7 @@
 {
 	ipfr_t	**fp, *fra;
 	nat_t	*nat;
-#if defined(USE_SPL) && defined(_KERNEL)
-	int	s;
-#endif
+	SPL_INT(s);
 
 	if (fr_frag_lock)
 		return;
@@ -763,9 +791,8 @@
 	for (fp = &ipfr_list; ((fra = *fp) != NULL); ) {
 		if (fra->ipfr_ttl > fr_ticks)
 			break;
+		fra->ipfr_ref--;
 		fr_fragdelete(fra, &ipfr_tail);
-		ipfr_stats.ifs_expire++;
-		ipfr_inuse--;
 	}
 	RWLOCK_EXIT(&ipf_frag);
 
@@ -773,9 +800,8 @@
 	for (fp = &ipfr_ipidlist; ((fra = *fp) != NULL); ) {
 		if (fra->ipfr_ttl > fr_ticks)
 			break;
+		fra->ipfr_ref--;
 		fr_fragdelete(fra, &ipfr_ipidtail);
-		ipfr_stats.ifs_expire++;
-		ipfr_inuse--;
 	}
 	RWLOCK_EXIT(&ipf_ipidfrag);
 
@@ -785,23 +811,27 @@
 	 * at the one to be free'd, NULL the reference from the NAT struct.
 	 * NOTE: We need to grab both mutex's early, and in this order so as
 	 * to prevent a deadlock if both try to expire at the same time.
+	 * The extra if() statement here is because it locks out all NAT
+	 * operations - no need to do that if there are no entries in this
+	 * list, right?
 	 */
-	WRITE_ENTER(&ipf_nat);
-	WRITE_ENTER(&ipf_natfrag);
-	for (fp = &ipfr_natlist; ((fra = *fp) != NULL); ) {
-		if (fra->ipfr_ttl > fr_ticks)
-			break;
-		nat = fra->ipfr_data;
-		if (nat != NULL) {
-			if (nat->nat_data == fra)
-				nat->nat_data = NULL;
+	if (ipfr_natlist != NULL) {
+		WRITE_ENTER(&ipf_nat);
+		WRITE_ENTER(&ipf_natfrag);
+		for (fp = &ipfr_natlist; ((fra = *fp) != NULL); ) {
+			if (fra->ipfr_ttl > fr_ticks)
+				break;
+			nat = fra->ipfr_data;
+			if (nat != NULL) {
+				if (nat->nat_data == fra)
+					nat->nat_data = NULL;
+			}
+			fra->ipfr_ref--;
+			fr_fragdelete(fra, &ipfr_nattail);
 		}
-		fr_fragdelete(fra, &ipfr_nattail);
-		ipfr_stats.ifs_expire++;
-		ipfr_inuse--;
+		RWLOCK_EXIT(&ipf_natfrag);
+		RWLOCK_EXIT(&ipf_nat);
 	}
-	RWLOCK_EXIT(&ipf_natfrag);
-	RWLOCK_EXIT(&ipf_nat);
 	SPL_X(s);
 }
 
@@ -815,7 +845,7 @@
 /* expectation of this being called twice per second.                       */
 /* ------------------------------------------------------------------------ */
 #if !defined(_KERNEL) || (!SOLARIS && !defined(__hpux) && !defined(__sgi) && \
-			  !defined(__osf__))
+			  !defined(__osf__) && !defined(linux))
 # if defined(_KERNEL) && ((BSD >= 199103) || defined(__sgi))
 void fr_slowtimer __P((void *ptr))
 # else
@@ -824,6 +854,7 @@
 {
 	READ_ENTER(&ipf_global);
 
+	ipf_expiretokens();
 	fr_fragexpire();
 	fr_timeoutstate();
 	fr_natexpire();
@@ -857,3 +888,106 @@
 # endif
 }
 #endif /* !SOLARIS && !defined(__hpux) && !defined(__sgi) */
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    fr_nextfrag                                                 */
+/* Returns:     int      - 0 == success, else error                         */
+/* Parameters:  token(I) - pointer to token information for this caller     */
+/*              itp(I)   - pointer to generic iterator from caller          */
+/*              top(I)   - top of the fragment list                         */
+/*              tail(I)  - tail of the fragment list                        */
+/*              lock(I)  - fragment cache lock                              */
+/*                                                                          */
+/* This function is used to interate through the list of entries in the     */
+/* fragment cache.  It increases the reference count on the one currently   */
+/* being returned so that the caller can come back and resume from it later.*/
+/*                                                                          */
+/* This function is used for both the NAT fragment cache as well as the ipf */
+/* fragment cache - hence the reason for passing in top, tail and lock.     */
+/* ------------------------------------------------------------------------ */
+int fr_nextfrag(token, itp, top, tail
+#ifdef USE_MUTEXES
+, lock
+#endif
+)
+ipftoken_t *token;
+ipfgeniter_t *itp;
+ipfr_t **top, ***tail;
+#ifdef USE_MUTEXES
+ipfrwlock_t *lock;
+#endif
+{
+	ipfr_t *frag, *next, zero;
+	int error = 0;
+
+	frag = token->ipt_data;
+	if (frag == (ipfr_t *)-1) {
+		ipf_freetoken(token);
+		return ESRCH;
+	}
+
+	READ_ENTER(lock);
+	if (frag == NULL)
+		next = *top;
+	else
+		next = frag->ipfr_next;
+
+	if (next != NULL) {
+		ATOMIC_INC(next->ipfr_ref);
+		token->ipt_data = next;
+	} else {
+		bzero(&zero, sizeof(zero));
+		next = &zero;
+		token->ipt_data = NULL;
+	}
+	RWLOCK_EXIT(lock);
+
+	if (frag != NULL) {
+#ifdef USE_MUTEXES
+		fr_fragderef(&frag, lock);
+#else
+		fr_fragderef(&frag);
+#endif
+	}
+
+	error = COPYOUT(next, itp->igi_data, sizeof(*next));
+	if (error != 0)
+		error = EFAULT;
+
+	return error;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    fr_fragderef                                                */
+/* Returns:     Nil                                                         */
+/* Parameters:  frp(IO) - pointer to fragment structure to deference        */
+/*              lock(I) - lock associated with the fragment                 */
+/*                                                                          */
+/* This function dereferences a fragment structure (ipfr_t).  The pointer   */
+/* passed in will always be reset back to NULL, even if the structure is    */
+/* not freed, to enforce the notion that the caller is no longer entitled   */
+/* to use the pointer it is dropping the reference to.                      */
+/* ------------------------------------------------------------------------ */
+void fr_fragderef(frp
+#ifdef USE_MUTEXES
+, lock
+#endif
+)
+ipfr_t **frp;
+#ifdef USE_MUTEXES
+ipfrwlock_t *lock;
+#endif
+{
+	ipfr_t *fra;
+
+	fra = *frp;
+	*frp = NULL;
+
+	WRITE_ENTER(lock);
+	fra->ipfr_ref--;
+	if (fra->ipfr_ref <= 0)
+		fr_fragfree(fra);
+	RWLOCK_EXIT(lock);
+}
Index: ip_scan.c
===================================================================
RCS file: /home/cvs/src/sys/contrib/ipfilter/netinet/ip_scan.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/contrib/ipfilter/netinet/ip_scan.c -L sys/contrib/ipfilter/netinet/ip_scan.c -u -r1.1.1.1 -r1.2
--- sys/contrib/ipfilter/netinet/ip_scan.c
+++ sys/contrib/ipfilter/netinet/ip_scan.c
@@ -1,5 +1,3 @@
-/*	$FreeBSD: src/sys/contrib/ipfilter/netinet/ip_scan.c,v 1.1.1.1 2005/04/25 18:15:35 darrenr Exp $	*/
-
 /*
  * Copyright (C) 1995-2001 by Darren Reed.
  *
@@ -34,7 +32,7 @@
 # endif
 #endif
 #include <sys/socket.h>
-#if !defined(__hpux) && !defined(__osf__) && !defined(linux)
+#if !defined(__hpux) && !defined(__osf__) && !defined(linux) && !defined(AIX)
 # include <sys/ioccom.h>
 #endif
 #ifdef __FreeBSD__
@@ -60,7 +58,7 @@
 
 #if !defined(lint)
 static const char sccsid[] = "@(#)ip_state.c	1.8 6/5/96 (C) 1993-2000 Darren Reed";
-static const char rcsid[] = "@(#)Id: ip_scan.c,v 2.40.2.2 2005/01/18 10:13:16 darrenr Exp";
+static const char rcsid[] = "@(#)$Id: ip_scan.c,v 2.40.2.10 2007/06/02 21:22:28 darrenr Exp $";
 #endif
 
 #ifdef	IPFILTER_SCAN	/* endif at bottom of file */
@@ -86,18 +84,23 @@
 int ipsc_matchisc __P((ipscan_t *, ipstate_t *, int, int, int *));
 int ipsc_match __P((ipstate_t *));
 
+static int	ipsc_inited = 0;
 
 
 int ipsc_init()
 {
 	RWLOCK_INIT(&ipsc_rwlock, "ip scan rwlock");
+	ipsc_inited = 1;
 	return 0;
 }
 
 
 void fr_scanunload()
 {
-	RW_DESTROY(&ipsc_rwlock);
+	if (ipsc_inited == 1) {
+		RW_DESTROY(&ipsc_rwlock);
+		ipsc_inited = 0;
+	}
 }
 
 
@@ -112,8 +115,10 @@
 		return ENOMEM;
 
 	err = copyinptr(data, isc, sizeof(*isc));
-	if (err)
+	if (err) {
+		KFREE(isc);
 		return err;
+	}
 
 	WRITE_ENTER(&ipsc_rwlock);
 
@@ -227,20 +232,17 @@
 	fr = is->is_rule;
 	if (fr) {
 		i = fr->fr_isc;
-		if (!i || (i != (ipscan_t *)-1)) {
+		if ((i != NULL) && (i != (ipscan_t *)-1)) {
 			is->is_isc = i;
-			if (i) {
-				ATOMIC_INC32(i->ipsc_sref);
-				if (i->ipsc_clen)
-					is->is_flags |= IS_SC_CLIENT;
-				else
-					is->is_flags |= IS_SC_MATCHC;
-				if (i->ipsc_slen)
-					is->is_flags |= IS_SC_SERVER;
-				else
-					is->is_flags |= IS_SC_MATCHS;
-			} else
-				is->is_flags |= (IS_SC_CLIENT|IS_SC_SERVER);
+			ATOMIC_INC32(i->ipsc_sref);
+			if (i->ipsc_clen)
+				is->is_flags |= IS_SC_CLIENT;
+			else
+				is->is_flags |= IS_SC_MATCHC;
+			if (i->ipsc_slen)
+				is->is_flags |= IS_SC_SERVER;
+			else
+				is->is_flags |= IS_SC_MATCHS;
 		}
 	}
 	RWLOCK_EXIT(&ipsc_rwlock);
@@ -433,6 +435,8 @@
 		}
 		if (k == 1)
 			isc = lm;
+		if (isc == NULL)
+			return 0;
 
 		/*
 		 * No matches or partial matches, so reset the respective
@@ -539,8 +543,8 @@
 	j = 0xffff >> (16 - dlen);
 	i = (0xffff & j) << off;
 #ifdef _KERNEL
-	COPYDATA(*(mb_t **)fin->fin_mp, fin->fin_hlen + thoff, dlen,
-		 (caddr_t)is->is_sbuf[rv] + off);
+	COPYDATA(*(mb_t **)fin->fin_mp, fin->fin_plen - fin->fin_dlen + thoff,
+		 dlen, (caddr_t)is->is_sbuf[rv] + off);
 #endif
 	is->is_smsk[rv] |= i;
 	for (j = 0, i = is->is_smsk[rv]; i & 1; i >>= 1)
@@ -563,10 +567,11 @@
 }
 
 
-int fr_scan_ioctl(data, cmd, mode)
+int fr_scan_ioctl(data, cmd, mode, uid, ctx)
 caddr_t data;
 ioctlcmd_t cmd;
-int mode;
+int mode, uid;
+void *ctx;
 {
 	ipscanstat_t ipscs;
 	int err = 0;
@@ -582,7 +587,9 @@
 	case SIOCGSCST :
 		bcopy((char *)&ipsc_stat, (char *)&ipscs, sizeof(ipscs));
 		ipscs.iscs_list = ipsc_list;
-		BCOPYOUT(&ipscs, data, sizeof(ipscs));
+		err = BCOPYOUT(&ipscs, data, sizeof(ipscs));
+		if (err != 0)
+			err = EFAULT;
 		break;
 	default :
 		err = EINVAL;
Index: ip_htable.h
===================================================================
RCS file: /home/cvs/src/sys/contrib/ipfilter/netinet/ip_htable.h,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/contrib/ipfilter/netinet/ip_htable.h -L sys/contrib/ipfilter/netinet/ip_htable.h -u -r1.1.1.1 -r1.2
--- sys/contrib/ipfilter/netinet/ip_htable.h
+++ sys/contrib/ipfilter/netinet/ip_htable.h
@@ -1,5 +1,3 @@
-/*	$FreeBSD: src/sys/contrib/ipfilter/netinet/ip_htable.h,v 1.1.1.1 2005/04/25 18:15:18 darrenr Exp $	*/
-
 #ifndef __IP_HTABLE_H__
 #define __IP_HTABLE_H__
 
@@ -7,10 +5,12 @@
 
 typedef	struct	iphtent_s	{
 	struct	iphtent_s	*ipe_next, **ipe_pnext;
+	struct	iphtent_s	*ipe_hnext, **ipe_phnext;
 	void		*ipe_ptr;
 	i6addr_t	ipe_addr;
 	i6addr_t	ipe_mask;
 	int		ipe_ref;
+	int		ipe_unit;
 	union	{
 		char	ipeu_char[16];
 		u_long	ipeu_long;
@@ -28,6 +28,7 @@
 	ipfrwlock_t	iph_rwlock;
 	struct	iphtable_s	*iph_next, **iph_pnext;
 	struct	iphtent_s	**iph_table;
+	struct	iphtent_s	*iph_list;
 	size_t	iph_size;		/* size of hash table */
 	u_long	iph_seed;		/* hashing seed */
 	u_32_t	iph_flags;
@@ -41,6 +42,7 @@
 /* iph_type */
 #define	IPHASH_LOOKUP	0
 #define	IPHASH_GROUPMAP	1
+#define	IPHASH_DELETE	2
 #define	IPHASH_ANON	0x80000000
 
 
@@ -55,17 +57,22 @@
 
 extern iphtable_t *ipf_htables[IPL_LOGSIZE];
 
+extern iphtable_t *fr_existshtable __P((int, char *));
+extern int fr_clearhtable __P((iphtable_t *));
 extern void fr_htable_unload __P((void));
 extern int fr_newhtable __P((iplookupop_t *));
 extern iphtable_t *fr_findhtable __P((int, char *));
-extern int fr_removehtable __P((iplookupop_t *));
+extern int fr_removehtable __P((int, char *));
 extern size_t fr_flushhtable __P((iplookupflush_t *));
 extern int fr_addhtent __P((iphtable_t *, iphtent_t *));
 extern int fr_delhtent __P((iphtable_t *, iphtent_t *));
-extern void fr_derefhtable __P((iphtable_t *));
-extern void fr_delhtable __P((iphtable_t *));
+extern int fr_derefhtable __P((iphtable_t *));
+extern int fr_derefhtent __P((iphtent_t *));
+extern int fr_delhtable __P((iphtable_t *));
 extern void *fr_iphmfindgroup __P((void *, void *));
 extern int fr_iphmfindip __P((void *, int, void *));
 extern int fr_gethtablestat __P((iplookupop_t *));
+extern int fr_htable_getnext __P((ipftoken_t *, ipflookupiter_t *));
+extern void fr_htable_iterderef __P((u_int, int, void *));
 
 #endif /* __IP_HTABLE_H__ */
Index: ip_raudio_pxy.c
===================================================================
RCS file: /home/cvs/src/sys/contrib/ipfilter/netinet/ip_raudio_pxy.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/contrib/ipfilter/netinet/ip_raudio_pxy.c -L sys/contrib/ipfilter/netinet/ip_raudio_pxy.c -u -r1.1.1.1 -r1.2
--- sys/contrib/ipfilter/netinet/ip_raudio_pxy.c
+++ sys/contrib/ipfilter/netinet/ip_raudio_pxy.c
@@ -1,12 +1,12 @@
-/*	$FreeBSD: src/sys/contrib/ipfilter/netinet/ip_raudio_pxy.c,v 1.11 2005/04/25 18:43:14 darrenr Exp $	*/
+/*	$FreeBSD: src/sys/contrib/ipfilter/netinet/ip_raudio_pxy.c,v 1.13 2007/06/04 02:54:36 darrenr Exp $	*/
 
 /*
- * $FreeBSD: src/sys/contrib/ipfilter/netinet/ip_raudio_pxy.c,v 1.11 2005/04/25 18:43:14 darrenr Exp $
+ * $FreeBSD: src/sys/contrib/ipfilter/netinet/ip_raudio_pxy.c,v 1.13 2007/06/04 02:54:36 darrenr Exp $
  * Copyright (C) 1998-2003 by Darren Reed
  *
  * See the IPFILTER.LICENCE file for details on licencing.
  *
- * Id: ip_raudio_pxy.c,v 1.40.2.3 2005/02/04 10:22:55 darrenr Exp
+ * $Id: ip_raudio_pxy.c,v 1.40.2.4 2006/07/14 06:12:17 darrenr Exp $
  */
 
 #define	IPF_RAUDIO_PROXY
@@ -307,7 +307,7 @@
 
 			(void) fr_addstate(&fi, NULL, (sp ? 0 : SI_W_SPORT));
 			if (fi.fin_state != NULL)
-				fr_statederef(&fi, (ipstate_t **)&fi.fin_state);
+				fr_statederef((ipstate_t **)&fi.fin_state);
 		}
 	}
 
@@ -327,7 +327,7 @@
 
 			(void) fr_addstate(&fi, NULL, SI_W_DPORT);
 			if (fi.fin_state != NULL)
-				fr_statederef(&fi, (ipstate_t **)&fi.fin_state);
+				fr_statederef((ipstate_t **)&fi.fin_state);
 		}
 	}
 
Index: ip_rcmd_pxy.c
===================================================================
RCS file: /home/cvs/src/sys/contrib/ipfilter/netinet/ip_rcmd_pxy.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/contrib/ipfilter/netinet/ip_rcmd_pxy.c -L sys/contrib/ipfilter/netinet/ip_rcmd_pxy.c -u -r1.1.1.1 -r1.2
--- sys/contrib/ipfilter/netinet/ip_rcmd_pxy.c
+++ sys/contrib/ipfilter/netinet/ip_rcmd_pxy.c
@@ -1,15 +1,15 @@
-/*	$FreeBSD: src/sys/contrib/ipfilter/netinet/ip_rcmd_pxy.c,v 1.12 2005/04/25 18:43:14 darrenr Exp $	*/
+/*	$FreeBSD: src/sys/contrib/ipfilter/netinet/ip_rcmd_pxy.c,v 1.15 2007/06/04 02:54:36 darrenr Exp $	*/
 
 /*
  * Copyright (C) 1998-2003 by Darren Reed
  *
  * See the IPFILTER.LICENCE file for details on licencing.
  *
- * Id: ip_rcmd_pxy.c,v 1.41.2.4 2005/02/04 10:22:55 darrenr Exp
+ * $Id: ip_rcmd_pxy.c,v 1.41.2.7 2006/07/14 06:12:18 darrenr Exp $
  *
  * Simple RCMD transparent proxy for in-kernel use.  For use with the NAT
  * code.
- * $FreeBSD: src/sys/contrib/ipfilter/netinet/ip_rcmd_pxy.c,v 1.12 2005/04/25 18:43:14 darrenr Exp $
+ * $FreeBSD: src/sys/contrib/ipfilter/netinet/ip_rcmd_pxy.c,v 1.15 2007/06/04 02:54:36 darrenr Exp $
  */
 
 #define	IPF_RCMD_PROXY
@@ -154,6 +154,8 @@
 	 * other way.
 	 */
 	bcopy((char *)fin, (char *)&fi, sizeof(fi));
+	fi.fin_state = NULL;
+	fi.fin_nat = NULL;
 	fi.fin_flx |= FI_IGNORE;
 	fi.fin_data[0] = sp;
 	fi.fin_data[1] = 0;
@@ -203,9 +205,9 @@
 				fi.fin_fi.fi_daddr = nat->nat_inip.s_addr;
 				ip->ip_dst = nat->nat_inip;
 			}
-			(void) fr_addstate(&fi, &nat2->nat_state, SI_W_DPORT);
+			(void) fr_addstate(&fi, NULL, SI_W_DPORT);
 			if (fi.fin_state != NULL)
-				fr_statederef(&fi, (ipstate_t **)&fi.fin_state);
+				fr_statederef((ipstate_t **)&fi.fin_state);
 		}
 		ip->ip_len = slen;
 		ip->ip_src = swip;
Index: ip_proxy.h
===================================================================
RCS file: /home/cvs/src/sys/contrib/ipfilter/netinet/ip_proxy.h,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/contrib/ipfilter/netinet/ip_proxy.h -L sys/contrib/ipfilter/netinet/ip_proxy.h -u -r1.1.1.1 -r1.2
--- sys/contrib/ipfilter/netinet/ip_proxy.h
+++ sys/contrib/ipfilter/netinet/ip_proxy.h
@@ -1,11 +1,11 @@
-/*	$FreeBSD: src/sys/contrib/ipfilter/netinet/ip_proxy.h,v 1.15 2005/04/27 03:48:10 darrenr Exp $	*/
+/*	$FreeBSD: src/sys/contrib/ipfilter/netinet/ip_proxy.h,v 1.17 2007/06/04 02:54:35 darrenr Exp $	*/
 
 /*
  * Copyright (C) 1997-2001 by Darren Reed.
  *
  * See the IPFILTER.LICENCE file for details on licencing.
  *
- * $FreeBSD: src/sys/contrib/ipfilter/netinet/ip_proxy.h,v 1.15 2005/04/27 03:48:10 darrenr Exp $
+ * $FreeBSD: src/sys/contrib/ipfilter/netinet/ip_proxy.h,v 1.17 2007/06/04 02:54:35 darrenr Exp $
  * Id: ip_proxy.h,v 2.31.2.2 2005/03/12 19:33:48 darrenr Exp
  */
 
@@ -16,7 +16,7 @@
 #define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4)))
 #endif
 
-#if defined(__STDC__) || defined(__GNUC__)
+#if defined(__STDC__) || defined(__GNUC__) || defined(_AIX51)
 #define	SIOCPROXY	_IOWR('r', 64, struct ap_control)
 #else
 #define	SIOCPROXY	_IOWR(r, 64, struct ap_control)
@@ -443,6 +443,7 @@
 extern	ap_session_t	*ap_sess_list;
 extern	aproxy_t	ap_proxies[];
 extern	int		ippr_ftp_pasvonly;
+extern	int		ipf_proxy_debug;
 
 extern	int	appr_add __P((aproxy_t *));
 extern	int	appr_ctl __P((ap_ctl_t *));
@@ -456,6 +457,6 @@
 extern	int	appr_check __P((fr_info_t *, struct nat *));
 extern	aproxy_t	*appr_lookup __P((u_int, char *));
 extern	int	appr_new __P((fr_info_t *, struct nat *));
-extern	int	appr_ioctl __P((caddr_t, ioctlcmd_t, int));
+extern	int	appr_ioctl __P((caddr_t, ioctlcmd_t, int, void *));
 
 #endif /* __IP_PROXY_H__ */
Index: ip_htable.c
===================================================================
RCS file: /home/cvs/src/sys/contrib/ipfilter/netinet/ip_htable.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/contrib/ipfilter/netinet/ip_htable.c -L sys/contrib/ipfilter/netinet/ip_htable.c -u -r1.1.1.1 -r1.2
--- sys/contrib/ipfilter/netinet/ip_htable.c
+++ sys/contrib/ipfilter/netinet/ip_htable.c
@@ -1,4 +1,4 @@
-/*	$FreeBSD: src/sys/contrib/ipfilter/netinet/ip_htable.c,v 1.2 2005/06/23 14:19:02 darrenr Exp $	*/
+/*	$FreeBSD: src/sys/contrib/ipfilter/netinet/ip_htable.c,v 1.4.2.1 2007/10/31 05:00:37 darrenr Exp $	*/
 
 /*
  * Copyright (C) 1993-2001, 2003 by Darren Reed.
@@ -53,7 +53,7 @@
 /* END OF INCLUDES */
 
 #if !defined(lint)
-static const char rcsid[] = "@(#)Id: ip_htable.c,v 2.34.2.2 2004/10/17 15:49:15 darrenr Exp";
+static const char rcsid[] = "@(#)$Id: ip_htable.c,v 2.34.2.11 2007/09/20 12:51:51 darrenr Exp $";
 #endif
 
 #ifdef	IPFILTER_LOOKUP
@@ -103,30 +103,34 @@
 	char name[FR_GROUPLEN];
 	int err, i, unit;
 
+	unit = op->iplo_unit;
+	if ((op->iplo_arg & IPHASH_ANON) == 0) {
+		iph = fr_existshtable(unit, op->iplo_name);
+		if (iph != NULL) {
+			if ((iph->iph_flags & IPHASH_DELETE) == 0)
+				return EEXIST;
+			iph->iph_flags &= ~IPHASH_DELETE;
+			return 0;
+		}
+	}
+
 	KMALLOC(iph, iphtable_t *);
 	if (iph == NULL) {
 		ipht_nomem[op->iplo_unit]++;
 		return ENOMEM;
 	}
-
 	err = COPYIN(op->iplo_struct, iph, sizeof(*iph));
 	if (err != 0) {
 		KFREE(iph);
 		return EFAULT;
 	}
 
-	unit = op->iplo_unit;
 	if (iph->iph_unit != unit) {
 		KFREE(iph);
 		return EINVAL;
 	}
 
-	if ((op->iplo_arg & IPHASH_ANON) == 0) {
-		if (fr_findhtable(op->iplo_unit, op->iplo_name) != NULL) {
-			KFREE(iph);
-			return EEXIST;
-		}
-	} else {
+	if ((op->iplo_arg & IPHASH_ANON) != 0) {
 		i = IPHASH_ANON;
 		do {
 			i++;
@@ -141,12 +145,9 @@
 					    sizeof(oiph->iph_name)) == 0)
 					break;
 		} while (oiph != NULL);
+
 		(void)strncpy(iph->iph_name, name, sizeof(iph->iph_name));
-		err = COPYOUT(iph, op->iplo_struct, sizeof(*iph));
-		if (err != 0) {
-			KFREE(iph);
-			return EFAULT;
-		}
+		(void)strncpy(op->iplo_name, name, sizeof(op->iplo_name));
 		iph->iph_type |= IPHASH_ANON;
 	}
 
@@ -160,13 +161,14 @@
 
 	bzero((char *)iph->iph_table, iph->iph_size * sizeof(*iph->iph_table));
 	iph->iph_masks = 0;
+	iph->iph_list = NULL;
 
+	iph->iph_ref = 1;
 	iph->iph_next = ipf_htables[unit];
 	iph->iph_pnext = &ipf_htables[unit];
 	if (ipf_htables[unit] != NULL)
 		ipf_htables[unit]->iph_pnext = &iph->iph_next;
 	ipf_htables[unit] = iph;
-
 	ipf_nhtables[unit]++;
 
 	return 0;
@@ -175,22 +177,24 @@
 
 /*
  */
-int fr_removehtable(op)
-iplookupop_t *op;
+int fr_removehtable(unit, name)
+int unit;
+char *name;
 {
 	iphtable_t *iph;
 
-
-	iph = fr_findhtable(op->iplo_unit, op->iplo_name);
+	iph = fr_findhtable(unit, name);
 	if (iph == NULL)
 		return ESRCH;
 
-	if (iph->iph_unit != op->iplo_unit) {
+	if (iph->iph_unit != unit) {
 		return EINVAL;
 	}
 
 	if (iph->iph_ref != 0) {
-		return EBUSY;
+		(void) fr_clearhtable(iph);
+		iph->iph_flags |= IPHASH_DELETE;
+		return 0;
 	}
 
 	fr_delhtable(iph);
@@ -199,40 +203,106 @@
 }
 
 
-void fr_delhtable(iph)
+int fr_clearhtable(iph)
 iphtable_t *iph;
 {
 	iphtent_t *ipe;
-	int i;
 
-	for (i = 0; i < iph->iph_size; i++)
-		while ((ipe = iph->iph_table[i]) != NULL)
-			if (fr_delhtent(iph, ipe) != 0)
-				return;
+	while ((ipe = iph->iph_list) != NULL)
+		if (fr_delhtent(iph, ipe) != 0)
+			return 1;
+	return 0;
+}
+
 
-	*iph->iph_pnext = iph->iph_next;
+int fr_delhtable(iph)
+iphtable_t *iph;
+{
+
+	if (fr_clearhtable(iph) != 0)
+		return 1;
+
+	if (iph->iph_pnext != NULL)
+		*iph->iph_pnext = iph->iph_next;
 	if (iph->iph_next != NULL)
 		iph->iph_next->iph_pnext = iph->iph_pnext;
 
 	ipf_nhtables[iph->iph_unit]--;
 
+	return fr_derefhtable(iph);
+}
+
+
+/*
+ * Delete an entry from a hash table.
+ */
+int fr_delhtent(iph, ipe)
+iphtable_t *iph;
+iphtent_t *ipe;
+{
+
+	if (ipe->ipe_phnext != NULL)
+		*ipe->ipe_phnext = ipe->ipe_hnext;
+	if (ipe->ipe_hnext != NULL)
+		ipe->ipe_hnext->ipe_phnext = ipe->ipe_phnext;
+
+	if (ipe->ipe_pnext != NULL)
+		*ipe->ipe_pnext = ipe->ipe_next;
+	if (ipe->ipe_next != NULL)
+		ipe->ipe_next->ipe_pnext = ipe->ipe_pnext;
+
+	switch (iph->iph_type & ~IPHASH_ANON)
+	{
+	case IPHASH_GROUPMAP :
+		if (ipe->ipe_group != NULL)
+			fr_delgroup(ipe->ipe_group, IPL_LOGIPF, fr_active);
+		break;
+
+	default :
+		ipe->ipe_ptr = NULL;
+		ipe->ipe_value = 0;
+		break;
+	}
+
+	return fr_derefhtent(ipe);
+}
+
+
+int fr_derefhtable(iph)
+iphtable_t *iph;
+{
+	int refs;
+
+	iph->iph_ref--;
+	refs = iph->iph_ref;
+
 	if (iph->iph_ref == 0) {
 		KFREES(iph->iph_table, iph->iph_size * sizeof(*iph->iph_table));
 		KFREE(iph);
 	}
+
+	return refs;
 }
 
 
-void fr_derefhtable(iph)
-iphtable_t *iph;
+int fr_derefhtent(ipe)
+iphtent_t *ipe;
 {
-	iph->iph_ref--;
-	if (iph->iph_ref == 0)
-		fr_delhtable(iph);
+
+	ipe->ipe_ref--;
+	if (ipe->ipe_ref == 0) {
+		ipf_nhtnodes[ipe->ipe_unit]--;
+
+		KFREE(ipe);
+
+		return 0;
+	}
+
+	return ipe->ipe_ref;
 }
 
 
-iphtable_t *fr_findhtable(unit, name)
+iphtable_t *fr_existshtable(unit, name)
 int unit;
 char *name;
 {
@@ -245,6 +315,20 @@
 }
 
 
+iphtable_t *fr_findhtable(unit, name)
+int unit;
+char *name;
+{
+	iphtable_t *iph;
+
+	iph = fr_existshtable(unit, name);
+	if ((iph != NULL) && (iph->iph_flags & IPHASH_DELETE) == 0)
+		return iph;
+
+	return NULL;
+}
+
+
 size_t fr_flushhtable(op)
 iplookupflush_t *op;
 {
@@ -257,8 +341,11 @@
 	for (i = 0; i <= IPL_LOGMAX; i++) {
 		if (op->iplf_unit == i || op->iplf_unit == IPL_LOGALL) {
 			while ((iph = ipf_htables[i]) != NULL) {
-				fr_delhtable(iph);
-				freed++;
+				if (fr_delhtable(iph) == 0) {
+					freed++;
+				} else {
+					iph->iph_flags |= IPHASH_DELETE;
+				}
 			}
 		}
 	}
@@ -290,13 +377,20 @@
 
 	hv = IPE_HASH_FN(ipe->ipe_addr.in4_addr, ipe->ipe_mask.in4_addr,
 			 iph->iph_size);
-	ipe->ipe_ref = 0;
-	ipe->ipe_next = iph->iph_table[hv];
-	ipe->ipe_pnext = iph->iph_table + hv;
+	ipe->ipe_ref = 1;
+	ipe->ipe_hnext = iph->iph_table[hv];
+	ipe->ipe_phnext = iph->iph_table + hv;
 
 	if (iph->iph_table[hv] != NULL)
-		iph->iph_table[hv]->ipe_pnext = &ipe->ipe_next;
+		iph->iph_table[hv]->ipe_phnext = &ipe->ipe_hnext;
 	iph->iph_table[hv] = ipe;
+
+	ipe->ipe_next = iph->iph_list;
+	ipe->ipe_pnext = &iph->iph_list;
+	if (ipe->ipe_next != NULL)
+		ipe->ipe_next->ipe_pnext = &ipe->ipe_next;
+	iph->iph_list = ipe;
+
 	if ((bits >= 0) && (bits != 32))
 		iph->iph_masks |= 1 << bits;
 
@@ -314,44 +408,8 @@
 		break;
 	}
 
-	ipf_nhtnodes[iph->iph_unit]++;
-
-	return 0;
-}
-
-
-/*
- * Delete an entry from a hash table.
- */
-int fr_delhtent(iph, ipe)
-iphtable_t *iph;
-iphtent_t *ipe;
-{
-
-	if (ipe->ipe_ref != 0)
-		return EBUSY;
-
-
-	*ipe->ipe_pnext = ipe->ipe_next;
-	if (ipe->ipe_next != NULL)
-		ipe->ipe_next->ipe_pnext = ipe->ipe_pnext;
-
-	switch (iph->iph_type & ~IPHASH_ANON)
-	{
-	case IPHASH_GROUPMAP :
-		if (ipe->ipe_group != NULL)
-			fr_delgroup(ipe->ipe_group, IPL_LOGIPF, fr_active);
-		break;
-
-	default :
-		ipe->ipe_ptr = NULL;
-		ipe->ipe_value = 0;
-		break;
-	}
-
-	KFREE(ipe);
-
-	ipf_nhtnodes[iph->iph_unit]--;
+	ipe->ipe_unit = iph->iph_unit;
+	ipf_nhtnodes[ipe->ipe_unit]++;
 
 	return 0;
 }
@@ -382,22 +440,22 @@
 /* ------------------------------------------------------------------------ */
 /* Function:    fr_iphmfindip                                               */
 /* Returns:     int     - 0 == +ve match, -1 == error, 1 == -ve/no match    */
-/* Parameters:  tptr(I)    - pointer to the pool to search                  */
-/*              version(I) - IP protocol version (4 or 6)                   */
-/*              aptr(I)    - pointer to address information                 */
+/* Parameters:  tptr(I)      - pointer to the pool to search                */
+/*              ipversion(I) - IP protocol version (4 or 6)                 */
+/*              aptr(I)      - pointer to address information               */
 /*                                                                          */
 /* Search the hash table for a given address and return a search result.    */
 /* ------------------------------------------------------------------------ */
-int fr_iphmfindip(tptr, version, aptr)
+int fr_iphmfindip(tptr, ipversion, aptr)
 void *tptr, *aptr;
-int version;
+int ipversion;
 {
 	struct in_addr *addr;
 	iphtable_t *iph;
 	iphtent_t *ipe;
 	int rval;
 
-	if (version != 4)
+	if (ipversion != 4)
 		return -1;
 
 	if (tptr == NULL || aptr == NULL)
@@ -431,7 +489,7 @@
 maskloop:
 	ips = ntohl(addr->s_addr) & msk;
 	hv = IPE_HASH_FN(ips, msk, iph->iph_size);
-	for (ipe = iph->iph_table[hv]; (ipe != NULL); ipe = ipe->ipe_next) {
+	for (ipe = iph->iph_table[hv]; (ipe != NULL); ipe = ipe->ipe_hnext) {
 		if (ipe->ipe_mask.in4_addr != msk ||
 		    ipe->ipe_addr.in4_addr != ips) {
 			continue;
@@ -454,4 +512,131 @@
 	return ipe;
 }
 
+
+int fr_htable_getnext(token, ilp)
+ipftoken_t *token;
+ipflookupiter_t *ilp;
+{
+	iphtent_t *node, zn, *nextnode;
+	iphtable_t *iph, zp, *nextiph;
+	int err;
+
+	err = 0;
+	iph = NULL;
+	node = NULL;
+	nextiph = NULL;
+	nextnode = NULL;
+
+	READ_ENTER(&ip_poolrw);
+
+	switch (ilp->ili_otype)
+	{
+	case IPFLOOKUPITER_LIST :
+		iph = token->ipt_data;
+		if (iph == NULL) {
+			nextiph = ipf_htables[(int)ilp->ili_unit];
+		} else {
+			nextiph = iph->iph_next;
+		}
+
+		if (nextiph != NULL) {
+			ATOMIC_INC(nextiph->iph_ref);
+			token->ipt_data = nextiph;
+		} else {
+			bzero((char *)&zp, sizeof(zp));
+			nextiph = &zp;
+			token->ipt_data = NULL;
+		}
+		break;
+
+	case IPFLOOKUPITER_NODE :
+		node = token->ipt_data;
+		if (node == NULL) {
+			iph = fr_findhtable(ilp->ili_unit, ilp->ili_name);
+			if (iph == NULL)
+				err = ESRCH;
+			else {
+				nextnode = iph->iph_list;
+			}
+		} else {
+			nextnode = node->ipe_next;
+		}
+
+		if (nextnode != NULL) {
+			ATOMIC_INC(nextnode->ipe_ref);
+			token->ipt_data = nextnode;
+		} else {
+			bzero((char *)&zn, sizeof(zn));
+			nextnode = &zn;
+			token->ipt_data = NULL;
+		}
+		break;
+	default :
+		err = EINVAL;
+		break;
+	}
+
+	RWLOCK_EXIT(&ip_poolrw);
+	if (err != 0)
+		return err;
+
+	switch (ilp->ili_otype)
+	{
+	case IPFLOOKUPITER_LIST :
+		if (iph != NULL) {
+			WRITE_ENTER(&ip_poolrw);
+			fr_derefhtable(iph);
+			RWLOCK_EXIT(&ip_poolrw);
+		}
+		err = COPYOUT(nextiph, ilp->ili_data, sizeof(*nextiph));
+		if (err != 0)
+			err = EFAULT;
+		break;
+
+	case IPFLOOKUPITER_NODE :
+		if (node != NULL) {
+			WRITE_ENTER(&ip_poolrw);
+			fr_derefhtent(node);
+			RWLOCK_EXIT(&ip_poolrw);
+		}
+		err = COPYOUT(nextnode, ilp->ili_data, sizeof(*nextnode));
+		if (err != 0)
+			err = EFAULT;
+		break;
+	}
+
+	return err;
+}
+
+
+void fr_htable_iterderef(otype, unit, data)
+u_int otype;
+int unit;
+void *data;
+{
+
+	if (data == NULL)
+		return;
+
+	if (unit < 0 || unit > IPL_LOGMAX)
+		return;
+
+	switch (otype)
+	{
+	case IPFLOOKUPITER_LIST :
+		WRITE_ENTER(&ip_poolrw);
+		fr_derefhtable((iphtable_t *)data);
+		RWLOCK_EXIT(&ip_poolrw);
+		break;
+
+	case IPFLOOKUPITER_NODE :
+		WRITE_ENTER(&ip_poolrw);
+		fr_derefhtent((iphtent_t *)data);
+		RWLOCK_EXIT(&ip_poolrw);
+		break;
+	default :
+		break;
+	}
+}
+
 #endif /* IPFILTER_LOOKUP */
Index: ip_rpcb_pxy.c
===================================================================
RCS file: /home/cvs/src/sys/contrib/ipfilter/netinet/ip_rpcb_pxy.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/contrib/ipfilter/netinet/ip_rpcb_pxy.c -L sys/contrib/ipfilter/netinet/ip_rpcb_pxy.c -u -r1.1.1.1 -r1.2
--- sys/contrib/ipfilter/netinet/ip_rpcb_pxy.c
+++ sys/contrib/ipfilter/netinet/ip_rpcb_pxy.c
@@ -1,5 +1,3 @@
-/*	$FreeBSD: src/sys/contrib/ipfilter/netinet/ip_rpcb_pxy.c,v 1.1.1.1 2005/04/25 18:15:34 darrenr Exp $	*/
-
 /*
  * Copyright (C) 2002-2003 by Ryan Beasley <ryanb at goddamnbastard.org>
  *
@@ -39,7 +37,7 @@
  *   o The enclosed hack of STREAMS support is pretty sick and most likely
  *     broken.
  *
- *	Id: ip_rpcb_pxy.c,v 2.25.2.3 2005/02/04 10:22:56 darrenr Exp
+ *	$Id: ip_rpcb_pxy.c,v 2.25.2.7 2007/06/04 09:16:31 darrenr Exp $
  */
 
 #define	IPF_RPCB_PROXY
@@ -292,6 +290,7 @@
 
 	/* Perform basic variable initialization. */
 	rs = (rpcb_session_t *)aps->aps_data;
+	rx = NULL;
 
 	m = fin->fin_m;
 	off = (char *)fin->fin_dp - (char *)fin->fin_ip;
@@ -309,6 +308,8 @@
 	COPYDATA(m, off, dlen, (caddr_t)&rm->rm_msgbuf);
 	rm->rm_buflen = dlen;
 
+	rx = NULL;		/* XXX gcc */
+
 	/* Send off to decode reply. */
 	rv = ippr_rpcb_decoderep(fin, nat, rs, rm, &rx);
 
@@ -1158,6 +1159,8 @@
 
 	/* Generate dummy fr_info */
 	bcopy((char *)fin, (char *)&fi, sizeof(fi));
+	fi.fin_state = NULL;
+	fi.fin_nat = NULL;
 	fi.fin_out = 0;
 	fi.fin_src = fin->fin_dst;
 	fi.fin_dst = nat->nat_outip;
@@ -1193,8 +1196,9 @@
 	 * no use for this lock, so simply unlock it if necessary.
 	 */
 	is = fr_stlookup(&fi, &tcp, NULL);
-	if (is != NULL)
+	if (is != NULL) {
 		RWLOCK_EXIT(&ipf_state);
+	}
 
 	RWLOCK_EXIT(&ipf_nat);
 
@@ -1273,7 +1277,7 @@
 			return(-1);
 		}
 		if (fi.fin_state != NULL)
-			fr_statederef(&fi, (ipstate_t **)&fi.fin_state);
+			fr_statederef((ipstate_t **)&fi.fin_state);
 	}
 
 	return(0);


More information about the Midnightbsd-cvs mailing list