[Midnightbsd-cvs] src [10139] trunk/sys/contrib/ipfilter/netinet: update

laffer1 at midnightbsd.org laffer1 at midnightbsd.org
Mon May 28 14:56:31 EDT 2018


Revision: 10139
          http://svnweb.midnightbsd.org/src/?rev=10139
Author:   laffer1
Date:     2018-05-28 14:56:30 -0400 (Mon, 28 May 2018)
Log Message:
-----------
update

Modified Paths:
--------------
    trunk/sys/contrib/ipfilter/netinet/IPFILTER.LICENCE
    trunk/sys/contrib/ipfilter/netinet/fil.c
    trunk/sys/contrib/ipfilter/netinet/ip_auth.c
    trunk/sys/contrib/ipfilter/netinet/ip_auth.h
    trunk/sys/contrib/ipfilter/netinet/ip_compat.h
    trunk/sys/contrib/ipfilter/netinet/ip_fil.h
    trunk/sys/contrib/ipfilter/netinet/ip_fil_freebsd.c
    trunk/sys/contrib/ipfilter/netinet/ip_frag.c
    trunk/sys/contrib/ipfilter/netinet/ip_frag.h
    trunk/sys/contrib/ipfilter/netinet/ip_ftp_pxy.c
    trunk/sys/contrib/ipfilter/netinet/ip_htable.c
    trunk/sys/contrib/ipfilter/netinet/ip_htable.h
    trunk/sys/contrib/ipfilter/netinet/ip_ipsec_pxy.c
    trunk/sys/contrib/ipfilter/netinet/ip_irc_pxy.c
    trunk/sys/contrib/ipfilter/netinet/ip_log.c
    trunk/sys/contrib/ipfilter/netinet/ip_lookup.c
    trunk/sys/contrib/ipfilter/netinet/ip_lookup.h
    trunk/sys/contrib/ipfilter/netinet/ip_nat.c
    trunk/sys/contrib/ipfilter/netinet/ip_nat.h
    trunk/sys/contrib/ipfilter/netinet/ip_netbios_pxy.c
    trunk/sys/contrib/ipfilter/netinet/ip_pool.c
    trunk/sys/contrib/ipfilter/netinet/ip_pool.h
    trunk/sys/contrib/ipfilter/netinet/ip_pptp_pxy.c
    trunk/sys/contrib/ipfilter/netinet/ip_proxy.c
    trunk/sys/contrib/ipfilter/netinet/ip_proxy.h
    trunk/sys/contrib/ipfilter/netinet/ip_raudio_pxy.c
    trunk/sys/contrib/ipfilter/netinet/ip_rcmd_pxy.c
    trunk/sys/contrib/ipfilter/netinet/ip_rpcb_pxy.c
    trunk/sys/contrib/ipfilter/netinet/ip_rules.c
    trunk/sys/contrib/ipfilter/netinet/ip_rules.h
    trunk/sys/contrib/ipfilter/netinet/ip_scan.c
    trunk/sys/contrib/ipfilter/netinet/ip_scan.h
    trunk/sys/contrib/ipfilter/netinet/ip_state.c
    trunk/sys/contrib/ipfilter/netinet/ip_state.h
    trunk/sys/contrib/ipfilter/netinet/ip_sync.c
    trunk/sys/contrib/ipfilter/netinet/ip_sync.h
    trunk/sys/contrib/ipfilter/netinet/ipl.h
    trunk/sys/contrib/ipfilter/netinet/mlfk_ipl.c

Added Paths:
-----------
    trunk/sys/contrib/ipfilter/netinet/ip_dns_pxy.c
    trunk/sys/contrib/ipfilter/netinet/ip_dstlist.c
    trunk/sys/contrib/ipfilter/netinet/ip_dstlist.h
    trunk/sys/contrib/ipfilter/netinet/ip_nat6.c
    trunk/sys/contrib/ipfilter/netinet/ip_tftp_pxy.c
    trunk/sys/contrib/ipfilter/netinet/ipf_rb.h
    trunk/sys/contrib/ipfilter/netinet/radix_ipf.c
    trunk/sys/contrib/ipfilter/netinet/radix_ipf.h

Property Changed:
----------------
    trunk/sys/contrib/ipfilter/netinet/IPFILTER.LICENCE

Modified: trunk/sys/contrib/ipfilter/netinet/IPFILTER.LICENCE
===================================================================
--- trunk/sys/contrib/ipfilter/netinet/IPFILTER.LICENCE	2018-05-28 18:55:30 UTC (rev 10138)
+++ trunk/sys/contrib/ipfilter/netinet/IPFILTER.LICENCE	2018-05-28 18:56:30 UTC (rev 10139)
@@ -1,4 +1,4 @@
-$FreeBSD$
+$FreeBSD: stable/10/sys/contrib/ipfilter/netinet/IPFILTER.LICENCE 95418 2002-04-25 03:31:39Z darrenr $
 
 Copyright (C) 1993-2002 by Darren Reed.
 


Property changes on: trunk/sys/contrib/ipfilter/netinet/IPFILTER.LICENCE
___________________________________________________________________
Added: mnbsd:nokeywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Modified: trunk/sys/contrib/ipfilter/netinet/fil.c
===================================================================
--- trunk/sys/contrib/ipfilter/netinet/fil.c	2018-05-28 18:55:30 UTC (rev 10138)
+++ trunk/sys/contrib/ipfilter/netinet/fil.c	2018-05-28 18:56:30 UTC (rev 10139)
@@ -1,9 +1,15 @@
-/*	$FreeBSD$	*/
+/* $MidnightBSD$ */
+/*	$FreeBSD: stable/10/sys/contrib/ipfilter/netinet/fil.c 317434 2017-04-26 02:37:25Z cy $	*/
 
 /*
- * Copyright (C) 1993-2003 by Darren Reed.
+ * Copyright (C) 2012 by Darren Reed.
  *
  * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * Copyright 2008 Sun Microsystems.
+ *
+ * $Id$
+ *
  */
 #if defined(KERNEL) || defined(_KERNEL)
 # undef KERNEL
@@ -15,15 +21,6 @@
 #include <sys/types.h>
 #include <sys/param.h>
 #include <sys/time.h>
-#if defined(__NetBSD__)
-# if (NetBSD >= 199905) && !defined(IPFILTER_LKM) && defined(_KERNEL)
-#  if (__NetBSD_Version__ < 301000000)
-#   include "opt_ipfilter_log.h"
-#  else
-#   include "opt_ipfilter.h"
-#  endif
-# endif
-#endif
 #if defined(_KERNEL) && defined(__FreeBSD_version) && \
     (__FreeBSD_version >= 220000)
 # if (__FreeBSD_version >= 400000)
@@ -82,23 +79,9 @@
 #ifdef sun
 # include <net/af.h>
 #endif
-#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 <netinet/in.h>
 #include <netinet/in_systm.h>
 #include <netinet/ip.h>
-#if !defined(linux)
-# include <netinet/ip_var.h>
-#endif
 #if defined(__sgi) && defined(IFF_DRVRLOCK) /* IRIX 6 */
 # include <sys/hashing.h>
 # include <netinet/in_var.h>
@@ -121,7 +104,6 @@
 #  include <netinet6/in6_var.h>
 # endif
 #endif
-#include <netinet/tcpip.h>
 #include "netinet/ip_fil.h"
 #include "netinet/ip_nat.h"
 #include "netinet/ip_frag.h"
@@ -131,9 +113,8 @@
 #ifdef IPFILTER_SCAN
 # include "netinet/ip_scan.h"
 #endif
-#ifdef IPFILTER_SYNC
-# include "netinet/ip_sync.h"
-#endif
+#include "netinet/ip_sync.h"
+#include "netinet/ip_lookup.h"
 #include "netinet/ip_pool.h"
 #include "netinet/ip_htable.h"
 #ifdef IPFILTER_COMPILED
@@ -144,121 +125,104 @@
 #endif
 #if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000)
 # include <sys/malloc.h>
-# if defined(_KERNEL) && !defined(IPFILTER_LKM)
-#  include "opt_ipfilter.h"
-# endif
 #endif
 #include "netinet/ipl.h"
+
+#if defined(__NetBSD__) && (__NetBSD_Version__ >= 104230000)
+# include <sys/callout.h>
+extern struct callout ipf_slowtimer_ch;
+#endif
+#if defined(__OpenBSD__)
+# include <sys/timeout.h>
+extern struct timeout ipf_slowtimer_ch;
+#endif
 /* END OF INCLUDES */
 
-#include <machine/in_cksum.h>
-
 #if !defined(lint)
 static const char sccsid[] = "@(#)fil.c	1.36 6/5/96 (C) 1993-2000 Darren Reed";
-static const char rcsid[] = "@(#)$FreeBSD$";
-/* static const char rcsid[] = "@(#)$Id: fil.c,v 1.5 2013-01-08 01:31:40 laffer1 Exp $"; */
+static const char rcsid[] = "@(#)$FreeBSD: stable/10/sys/contrib/ipfilter/netinet/fil.c 317434 2017-04-26 02:37:25Z cy $";
+/* static const char rcsid[] = "@(#)$Id: fil.c,v 2.243.2.125 2007/10/10 09:27:20 darrenr Exp $"; */
 #endif
 
 #ifndef	_KERNEL
 # include "ipf.h"
 # include "ipt.h"
-# include "bpf-ipf.h"
 extern	int	opts;
+extern	int	blockreason;
 #endif /* _KERNEL */
 
+#define	LBUMP(x)	softc->x++
+#define	LBUMPD(x, y)	do { softc->x.y++; DT(y); } while (0)
 
-fr_info_t	frcache[2][8];
-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 } },
-		*ipacct[2][2] = { { NULL, NULL }, { NULL, NULL } },
-		*ipnatrules[2][2] = { { NULL, NULL }, { NULL, NULL } };
-struct	frgroup *ipfgroups[IPL_LOGSIZE][2];
-char	ipfilter_version[] = IPL_VERSION;
-int	fr_refcnt = 0;
-/*
- * For fr_running:
- * 0 == loading, 1 = running, -1 = disabled, -2 = unloading
- */
-int	fr_running = 0;
-int	fr_flags = IPF_LOGGING;
-int	fr_active = 0;
-int	fr_control_forwarding = 0;
-int	fr_update_ipid = 0;
-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};
-u_char	ipf_iss_secret[32];
-#if defined(IPFILTER_DEFAULT_BLOCK)
-int	fr_pass = FR_BLOCK|FR_NOMATCH;
-#else
-int	fr_pass = (IPF_DEFAULT_PASS)|FR_NOMATCH;
+static	INLINE int	ipf_check_ipf __P((fr_info_t *, frentry_t *, int));
+static	u_32_t		ipf_checkcipso __P((fr_info_t *, u_char *, int));
+static	u_32_t		ipf_checkripso __P((u_char *));
+static	u_32_t		ipf_decaps __P((fr_info_t *, u_32_t, int));
+#ifdef IPFILTER_LOG
+static	frentry_t	*ipf_dolog __P((fr_info_t *, u_32_t *));
 #endif
-int	fr_features = 0
-#ifdef	IPFILTER_LKM
-		| IPF_FEAT_LKM
+static	int		ipf_flushlist __P((ipf_main_softc_t *, int *,
+					   frentry_t **));
+static	int		ipf_flush_groups __P((ipf_main_softc_t *, frgroup_t **,
+					      int));
+static	ipfunc_t	ipf_findfunc __P((ipfunc_t));
+static	void		*ipf_findlookup __P((ipf_main_softc_t *, int,
+					     frentry_t *,
+					     i6addr_t *, i6addr_t *));
+static	frentry_t	*ipf_firewall __P((fr_info_t *, u_32_t *));
+static	int		ipf_fr_matcharray __P((fr_info_t *, int *));
+static	int		ipf_frruleiter __P((ipf_main_softc_t *, void *, int,
+					    void *));
+static	void		ipf_funcfini __P((ipf_main_softc_t *, frentry_t *));
+static	int		ipf_funcinit __P((ipf_main_softc_t *, frentry_t *));
+static	int		ipf_geniter __P((ipf_main_softc_t *, ipftoken_t *,
+					 ipfgeniter_t *));
+static	void		ipf_getstat __P((ipf_main_softc_t *,
+					 struct friostat *, int));
+static	int		ipf_group_flush __P((ipf_main_softc_t *, frgroup_t *));
+static	void		ipf_group_free __P((frgroup_t *));
+static	int		ipf_grpmapfini __P((struct ipf_main_softc_s *,
+					    frentry_t *));
+static	int		ipf_grpmapinit __P((struct ipf_main_softc_s *,
+					    frentry_t *));
+static	frentry_t	*ipf_nextrule __P((ipf_main_softc_t *, int, int,
+					   frentry_t *, int));
+static	int		ipf_portcheck __P((frpcmp_t *, u_32_t));
+static	INLINE int	ipf_pr_ah __P((fr_info_t *));
+static	INLINE void	ipf_pr_esp __P((fr_info_t *));
+static	INLINE void	ipf_pr_gre __P((fr_info_t *));
+static	INLINE void	ipf_pr_udp __P((fr_info_t *));
+static	INLINE void	ipf_pr_tcp __P((fr_info_t *));
+static	INLINE void	ipf_pr_icmp __P((fr_info_t *));
+static	INLINE void	ipf_pr_ipv4hdr __P((fr_info_t *));
+static	INLINE void	ipf_pr_short __P((fr_info_t *, int));
+static	INLINE int	ipf_pr_tcpcommon __P((fr_info_t *));
+static	INLINE int	ipf_pr_udpcommon __P((fr_info_t *));
+static	void		ipf_rule_delete __P((ipf_main_softc_t *, frentry_t *f,
+					     int, int));
+static	void		ipf_rule_expire_insert __P((ipf_main_softc_t *,
+						    frentry_t *, int));
+static	int		ipf_synclist __P((ipf_main_softc_t *, frentry_t *,
+					  void *));
+static	void		ipf_token_flush __P((ipf_main_softc_t *));
+static	void		ipf_token_unlink __P((ipf_main_softc_t *,
+					      ipftoken_t *));
+static	ipftuneable_t	*ipf_tune_findbyname __P((ipftuneable_t *,
+						  const char *));
+static	ipftuneable_t	*ipf_tune_findbycookie __P((ipftuneable_t **, void *,
+						    void **));
+static	int		ipf_updateipid __P((fr_info_t *));
+static	int		ipf_settimeout __P((struct ipf_main_softc_s *,
+					    struct ipftuneable *,
+					    ipftuneval_t *));
+#if !defined(_KERNEL) || (!defined(__NetBSD__) && !defined(__OpenBSD__) && \
+     !defined(__FreeBSD__)) || \
+    FREEBSD_LT_REV(501000) || NETBSD_LT_REV(105000000) || \
+    OPENBSD_LT_REV(200006)
+static	int		ppsratecheck(struct timeval *, int *, int);
 #endif
-#ifdef	IPFILTER_LOG
-		| IPF_FEAT_LOG
-#endif
-#ifdef	IPFILTER_LOOKUP
-		| IPF_FEAT_LOOKUP
-#endif
-#ifdef	IPFILTER_BPF
-		| IPF_FEAT_BPF
-#endif
-#ifdef	IPFILTER_COMPILED
-		| IPF_FEAT_COMPILED
-#endif
-#ifdef	IPFILTER_CKSUM
-		| IPF_FEAT_CKSUM
-#endif
-#ifdef	IPFILTER_SYNC
-		| IPF_FEAT_SYNC
-#endif
-#ifdef	IPFILTER_SCAN
-		| IPF_FEAT_SCAN
-#endif
-#ifdef	USE_INET6
-		| IPF_FEAT_IPV6
-#endif
-	;
 
-static	INLINE int	fr_ipfcheck __P((fr_info_t *, frentry_t *, int));
-static	int		fr_portcheck __P((frpcmp_t *, u_short *));
-static	int		frflushlist __P((int, minor_t, int *, frentry_t **));
-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 *));
-static	INLINE void	frpr_tcp __P((fr_info_t *));
-static	INLINE void	frpr_icmp __P((fr_info_t *));
-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 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, i6addr_t *, lookupfunc_t *));
-#endif
-static	void		frsynclist __P((frentry_t *, void *));
-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 *));
 
-
 /*
  * bit values for identifying presence of individual IP options
  * All of these tables should be ordered by increasing key value on the left
@@ -265,7 +229,7 @@
  * hand side to allow for binary searching of the array and include a trailer
  * with a 0 for the bitmask for linear searches to easily find the end with.
  */
-const	struct	optlist	ipopts[20] = {
+static const	struct	optlist	ipopts[20] = {
 	{ IPOPT_NOP,	0x000001 },
 	{ IPOPT_RR,	0x000002 },
 	{ IPOPT_ZSU,	0x000004 },
@@ -289,7 +253,7 @@
 };
 
 #ifdef USE_INET6
-struct optlist ip6exthdr[] = {
+static const struct optlist ip6exthdr[] = {
 	{ IPPROTO_HOPOPTS,		0x000001 },
 	{ IPPROTO_IPV6,			0x000002 },
 	{ IPPROTO_ROUTING,		0x000004 },
@@ -303,20 +267,10 @@
 };
 #endif
 
-struct optlist tcpopts[] = {
-	{ TCPOPT_NOP,			0x000001 },
-	{ TCPOPT_MAXSEG,		0x000002 },
-	{ TCPOPT_WINDOW,		0x000004 },
-	{ TCPOPT_SACK_PERMITTED,	0x000008 },
-	{ TCPOPT_SACK,			0x000010 },
-	{ TCPOPT_TIMESTAMP,		0x000020 },
-	{ 0,				0x000000 }
-};
-
 /*
  * bit values for identifying presence of individual IP security options
  */
-const	struct	optlist	secopt[8] = {
+static const	struct	optlist	secopt[8] = {
 	{ IPSO_CLASS_RES4,	0x01 },
 	{ IPSO_CLASS_TOPS,	0x02 },
 	{ IPSO_CLASS_SECR,	0x04 },
@@ -327,16 +281,143 @@
 	{ IPSO_CLASS_RES1,	0x80 }
 };
 
+char	ipfilter_version[] = IPL_VERSION;
 
+int	ipf_features = 0
+#ifdef	IPFILTER_LKM
+		| IPF_FEAT_LKM
+#endif
+#ifdef	IPFILTER_LOG
+		| IPF_FEAT_LOG
+#endif
+		| IPF_FEAT_LOOKUP
+#ifdef	IPFILTER_BPF
+		| IPF_FEAT_BPF
+#endif
+#ifdef	IPFILTER_COMPILED
+		| IPF_FEAT_COMPILED
+#endif
+#ifdef	IPFILTER_CKSUM
+		| IPF_FEAT_CKSUM
+#endif
+		| IPF_FEAT_SYNC
+#ifdef	IPFILTER_SCAN
+		| IPF_FEAT_SCAN
+#endif
+#ifdef	USE_INET6
+		| IPF_FEAT_IPV6
+#endif
+	;
+
+
 /*
  * Table of functions available for use with call rules.
  */
-static ipfunc_resolve_t fr_availfuncs[] = {
-#ifdef	IPFILTER_LOOKUP
-	{ "fr_srcgrpmap", fr_srcgrpmap, fr_grpmapinit },
-	{ "fr_dstgrpmap", fr_dstgrpmap, fr_grpmapinit },
+static ipfunc_resolve_t ipf_availfuncs[] = {
+	{ "srcgrpmap", ipf_srcgrpmap, ipf_grpmapinit, ipf_grpmapfini },
+	{ "dstgrpmap", ipf_dstgrpmap, ipf_grpmapinit, ipf_grpmapfini },
+	{ "",	      NULL,	      NULL,	      NULL }
+};
+
+static ipftuneable_t ipf_main_tuneables[] = {
+	{ { (void *)offsetof(struct ipf_main_softc_s, ipf_flags) },
+		"ipf_flags",		0,	0xffffffff,
+		stsizeof(ipf_main_softc_t, ipf_flags),
+		0,			NULL,	NULL },
+	{ { (void *)offsetof(struct ipf_main_softc_s, ipf_active) },
+		"active",		0,	0,
+		stsizeof(ipf_main_softc_t, ipf_active),
+		IPFT_RDONLY,		NULL,	NULL },
+	{ { (void *)offsetof(ipf_main_softc_t, ipf_control_forwarding) },
+		"control_forwarding",	0, 1,
+		stsizeof(ipf_main_softc_t, ipf_control_forwarding),
+		0,			NULL,	NULL },
+	{ { (void *)offsetof(ipf_main_softc_t, ipf_update_ipid) },
+		"update_ipid",		0,	1,
+		stsizeof(ipf_main_softc_t, ipf_update_ipid),
+		0,			NULL,	NULL },
+	{ { (void *)offsetof(ipf_main_softc_t, ipf_chksrc) },
+		"chksrc",		0,	1,
+		stsizeof(ipf_main_softc_t, ipf_chksrc),
+		0,			NULL,	NULL },
+	{ { (void *)offsetof(ipf_main_softc_t, ipf_minttl) },
+		"min_ttl",		0,	1,
+		stsizeof(ipf_main_softc_t, ipf_minttl),
+		0,			NULL,	NULL },
+	{ { (void *)offsetof(ipf_main_softc_t, ipf_icmpminfragmtu) },
+		"icmp_minfragmtu",	0,	1,
+		stsizeof(ipf_main_softc_t, ipf_icmpminfragmtu),
+		0,			NULL,	NULL },
+	{ { (void *)offsetof(ipf_main_softc_t, ipf_pass) },
+		"default_pass",		0,	0xffffffff,
+		stsizeof(ipf_main_softc_t, ipf_pass),
+		0,			NULL,	NULL },
+	{ { (void *)offsetof(ipf_main_softc_t, ipf_tcpidletimeout) },
+		"tcp_idle_timeout",	1,	0x7fffffff,
+		stsizeof(ipf_main_softc_t, ipf_tcpidletimeout),
+		0,			NULL,	ipf_settimeout },
+	{ { (void *)offsetof(ipf_main_softc_t, ipf_tcpclosewait) },
+		"tcp_close_wait",	1,	0x7fffffff,
+		stsizeof(ipf_main_softc_t, ipf_tcpclosewait),
+		0,			NULL,	ipf_settimeout },
+	{ { (void *)offsetof(ipf_main_softc_t, ipf_tcplastack) },
+		"tcp_last_ack",		1,	0x7fffffff,
+		stsizeof(ipf_main_softc_t, ipf_tcplastack),
+		0,			NULL,	ipf_settimeout },
+	{ { (void *)offsetof(ipf_main_softc_t, ipf_tcptimeout) },
+		"tcp_timeout",		1,	0x7fffffff,
+		stsizeof(ipf_main_softc_t, ipf_tcptimeout),
+		0,			NULL,	ipf_settimeout },
+	{ { (void *)offsetof(ipf_main_softc_t, ipf_tcpsynsent) },
+		"tcp_syn_sent",		1,	0x7fffffff,
+		stsizeof(ipf_main_softc_t, ipf_tcpsynsent),
+		0,			NULL,	ipf_settimeout },
+	{ { (void *)offsetof(ipf_main_softc_t, ipf_tcpsynrecv) },
+		"tcp_syn_received",	1,	0x7fffffff,
+		stsizeof(ipf_main_softc_t, ipf_tcpsynrecv),
+		0,			NULL,	ipf_settimeout },
+	{ { (void *)offsetof(ipf_main_softc_t, ipf_tcpclosed) },
+		"tcp_closed",		1,	0x7fffffff,
+		stsizeof(ipf_main_softc_t, ipf_tcpclosed),
+		0,			NULL,	ipf_settimeout },
+	{ { (void *)offsetof(ipf_main_softc_t, ipf_tcphalfclosed) },
+		"tcp_half_closed",	1,	0x7fffffff,
+		stsizeof(ipf_main_softc_t, ipf_tcphalfclosed),
+		0,			NULL,	ipf_settimeout },
+	{ { (void *)offsetof(ipf_main_softc_t, ipf_tcptimewait) },
+		"tcp_time_wait",	1,	0x7fffffff,
+		stsizeof(ipf_main_softc_t, ipf_tcptimewait),
+		0,			NULL,	ipf_settimeout },
+	{ { (void *)offsetof(ipf_main_softc_t, ipf_udptimeout) },
+		"udp_timeout",		1,	0x7fffffff,
+		stsizeof(ipf_main_softc_t, ipf_udptimeout),
+		0,			NULL,	ipf_settimeout },
+	{ { (void *)offsetof(ipf_main_softc_t, ipf_udpacktimeout) },
+		"udp_ack_timeout",	1,	0x7fffffff,
+		stsizeof(ipf_main_softc_t, ipf_udpacktimeout),
+		0,			NULL,	ipf_settimeout },
+	{ { (void *)offsetof(ipf_main_softc_t, ipf_icmptimeout) },
+		"icmp_timeout",		1,	0x7fffffff,
+		stsizeof(ipf_main_softc_t, ipf_icmptimeout),
+		0,			NULL,	ipf_settimeout },
+	{ { (void *)offsetof(ipf_main_softc_t, ipf_icmpacktimeout) },
+		"icmp_ack_timeout",	1,	0x7fffffff,
+		stsizeof(ipf_main_softc_t, ipf_icmpacktimeout),
+		0,			NULL,	ipf_settimeout },
+	{ { (void *)offsetof(ipf_main_softc_t, ipf_iptimeout) },
+		"ip_timeout",		1,	0x7fffffff,
+		stsizeof(ipf_main_softc_t, ipf_iptimeout),
+		0,			NULL,	ipf_settimeout },
+#if defined(INSTANCES) && defined(_KERNEL)
+	{ { (void *)offsetof(ipf_main_softc_t, ipf_get_loopback) },
+		"intercept_loopback",	0,	1,
+		stsizeof(ipf_main_softc_t, ipf_get_loopback),
+		0,			NULL,	ipf_set_loopback },
 #endif
-	{ "", NULL, NULL }
+	{ { 0 },
+		NULL,			0,	0,
+		0,
+		0,			NULL,	NULL }
 };
 
 
@@ -346,39 +427,41 @@
  * current packet.  There are different routines for the same protocol
  * for each of IPv4 and IPv6.  Adding a new protocol, for which there
  * will "special" inspection for setup, is now more easily done by adding
- * a new routine and expanding the frpr_ipinit*() function rather than by
+ * a new routine and expanding the ipf_pr_ipinit*() function rather than by
  * 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 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));
+static	INLINE int	ipf_pr_ah6 __P((fr_info_t *));
+static	INLINE void	ipf_pr_esp6 __P((fr_info_t *));
+static	INLINE void	ipf_pr_gre6 __P((fr_info_t *));
+static	INLINE void	ipf_pr_udp6 __P((fr_info_t *));
+static	INLINE void	ipf_pr_tcp6 __P((fr_info_t *));
+static	INLINE void	ipf_pr_icmp6 __P((fr_info_t *));
+static	INLINE void	ipf_pr_ipv6hdr __P((fr_info_t *));
+static	INLINE void	ipf_pr_short6 __P((fr_info_t *, int));
+static	INLINE int	ipf_pr_hopopts6 __P((fr_info_t *));
+static	INLINE int	ipf_pr_mobility6 __P((fr_info_t *));
+static	INLINE int	ipf_pr_routing6 __P((fr_info_t *));
+static	INLINE int	ipf_pr_dstopts6 __P((fr_info_t *));
+static	INLINE int	ipf_pr_fragment6 __P((fr_info_t *));
+static	INLINE struct ip6_ext *ipf_pr_ipv6exthdr __P((fr_info_t *, int, int));
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    frpr_short6                                                 */
+/* Function:    ipf_pr_short6                                               */
 /* Returns:     void                                                        */
-/* Parameters:  fin(I) - pointer to packet information                      */
+/* Parameters:  fin(I)  - pointer to packet information                     */
+/*              xmin(I) - minimum header size                               */
 /*                                                                          */
 /* IPv6 Only                                                                */
 /* This is function enforces the 'is a packet too short to be legit' rule   */
 /* for IPv6 and marks the packet with FI_SHORT if so.  See function comment */
-/* for frpr_short() for more details.                                       */
+/* for ipf_pr_short() for more details.                                     */
 /* ------------------------------------------------------------------------ */
-static INLINE void frpr_short6(fin, xmin)
-fr_info_t *fin;
-int xmin;
+static INLINE void
+ipf_pr_short6(fin, xmin)
+	fr_info_t *fin;
+	int xmin;
 {
 
 	if (fin->fin_dlen < xmin)
@@ -387,8 +470,8 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    frpr_ipv6hdr                                                */
-/* Returns:     int    - 0 = IPv6 packet intact, -1 = packet lost           */
+/* Function:    ipf_pr_ipv6hdr                                              */
+/* Returns:     void                                                        */
 /* Parameters:  fin(I) - pointer to packet information                      */
 /*                                                                          */
 /* IPv6 Only                                                                */
@@ -397,8 +480,9 @@
 /* analyzer may pullup or free the packet itself so we need to be vigiliant */
 /* of that possibility arising.                                             */
 /* ------------------------------------------------------------------------ */
-static INLINE int frpr_ipv6hdr(fin)
-fr_info_t *fin;
+static INLINE void
+ipf_pr_ipv6hdr(fin)
+	fr_info_t *fin;
 {
 	ip6_t *ip6 = (ip6_t *)fin->fin_ip;
 	int p, go = 1, i, hdrcount;
@@ -412,57 +496,68 @@
 	fi->fi_auth = 0;
 
 	p = ip6->ip6_nxt;
+	fin->fin_crc = p;
 	fi->fi_ttl = ip6->ip6_hlim;
 	fi->fi_src.in6 = ip6->ip6_src;
+	fin->fin_crc += fi->fi_src.i6[0];
+	fin->fin_crc += fi->fi_src.i6[1];
+	fin->fin_crc += fi->fi_src.i6[2];
+	fin->fin_crc += fi->fi_src.i6[3];
 	fi->fi_dst.in6 = ip6->ip6_dst;
-	fin->fin_id = (u_short)(ip6->ip6_flow & 0xffff);
+	fin->fin_crc += fi->fi_dst.i6[0];
+	fin->fin_crc += fi->fi_dst.i6[1];
+	fin->fin_crc += fi->fi_dst.i6[2];
+	fin->fin_crc += fi->fi_dst.i6[3];
+	fin->fin_id = 0;
+	if (IN6_IS_ADDR_MULTICAST(&fi->fi_dst.in6))
+		fin->fin_flx |= FI_MULTICAST|FI_MBCAST;
 
 	hdrcount = 0;
-	while (go && !(fin->fin_flx & (FI_BAD|FI_SHORT))) {
+	while (go && !(fin->fin_flx & FI_SHORT)) {
 		switch (p)
 		{
 		case IPPROTO_UDP :
-			frpr_udp6(fin);
+			ipf_pr_udp6(fin);
 			go = 0;
 			break;
 
 		case IPPROTO_TCP :
-			frpr_tcp6(fin);
+			ipf_pr_tcp6(fin);
 			go = 0;
 			break;
 
 		case IPPROTO_ICMPV6 :
-			frpr_icmp6(fin);
+			ipf_pr_icmp6(fin);
 			go = 0;
 			break;
 
 		case IPPROTO_GRE :
-			frpr_gre6(fin);
+			ipf_pr_gre6(fin);
 			go = 0;
 			break;
 
 		case IPPROTO_HOPOPTS :
-			p = frpr_hopopts6(fin);
+			p = ipf_pr_hopopts6(fin);
 			break;
 
 		case IPPROTO_MOBILITY :
-			p = frpr_mobility6(fin);
+			p = ipf_pr_mobility6(fin);
 			break;
 
 		case IPPROTO_DSTOPTS :
-			p = frpr_dstopts6(fin);
+			p = ipf_pr_dstopts6(fin);
 			break;
 
 		case IPPROTO_ROUTING :
-			p = frpr_routing6(fin);
+			p = ipf_pr_routing6(fin);
 			break;
 
 		case IPPROTO_AH :
-			p = frpr_ah6(fin);
+			p = ipf_pr_ah6(fin);
 			break;
 
 		case IPPROTO_ESP :
-			frpr_esp6(fin);
+			ipf_pr_esp6(fin);
 			go = 0;
 			break;
 
@@ -480,7 +575,13 @@
 			break;
 
 		case IPPROTO_FRAGMENT :
-			p = frpr_fragment6(fin);
+			p = ipf_pr_fragment6(fin);
+			/*
+			 * Given that the only fragments we want to let through
+			 * (where fin_off != 0) are those where the non-first
+			 * fragments only have data, we can safely stop looking
+			 * at headers if this is a non-leading fragment.
+			 */
 			if (fin->fin_off != 0)
 				go = 0;
 			break;
@@ -501,28 +602,44 @@
 		 * header.
 		 */
 		if ((go != 0) && (p != IPPROTO_NONE) &&
-		    (frpr_pullup(fin, 0) == -1)) {
+		    (ipf_pr_pullup(fin, 0) == -1)) {
 			p = IPPROTO_NONE;
-			go = 0;
+			break;
 		}
 	}
-	fi->fi_p = p;
 
 	/*
-	 * Some of the above functions, like frpr_esp6(), can call fr_pullup
+	 * Some of the above functions, like ipf_pr_esp6(), can call ipf_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.
+	 * expects us to return if there is a problem with ipf_pullup.
 	 */
-	if (fin->fin_m == NULL)
-		return -1;
+	if (fin->fin_m == NULL) {
+		ipf_main_softc_t *softc = fin->fin_main_soft;
 
-	return 0;
+		LBUMPD(ipf_stats[fin->fin_out], fr_v6_bad);
+		return;
+	}
+
+	fi->fi_p = p;
+
+	/*
+	 * IPv6 fragment case 1 - see comment for ipf_pr_fragment6().
+	 * "go != 0" imples the above loop hasn't arrived at a layer 4 header.
+	 */
+	if ((go != 0) && (fin->fin_flx & FI_FRAG) && (fin->fin_off == 0)) {
+		ipf_main_softc_t *softc = fin->fin_main_soft;
+
+		fin->fin_flx |= FI_BAD;
+		LBUMPD(ipf_stats[fin->fin_out], fr_v6_badfrag);
+		LBUMP(ipf_stats[fin->fin_out].fr_v6_bad);
+	}
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    frpr_ipv6exthdr                                             */
-/* Returns:     int    - value of the next header or IPPROTO_NONE if error  */
+/* Function:    ipf_pr_ipv6exthdr                                           */
+/* Returns:     struct ip6_ext * - pointer to the start of the next header  */
+/*                                 or NULL if there is a prolblem.          */
 /* Parameters:  fin(I)      - pointer to packet information                 */
 /*              multiple(I) - flag indicating yes/no if multiple occurances */
 /*                            of this extension header are allowed.         */
@@ -529,11 +646,17 @@
 /*              proto(I)    - protocol number for this extension header     */
 /*                                                                          */
 /* IPv6 Only                                                                */
+/* This function embodies a number of common checks that all IPv6 extension */
+/* headers must be subjected to.  For example, making sure the packet is    */
+/* big enough for it to be in, checking if it is repeated and setting a     */
+/* flag to indicate its presence.                                           */
 /* ------------------------------------------------------------------------ */
-static INLINE int frpr_ipv6exthdr(fin, multiple, proto)
-fr_info_t *fin;
-int multiple, proto;
+static INLINE struct ip6_ext *
+ipf_pr_ipv6exthdr(fin, multiple, proto)
+	fr_info_t *fin;
+	int multiple, proto;
 {
+	ipf_main_softc_t *softc = fin->fin_main_soft;
 	struct ip6_ext *hdr;
 	u_short shift;
 	int i;
@@ -543,11 +666,14 @@
 				/* 8 is default length of extension hdr */
 	if ((fin->fin_dlen - 8) < 0) {
 		fin->fin_flx |= FI_SHORT;
-		return IPPROTO_NONE;
+		LBUMPD(ipf_stats[fin->fin_out], fr_v6_ext_short);
+		return NULL;
 	}
 
-	if (frpr_pullup(fin, 8) == -1)
-		return IPPROTO_NONE;
+	if (ipf_pr_pullup(fin, 8) == -1) {
+		LBUMPD(ipf_stats[fin->fin_out], fr_v6_ext_pullup);
+		return NULL;
+	}
 
 	hdr = fin->fin_dp;
 	switch (proto)
@@ -562,9 +688,21 @@
 
 	if (shift > fin->fin_dlen) {	/* Nasty extension header length? */
 		fin->fin_flx |= FI_BAD;
-		return IPPROTO_NONE;
+		LBUMPD(ipf_stats[fin->fin_out], fr_v6_ext_hlen);
+		return NULL;
 	}
 
+	fin->fin_dp = (char *)fin->fin_dp + shift;
+	fin->fin_dlen -= shift;
+
+	/*
+	 * If we have seen a fragment header, do not set any flags to indicate
+	 * the presence of this extension header as it has no impact on the
+	 * end result until after it has been defragmented.
+	 */
+	if (fin->fin_flx & FI_FRAG)
+		return hdr;
+
 	for (i = 0; ip6exthdr[i].ol_bit != 0; i++)
 		if (ip6exthdr[i].ol_val == proto) {
 			/*
@@ -578,16 +716,12 @@
 			break;
 		}
 
-	fin->fin_exthdr = fin->fin_dp;
-	fin->fin_dp = (char *)fin->fin_dp + shift;
-	fin->fin_dlen -= shift;
-
-	return hdr->ip6e_nxt;
+	return hdr;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    frpr_hopopts6                                               */
+/* Function:    ipf_pr_hopopts6                                             */
 /* Returns:     int    - value of the next header or IPPROTO_NONE if error  */
 /* Parameters:  fin(I) - pointer to packet information                      */
 /*                                                                          */
@@ -594,15 +728,21 @@
 /* IPv6 Only                                                                */
 /* This is function checks pending hop by hop options extension header      */
 /* ------------------------------------------------------------------------ */
-static INLINE int frpr_hopopts6(fin)
-fr_info_t *fin;
+static INLINE int
+ipf_pr_hopopts6(fin)
+	fr_info_t *fin;
 {
-	return frpr_ipv6exthdr(fin, 0, IPPROTO_HOPOPTS);
+	struct ip6_ext *hdr;
+
+	hdr = ipf_pr_ipv6exthdr(fin, 0, IPPROTO_HOPOPTS);
+	if (hdr == NULL)
+		return IPPROTO_NONE;
+	return hdr->ip6e_nxt;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    frpr_mobility6                                              */
+/* Function:    ipf_pr_mobility6                                            */
 /* Returns:     int    - value of the next header or IPPROTO_NONE if error  */
 /* Parameters:  fin(I) - pointer to packet information                      */
 /*                                                                          */
@@ -609,15 +749,21 @@
 /* IPv6 Only                                                                */
 /* This is function checks the IPv6 mobility extension header               */
 /* ------------------------------------------------------------------------ */
-static INLINE int frpr_mobility6(fin)
-fr_info_t *fin;
+static INLINE int
+ipf_pr_mobility6(fin)
+	fr_info_t *fin;
 {
-	return frpr_ipv6exthdr(fin, 0, IPPROTO_MOBILITY);
+	struct ip6_ext *hdr;
+
+	hdr = ipf_pr_ipv6exthdr(fin, 0, IPPROTO_MOBILITY);
+	if (hdr == NULL)
+		return IPPROTO_NONE;
+	return hdr->ip6e_nxt;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    frpr_routing6                                               */
+/* Function:    ipf_pr_routing6                                             */
 /* Returns:     int    - value of the next header or IPPROTO_NONE if error  */
 /* Parameters:  fin(I) - pointer to packet information                      */
 /*                                                                          */
@@ -624,35 +770,42 @@
 /* IPv6 Only                                                                */
 /* This is function checks pending routing extension header                 */
 /* ------------------------------------------------------------------------ */
-static INLINE int frpr_routing6(fin)
-fr_info_t *fin;
+static INLINE int
+ipf_pr_routing6(fin)
+	fr_info_t *fin;
 {
-	struct ip6_ext *hdr;
+	struct ip6_routing *hdr;
 
-	if (frpr_ipv6exthdr(fin, 0, IPPROTO_ROUTING) == IPPROTO_NONE)
+	hdr = (struct ip6_routing *)ipf_pr_ipv6exthdr(fin, 0, IPPROTO_ROUTING);
+	if (hdr == NULL)
 		return IPPROTO_NONE;
-	hdr = fin->fin_exthdr;
 
-	if ((hdr->ip6e_len & 1) != 0) {
+	switch (hdr->ip6r_type)
+	{
+	case 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.
+		 * Nasty extension header 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;
+		if (((hdr->ip6r_len >> 1) < hdr->ip6r_segleft) ||
+		    (hdr->ip6r_segleft && (hdr->ip6r_len & 1))) {
+			ipf_main_softc_t *softc = fin->fin_main_soft;
+
+			fin->fin_flx |= FI_BAD;
+			LBUMPD(ipf_stats[fin->fin_out], fr_v6_rh_bad);
+			return IPPROTO_NONE;
+		}
+		break;
+
+	default :
+		break;
 	}
 
-	return hdr->ip6e_nxt;
+	return hdr->ip6r_nxt;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    frpr_fragment6                                              */
+/* Function:    ipf_pr_fragment6                                            */
 /* Returns:     int    - value of the next header or IPPROTO_NONE if error  */
 /* Parameters:  fin(I) - pointer to packet information                      */
 /*                                                                          */
@@ -659,68 +812,100 @@
 /* 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.      */
+/* Fragments in IPv6 are extraordinarily difficult to deal with - much more */
+/* so than in IPv4.  There are 5 cases of fragments with IPv6 that all      */
+/* packets with a fragment header can fit into.  They are as follows:       */
+/*                                                                          */
+/* 1.  [IPv6][0-n EH][FH][0-n EH] (no L4HDR present)                        */
+/* 2.  [IPV6][0-n EH][FH][0-n EH][L4HDR part] (short)                       */
+/* 3.  [IPV6][0-n EH][FH][L4HDR part][0-n data] (short)                     */
+/* 4.  [IPV6][0-n EH][FH][0-n EH][L4HDR][0-n data]                          */
+/* 5.  [IPV6][0-n EH][FH][data]                                             */
+/*                                                                          */
+/* IPV6 = IPv6 header, FH = Fragment Header,                                */
+/* 0-n EH = 0 or more extension headers, 0-n data = 0 or more bytes of data */
+/*                                                                          */
+/* Packets that match 1, 2, 3 will be dropped as the only reasonable        */
+/* scenario in which they happen is in extreme circumstances that are most  */
+/* likely to be an indication of an attack rather than normal traffic.      */
+/* A type 3 packet may be sent by an attacked after a type 4 packet.  There */
+/* are two rules that can be used to guard against type 3 packets: L4       */
+/* headers must always be in a packet that has the offset field set to 0    */
+/* and no packet is allowed to overlay that where offset = 0.               */
 /* ------------------------------------------------------------------------ */
-static INLINE int frpr_fragment6(fin)
-fr_info_t *fin;
+static INLINE int
+ipf_pr_fragment6(fin)
+	fr_info_t *fin;
 {
+	ipf_main_softc_t *softc = fin->fin_main_soft;
 	struct ip6_frag *frag;
-	int extoff;
 
 	fin->fin_flx |= FI_FRAG;
 
-	if (frpr_ipv6exthdr(fin, 0, IPPROTO_FRAGMENT) == IPPROTO_NONE)
+	frag = (struct ip6_frag *)ipf_pr_ipv6exthdr(fin, 0, IPPROTO_FRAGMENT);
+	if (frag == NULL) {
+		LBUMPD(ipf_stats[fin->fin_out], fr_v6_frag_bad);
 		return IPPROTO_NONE;
+	}
 
-	extoff = (char *)fin->fin_exthdr - (char *)fin->fin_dp;
-
-	if (frpr_pullup(fin, sizeof(*frag)) == -1)
-		return IPPROTO_NONE;
-
-	fin->fin_exthdr = (char *)fin->fin_dp + extoff;
-	frag = fin->fin_exthdr;
-	/*
-	 * Fragment but no fragmentation info set?  Bad packet...
-	 */
-	if (frag->ip6f_offlg == 0) {
-		fin->fin_flx |= FI_BAD;
-		return IPPROTO_NONE;
+	if ((frag->ip6f_offlg & IP6F_MORE_FRAG) != 0) {
+		/*
+		 * Any fragment that isn't the last fragment must have its
+		 * length as a multiple of 8.
+		 */
+		if ((fin->fin_plen & 7) != 0)
+			fin->fin_flx |= FI_BAD;
 	}
 
+	fin->fin_fraghdr = frag;
+	fin->fin_id = frag->ip6f_ident;
 	fin->fin_off = ntohs(frag->ip6f_offlg & IP6F_OFF_MASK);
-	fin->fin_off <<= 3;
 	if (fin->fin_off != 0)
 		fin->fin_flx |= FI_FRAGBODY;
 
-	fin->fin_dp = (char *)fin->fin_dp + sizeof(*frag);
-	fin->fin_dlen -= sizeof(*frag);
+	/*
+	 * Jumbograms aren't handled, so the max. length is 64k
+	 */
+	if ((fin->fin_off << 3) + fin->fin_dlen > 65535)
+		  fin->fin_flx |= FI_BAD;
 
+	/*
+	 * We don't know where the transport layer header (or whatever is next
+	 * is), as it could be behind destination options (amongst others) so
+	 * return the fragment header as the type of packet this is.  Note that
+	 * this effectively disables the fragment cache for > 1 protocol at a
+	 * time.
+	 */
 	return frag->ip6f_nxt;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    frpr_dstopts6                                               */
+/* Function:    ipf_pr_dstopts6                                             */
 /* Returns:     int    - value of the next header or IPPROTO_NONE if error  */
 /* Parameters:  fin(I) - pointer to packet information                      */
-/*              nextheader(I) - stores next header value                    */
 /*                                                                          */
 /* IPv6 Only                                                                */
 /* This is function checks pending destination options extension header     */
 /* ------------------------------------------------------------------------ */
-static INLINE int frpr_dstopts6(fin)
-fr_info_t *fin;
+static INLINE int
+ipf_pr_dstopts6(fin)
+	fr_info_t *fin;
 {
-	return frpr_ipv6exthdr(fin, 1, IPPROTO_DSTOPTS);
+	ipf_main_softc_t *softc = fin->fin_main_soft;
+	struct ip6_ext *hdr;
+
+	hdr = ipf_pr_ipv6exthdr(fin, 0, IPPROTO_DSTOPTS);
+	if (hdr == NULL) {
+		LBUMPD(ipf_stats[fin->fin_out], fr_v6_dst_bad);
+		return IPPROTO_NONE;
+	}
+	return hdr->ip6e_nxt;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    frpr_icmp6                                                  */
+/* Function:    ipf_pr_icmp6                                                */
 /* Returns:     void                                                        */
 /* Parameters:  fin(I) - pointer to packet information                      */
 /*                                                                          */
@@ -728,14 +913,19 @@
 /* This routine is mainly concerned with determining the minimum valid size */
 /* for an ICMPv6 packet.                                                    */
 /* ------------------------------------------------------------------------ */
-static INLINE void frpr_icmp6(fin)
-fr_info_t *fin;
+static INLINE void
+ipf_pr_icmp6(fin)
+	fr_info_t *fin;
 {
 	int minicmpsz = sizeof(struct icmp6_hdr);
 	struct icmp6_hdr *icmp6;
 
-	if (frpr_pullup(fin, ICMP6ERR_MINPKTLEN - sizeof(ip6_t)) == -1)
+	if (ipf_pr_pullup(fin, ICMP6ERR_MINPKTLEN - sizeof(ip6_t)) == -1) {
+		ipf_main_softc_t *softc = fin->fin_main_soft;
+
+		LBUMPD(ipf_stats[fin->fin_out], fr_v6_icmp6_pullup);
 		return;
+	}
 
 	if (fin->fin_dlen > 1) {
 		ip6_t *ip6;
@@ -744,12 +934,18 @@
 
 		fin->fin_data[0] = *(u_short *)icmp6;
 
+		if ((icmp6->icmp6_type & ICMP6_INFOMSG_MASK) != 0)
+			fin->fin_flx |= FI_ICMPQUERY;
+
 		switch (icmp6->icmp6_type)
 		{
 		case ICMP6_ECHO_REPLY :
 		case ICMP6_ECHO_REQUEST :
+			if (fin->fin_dlen >= 6)
+				fin->fin_data[1] = icmp6->icmp6_id;
 			minicmpsz = ICMP6ERR_MINPKTLEN - sizeof(ip6_t);
 			break;
+
 		case ICMP6_DST_UNREACH :
 		case ICMP6_PACKET_TOO_BIG :
 		case ICMP6_TIME_EXCEEDED :
@@ -760,10 +956,13 @@
 				break;
 
 			if (M_LEN(fin->fin_m) < fin->fin_plen) {
-				if (fr_coalesce(fin) != 1)
+				if (ipf_coalesce(fin) != 1)
 					return;
 			}
 
+			if (ipf_pr_pullup(fin, ICMP6ERR_MINPKTLEN) == -1)
+				return;
+
 			/*
 			 * If the destination of this packet doesn't match the
 			 * source of the original packet then this packet is
@@ -774,7 +973,6 @@
 			if (IP6_NEQ(&fin->fin_fi.fi_dst,
 				    (i6addr_t *)&ip6->ip6_src))
 				fin->fin_flx |= FI_BAD;
-
 			break;
 		default :
 			break;
@@ -781,12 +979,19 @@
 		}
 	}
 
-	frpr_short6(fin, minicmpsz);
+	ipf_pr_short6(fin, minicmpsz);
+	if ((fin->fin_flx & (FI_SHORT|FI_BAD)) == 0) {
+		u_char p = fin->fin_p;
+
+		fin->fin_p = IPPROTO_ICMPV6;
+		ipf_checkv6sum(fin);
+		fin->fin_p = p;
+	}
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    frpr_udp6                                                   */
+/* Function:    ipf_pr_udp6                                                 */
 /* Returns:     void                                                        */
 /* Parameters:  fin(I) - pointer to packet information                      */
 /*                                                                          */
@@ -794,17 +999,16 @@
 /* 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;
+static INLINE void
+ipf_pr_udp6(fin)
+	fr_info_t *fin;
 {
 
-	frpr_short6(fin, sizeof(struct udphdr));
-
-	if (frpr_udpcommon(fin) == 0) {
+	if (ipf_pr_udpcommon(fin) == 0) {
 		u_char p = fin->fin_p;
 
 		fin->fin_p = IPPROTO_UDP;
-		fr_checkv6sum(fin);
+		ipf_checkv6sum(fin);
 		fin->fin_p = p;
 	}
 }
@@ -811,7 +1015,7 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    frpr_tcp6                                                   */
+/* Function:    ipf_pr_tcp6                                                 */
 /* Returns:     void                                                        */
 /* Parameters:  fin(I) - pointer to packet information                      */
 /*                                                                          */
@@ -819,17 +1023,16 @@
 /* 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;
+static INLINE void
+ipf_pr_tcp6(fin)
+	fr_info_t *fin;
 {
 
-	frpr_short6(fin, sizeof(struct tcphdr));
-
-	if (frpr_tcpcommon(fin) == 0) {
+	if (ipf_pr_tcpcommon(fin) == 0) {
 		u_char p = fin->fin_p;
 
 		fin->fin_p = IPPROTO_TCP;
-		fr_checkv6sum(fin);
+		ipf_checkv6sum(fin);
 		fin->fin_p = p;
 	}
 }
@@ -836,7 +1039,7 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    frpr_esp6                                                   */
+/* Function:    ipf_pr_esp6                                                 */
 /* Returns:     void                                                        */
 /* Parameters:  fin(I) - pointer to packet information                      */
 /*                                                                          */
@@ -847,19 +1050,23 @@
 /* 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;
+static INLINE void
+ipf_pr_esp6(fin)
+	fr_info_t *fin;
 {
 
-	frpr_short6(fin, sizeof(grehdr_t));
+	if ((fin->fin_off == 0) && (ipf_pr_pullup(fin, 8) == -1)) {
+		ipf_main_softc_t *softc = fin->fin_main_soft;
 
-	(void) frpr_pullup(fin, 8);
+		LBUMPD(ipf_stats[fin->fin_out], fr_v6_esp_pullup);
+		return;
+	}
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    frpr_ah6                                                    */
-/* Returns:     void                                                        */
+/* Function:    ipf_pr_ah6                                                  */
+/* Returns:     int    - value of the next header or IPPROTO_NONE if error  */
 /* Parameters:  fin(I) - pointer to packet information                      */
 /*                                                                          */
 /* IPv6 Only                                                                */
@@ -867,37 +1074,51 @@
 /* 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;
+static INLINE int
+ipf_pr_ah6(fin)
+	fr_info_t *fin;
 {
 	authhdr_t *ah;
 
-	frpr_short6(fin, 12);
+	fin->fin_flx |= FI_AH;
 
-	if (frpr_pullup(fin, sizeof(*ah)) == -1)
+	ah = (authhdr_t *)ipf_pr_ipv6exthdr(fin, 0, IPPROTO_HOPOPTS);
+	if (ah == NULL) {
+		ipf_main_softc_t *softc = fin->fin_main_soft;
+
+		LBUMPD(ipf_stats[fin->fin_out], fr_v6_ah_bad);
 		return IPPROTO_NONE;
+	}
 
-	ah = (authhdr_t *)fin->fin_dp;
+	ipf_pr_short6(fin, sizeof(*ah));
+
+	/*
+	 * No need for another pullup, ipf_pr_ipv6exthdr() will pullup
+	 * enough data to satisfy ah_next (the very first one.)
+	 */
 	return ah->ah_next;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    frpr_gre6                                                   */
+/* Function:    ipf_pr_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;
+static INLINE void
+ipf_pr_gre6(fin)
+	fr_info_t *fin;
 {
 	grehdr_t *gre;
 
-	frpr_short6(fin, sizeof(grehdr_t));
+	if (ipf_pr_pullup(fin, sizeof(grehdr_t)) == -1) {
+		ipf_main_softc_t *softc = fin->fin_main_soft;
 
-	if (frpr_pullup(fin, sizeof(grehdr_t)) == -1)
+		LBUMPD(ipf_stats[fin->fin_out], fr_v6_gre_pullup);
 		return;
+	}
 
 	gre = fin->fin_dp;
 	if (GRE_REV(gre->gr_flags) == 1)
@@ -907,13 +1128,13 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    frpr_pullup                                                 */
+/* Function:    ipf_pr_pullup                                               */
 /* Returns:     int     - 0 == pullup succeeded, -1 == failure              */
 /* Parameters:  fin(I)  - pointer to packet information                     */
 /*              plen(I) - length (excluding L3 header) to pullup            */
 /*                                                                          */
 /* 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,             */
+/* to ipf_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   */
@@ -924,23 +1145,32 @@
 /* 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;
+int
+ipf_pr_pullup(fin, plen)
+	fr_info_t *fin;
+	int plen;
 {
+	ipf_main_softc_t *softc = fin->fin_main_soft;
+
 	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 (M_LEN(fin->fin_m) < plen + fin->fin_ipoff) {
 #if defined(_KERNEL)
-			if (fr_pullup(fin->fin_m, fin, plen) == NULL)
+			if (ipf_pullup(fin->fin_m, fin, plen) == NULL) {
+				DT(ipf_pullup_fail);
+				LBUMP(ipf_stats[fin->fin_out].fr_pull[1]);
 				return -1;
+			}
+			LBUMP(ipf_stats[fin->fin_out].fr_pull[0]);
 #else
+			LBUMP(ipf_stats[fin->fin_out].fr_pull[1]);
 			/*
-			 * Fake fr_pullup failing
+			 * Fake ipf_pullup failing
 			 */
+			fin->fin_reason = FRB_PULLUP;
 			*fin->fin_mp = NULL;
 			fin->fin_m = NULL;
 			fin->fin_ip = NULL;
@@ -953,7 +1183,7 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    frpr_short                                                  */
+/* Function:    ipf_pr_short                                                */
 /* Returns:     void                                                        */
 /* Parameters:  fin(I)  - pointer to packet information                     */
 /*              xmin(I) - minimum header size                               */
@@ -964,9 +1194,10 @@
 /* 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, xmin)
-fr_info_t *fin;
-int xmin;
+static INLINE void
+ipf_pr_short(fin, xmin)
+	fr_info_t *fin;
+	int xmin;
 {
 
 	if (fin->fin_off == 0) {
@@ -979,7 +1210,7 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    frpr_icmp                                                   */
+/* Function:    ipf_pr_icmp                                                 */
 /* Returns:     void                                                        */
 /* Parameters:  fin(I) - pointer to packet information                      */
 /*                                                                          */
@@ -991,110 +1222,111 @@
 /*                                                                          */
 /* XXX - other ICMP sanity checks?                                          */
 /* ------------------------------------------------------------------------ */
-static INLINE void frpr_icmp(fin)
-fr_info_t *fin;
+static INLINE void
+ipf_pr_icmp(fin)
+	fr_info_t *fin;
 {
+	ipf_main_softc_t *softc = fin->fin_main_soft;
 	int minicmpsz = sizeof(struct icmp);
 	icmphdr_t *icmp;
 	ip_t *oip;
 
+	ipf_pr_short(fin, ICMPERR_ICMPHLEN);
+
 	if (fin->fin_off != 0) {
-		frpr_short(fin, ICMPERR_ICMPHLEN);
+		LBUMPD(ipf_stats[fin->fin_out], fr_v4_icmp_frag);
 		return;
 	}
 
-	if (frpr_pullup(fin, ICMPERR_ICMPHLEN) == -1)
+	if (ipf_pr_pullup(fin, ICMPERR_ICMPHLEN) == -1) {
+		LBUMPD(ipf_stats[fin->fin_out], fr_v4_icmp_pullup);
 		return;
+	}
 
-	if (fin->fin_dlen > 1) {
-		icmp = fin->fin_dp;
+	icmp = fin->fin_dp;
 
-		fin->fin_data[0] = *(u_short *)icmp;
+	fin->fin_data[0] = *(u_short *)icmp;
+	fin->fin_data[1] = icmp->icmp_id;
 
-		if (fin->fin_dlen >= 6)				/* ID field */
-			fin->fin_data[1] = icmp->icmp_id;
+	switch (icmp->icmp_type)
+	{
+	case ICMP_ECHOREPLY :
+	case ICMP_ECHO :
+	/* Router discovery messaes - RFC 1256 */
+	case ICMP_ROUTERADVERT :
+	case ICMP_ROUTERSOLICIT :
+		fin->fin_flx |= FI_ICMPQUERY;
+		minicmpsz = ICMP_MINLEN;
+		break;
+	/*
+	 * type(1) + code(1) + cksum(2) + id(2) seq(2) +
+	 * 3 * timestamp(3 * 4)
+	 */
+	case ICMP_TSTAMP :
+	case ICMP_TSTAMPREPLY :
+		fin->fin_flx |= FI_ICMPQUERY;
+		minicmpsz = 20;
+		break;
+	/*
+	 * type(1) + code(1) + cksum(2) + id(2) seq(2) +
+	 * mask(4)
+	 */
+	case ICMP_IREQ :
+	case ICMP_IREQREPLY :
+	case ICMP_MASKREQ :
+	case ICMP_MASKREPLY :
+		fin->fin_flx |= FI_ICMPQUERY;
+		minicmpsz = 12;
+		break;
+	/*
+	 * 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 < softc->ipf_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 (ipf_coalesce(fin) != 1) {
+			LBUMPD(ipf_stats[fin->fin_out], fr_icmp_coalesce);
+			return;
+		}
 
-		switch (icmp->icmp_type)
-		{
-		case ICMP_ECHOREPLY :
-		case ICMP_ECHO :
-		/* Router discovery messaes - RFC 1256 */
-		case ICMP_ROUTERADVERT :
-		case ICMP_ROUTERSOLICIT :
-			minicmpsz = ICMP_MINLEN;
-			break;
 		/*
-		 * type(1) + code(1) + cksum(2) + id(2) seq(2) +
-		 * 3 * timestamp(3 * 4)
+		 * ICMP error packets should not be generated for IP
+		 * packets that are a fragment that isn't the first
+		 * fragment.
 		 */
-		case ICMP_TSTAMP :
-		case ICMP_TSTAMPREPLY :
-			minicmpsz = 20;
-			break;
+		oip = (ip_t *)((char *)fin->fin_dp + ICMPERR_ICMPHLEN);
+		if ((ntohs(oip->ip_off) & IP_OFFMASK) != 0)
+			fin->fin_flx |= FI_BAD;
+
 		/*
-		 * type(1) + code(1) + cksum(2) + id(2) seq(2) +
-		 * mask(4)
+		 * If the destination of this packet doesn't match the
+		 * source of the original packet then this packet is
+		 * not correct.
 		 */
-		case ICMP_MASKREQ :
-		case ICMP_MASKREPLY :
-			minicmpsz = 12;
-			break;
-		/*
-		 * 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;
-			/*
-			 * 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;
-		}
+		if (oip->ip_src.s_addr != fin->fin_daddr)
+			fin->fin_flx |= FI_BAD;
+		break;
+	default :
+		break;
 	}
 
-	frpr_short(fin, minicmpsz);
+	ipf_pr_short(fin, minicmpsz);
 
-	if ((fin->fin_flx & FI_FRAG) == 0)
-		fr_checkv4sum(fin);
+	ipf_checkv4sum(fin);
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    frpr_tcpcommon                                              */
+/* Function:    ipf_pr_tcpcommon                                            */
 /* Returns:     int    - 0 = header ok, 1 = bad packet, -1 = buffer error   */
 /* Parameters:  fin(I) - pointer to packet information                      */
 /*                                                                          */
@@ -1103,27 +1335,35 @@
 /* If compiled with IPFILTER_CKSUM, check to see if the TCP checksum is     */
 /* valid and mark the packet as bad if not.                                 */
 /* ------------------------------------------------------------------------ */
-static INLINE int frpr_tcpcommon(fin)
-fr_info_t *fin;
+static INLINE int
+ipf_pr_tcpcommon(fin)
+	fr_info_t *fin;
 {
+	ipf_main_softc_t *softc = fin->fin_main_soft;
 	int flags, tlen;
 	tcphdr_t *tcp;
 
 	fin->fin_flx |= FI_TCPUDP;
-	if (fin->fin_off != 0)
+	if (fin->fin_off != 0) {
+		LBUMPD(ipf_stats[fin->fin_out], fr_tcp_frag);
 		return 0;
+	}
 
-	if (frpr_pullup(fin, sizeof(*tcp)) == -1)
+	if (ipf_pr_pullup(fin, sizeof(*tcp)) == -1) {
+		LBUMPD(ipf_stats[fin->fin_out], fr_tcp_pullup);
 		return -1;
+	}
+
 	tcp = fin->fin_dp;
-
 	if (fin->fin_dlen > 3) {
 		fin->fin_sport = ntohs(tcp->th_sport);
 		fin->fin_dport = ntohs(tcp->th_dport);
 	}
 
-	if ((fin->fin_flx & FI_SHORT) != 0)
+	if ((fin->fin_flx & FI_SHORT) != 0) {
+		LBUMPD(ipf_stats[fin->fin_out], fr_tcp_short);
 		return 1;
+	}
 
 	/*
 	 * Use of the TCP data offset *must* result in a value that is at
@@ -1131,6 +1371,7 @@
 	 */
 	tlen = TCP_OFF(tcp) << 2;
 	if (tlen < sizeof(tcphdr_t)) {
+		LBUMPD(ipf_stats[fin->fin_out], fr_tcp_small);
 		fin->fin_flx |= FI_BAD;
 		return 1;
 	}
@@ -1189,6 +1430,10 @@
 			fin->fin_flx |= FI_BAD;
 		}
 	}
+	if (fin->fin_flx & FI_BAD) {
+		LBUMPD(ipf_stats[fin->fin_out], fr_tcp_bad_flags);
+		return 1;
+	}
 
 	/*
 	 * At this point, it's not exactly clear what is to be gained by
@@ -1198,11 +1443,14 @@
 	 * Now if we were to analyse the header for passive fingerprinting,
 	 * then that might add some weight to adding this...
 	 */
-	if (tlen == sizeof(tcphdr_t))
+	if (tlen == sizeof(tcphdr_t)) {
 		return 0;
+	}
 
-	if (frpr_pullup(fin, tlen) == -1)
+	if (ipf_pr_pullup(fin, tlen) == -1) {
+		LBUMPD(ipf_stats[fin->fin_out], fr_tcp_pullup);
 		return -1;
+	}
 
 #if 0
 	tcp = fin->fin_dp;
@@ -1249,7 +1497,7 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    frpr_udpcommon                                              */
+/* Function:    ipf_pr_udpcommon                                            */
 /* Returns:     int    - 0 = header ok, 1 = bad packet                      */
 /* Parameters:  fin(I) - pointer to packet information                      */
 /*                                                                          */
@@ -1256,8 +1504,9 @@
 /* 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 int frpr_udpcommon(fin)
-fr_info_t *fin;
+static INLINE int
+ipf_pr_udpcommon(fin)
+	fr_info_t *fin;
 {
 	udphdr_t *udp;
 
@@ -1264,8 +1513,11 @@
 	fin->fin_flx |= FI_TCPUDP;
 
 	if (!fin->fin_off && (fin->fin_dlen > 3)) {
-		if (frpr_pullup(fin, sizeof(*udp)) == -1) {
+		if (ipf_pr_pullup(fin, sizeof(*udp)) == -1) {
+			ipf_main_softc_t *softc = fin->fin_main_soft;
+
 			fin->fin_flx |= FI_SHORT;
+			LBUMPD(ipf_stats[fin->fin_out], fr_udp_pullup);
 			return 1;
 		}
 
@@ -1280,7 +1532,7 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    frpr_tcp                                                    */
+/* Function:    ipf_pr_tcp                                                  */
 /* Returns:     void                                                        */
 /* Parameters:  fin(I) - pointer to packet information                      */
 /*                                                                          */
@@ -1287,21 +1539,20 @@
 /* IPv4 Only                                                                */
 /* Analyse the packet for IPv4/TCP properties.                              */
 /* ------------------------------------------------------------------------ */
-static INLINE void frpr_tcp(fin)
-fr_info_t *fin;
+static INLINE void
+ipf_pr_tcp(fin)
+	fr_info_t *fin;
 {
 
-	frpr_short(fin, sizeof(tcphdr_t));
+	ipf_pr_short(fin, sizeof(tcphdr_t));
 
-	if (frpr_tcpcommon(fin) == 0) {
-		if ((fin->fin_flx & FI_FRAG) == 0)
-			fr_checkv4sum(fin);
-	}
+	if (ipf_pr_tcpcommon(fin) == 0)
+		ipf_checkv4sum(fin);
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    frpr_udp                                                    */
+/* Function:    ipf_pr_udp                                                  */
 /* Returns:     void                                                        */
 /* Parameters:  fin(I) - pointer to packet information                      */
 /*                                                                          */
@@ -1308,21 +1559,20 @@
 /* IPv4 Only                                                                */
 /* Analyse the packet for IPv4/UDP properties.                              */
 /* ------------------------------------------------------------------------ */
-static INLINE void frpr_udp(fin)
-fr_info_t *fin;
+static INLINE void
+ipf_pr_udp(fin)
+	fr_info_t *fin;
 {
 
-	frpr_short(fin, sizeof(udphdr_t));
+	ipf_pr_short(fin, sizeof(udphdr_t));
 
-	if (frpr_udpcommon(fin) == 0) {
-		if ((fin->fin_flx & FI_FRAG) == 0)
-			fr_checkv4sum(fin);
-	}
+	if (ipf_pr_udpcommon(fin) == 0)
+		ipf_checkv4sum(fin);
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    frpr_esp                                                    */
+/* Function:    ipf_pr_esp                                                  */
 /* Returns:     void                                                        */
 /* Parameters:  fin(I) - pointer to packet information                      */
 /*                                                                          */
@@ -1332,21 +1582,25 @@
 /* is 32bits as well, it is not possible(?) to determine the version from a */
 /* simple packet header.                                                    */
 /* ------------------------------------------------------------------------ */
-static INLINE void frpr_esp(fin)
-fr_info_t *fin;
+static INLINE void
+ipf_pr_esp(fin)
+	fr_info_t *fin;
 {
 
 	if (fin->fin_off == 0) {
-		frpr_short(fin, 8);
-		(void) frpr_pullup(fin, 8);
+		ipf_pr_short(fin, 8);
+		if (ipf_pr_pullup(fin, 8) == -1) {
+			ipf_main_softc_t *softc = fin->fin_main_soft;
+
+			LBUMPD(ipf_stats[fin->fin_out], fr_v4_esp_pullup);
+		}
 	}
-
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    frpr_ah                                                     */
-/* Returns:     void                                                        */
+/* Function:    ipf_pr_ah                                                   */
+/* Returns:     int    - value of the next header or IPPROTO_NONE if error  */
 /* Parameters:  fin(I) - pointer to packet information                      */
 /*                                                                          */
 /* Analyse the packet for AH properties.                                    */
@@ -1353,57 +1607,82 @@
 /* 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;
+static INLINE int
+ipf_pr_ah(fin)
+	fr_info_t *fin;
 {
+	ipf_main_softc_t *softc = fin->fin_main_soft;
 	authhdr_t *ah;
 	int len;
 
-	frpr_short(fin, sizeof(*ah));
+	fin->fin_flx |= FI_AH;
+	ipf_pr_short(fin, sizeof(*ah));
 
-	if (((fin->fin_flx & FI_SHORT) != 0) || (fin->fin_off != 0))
-		return;
+	if (((fin->fin_flx & FI_SHORT) != 0) || (fin->fin_off != 0)) {
+		LBUMPD(ipf_stats[fin->fin_out], fr_v4_ah_bad);
+		return IPPROTO_NONE;
+	}
 
-	if (frpr_pullup(fin, sizeof(*ah)) == -1)
-		return;
+	if (ipf_pr_pullup(fin, sizeof(*ah)) == -1) {
+		DT(fr_v4_ah_pullup_1);
+		LBUMP(ipf_stats[fin->fin_out].fr_v4_ah_pullup);
+		return IPPROTO_NONE;
+	}
 
 	ah = (authhdr_t *)fin->fin_dp;
 
 	len = (ah->ah_plen + 2) << 2;
-	frpr_short(fin, len);
+	ipf_pr_short(fin, len);
+	if (ipf_pr_pullup(fin, len) == -1) {
+		DT(fr_v4_ah_pullup_2);
+		LBUMP(ipf_stats[fin->fin_out].fr_v4_ah_pullup);
+		return IPPROTO_NONE;
+	}
+
+	/*
+	 * Adjust fin_dp and fin_dlen for skipping over the authentication
+	 * header.
+	 */
+	fin->fin_dp = (char *)fin->fin_dp + len;
+	fin->fin_dlen -= len;
+	return ah->ah_next;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    frpr_gre                                                    */
+/* Function:    ipf_pr_gre                                                  */
 /* Returns:     void                                                        */
 /* Parameters:  fin(I) - pointer to packet information                      */
 /*                                                                          */
 /* Analyse the packet for GRE properties.                                   */
 /* ------------------------------------------------------------------------ */
-static INLINE void frpr_gre(fin)
-fr_info_t *fin;
+static INLINE void
+ipf_pr_gre(fin)
+	fr_info_t *fin;
 {
+	ipf_main_softc_t *softc = fin->fin_main_soft;
 	grehdr_t *gre;
 
-	frpr_short(fin, sizeof(*gre));
+	ipf_pr_short(fin, sizeof(grehdr_t));
 
-	if (fin->fin_off != 0)
+	if (fin->fin_off != 0) {
+		LBUMPD(ipf_stats[fin->fin_out], fr_v4_gre_frag);
 		return;
+	}
 
-	if (frpr_pullup(fin, sizeof(*gre)) == -1)
+	if (ipf_pr_pullup(fin, sizeof(grehdr_t)) == -1) {
+		LBUMPD(ipf_stats[fin->fin_out], fr_v4_gre_pullup);
 		return;
+	}
 
-	if (fin->fin_off == 0) {
-		gre = fin->fin_dp;
-		if (GRE_REV(gre->gr_flags) == 1)
-			fin->fin_data[0] = gre->gr_call;
-	}
+	gre = fin->fin_dp;
+	if (GRE_REV(gre->gr_flags) == 1)
+		fin->fin_data[0] = gre->gr_call;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    frpr_ipv4hdr                                                */
+/* Function:    ipf_pr_ipv4hdr                                              */
 /* Returns:     void                                                        */
 /* Parameters:  fin(I) - pointer to packet information                      */
 /*                                                                          */
@@ -1411,8 +1690,9 @@
 /* Analyze the IPv4 header and set fields in the fr_info_t structure.       */
 /* Check all options present and flag their presence if any exist.          */
 /* ------------------------------------------------------------------------ */
-static INLINE void frpr_ipv4hdr(fin)
-fr_info_t *fin;
+static INLINE void
+ipf_pr_ipv4hdr(fin)
+	fr_info_t *fin;
 {
 	u_short optmsk = 0, secmsk = 0, auth = 0;
 	int hlen, ol, mv, p, i;
@@ -1428,16 +1708,14 @@
 	ip = fin->fin_ip;
 	p = ip->ip_p;
 	fi->fi_p = p;
+	fin->fin_crc = p;
 	fi->fi_tos = ip->ip_tos;
 	fin->fin_id = ip->ip_id;
-	off = ip->ip_off;
+	off = ntohs(ip->ip_off);
 
 	/* Get both TTL and protocol */
 	fi->fi_p = ip->ip_p;
 	fi->fi_ttl = ip->ip_ttl;
-#if 0
-	(*(((u_short *)fi) + 1)) = (*(((u_short *)ip) + 4));
-#endif
 
 	/* Zero out bits not used in IPv6 address */
 	fi->fi_src.i6[1] = 0;
@@ -1448,7 +1726,11 @@
 	fi->fi_dst.i6[3] = 0;
 
 	fi->fi_saddr = ip->ip_src.s_addr;
+	fin->fin_crc += fi->fi_saddr;
 	fi->fi_daddr = ip->ip_dst.s_addr;
+	fin->fin_crc += fi->fi_daddr;
+	if (IN_CLASSD(ntohl(fi->fi_daddr)))
+		fin->fin_flx |= FI_MULTICAST|FI_MBCAST;
 
 	/*
 	 * set packet attribute flags based on the offset and
@@ -1463,12 +1745,12 @@
 		if (off != 0) {
 			fin->fin_flx |= FI_FRAGBODY;
 			off <<= 3;
-			if ((off + fin->fin_dlen > 65535) || 
+			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 
+				 * offset cannot exceed 65535 (0xffff) as the
 				 * length of an IP packet is only 16 bits.
 				 *
 				 * Any fragment that isn't the last fragment
@@ -1484,25 +1766,30 @@
 	/*
 	 * Call per-protocol setup and checking
 	 */
+	if (p == IPPROTO_AH) {
+		/*
+		 * Treat AH differently because we expect there to be another
+		 * layer 4 header after it.
+		 */
+		p = ipf_pr_ah(fin);
+	}
+
 	switch (p)
 	{
 	case IPPROTO_UDP :
-		frpr_udp(fin);
+		ipf_pr_udp(fin);
 		break;
 	case IPPROTO_TCP :
-		frpr_tcp(fin);
+		ipf_pr_tcp(fin);
 		break;
 	case IPPROTO_ICMP :
-		frpr_icmp(fin);
+		ipf_pr_icmp(fin);
 		break;
-	case IPPROTO_AH :
-		frpr_ah(fin);
-		break;
 	case IPPROTO_ESP :
-		frpr_esp(fin);
+		ipf_pr_esp(fin);
 		break;
 	case IPPROTO_GRE :
-		frpr_gre(fin);
+		ipf_pr_gre(fin);
 		break;
 	}
 
@@ -1545,32 +1832,37 @@
 		}
 		for (i = 9, mv = 4; mv >= 0; ) {
 			op = ipopts + i;
+
 			if ((opt == (u_char)op->ol_val) && (ol > 4)) {
-				optmsk |= op->ol_bit;
-				if (opt == IPOPT_SECURITY) {
-					const struct optlist *sp;
-					u_char	sec;
-					int j, m;
+				u_32_t doi;
 
-					sec = *(s + 2);	/* classification */
-					for (j = 3, m = 2; m >= 0; ) {
-						sp = secopt + j;
-						if (sec == sp->ol_val) {
-							secmsk |= sp->ol_bit;
-							auth = *(s + 3);
-							auth *= 256;
-							auth += *(s + 4);
-							break;
-						}
-						if (sec < sp->ol_val)
-							j -= m;
-						else
-							j += m;
-						m--;
+				switch (opt)
+				{
+				case IPOPT_SECURITY :
+					if (optmsk & op->ol_bit) {
+						fin->fin_flx |= FI_BAD;
+					} else {
+						doi = ipf_checkripso(s);
+						secmsk = doi >> 16;
+						auth = doi & 0xffff;
 					}
+					break;
+
+				case IPOPT_CIPSO :
+
+					if (optmsk & op->ol_bit) {
+						fin->fin_flx |= FI_BAD;
+					} else {
+						doi = ipf_checkcipso(fin,
+								     s, ol);
+						secmsk = doi >> 16;
+						auth = doi & 0xffff;
+					}
+					break;
 				}
-				break;
+				optmsk |= op->ol_bit;
 			}
+
 			if (opt < op->ol_val)
 				i -= mv;
 			else
@@ -1593,8 +1885,142 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_makefrip                                                 */
+/* Function:    ipf_checkripso                                              */
 /* Returns:     void                                                        */
+/* Parameters:  s(I)   - pointer to start of RIPSO option                   */
+/*                                                                          */
+/* ------------------------------------------------------------------------ */
+static u_32_t
+ipf_checkripso(s)
+	u_char *s;
+{
+	const struct optlist *sp;
+	u_short secmsk = 0, auth = 0;
+	u_char sec;
+	int j, m;
+
+	sec = *(s + 2);	/* classification */
+	for (j = 3, m = 2; m >= 0; ) {
+		sp = secopt + j;
+		if (sec == sp->ol_val) {
+			secmsk |= sp->ol_bit;
+			auth = *(s + 3);
+			auth *= 256;
+			auth += *(s + 4);
+			break;
+		}
+		if (sec < sp->ol_val)
+			j -= m;
+		else
+			j += m;
+		m--;
+	}
+
+	return (secmsk << 16) | auth;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_checkcipso                                              */
+/* Returns:     u_32_t  - 0 = failure, else the doi from the header         */
+/* Parameters:  fin(IO) - pointer to packet information                     */
+/*              s(I)    - pointer to start of CIPSO option                  */
+/*              ol(I)   - length of CIPSO option field                      */
+/*                                                                          */
+/* This function returns the domain of integrity (DOI) field from the CIPSO */
+/* header and returns that whilst also storing the highest sensitivity      */
+/* value found in the fr_info_t structure.                                  */
+/*                                                                          */
+/* No attempt is made to extract the category bitmaps as these are defined  */
+/* by the user (rather than the protocol) and can be rather numerous on the */
+/* end nodes.                                                               */
+/* ------------------------------------------------------------------------ */
+static u_32_t
+ipf_checkcipso(fin, s, ol)
+	fr_info_t *fin;
+	u_char *s;
+	int ol;
+{
+	ipf_main_softc_t *softc = fin->fin_main_soft;
+	fr_ip_t *fi;
+	u_32_t doi;
+	u_char *t, tag, tlen, sensitivity;
+	int len;
+
+	if (ol < 6 || ol > 40) {
+		LBUMPD(ipf_stats[fin->fin_out], fr_v4_cipso_bad);
+		fin->fin_flx |= FI_BAD;
+		return 0;
+	}
+
+	fi = &fin->fin_fi;
+	fi->fi_sensitivity = 0;
+	/*
+	 * The DOI field MUST be there.
+	 */
+	bcopy(s + 2, &doi, sizeof(doi));
+
+	t = (u_char *)s + 6;
+	for (len = ol - 6; len >= 2; len -= tlen, t+= tlen) {
+		tag = *t;
+		tlen = *(t + 1);
+		if (tlen > len || tlen < 4 || tlen > 34) {
+			LBUMPD(ipf_stats[fin->fin_out], fr_v4_cipso_tlen);
+			fin->fin_flx |= FI_BAD;
+			return 0;
+		}
+
+		sensitivity = 0;
+		/*
+		 * Tag numbers 0, 1, 2, 5 are laid out in the CIPSO Internet
+		 * draft (16 July 1992) that has expired.
+		 */
+		if (tag == 0) {
+			fin->fin_flx |= FI_BAD;
+			continue;
+		} else if (tag == 1) {
+			if (*(t + 2) != 0) {
+				fin->fin_flx |= FI_BAD;
+				continue;
+			}
+			sensitivity = *(t + 3);
+			/* Category bitmap for categories 0-239 */
+
+		} else if (tag == 4) {
+			if (*(t + 2) != 0) {
+				fin->fin_flx |= FI_BAD;
+				continue;
+			}
+			sensitivity = *(t + 3);
+			/* Enumerated categories, 16bits each, upto 15 */
+
+		} else if (tag == 5) {
+			if (*(t + 2) != 0) {
+				fin->fin_flx |= FI_BAD;
+				continue;
+			}
+			sensitivity = *(t + 3);
+			/* Range of categories (2*16bits), up to 7 pairs */
+
+		} else if (tag > 127) {
+			/* Custom defined DOI */
+			;
+		} else {
+			fin->fin_flx |= FI_BAD;
+			continue;
+		}
+
+		if (sensitivity > fi->fi_sensitivity)
+			fi->fi_sensitivity = sensitivity;
+	}
+
+	return doi;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_makefrip                                                */
+/* Returns:     int     - 0 == packet ok, -1 == packet freed                */
 /* Parameters:  hlen(I) - length of IP packet header                        */
 /*              ip(I)   - pointer to the IP header                          */
 /*              fin(IO) - pointer to packet information                     */
@@ -1604,15 +2030,15 @@
 /* in the fr_info_t structure pointer to by fin.  At present, it is assumed */
 /* this function will be called with either an IPv4 or IPv6 packet.         */
 /* ------------------------------------------------------------------------ */
-int	fr_makefrip(hlen, ip, fin)
-int hlen;
-ip_t *ip;
-fr_info_t *fin;
+int
+ipf_makefrip(hlen, ip, fin)
+	int hlen;
+	ip_t *ip;
+	fr_info_t *fin;
 {
+	ipf_main_softc_t *softc = fin->fin_main_soft;
 	int v;
 
-	fin->fin_nat = NULL;
-	fin->fin_state = NULL;
 	fin->fin_depth = 0;
 	fin->fin_hlen = (u_short)hlen;
 	fin->fin_ip = ip;
@@ -1623,10 +2049,9 @@
 
 	v = fin->fin_v;
 	if (v == 4) {
-		fin->fin_plen = ip->ip_len;
+		fin->fin_plen = ntohs(ip->ip_len);
 		fin->fin_dlen = fin->fin_plen - hlen;
-
-		frpr_ipv4hdr(fin);
+		ipf_pr_ipv4hdr(fin);
 #ifdef	USE_INET6
 	} else if (v == 6) {
 		fin->fin_plen = ntohs(((ip6_t *)ip)->ip6_plen);
@@ -1633,33 +2058,34 @@
 		fin->fin_dlen = fin->fin_plen;
 		fin->fin_plen += hlen;
 
-		if (frpr_ipv6hdr(fin) == -1)
-			return -1;
+		ipf_pr_ipv6hdr(fin);
 #endif
 	}
-	if (fin->fin_ip == NULL)
+	if (fin->fin_ip == NULL) {
+		LBUMP(ipf_stats[fin->fin_out].fr_ip_freed);
 		return -1;
+	}
 	return 0;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_portcheck                                                */
+/* Function:    ipf_portcheck                                               */
 /* Returns:     int - 1 == port matched, 0 == port match failed             */
 /* Parameters:  frp(I) - pointer to port check `expression'                 */
-/*              pop(I) - pointer to port number to evaluate                 */
+/*              pop(I) - port number to evaluate                            */
 /*                                                                          */
 /* Perform a comparison of a port number against some other(s), using a     */
 /* structure with compare information stored in it.                         */
 /* ------------------------------------------------------------------------ */
-static INLINE int fr_portcheck(frp, pop)
-frpcmp_t *frp;
-u_short *pop;
+static INLINE int
+ipf_portcheck(frp, pop)
+	frpcmp_t *frp;
+	u_32_t pop;
 {
-	u_short tup, po;
 	int err = 1;
+	u_32_t po;
 
-	tup = *pop;
 	po = frp->frp_port;
 
 	/*
@@ -1668,39 +2094,39 @@
 	switch (frp->frp_cmp)
 	{
 	case FR_EQUAL :
-		if (tup != po) /* EQUAL */
+		if (pop != po) /* EQUAL */
 			err = 0;
 		break;
 	case FR_NEQUAL :
-		if (tup == po) /* NOTEQUAL */
+		if (pop == po) /* NOTEQUAL */
 			err = 0;
 		break;
 	case FR_LESST :
-		if (tup >= po) /* LESSTHAN */
+		if (pop >= po) /* LESSTHAN */
 			err = 0;
 		break;
 	case FR_GREATERT :
-		if (tup <= po) /* GREATERTHAN */
+		if (pop <= po) /* GREATERTHAN */
 			err = 0;
 		break;
 	case FR_LESSTE :
-		if (tup > po) /* LT or EQ */
+		if (pop > po) /* LT or EQ */
 			err = 0;
 		break;
 	case FR_GREATERTE :
-		if (tup < po) /* GT or EQ */
+		if (pop < po) /* GT or EQ */
 			err = 0;
 		break;
 	case FR_OUTRANGE :
-		if (tup >= po && tup <= frp->frp_top) /* Out of range */
+		if (pop >= po && pop <= frp->frp_top) /* Out of range */
 			err = 0;
 		break;
 	case FR_INRANGE :
-		if (tup <= po || tup >= frp->frp_top) /* In range */
+		if (pop <= po || pop >= frp->frp_top) /* In range */
 			err = 0;
 		break;
 	case FR_INCRANGE :
-		if (tup < po || tup > frp->frp_top) /* Inclusive range */
+		if (pop < po || pop > frp->frp_top) /* Inclusive range */
 			err = 0;
 		break;
 	default :
@@ -1711,17 +2137,18 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_tcpudpchk                                                */
+/* Function:    ipf_tcpudpchk                                               */
 /* Returns:     int - 1 == protocol matched, 0 == check failed              */
-/* Parameters:  fin(I) - pointer to packet information                      */
+/* Parameters:  fda(I) - pointer to packet information                      */
 /*              ft(I)  - pointer to structure with comparison data          */
 /*                                                                          */
 /* Compares the current pcket (assuming it is TCP/UDP) information with a   */
 /* structure containing information that we want to match against.          */
 /* ------------------------------------------------------------------------ */
-int fr_tcpudpchk(fin, ft)
-fr_info_t *fin;
-frtuc_t *ft;
+int
+ipf_tcpudpchk(fi, ft)
+	fr_ip_t *fi;
+	frtuc_t *ft;
 {
 	int err = 1;
 
@@ -1732,13 +2159,13 @@
 	 * compare destination ports
 	 */
 	if (ft->ftu_dcmp)
-		err = fr_portcheck(&ft->ftu_dst, &fin->fin_dport);
+		err = ipf_portcheck(&ft->ftu_dst, fi->fi_ports[1]);
 
 	/*
 	 * compare source ports
 	 */
 	if (err && ft->ftu_scmp)
-		err = fr_portcheck(&ft->ftu_src, &fin->fin_sport);
+		err = ipf_portcheck(&ft->ftu_src, fi->fi_ports[0]);
 
 	/*
 	 * If we don't have all the TCP/UDP header, then how can we
@@ -1746,15 +2173,15 @@
 	 * TCP flags, then NO match.  If not, then match (which should
 	 * satisfy the "short" class too).
 	 */
-	if (err && (fin->fin_p == IPPROTO_TCP)) {
-		if (fin->fin_flx & FI_SHORT)
+	if (err && (fi->fi_p == IPPROTO_TCP)) {
+		if (fi->fi_flx & FI_SHORT)
 			return !(ft->ftu_tcpf | ft->ftu_tcpfm);
 		/*
 		 * Match the flags ?  If not, abort this match.
 		 */
 		if (ft->ftu_tcpfm &&
-		    ft->ftu_tcpf != (fin->fin_tcpf & ft->ftu_tcpfm)) {
-			FR_DEBUG(("f. %#x & %#x != %#x\n", fin->fin_tcpf,
+		    ft->ftu_tcpf != (fi->fi_tcpf & ft->ftu_tcpfm)) {
+			FR_DEBUG(("f. %#x & %#x != %#x\n", fi->fi_tcpf,
 				 ft->ftu_tcpfm, ft->ftu_tcpf));
 			err = 0;
 		}
@@ -1763,10 +2190,9 @@
 }
 
 
-
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_ipfcheck                                                 */
-/* Returns:     int - 0 == match, 1 == no match                             */
+/* Function:    ipf_check_ipf                                               */
+/* Returns:     int - 0 == match, else no match                             */
 /* Parameters:  fin(I)     - pointer to packet information                  */
 /*              fr(I)      - pointer to filter rule                         */
 /*              portcmp(I) - flag indicating whether to attempt matching on */
@@ -1776,10 +2202,11 @@
 /* port numbers, etc, for "standard" IPFilter rules are all orchestrated in */
 /* this function.                                                           */
 /* ------------------------------------------------------------------------ */
-static INLINE int fr_ipfcheck(fin, fr, portcmp)
-fr_info_t *fin;
-frentry_t *fr;
-int portcmp;
+static INLINE int
+ipf_check_ipf(fin, fr, portcmp)
+	fr_info_t *fin;
+	frentry_t *fr;
+	int portcmp;
 {
 	u_32_t	*ld, *lm, *lip;
 	fripf_t *fri;
@@ -1807,10 +2234,10 @@
 	 * are present (if any) in this packet.
 	 */
 	lip++, lm++, ld++;
-	i |= ((*lip & *lm) != *ld);
+	i = ((*lip & *lm) != *ld);
 	FR_DEBUG(("1. %#08x & %#08x != %#08x\n",
 		   ntohl(*lip), ntohl(*lm), ntohl(*ld)));
-	if (i)
+	if (i != 0)
 		return 1;
 
 	lip++, lm++, ld++;
@@ -1820,9 +2247,9 @@
 	/*
 	 * Check the source address.
 	 */
-#ifdef	IPFILTER_LOOKUP
 	if (fr->fr_satype == FRI_LOOKUP) {
-		i = (*fr->fr_srcfunc)(fr->fr_srcptr, fi->fi_v, lip);
+		i = (*fr->fr_srcfunc)(fin->fin_main_soft, fr->fr_srcptr,
+				      fi->fi_v, lip, fin->fin_plen);
 		if (i == -1)
 			return 1;
 		lip += 3;
@@ -1829,7 +2256,6 @@
 		lm += 3;
 		ld += 3;
 	} else {
-#endif
 		i = ((*lip & *lm) != *ld);
 		FR_DEBUG(("2a. %#08x & %#08x != %#08x\n",
 			   ntohl(*lip), ntohl(*lm), ntohl(*ld)));
@@ -1851,11 +2277,9 @@
 			lm += 3;
 			ld += 3;
 		}
-#ifdef	IPFILTER_LOOKUP
 	}
-#endif
 	i ^= (fr->fr_flags & FR_NOTSRCIP) >> 6;
-	if (i)
+	if (i != 0)
 		return 1;
 
 	/*
@@ -1862,9 +2286,9 @@
 	 * Check the destination address.
 	 */
 	lip++, lm++, ld++;
-#ifdef	IPFILTER_LOOKUP
 	if (fr->fr_datype == FRI_LOOKUP) {
-		i = (*fr->fr_dstfunc)(fr->fr_dstptr, fi->fi_v, lip);
+		i = (*fr->fr_dstfunc)(fin->fin_main_soft, fr->fr_dstptr,
+				      fi->fi_v, lip, fin->fin_plen);
 		if (i == -1)
 			return 1;
 		lip += 3;
@@ -1871,7 +2295,6 @@
 		lm += 3;
 		ld += 3;
 	} else {
-#endif
 		i = ((*lip & *lm) != *ld);
 		FR_DEBUG(("3a. %#08x & %#08x != %#08x\n",
 			   ntohl(*lip), ntohl(*lm), ntohl(*ld)));
@@ -1893,11 +2316,9 @@
 			lm += 3;
 			ld += 3;
 		}
-#ifdef	IPFILTER_LOOKUP
 	}
-#endif
 	i ^= (fr->fr_flags & FR_NOTDSTIP) >> 7;
-	if (i)
+	if (i != 0)
 		return 1;
 	/*
 	 * IP addresses matched.  The next 32bits contains:
@@ -1904,17 +2325,15 @@
 	 * mast of old IP header security & authentication bits.
 	 */
 	lip++, lm++, ld++;
-	i |= ((*lip & *lm) != *ld);
-	FR_DEBUG(("4. %#08x & %#08x != %#08x\n",
-		   *lip, *lm, *ld));
+	i = (*ld - (*lip & *lm));
+	FR_DEBUG(("4. %#08x & %#08x != %#08x\n", *lip, *lm, *ld));
 
 	/*
 	 * Next we have 32 bits of packet flags.
 	 */
 	lip++, lm++, ld++;
-	i |= ((*lip & *lm) != *ld);
-	FR_DEBUG(("5. %#08x & %#08x != %#08x\n",
-		   *lip, *lm, *ld));
+	i |= (*ld - (*lip & *lm));
+	FR_DEBUG(("5. %#08x & %#08x != %#08x\n", *lip, *lm, *ld));
 
 	if (i == 0) {
 		/*
@@ -1922,7 +2341,7 @@
 		 * looking for here...
 		 */
 		if (portcmp) {
-			if (!fr_tcpudpchk(fin, &fr->fr_tuc))
+			if (!ipf_tcpudpchk(&fin->fin_fi, &fr->fr_tuc))
 				i = 1;
 		} else {
 			if (fr->fr_dcmp || fr->fr_scmp ||
@@ -1948,7 +2367,7 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_scanlist                                                 */
+/* Function:    ipf_scanlist                                                */
 /* Returns:     int - result flags of scanning filter list                  */
 /* Parameters:  fin(I) - pointer to packet information                      */
 /*              pass(I) - default result to return for filtering            */
@@ -1963,10 +2382,12 @@
 /* Could be per interface, but this gets real nasty when you don't have,    */
 /* or can't easily change, the kernel source code to .                      */
 /* ------------------------------------------------------------------------ */
-int fr_scanlist(fin, pass)
-fr_info_t *fin;
-u_32_t pass;
+int
+ipf_scanlist(fin, pass)
+	fr_info_t *fin;
+	u_32_t pass;
 {
+	ipf_main_softc_t *softc = fin->fin_main_soft;
 	int rulen, portcmp, off, skip;
 	struct frentry *fr, *fnext;
 	u_32_t passt, passo;
@@ -1997,7 +2418,7 @@
 	for (rulen = 0; fr; fr = fnext, rulen++) {
 		fnext = fr->fr_next;
 		if (skip != 0) {
-			FR_VERBOSE(("%d (%#x)\n", skip, fr->fr_flags));
+			FR_VERBOSE(("SKIP %d (%#x)\n", skip, fr->fr_flags));
 			skip--;
 			continue;
 		}
@@ -2027,27 +2448,29 @@
 		switch (fr->fr_type)
 		{
 		case FR_T_IPF :
-		case FR_T_IPF|FR_T_BUILTIN :
-			if (fr_ipfcheck(fin, fr, portcmp))
+		case FR_T_IPF_BUILTIN :
+			if (ipf_check_ipf(fin, fr, portcmp))
 				continue;
 			break;
 #if defined(IPFILTER_BPF)
 		case FR_T_BPFOPC :
-		case FR_T_BPFOPC|FR_T_BUILTIN :
+		case FR_T_BPFOPC_BUILTIN :
 		    {
 			u_char *mc;
+			int wlen;
 
 			if (*fin->fin_mp == NULL)
 				continue;
-			if (fin->fin_v != fr->fr_v)
+			if (fin->fin_family != fr->fr_family)
 				continue;
 			mc = (u_char *)fin->fin_m;
-			if (!bpf_filter(fr->fr_data, mc, fin->fin_plen, 0))
+			wlen = fin->fin_dlen + fin->fin_hlen;
+			if (!bpf_filter(fr->fr_data, mc, wlen, 0))
 				continue;
 			break;
 		    }
 #endif
-		case FR_T_CALLFUNC|FR_T_BUILTIN :
+		case FR_T_CALLFUNC_BUILTIN :
 		    {
 			frentry_t *f;
 
@@ -2058,6 +2481,15 @@
 				continue;
 			break;
 		    }
+
+		case FR_T_IPFEXPR :
+		case FR_T_IPFEXPR_BUILTIN :
+			if (fin->fin_family != fr->fr_family)
+				continue;
+			if (ipf_fr_matcharray(fin, fr->fr_data) == 0)
+				continue;
+			break;
+
 		default :
 			break;
 		}
@@ -2065,23 +2497,14 @@
 		if ((fin->fin_out == 0) && (fr->fr_nattag.ipt_num[0] != 0)) {
 			if (fin->fin_nattag == NULL)
 				continue;
-			if (fr_matchtag(&fr->fr_nattag, fin->fin_nattag) == 0)
+			if (ipf_matchtag(&fr->fr_nattag, fin->fin_nattag) == 0)
 				continue;
 		}
-		FR_VERBOSE(("=%s.%d *", fr->fr_group, rulen));
+		FR_VERBOSE(("=%d/%d.%d *", fr->fr_grhead, fr->fr_group, rulen));
 
 		passt = fr->fr_flags;
 
 		/*
-		 * Allowing a rule with the "keep state" flag set to match
-		 * packets that have been tagged "out of window" by the TCP
-		 * state tracking is foolish as the attempt to add a new
-		 * state entry to the table will fail.
-		 */
-		if ((passt & FR_KEEPSTATE) && (fin->fin_flx & FI_OOW))
-			continue;
-
-		/*
 		 * If the rule is a "call now" rule, then call the function
 		 * in the rule, if it exists and use the results from that.
 		 * If the function pointer is bad, just make like we ignore
@@ -2091,7 +2514,7 @@
 			frentry_t *frs;
 
 			ATOMIC_INC64(fr->fr_hits);
-			if ((fr->fr_func != NULL) &&
+			if ((fr->fr_func == NULL) ||
 			    (fr->fr_func == (ipfunc_t)-1))
 				continue;
 
@@ -2111,36 +2534,62 @@
 		 * Just log this packet...
 		 */
 		if ((passt & FR_LOGMASK) == FR_LOG) {
-			if (ipflog(fin, passt) == -1) {
+			if (ipf_log_pkt(fin, passt) == -1) {
 				if (passt & FR_LOGORBLOCK) {
+					DT(frb_logfail);
 					passt &= ~FR_CMDMASK;
 					passt |= FR_BLOCK|FR_QUICK;
+					fin->fin_reason = FRB_LOGFAIL;
 				}
-				ATOMIC_INCL(frstats[fin->fin_out].fr_skip);
 			}
-			ATOMIC_INCL(frstats[fin->fin_out].fr_pkl);
-			fin->fin_flx |= FI_DONTCACHE;
 		}
 #endif /* IPFILTER_LOG */
+
+		MUTEX_ENTER(&fr->fr_lock);
 		fr->fr_bytes += (U_QUAD_T)fin->fin_plen;
+		fr->fr_hits++;
+		MUTEX_EXIT(&fr->fr_lock);
+		fin->fin_rule = rulen;
+
 		passo = pass;
-		if (FR_ISSKIP(passt))
+		if (FR_ISSKIP(passt)) {
 			skip = fr->fr_arg;
-		else if ((passt & FR_LOGMASK) != FR_LOG)
+			continue;
+		} else if (((passt & FR_LOGMASK) != FR_LOG) &&
+			   ((passt & FR_LOGMASK) != FR_DECAPSULATE)) {
 			pass = passt;
+		}
+
 		if (passt & (FR_RETICMP|FR_FAKEICMP))
 			fin->fin_icode = fr->fr_icode;
-		FR_DEBUG(("pass %#x\n", pass));
-		ATOMIC_INC64(fr->fr_hits);
-		fin->fin_rule = rulen;
-		(void) strncpy(fin->fin_group, fr->fr_group, FR_GROUPLEN);
-		if (fr->fr_grp != NULL) {
-			fin->fin_fr = *fr->fr_grp;
-			passt = fr_scanlist(fin, pass);
+
+		if (fr->fr_group != -1) {
+			(void) strncpy(fin->fin_group,
+				       FR_NAME(fr, fr_group),
+				       strlen(FR_NAME(fr, fr_group)));
+		} else {
+			fin->fin_group[0] = '\0';
+		}
+
+		FR_DEBUG(("pass %#x/%#x/%x\n", passo, pass, passt));
+
+		if (fr->fr_grphead != NULL) {
+			fin->fin_fr = fr->fr_grphead->fg_start;
+			FR_VERBOSE(("group %s\n", FR_NAME(fr, fr_grhead)));
+
+			if (FR_ISDECAPS(passt))
+				passt = ipf_decaps(fin, pass, fr->fr_icode);
+			else
+				passt = ipf_scanlist(fin, pass);
+
 			if (fin->fin_fr == NULL) {
 				fin->fin_rule = rulen;
-				(void) strncpy(fin->fin_group, fr->fr_group,
-					       FR_GROUPLEN);
+				if (fr->fr_group != -1)
+					(void) strncpy(fin->fin_group,
+						       fr->fr_names +
+						       fr->fr_group,
+						       strlen(fr->fr_names +
+							      fr->fr_group));
 				fin->fin_fr = fr;
 				passt = pass;
 			}
@@ -2147,7 +2596,7 @@
 			pass = passt;
 		}
 
-		if (passt & FR_QUICK) {
+		if (pass & FR_QUICK) {
 			/*
 			 * Finally, if we've asked to track state for this
 			 * packet, set it up.  Add state for "quick" rules
@@ -2155,15 +2604,15 @@
 			 * the rule to "not match" and keep on processing
 			 * filter rules.
 			 */
-			if ((pass & FR_KEEPSTATE) &&
+			if ((pass & FR_KEEPSTATE) && !FR_ISAUTH(pass) &&
 			    !(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);
+				if (ipf_state_add(softc, fin, NULL, 0) == 0) {
+					LBUMPD(ipf_stats[out], fr_ads);
 				} else {
-					ATOMIC_INCL(frstats[out].fr_bads);
+					LBUMPD(ipf_stats[out], fr_bads);
 					pass = passo;
 					continue;
 				}
@@ -2177,7 +2626,7 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_acctpkt                                                  */
+/* Function:    ipf_acctpkt                                                 */
 /* Returns:     frentry_t* - always returns NULL                            */
 /* Parameters:  fin(I) - pointer to packet information                      */
 /*              passp(IO) - pointer to current/new filter decision (unused) */
@@ -2186,23 +2635,20 @@
 /* IP protocol version.                                                     */
 /*                                                                          */
 /* N.B.: this function returns NULL to match the prototype used by other    */
-/* functions called from the IPFilter "mainline" in fr_check().             */
+/* functions called from the IPFilter "mainline" in ipf_check().            */
 /* ------------------------------------------------------------------------ */
-frentry_t *fr_acctpkt(fin, passp)
-fr_info_t *fin;
-u_32_t *passp;
+frentry_t *
+ipf_acctpkt(fin, passp)
+	fr_info_t *fin;
+	u_32_t *passp;
 {
+	ipf_main_softc_t *softc = fin->fin_main_soft;
 	char group[FR_GROUPLEN];
 	frentry_t *fr, *frsave;
 	u_32_t pass, rulen;
 
 	passp = passp;
-#ifdef	USE_INET6
-	if (fin->fin_v == 6)
-		fr = ipacct6[fin->fin_out][fr_active];
-	else
-#endif
-		fr = ipacct[fin->fin_out][fr_active];
+	fr = softc->ipf_acct[fin->fin_out][softc->ipf_active];
 
 	if (fr != NULL) {
 		frsave = fin->fin_fr;
@@ -2209,9 +2655,9 @@
 		bcopy(fin->fin_group, group, FR_GROUPLEN);
 		rulen = fin->fin_rule;
 		fin->fin_fr = fr;
-		pass = fr_scanlist(fin, FR_NOMATCH);
+		pass = ipf_scanlist(fin, FR_NOMATCH);
 		if (FR_ISACCOUNT(pass)) {
-			ATOMIC_INCL(frstats[0].fr_acct);
+			LBUMPD(ipf_stats[0], fr_acct);
 		}
 		fin->fin_fr = frsave;
 		bcopy(group, fin->fin_group, FR_GROUPLEN);
@@ -2222,7 +2668,7 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_firewall                                                 */
+/* Function:    ipf_firewall                                                */
 /* Returns:     frentry_t* - returns pointer to matched rule, if no matches */
 /*                           were found, returns NULL.                      */
 /* Parameters:  fin(I) - pointer to packet information                      */
@@ -2234,12 +2680,13 @@
 /* matching rule is found, take any appropriate actions as defined by the   */
 /* rule - except logging.                                                   */
 /* ------------------------------------------------------------------------ */
-static frentry_t *fr_firewall(fin, passp)
-fr_info_t *fin;
-u_32_t *passp;
+static frentry_t *
+ipf_firewall(fin, passp)
+	fr_info_t *fin;
+	u_32_t *passp;
 {
+	ipf_main_softc_t *softc = fin->fin_main_soft;
 	frentry_t *fr;
-	fr_info_t *fc;
 	u_32_t pass;
 	int out;
 
@@ -2247,47 +2694,17 @@
 	pass = *passp;
 
 	/*
-	 * If a packet is found in the auth table, then skip checking
-	 * the access lists for permission but we do need to consider
-	 * the result as if it were from the ACL's.
+	 * This rule cache will only affect packets that are not being
+	 * statefully filtered.
 	 */
-	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 mutexes earlier.
-		 */
-		bcopy((char *)fc, (char *)fin, FI_COPYSIZE);
-		RWLOCK_EXIT(&ipf_frcache);
-		ATOMIC_INCL(frstats[out].fr_chit);
+	fin->fin_fr = softc->ipf_rules[out][softc->ipf_active];
+	if (fin->fin_fr != NULL)
+		pass = ipf_scanlist(fin, softc->ipf_pass);
 
-		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];
-		else
-#endif
-			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)) {
-			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);
-		}
-		fr = fin->fin_fr;
+	if ((pass & FR_NOMATCH)) {
+		LBUMPD(ipf_stats[out], fr_nom);
 	}
+	fr = fin->fin_fr;
 
 	/*
 	 * Apply packets per second rate-limiting to a rule as required.
@@ -2294,9 +2711,11 @@
 	 */
 	if ((fr != NULL) && (fr->fr_pps != 0) &&
 	    !ppsratecheck(&fr->fr_lastpkt, &fr->fr_curpps, fr->fr_pps)) {
-		pass &= ~(FR_CMDMASK|FR_DUP|FR_RETICMP|FR_RETRST);
+		DT2(frb_ppsrate, fr_info_t *, fin, frentry_t *, fr);
+		pass &= ~(FR_CMDMASK|FR_RETICMP|FR_RETRST);
 		pass |= FR_BLOCK;
-		ATOMIC_INCL(frstats[out].fr_ppshit);
+		LBUMPD(ipf_stats[out], fr_ppshit);
+		fin->fin_reason = FRB_PPSRATE;
 	}
 
 	/*
@@ -2305,15 +2724,15 @@
 	 * we've dropped it already.
 	 */
 	if (FR_ISAUTH(pass)) {
-		if (fr_newauth(fin->fin_m, fin) != 0) {
-#ifdef	_KERNEL
+		if (ipf_auth_new(fin->fin_m, fin) != 0) {
+			DT1(frb_authnew, fr_info_t *, fin);
 			fin->fin_m = *fin->fin_mp = NULL;
-#else
-			;
-#endif
+			fin->fin_reason = FRB_AUTHNEW;
 			fin->fin_error = 0;
-		} else
+		} else {
+			IPFERROR(1);
 			fin->fin_error = ENOSPC;
+		}
 	}
 
 	if ((fr != NULL) && (fr->fr_func != NULL) &&
@@ -2327,8 +2746,7 @@
 	 * is treated as "not a pass", hence the packet is blocked.
 	 */
 	if (FR_ISPREAUTH(pass)) {
-		if ((fin->fin_fr = ipauth) != NULL)
-			pass = fr_scanlist(fin, fr_pass);
+		pass = ipf_auth_pre_scanlist(softc, fin, pass);
 	}
 
 	/*
@@ -2335,29 +2753,27 @@
 	 * If the rule has "keep frag" and the packet is actually a fragment,
 	 * then create a fragment state entry.
 	 */
-	if ((pass & (FR_KEEPFRAG|FR_KEEPSTATE)) == FR_KEEPFRAG) {
+	if (pass & FR_KEEPFRAG) {
 		if (fin->fin_flx & FI_FRAG) {
-			if (fr_newfrag(fin, pass) == -1) {
-				ATOMIC_INCL(frstats[out].fr_bnfr);
+			if (ipf_frag_new(softc, fin, pass) == -1) {
+				LBUMP(ipf_stats[out].fr_bnfr);
 			} else {
-				ATOMIC_INCL(frstats[out].fr_nfr);
+				LBUMP(ipf_stats[out].fr_nfr);
 			}
 		} else {
-			ATOMIC_INCL(frstats[out].fr_cfr);
+			LBUMP(ipf_stats[out].fr_cfr);
 		}
 	}
 
 	fr = fin->fin_fr;
+	*passp = pass;
 
-	if (passp != NULL)
-		*passp = pass;
-
 	return fr;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_check                                                    */
+/* Function:    ipf_check                                                   */
 /* Returns:     int -  0 == packet allowed through,                         */
 /*              User space:                                                 */
 /*                    -1 == packet blocked                                  */
@@ -2375,7 +2791,7 @@
 /*             qpi(I)  - pointer to STREAMS queue information for this      */
 /*                       interface & direction.                             */
 /*                                                                          */
-/* fr_check() is the master function for all IPFilter packet processing.    */
+/* ipf_check() is the master function for all IPFilter packet processing.   */
 /* It orchestrates: Network Address Translation (NAT), checking for packet  */
 /* authorisation (or pre-authorisation), presence of related state info.,   */
 /* generating log entries, IP packet accounting, routing of packets as      */
@@ -2386,31 +2802,34 @@
 /* freed.  Packets passed may be returned with the pointer pointed to by    */
 /* by "mp" changed to a new buffer.                                         */
 /* ------------------------------------------------------------------------ */
-int fr_check(ip, hlen, ifp, out
+int
+ipf_check(ctx, ip, hlen, ifp, out
 #if defined(_KERNEL) && defined(MENTAT)
-, qif, mp)
-void *qif;
+	, qif, mp)
+	void *qif;
 #else
-, mp)
+	, mp)
 #endif
-mb_t **mp;
-ip_t *ip;
-int hlen;
-void *ifp;
-int out;
+	mb_t **mp;
+	ip_t *ip;
+	int hlen;
+	void *ifp;
+	int out;
+	void *ctx;
 {
 	/*
 	 * The above really sucks, but short of writing a diff
 	 */
+	ipf_main_softc_t *softc = ctx;
 	fr_info_t frinfo;
 	fr_info_t *fin = &frinfo;
-	u_32_t pass = fr_pass;
+	u_32_t pass = softc->ipf_pass;
 	frentry_t *fr = NULL;
 	int v = IP_V(ip);
 	mb_t *mc = NULL;
 	mb_t *m;
 	/*
-	 * The first part of fr_check() deals with making sure that what goes
+	 * The first part of ipf_check() deals with making sure that what goes
 	 * into the filtering engine makes some sense.  Information about the
 	 * the packet is distilled, collected into a fr_info_t structure and
 	 * the an attempt to ensure the buffer the packet is in is big enough
@@ -2420,7 +2839,7 @@
 # ifdef MENTAT
 	qpktinfo_t *qpi = qif;
 
-#  if !defined(_INET_IP_STACK_H)
+#  ifdef __sparc
 	if ((u_int)ip & 0x3)
 		return 2;
 #  endif
@@ -2428,10 +2847,7 @@
 	SPL_INT(s);
 # endif
 
-	READ_ENTER(&ipf_global);
-
-	if (fr_running <= 0) {
-		RWLOCK_EXIT(&ipf_global);
+	if (softc->ipf_running <= 0) {
 		return 0;
 	}
 
@@ -2438,8 +2854,10 @@
 	bzero((char *)fin, sizeof(*fin));
 
 # ifdef MENTAT
-	if (qpi->qpi_flags & QF_GROUP)
-		fin->fin_flx |= FI_MBCAST;
+	if (qpi->qpi_flags & QF_BROADCAST)
+		fin->fin_flx |= FI_MBCAST|FI_BROADCAST;
+	if (qpi->qpi_flags & QF_MULTICAST)
+		fin->fin_flx |= FI_MBCAST|FI_MULTICAST;
 	m = qpi->qpi_m;
 	fin->fin_qfm = m;
 	fin->fin_qpi = qpi;
@@ -2467,7 +2885,8 @@
 	 */
 	m->m_flags &= ~M_CANFASTFWD;
 #  endif /* M_CANFASTFWD */
-#  ifdef CSUM_DELAY_DATA
+#  if defined(CSUM_DELAY_DATA) && (!defined(__FreeBSD_version) || \
+				   (__FreeBSD_version < 501108))
 	/*
 	 * disable delayed checksums.
 	 */
@@ -2478,10 +2897,20 @@
 #  endif /* CSUM_DELAY_DATA */
 # endif /* MENTAT */
 #else
-	READ_ENTER(&ipf_global);
-
 	bzero((char *)fin, sizeof(*fin));
 	m = *mp;
+# if defined(M_MCAST)
+	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;
+# endif
 #endif /* _KERNEL */
 
 	fin->fin_v = v;
@@ -2493,6 +2922,7 @@
 	fin->fin_error = ENETUNREACH;
 	fin->fin_hlen = (u_short)hlen;
 	fin->fin_dp = (char *)ip + hlen;
+	fin->fin_main_soft = softc;
 
 	fin->fin_ipoff = (char *)ip - MTOD(m, char *);
 
@@ -2500,7 +2930,7 @@
 
 #ifdef	USE_INET6
 	if (v == 6) {
-		ATOMIC_INCL(frstats[out].fr_ipv6);
+		LBUMP(ipf_stats[out].fr_ipv6);
 		/*
 		 * Jumbo grams are quite likely too big for internal buffer
 		 * structures to handle comfortably, for now, so just drop
@@ -2507,20 +2937,22 @@
 		 * them.
 		 */
 		if (((ip6_t *)ip)->ip6_plen == 0) {
+			DT1(frb_jumbo, ip6_t *, (ip6_t *)ip);
 			pass = FR_BLOCK|FR_NOMATCH;
+			fin->fin_reason = FRB_JUMBO;
 			goto finished;
 		}
+		fin->fin_family = AF_INET6;
 	} else
 #endif
 	{
-#if (defined(OpenBSD) && (OpenBSD >= 200311)) && defined(_KERNEL)
-		ip->ip_len = ntohs(ip->ip_len);
-		ip->ip_off = ntohs(ip->ip_off);
-#endif
+		fin->fin_family = AF_INET;
 	}
 
-	if (fr_makefrip(hlen, ip, fin) == -1) {
+	if (ipf_makefrip(hlen, ip, fin) == -1) {
+		DT1(frb_makefrip, fr_info_t *, fin);
 		pass = FR_BLOCK|FR_NOMATCH;
+		fin->fin_reason = FRB_MAKEFRIP;
 		goto finished;
 	}
 
@@ -2533,21 +2965,19 @@
 
 	if (!out) {
 		if (v == 4) {
-#ifdef _KERNEL
-			if (fr_chksrc && !fr_verifysrc(fin)) {
-				ATOMIC_INCL(frstats[0].fr_badsrc);
+			if (softc->ipf_chksrc && !ipf_verifysrc(fin)) {
+				LBUMPD(ipf_stats[0], fr_v4_badsrc);
 				fin->fin_flx |= FI_BADSRC;
 			}
-#endif
-			if (fin->fin_ip->ip_ttl < fr_minttl) {
-				ATOMIC_INCL(frstats[0].fr_badttl);
+			if (fin->fin_ip->ip_ttl < softc->ipf_minttl) {
+				LBUMPD(ipf_stats[0], fr_v4_badttl);
 				fin->fin_flx |= FI_LOWTTL;
 			}
 		}
 #ifdef USE_INET6
 		else  if (v == 6) {
-			if (((ip6_t *)ip)->ip6_hlim < fr_minttl) {
-				ATOMIC_INCL(frstats[0].fr_badttl);
+			if (((ip6_t *)ip)->ip6_hlim < softc->ipf_minttl) {
+				LBUMPD(ipf_stats[0], fr_v6_badttl);
 				fin->fin_flx |= FI_LOWTTL;
 			}
 		}
@@ -2555,64 +2985,78 @@
 	}
 
 	if (fin->fin_flx & FI_SHORT) {
-		ATOMIC_INCL(frstats[out].fr_short);
+		LBUMPD(ipf_stats[out], fr_short);
 	}
 
-	READ_ENTER(&ipf_mutex);
+	READ_ENTER(&softc->ipf_mutex);
 
-	/*
-	 * Check auth now.  This, combined with the check below to see if apass
-	 * is 0 is to ensure that we don't count the packet twice, which can
-	 * otherwise occur when we reprocess it.  As it is, we only count it
-	 * after it has no auth. table matchup.  This also stops NAT from
-	 * occuring until after the packet has been auth'd.
-	 */
-	fr = fr_checkauth(fin, &pass);
 	if (!out) {
-		if (fr_checknatin(fin, &pass) == -1) {
-			goto filterdone;
+		switch (fin->fin_v)
+		{
+		case 4 :
+			if (ipf_nat_checkin(fin, &pass) == -1) {
+				goto filterdone;
+			}
+			break;
+#ifdef USE_INET6
+		case 6 :
+			if (ipf_nat6_checkin(fin, &pass) == -1) {
+				goto filterdone;
+			}
+			break;
+#endif
+		default :
+			break;
 		}
 	}
-	if (!out)
-		(void) fr_acctpkt(fin, NULL);
+	/*
+	 * Check auth now.
+	 * If a packet is found in the auth table, then skip checking
+	 * the access lists for permission but we do need to consider
+	 * the result as if it were from the ACL's.  In addition, being
+	 * found in the auth table means it has been seen before, so do
+	 * not pass it through accounting (again), lest it be counted twice.
+	 */
+	fr = ipf_auth_check(fin, &pass);
+	if (!out && (fr == NULL))
+		(void) ipf_acctpkt(fin, NULL);
 
 	if (fr == NULL) {
-		if ((fin->fin_flx & (FI_FRAG|FI_BAD)) == FI_FRAG) {
-			fr = fr_knownfrag(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 ((fin->fin_flx & FI_FRAG) != 0)
+			fr = ipf_frag_known(fin, &pass);
+
 		if (fr == NULL)
-			fr = fr_checkstate(fin, &pass);
+			fr = ipf_state_check(fin, &pass);
 	}
 
 	if ((pass & FR_NOMATCH) || (fr == NULL))
-		fr = fr_firewall(fin, &pass);
+		fr = ipf_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
+	 * Here rather than ipf_firewall because ipf_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);
+		if (ipf_state_add(softc, fin, NULL, 0) == 0) {
+			LBUMP(ipf_stats[out].fr_ads);
 		} else {
-			ATOMIC_INCL(frstats[out].fr_bads);
+			LBUMP(ipf_stats[out].fr_bads);
 			if (FR_ISPASS(pass)) {
+				DT(frb_stateadd);
 				pass &= ~FR_CMDMASK;
 				pass |= FR_BLOCK;
+				fin->fin_reason = FRB_STATEADD;
 			}
 		}
 	}
 
 	fin->fin_fr = fr;
+	if ((fr != NULL) && !(fin->fin_flx & FI_STATE)) {
+		fin->fin_dif = &fr->fr_dif;
+		fin->fin_tif = &fr->fr_tifs[fin->fin_rev];
+	}
 
 	/*
 	 * Only count/translate packets which will be passed on, out the
@@ -2619,56 +3063,57 @@
 	 * interface.
 	 */
 	if (out && FR_ISPASS(pass)) {
-		(void) fr_acctpkt(fin, NULL);
+		(void) ipf_acctpkt(fin, NULL);
 
-		if (fr_checknatout(fin, &pass) == -1) {
-			;
-		} else if ((fr_update_ipid != 0) && (v == 4)) {
-			if (fr_updateipid(fin) == -1) {
-				ATOMIC_INCL(frstats[1].fr_ipud);
-				pass &= ~FR_CMDMASK;
-				pass |= FR_BLOCK;
-			} else {
-				ATOMIC_INCL(frstats[0].fr_ipud);
+		switch (fin->fin_v)
+		{
+		case 4 :
+			if (ipf_nat_checkout(fin, &pass) == -1) {
+				;
+			} else if ((softc->ipf_update_ipid != 0) && (v == 4)) {
+				if (ipf_updateipid(fin) == -1) {
+					DT(frb_updateipid);
+					LBUMP(ipf_stats[1].fr_ipud);
+					pass &= ~FR_CMDMASK;
+					pass |= FR_BLOCK;
+					fin->fin_reason = FRB_UPDATEIPID;
+				} else {
+					LBUMP(ipf_stats[0].fr_ipud);
+				}
 			}
+			break;
+#ifdef USE_INET6
+		case 6 :
+			(void) ipf_nat6_checkout(fin, &pass);
+			break;
+#endif
+		default :
+			break;
 		}
 	}
 
 filterdone:
 #ifdef	IPFILTER_LOG
-	if ((fr_flags & FF_LOGGING) || (pass & FR_LOGMASK)) {
-		(void) fr_dolog(fin, &pass);
+	if ((softc->ipf_flags & FF_LOGGING) || (pass & FR_LOGMASK)) {
+		(void) ipf_dolog(fin, &pass);
 	}
 #endif
 
 	/*
-	 * The FI_STATE flag is cleared here so that calling fr_checkstate
+	 * The FI_STATE flag is cleared here so that calling ipf_state_check
 	 * 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;
-	}
+	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);
-		}
-	}
-
+#if defined(FASTROUTE_RECURSION)
 	/*
-	 * 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.
+	 * Up the reference on fr_lock and exit ipf_mutex. The generation of
+	 * a packet below can sometimes cause a recursive call into IPFilter.
+	 * On those platforms where that does happen, we need to hang onto
+	 * the filter rule just in case someone decides to remove or flush it
+	 * in the meantime.
 	 */
 	if (fr != NULL) {
 		MUTEX_ENTER(&fr->fr_lock);
@@ -2676,7 +3121,8 @@
 		MUTEX_EXIT(&fr->fr_lock);
 	}
 
-	RWLOCK_EXIT(&ipf_mutex);
+	RWLOCK_EXIT(&softc->ipf_mutex);
+#endif
 
 	if ((pass & FR_RETMASK) != 0) {
 		/*
@@ -2683,9 +3129,9 @@
 		 * Should we return an ICMP packet to indicate error
 		 * status passing through the packet filter ?
 		 * WARNING: ICMP error packets AND TCP RST packets should
-		 * ONLY be sent in repsonse to incoming packets.  Sending them
-		 * in response to outbound packets can result in a panic on
-		 * some operating systems.
+		 * ONLY be sent in repsonse to incoming packets.  Sending
+		 * them in response to outbound packets can result in a
+		 * panic on some operating systems.
 		 */
 		if (!out) {
 			if (pass & FR_RETICMP) {
@@ -2695,13 +3141,14 @@
 					dst = 1;
 				else
 					dst = 0;
-				(void) fr_send_icmp_err(ICMP_UNREACH, fin, dst);
-				ATOMIC_INCL(frstats[0].fr_ret);
+				(void) ipf_send_icmp_err(ICMP_UNREACH, fin,
+							 dst);
+				LBUMP(ipf_stats[0].fr_ret);
 			} else if (((pass & FR_RETMASK) == FR_RETRST) &&
 				   !(fin->fin_flx & FI_SHORT)) {
 				if (((fin->fin_flx & FI_OOW) != 0) ||
-				    (fr_send_reset(fin) == 0)) {
-					ATOMIC_INCL(frstats[1].fr_ret);
+				    (ipf_send_reset(fin) == 0)) {
+					LBUMP(ipf_stats[1].fr_ret);
 				}
 			}
 
@@ -2710,61 +3157,81 @@
 			 * takes over disposing of this packet.
 			 */
 			if (FR_ISAUTH(pass) && (fin->fin_m != NULL)) {
+				DT1(frb_authcapture, fr_info_t *, fin);
 				fin->fin_m = *fin->fin_mp = NULL;
+				fin->fin_reason = FRB_AUTHCAPTURE;
+				m = NULL;
 			}
 		} else {
-			if (pass & FR_RETRST)
+			if (pass & FR_RETRST) {
 				fin->fin_error = ECONNRESET;
+			}
 		}
 	}
 
 	/*
+	 * After the above so that ICMP unreachables and TCP RSTs get
+	 * created properly.
+	 */
+	if (FR_ISBLOCK(pass) && (fin->fin_flx & FI_NEWNAT))
+		ipf_nat_uncreate(fin);
+
+	/*
 	 * If we didn't drop off the bottom of the list of rules (and thus
 	 * the 'current' rule fr is not NULL), then we may have some extra
 	 * 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 *).
+	 * we are dropping it.
 	 */
 	if (fr != NULL) {
 		frdest_t *fdp;
 
-		fdp = &fr->fr_tifs[fin->fin_rev];
+		/*
+		 * Generate a duplicated packet first because ipf_fastroute
+		 * can lead to fin_m being free'd... not good.
+		 */
+		fdp = fin->fin_dif;
+		if ((fdp != NULL) && (fdp->fd_ptr != NULL) &&
+		    (fdp->fd_ptr != (void *)-1)) {
+			mc = M_COPY(fin->fin_m);
+			if (mc != NULL)
+				ipf_fastroute(mc, &mc, fin, fdp);
+		}
 
+		fdp = fin->fin_tif;
 		if (!out && (pass & FR_FASTROUTE)) {
 			/*
-			 * For fastroute rule, no destioation interface defined
+			 * For fastroute rule, no destination interface defined
 			 * so pass NULL as the frdest_t parameter
 			 */
-			(void) fr_fastroute(fin->fin_m, mp, fin, NULL);
+			(void) ipf_fastroute(fin->fin_m, mp, fin, NULL);
 			m = *mp = NULL;
-		} else if ((fdp->fd_ifp != NULL) &&
-			   (fdp->fd_ifp != (struct ifnet *)-1)) {
+		} else if ((fdp != NULL) && (fdp->fd_ptr != NULL) &&
+			   (fdp->fd_ptr != (struct ifnet *)-1)) {
 			/* this is for to rules: */
-			(void) fr_fastroute(fin->fin_m, mp, fin, fdp);
+			ipf_fastroute(fin->fin_m, mp, fin, fdp);
 			m = *mp = NULL;
 		}
 
-		/*
-		 * Generate a duplicated packet.
-		 */
-		if ((pass & FR_DUP) != 0) {
-			mc = M_DUPLICATE(fin->fin_m);
-			if (mc != NULL)
-				(void) fr_fastroute(mc, &mc, fin, &fr->fr_dif);
-		}
-
-		(void) fr_derefrule(&fr);
+#if defined(FASTROUTE_RECURSION)
+		(void) ipf_derefrule(softc, &fr);
+#endif
 	}
+#if !defined(FASTROUTE_RECURSION)
+	RWLOCK_EXIT(&softc->ipf_mutex);
+#endif
 
 finished:
 	if (!FR_ISPASS(pass)) {
-		ATOMIC_INCL(frstats[out].fr_block);
+		LBUMP(ipf_stats[out].fr_block);
 		if (*mp != NULL) {
+#ifdef _KERNEL
 			FREE_MB_T(*mp);
+#endif
 			m = *mp = NULL;
 		}
 	} else {
-		ATOMIC_INCL(frstats[out].fr_pass);
+		LBUMP(ipf_stats[out].fr_pass);
 #if defined(_KERNEL) && defined(__sgi)
 		if ((fin->fin_hbuf != NULL) &&
 		    (mtod(fin->fin_m, struct ip *) != fin->fin_ip)) {
@@ -2774,21 +3241,20 @@
 	}
 
 	SPL_X(s);
-	RWLOCK_EXIT(&ipf_global);
 
 #ifdef _KERNEL
-# if (defined(OpenBSD) && (OpenBSD >= 200311))
-	if (FR_ISPASS(pass) && (v == 4)) {
-		ip = fin->fin_ip;
-		ip->ip_len = ntohs(ip->ip_len);
-		ip->ip_off = ntohs(ip->ip_off);
-	}
-# endif
-	return (FR_ISPASS(pass)) ? 0 : fin->fin_error;
+	if (FR_ISPASS(pass))
+		return 0;
+	LBUMP(ipf_stats[out].fr_blocked[fin->fin_reason]);
+	return fin->fin_error;
 #else /* _KERNEL */
+	if (*mp != NULL)
+		(*mp)->mb_ifp = fin->fin_ifp;
+	blockreason = fin->fin_reason;
 	FR_VERBOSE(("fin_flx %#x pass %#x ", fin->fin_flx, pass));
-	if ((pass & FR_NOMATCH) != 0)
-		return 1;
+	/*if ((pass & FR_CMDMASK) == (softc->ipf_pass & FR_CMDMASK))*/
+		if ((pass & FR_NOMATCH) != 0)
+			return 1;
 
 	if ((pass & FR_RETMASK) != 0)
 		switch (pass & FR_RETMASK)
@@ -2821,7 +3287,7 @@
 
 #ifdef	IPFILTER_LOG
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_dolog                                                    */
+/* Function:    ipf_dolog                                                   */
 /* Returns:     frentry_t* - returns contents of fin_fr (no change made)    */
 /* Parameters:  fin(I) - pointer to packet information                      */
 /*              passp(IO) - pointer to current/new filter decision (unused) */
@@ -2829,10 +3295,12 @@
 /* Checks flags set to see how a packet should be logged, if it is to be    */
 /* logged.  Adjust statistics based on its success or not.                  */
 /* ------------------------------------------------------------------------ */
-frentry_t *fr_dolog(fin, passp)
-fr_info_t *fin;
-u_32_t *passp;
+frentry_t *
+ipf_dolog(fin, passp)
+	fr_info_t *fin;
+	u_32_t *passp;
 {
+	ipf_main_softc_t *softc = fin->fin_main_soft;
 	u_32_t pass;
 	int out;
 
@@ -2839,33 +3307,35 @@
 	out = fin->fin_out;
 	pass = *passp;
 
-	if ((fr_flags & FF_LOGNOMATCH) && (pass & FR_NOMATCH)) {
+	if ((softc->ipf_flags & FF_LOGNOMATCH) && (pass & FR_NOMATCH)) {
 		pass |= FF_LOGNOMATCH;
-		ATOMIC_INCL(frstats[out].fr_npkl);
+		LBUMPD(ipf_stats[out], fr_npkl);
 		goto logit;
+
 	} else if (((pass & FR_LOGMASK) == FR_LOGP) ||
-	    (FR_ISPASS(pass) && (fr_flags & FF_LOGPASS))) {
+	    (FR_ISPASS(pass) && (softc->ipf_flags & FF_LOGPASS))) {
 		if ((pass & FR_LOGMASK) != FR_LOGP)
 			pass |= FF_LOGPASS;
-		ATOMIC_INCL(frstats[out].fr_ppkl);
+		LBUMPD(ipf_stats[out], fr_ppkl);
 		goto logit;
+
 	} else if (((pass & FR_LOGMASK) == FR_LOGB) ||
-		   (FR_ISBLOCK(pass) && (fr_flags & FF_LOGBLOCK))) {
+		   (FR_ISBLOCK(pass) && (softc->ipf_flags & FF_LOGBLOCK))) {
 		if ((pass & FR_LOGMASK) != FR_LOGB)
 			pass |= FF_LOGBLOCK;
-		ATOMIC_INCL(frstats[out].fr_bpkl);
+		LBUMPD(ipf_stats[out], fr_bpkl);
+
 logit:
-		if (ipflog(fin, pass) == -1) {
-			ATOMIC_INCL(frstats[out].fr_skip);
-
+		if (ipf_log_pkt(fin, pass) == -1) {
 			/*
 			 * If the "or-block" option has been used then
 			 * block the packet if we failed to log it.
 			 */
-			if ((pass & FR_LOGORBLOCK) &&
-			    FR_ISPASS(pass)) {
+			if ((pass & FR_LOGORBLOCK) && FR_ISPASS(pass)) {
+				DT1(frb_logfail2, u_int, pass);
 				pass &= ~FR_CMDMASK;
 				pass |= FR_BLOCK;
+				fin->fin_reason = FRB_LOGFAIL2;
 			}
 		}
 		*passp = pass;
@@ -2886,9 +3356,10 @@
 /*                                                                          */
 /* N.B.: addr should be 16bit aligned.                                      */
 /* ------------------------------------------------------------------------ */
-u_short ipf_cksum(addr, len)
-u_short *addr;
-int len;
+u_short
+ipf_cksum(addr, len)
+	u_short *addr;
+	int len;
 {
 	u_32_t sum = 0;
 
@@ -2911,11 +3382,10 @@
 /* ------------------------------------------------------------------------ */
 /* Function:    fr_cksum                                                    */
 /* Returns:     u_short - layer 4 checksum                                  */
-/* Parameters:  m(I  )     - pointer to buffer holding packet               */
+/* Parameters:  fin(I)     - pointer to packet information                  */
 /*              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.                                        */
@@ -2924,19 +3394,19 @@
 /* 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.                     */
+/* Expects ip_len and ip_off to be in network byte order when called.       */
 /* ------------------------------------------------------------------------ */
-u_short fr_cksum(m, ip, l4proto, l4hdr, l3len)
-mb_t *m;
-ip_t *ip;
-int l4proto, l3len;
-void *l4hdr;
+u_short
+fr_cksum(fin, ip, l4proto, l4hdr)
+	fr_info_t *fin;
+	ip_t *ip;
+	int l4proto;
+	void *l4hdr;
 {
-	u_short *sp, slen, sumsave, l4hlen, *csump;
+	u_short *sp, slen, sumsave, *csump;
 	u_int sum, sum2;
 	int hlen;
+	int off;
 #ifdef	USE_INET6
 	ip6_t *ip6;
 #endif
@@ -2943,12 +3413,12 @@
 
 	csump = NULL;
 	sumsave = 0;
-	l4hlen = 0;
 	sp = NULL;
 	slen = 0;
 	hlen = 0;
 	sum = 0;
 
+	sum = htons((u_short)l4proto);
 	/*
 	 * Add up IP Header portion
 	 */
@@ -2956,9 +3426,7 @@
 	if (IP_V(ip) == 4) {
 #endif
 		hlen = IP_HL(ip) << 2;
-		slen = l3len - hlen;
-		sum = htons((u_short)l4proto);
-		sum += htons(slen);
+		off = hlen;
 		sp = (u_short *)&ip->ip_src;
 		sum += *sp++;	/* ip_src */
 		sum += *sp++;
@@ -2968,9 +3436,7 @@
 	} else if (IP_V(ip) == 6) {
 		ip6 = (ip6_t *)ip;
 		hlen = sizeof(*ip6);
-		slen = l3len - hlen;
-		sum = htons((u_short)l4proto);
-		sum += htons(slen);
+		off = ((char *)fin->fin_dp - (char *)fin->fin_ip);
 		sp = (u_short *)&ip6->ip6_src;
 		sum += *sp++;	/* ip6_src */
 		sum += *sp++;
@@ -2980,6 +3446,7 @@
 		sum += *sp++;
 		sum += *sp++;
 		sum += *sp++;
+		/* This needs to be routing header aware. */
 		sum += *sp++;	/* ip6_dst */
 		sum += *sp++;
 		sum += *sp++;
@@ -2988,25 +3455,31 @@
 		sum += *sp++;
 		sum += *sp++;
 		sum += *sp++;
+	} else {
+		return 0xffff;
 	}
 #endif
+	slen = fin->fin_plen - off;
+	sum += htons(slen);
 
 	switch (l4proto)
 	{
 	case IPPROTO_UDP :
 		csump = &((udphdr_t *)l4hdr)->uh_sum;
-		l4hlen = sizeof(udphdr_t);
 		break;
 
 	case IPPROTO_TCP :
 		csump = &((tcphdr_t *)l4hdr)->th_sum;
-		l4hlen = sizeof(tcphdr_t);
 		break;
 	case IPPROTO_ICMP :
 		csump = &((icmphdr_t *)l4hdr)->icmp_cksum;
-		l4hlen = 4;
-		sum = 0;
+		sum = 0;	/* Pseudo-checksum is not included */
 		break;
+#ifdef USE_INET6
+	case IPPROTO_ICMPV6 :
+		csump = &((struct icmp6_hdr *)l4hdr)->icmp6_cksum;
+		break;
+#endif
 	default :
 		break;
 	}
@@ -3016,160 +3489,7 @@
 		*csump = 0;
 	}
 
-	l4hlen = l4hlen;	/* LINT */
-
-#ifdef	_KERNEL
-# ifdef MENTAT
-	{
-	void *rp = m->b_rptr;
-
-	if ((unsigned char *)ip > m->b_rptr && (unsigned char *)ip < m->b_wptr)
-		m->b_rptr = (u_char *)ip;
-	sum2 = ip_cksum(m, hlen, sum);	/* hlen == offset */
-	m->b_rptr = rp;
-	sum2 = (u_short)(~sum2 & 0xffff);
-	}
-# else /* MENTAT */
-#  if defined(BSD) || defined(sun)
-#   if BSD >= 199103
-	m->m_data += hlen;
-#   else
-	m->m_off += hlen;
-#   endif
-	m->m_len -= hlen;
-	sum2 = in_cksum(m, slen);
-	m->m_len += hlen;
-#   if BSD >= 199103
-	m->m_data -= hlen;
-#   else
-	m->m_off -= hlen;
-#   endif
-	/*
-	 * Both sum and sum2 are partial sums, so combine them together.
-	 */
-	sum += ~sum2 & 0xffff;
-	while (sum > 0xffff)
-		sum = (sum & 0xffff) + (sum >> 16);
-	sum2 = ~sum & 0xffff;
-#  else /* defined(BSD) || defined(sun) */
-{
-	union {
-		u_char	c[2];
-		u_short	s;
-	} bytes;
-	u_short len = ip->ip_len;
-#   if defined(__sgi)
-	int add;
-#   endif
-
-	/*
-	 * Add up IP Header portion
-	 */
-	if (sp != (u_short *)l4hdr)
-		sp = (u_short *)l4hdr;
-
-	switch (l4proto)
-	{
-	case IPPROTO_UDP :
-		sum += *sp++;	/* sport */
-		sum += *sp++;	/* dport */
-		sum += *sp++;	/* udp length */
-		sum += *sp++;	/* checksum */
-		break;
-
-	case IPPROTO_TCP :
-		sum += *sp++;	/* sport */
-		sum += *sp++;	/* dport */
-		sum += *sp++;	/* seq */
-		sum += *sp++;
-		sum += *sp++;	/* ack */
-		sum += *sp++;
-		sum += *sp++;	/* off */
-		sum += *sp++;	/* win */
-		sum += *sp++;	/* checksum */
-		sum += *sp++;	/* urp */
-		break;
-	case IPPROTO_ICMP :
-		sum = *sp++;	/* type/code */
-		sum += *sp++;	/* checksum */
-		break;
-	}
-
-#   ifdef	__sgi
-	/*
-	 * In case we had to copy the IP & TCP header out of mbufs,
-	 * skip over the mbuf bits which are the header
-	 */
-	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);
-			hlen -= add;
-			if (add == m->m_len) {
-				m = m->m_next;
-				if (!hlen) {
-					if (!m)
-						break;
-					sp = mtod(m, u_short *);
-				}
-				PANIC((!m),("fr_cksum(1): not enough data"));
-			}
-		}
-	}
-#   endif
-
-	len -= (l4hlen + hlen);
-	if (len <= 0)
-		goto nodata;
-
-	while (len > 1) {
-		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 (((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"));
-			sp = mtod(m, u_short *);
-			bytes.c[1] = *(u_char *)sp;
-			sum += bytes.s;
-			sp = (u_short *)((u_char *)sp + 1);
-		}
-		if ((u_long)sp & 1) {
-			bcopy((char *)sp++, (char *)&bytes.s, sizeof(bytes.s));
-			sum += bytes.s;
-		} else
-			sum += *sp++;
-		len -= 2;
-	}
-
-	if (len != 0)
-		sum += ntohs(*(u_char *)sp << 8);
-nodata:
-	while (sum > 0xffff)
-		sum = (sum & 0xffff) + (sum >> 16);
-	sum2 = (u_short)(~sum & 0xffff);
-}
-#  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)
-		sum += ntohs(*(u_char *)sp << 8);
-	while (sum > 0xffff)
-		sum = (sum & 0xffff) + (sum >> 16);
-	sum2 = (u_short)(~sum & 0xffff);
-#endif /* _KERNEL */
+	sum2 = ipf_pcksum(fin, off, sum);
 	if (csump != NULL)
 		*csump = sumsave;
 	return sum2;
@@ -3176,138 +3496,11 @@
 }
 
 
-#if defined(_KERNEL) && ( ((BSD < 199103) && !defined(MENTAT)) || \
-    defined(__sgi) ) && !defined(linux) && !defined(_AIX51)
-/*
- * Copyright (c) 1982, 1986, 1988, 1991, 1993
- *	The Regents of the University of California.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- *	@(#)uipc_mbuf.c	8.2 (Berkeley) 1/4/94
- * $Id: fil.c,v 1.5 2013-01-08 01:31:40 laffer1 Exp $
- */
-/*
- * Copy data from an mbuf chain starting "off" bytes from the beginning,
- * continuing for "len" bytes, into the indicated buffer.
- */
-void
-m_copydata(m, off, len, cp)
-	mb_t *m;
-	int off;
-	int len;
-	caddr_t cp;
-{
-	unsigned count;
-
-	if (off < 0 || len < 0)
-		panic("m_copydata");
-	while (off > 0) {
-		if (m == 0)
-			panic("m_copydata");
-		if (off < m->m_len)
-			break;
-		off -= m->m_len;
-		m = m->m_next;
-	}
-	while (len > 0) {
-		if (m == 0)
-			panic("m_copydata");
-		count = MIN(m->m_len - off, len);
-		bcopy(mtod(m, caddr_t) + off, cp, count);
-		len -= count;
-		cp += count;
-		off = 0;
-		m = m->m_next;
-	}
-}
-
-
-/*
- * Copy data from a buffer back into the indicated mbuf chain,
- * starting "off" bytes from the beginning, extending the mbuf
- * chain if necessary.
- */
-void
-m_copyback(m0, off, len, cp)
-	struct	mbuf *m0;
-	int off;
-	int len;
-	caddr_t cp;
-{
-	int mlen;
-	struct mbuf *m = m0, *n;
-	int totlen = 0;
-
-	if (m0 == 0)
-		return;
-	while (off > (mlen = m->m_len)) {
-		off -= mlen;
-		totlen += mlen;
-		if (m->m_next == 0) {
-			n = m_getclr(M_DONTWAIT, m->m_type);
-			if (n == 0)
-				goto out;
-			n->m_len = min(MLEN, len + off);
-			m->m_next = n;
-		}
-		m = m->m_next;
-	}
-	while (len > 0) {
-		mlen = min(m->m_len - off, len);
-		bcopy(cp, off + mtod(m, caddr_t), (unsigned)mlen);
-		cp += mlen;
-		len -= mlen;
-		mlen += off;
-		off = 0;
-		totlen += mlen;
-		if (len == 0)
-			break;
-		if (m->m_next == 0) {
-			n = m_get(M_DONTWAIT, m->m_type);
-			if (n == 0)
-				break;
-			n->m_len = min(MLEN, len);
-			m->m_next = n;
-		}
-		m = m->m_next;
-	}
-out:
-#if 0
-	if (((m = m0)->m_flags & M_PKTHDR) && (m->m_pkthdr.len < totlen))
-		m->m_pkthdr.len = totlen;
-#endif
-	return;
-}
-#endif /* (_KERNEL) && ( ((BSD < 199103) && !MENTAT) || __sgi) */
-
-
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_findgroup                                                */
+/* Function:    ipf_findgroup                                               */
 /* Returns:     frgroup_t * - NULL = group not found, else pointer to group */
-/* Parameters:  group(I) - group name to search for                         */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              group(I) - group name to search for                         */
 /*              unit(I)  - device to which this group belongs               */
 /*              set(I)   - which set of rules (inactive/inactive) this is   */
 /*              fgpp(O)  - pointer to place to store pointer to the pointer */
@@ -3316,11 +3509,13 @@
 /*                                                                          */
 /* Search amongst the defined groups for a particular group number.         */
 /* ------------------------------------------------------------------------ */
-frgroup_t *fr_findgroup(group, unit, set, fgpp)
-char *group;
-minor_t unit;
-int set;
-frgroup_t ***fgpp;
+frgroup_t *
+ipf_findgroup(softc, group, unit, set, fgpp)
+	ipf_main_softc_t *softc;
+	char *group;
+	minor_t unit;
+	int set;
+	frgroup_t ***fgpp;
 {
 	frgroup_t *fg, **fgp;
 
@@ -3328,7 +3523,7 @@
 	 * Which list of groups to search in is dependent on which list of
 	 * rules are being operated on.
 	 */
-	fgp = &ipfgroups[unit][set];
+	fgp = &softc->ipf_groups[unit][set];
 
 	while ((fg = *fgp) != NULL) {
 		if (strncmp(group, fg->fg_name, FR_GROUPLEN) == 0)
@@ -3343,10 +3538,11 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_addgroup                                                 */
+/* Function:    ipf_group_add                                               */
 /* Returns:     frgroup_t * - NULL == did not create group,                 */
 /*                            != NULL == pointer to the group               */
-/* Parameters:  num(I)   - group number to add                              */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              num(I)   - group number to add                              */
 /*              head(I)  - rule pointer that is using this as the head      */
 /*              flags(I) - rule flags which describe the type of rule it is */
 /*              unit(I)  - device to which this group will belong to        */
@@ -3356,12 +3552,14 @@
 /* Add a new group head, or if it already exists, increase the reference    */
 /* count to it.                                                             */
 /* ------------------------------------------------------------------------ */
-frgroup_t *fr_addgroup(group, head, flags, unit, set)
-char *group;
-void *head;
-u_32_t flags;
-minor_t unit;
-int set;
+frgroup_t *
+ipf_group_add(softc, group, head, flags, unit, set)
+	ipf_main_softc_t *softc;
+	char *group;
+	void *head;
+	u_32_t flags;
+	minor_t unit;
+	int set;
 {
 	frgroup_t *fg, **fgp;
 	u_32_t gflags;
@@ -3375,8 +3573,10 @@
 	fgp = NULL;
 	gflags = flags & FR_INOUT;
 
-	fg = fr_findgroup(group, unit, set, &fgp);
+	fg = ipf_findgroup(softc, group, unit, set, &fgp);
 	if (fg != NULL) {
+		if (fg->fg_head == NULL && head != NULL)
+			fg->fg_head = head;
 		if (fg->fg_flags == 0)
 			fg->fg_flags = gflags;
 		else if (gflags != fg->fg_flags)
@@ -3384,14 +3584,16 @@
 		fg->fg_ref++;
 		return fg;
 	}
+
 	KMALLOC(fg, frgroup_t *);
 	if (fg != NULL) {
 		fg->fg_head = head;
 		fg->fg_start = NULL;
 		fg->fg_next = *fgp;
-		bcopy(group, fg->fg_name, FR_GROUPLEN);
+		bcopy(group, fg->fg_name, strlen(group) + 1);
 		fg->fg_flags = gflags;
 		fg->fg_ref = 1;
+		fg->fg_set = &softc->ipf_groups[unit][set];
 		*fgp = fg;
 	}
 	return fg;
@@ -3399,38 +3601,82 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_delgroup                                                 */
-/* Returns:     Nil                                                         */
-/* Parameters:  group(I) - group name to delete                             */
-/*              unit(I)  - device to which this group belongs               */
-/*              set(I)   - which set of rules (inactive/inactive) this is   */
+/* Function:    ipf_group_del                                               */
+/* Returns:     int      - number of rules deleted                          */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              group(I) - group name to delete                             */
+/*              fr(I)    - filter rule from which group is referenced       */
 /* Write Locks: ipf_mutex                                                   */
 /*                                                                          */
-/* Attempt to delete a group head.                                          */
-/* Only do this when its reference count reaches 0.                         */
+/* This function is called whenever a reference to a group is to be dropped */
+/* and thus its reference count needs to be lowered and the group free'd if */
+/* the reference count reaches zero. Passing in fr is really for the sole   */
+/* purpose of knowing when the head rule is being deleted.                  */
 /* ------------------------------------------------------------------------ */
-void fr_delgroup(group, unit, set)
-char *group;
-minor_t unit;
-int set;
+void
+ipf_group_del(softc, group, fr)
+	ipf_main_softc_t *softc;
+	frgroup_t *group;
+	frentry_t *fr;
 {
-	frgroup_t *fg, **fgp;
 
-	fg = fr_findgroup(group, unit, set, &fgp);
-	if (fg == NULL)
-		return;
+	if (group->fg_head == fr)
+		group->fg_head = NULL;
 
-	fg->fg_ref--;
-	if (fg->fg_ref == 0) {
-		*fgp = fg->fg_next;
-		KFREE(fg);
+	group->fg_ref--;
+	if ((group->fg_ref == 0) && (group->fg_start == NULL))
+		ipf_group_free(group);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_group_free                                              */
+/* Returns:     Nil                                                         */
+/* Parameters:  group(I) - pointer to filter rule group                     */
+/*                                                                          */
+/* Remove the group from the list of groups and free it.                    */
+/* ------------------------------------------------------------------------ */
+static void
+ipf_group_free(group)
+	frgroup_t *group;
+{
+	frgroup_t **gp;
+
+	for (gp = group->fg_set; *gp != NULL; gp = &(*gp)->fg_next) {
+		if (*gp == group) {
+			*gp = group->fg_next;
+			break;
+		}
 	}
+	KFREE(group);
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_getrulen                                                 */
+/* Function:    ipf_group_flush                                             */
+/* Returns:     int      - number of rules flush from group                 */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/* Parameters:  group(I) - pointer to filter rule group                     */
+/*                                                                          */
+/* Remove all of the rules that currently are listed under the given group. */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_group_flush(softc, group)
+	ipf_main_softc_t *softc;
+	frgroup_t *group;
+{
+	int gone = 0;
+
+	(void) ipf_flushlist(softc, &gone, &group->fg_start);
+
+	return gone;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_getrulen                                                */
 /* Returns:     frentry_t * - NULL == not found, else pointer to rule n     */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
 /* Parameters:  unit(I)  - device for which to count the rule's number      */
 /*              flags(I) - which set of rules to find the rule in           */
 /*              group(I) - group name                                       */
@@ -3439,18 +3685,20 @@
 /* Find rule # n in group # g and return a pointer to it.  Return NULl if   */
 /* group # g doesn't exist or there are less than n rules in the group.     */
 /* ------------------------------------------------------------------------ */
-frentry_t *fr_getrulen(unit, group, n)
-int unit;
-char *group;
-u_32_t n;
+frentry_t *
+ipf_getrulen(softc, unit, group, n)
+	ipf_main_softc_t *softc;
+	int unit;
+	char *group;
+	u_32_t n;
 {
 	frentry_t *fr;
 	frgroup_t *fg;
 
-	fg = fr_findgroup(group, unit, fr_active, NULL);
+	fg = ipf_findgroup(softc, group, unit, softc->ipf_active, NULL);
 	if (fg == NULL)
 		return NULL;
-	for (fr = fg->fg_head; fr && n; fr = fr->fr_next, n--)
+	for (fr = fg->fg_start; fr && n; fr = fr->fr_next, n--)
 		;
 	if (n != 0)
 		return NULL;
@@ -3459,41 +3707,9 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_rulen                                                    */
-/* Returns:     int - >= 0 - rule number, -1 == search failed               */
-/* Parameters:  unit(I) - device for which to count the rule's number       */
-/*              fr(I)   - pointer to rule to match                          */
-/*                                                                          */
-/* Return the number for a rule on a specific filtering device.             */
-/* ------------------------------------------------------------------------ */
-int fr_rulen(unit, fr)
-int unit;
-frentry_t *fr;
-{
-	frentry_t *fh;
-	frgroup_t *fg;
-	u_32_t n = 0;
-
-	if (fr == NULL)
-		return -1;
-	fg = fr_findgroup(fr->fr_group, unit, fr_active, NULL);
-	if (fg == NULL)
-		return -1;
-	for (fh = fg->fg_head; fh; n++, fh = fh->fr_next)
-		if (fh == fr)
-			break;
-	if (fh == NULL)
-		return -1;
-	return n;
-}
-
-
-/* ------------------------------------------------------------------------ */
-/* Function:    frflushlist                                                 */
+/* Function:    ipf_flushlist                                               */
 /* Returns:     int - >= 0 - number of flushed rules                        */
-/* Parameters:  set(I)   - which set of rules (inactive/inactive) this is   */
-/*              unit(I)  - device for which to flush rules                  */
-/*              flags(I) - which set of rules to flush                      */
+/* Parameters:  softc(I)   - pointer to soft context main structure         */
 /*              nfreedp(O) - pointer to int where flush count is stored     */
 /*              listp(I)   - pointer to list to flush pointer               */
 /* Write Locks: ipf_mutex                                                   */
@@ -3507,11 +3723,11 @@
 /*                                                                          */
 /* NOTE: Rules not loaded from user space cannot be flushed.                */
 /* ------------------------------------------------------------------------ */
-static int frflushlist(set, unit, nfreedp, listp)
-int set;
-minor_t unit;
-int *nfreedp;
-frentry_t **listp;
+static int
+ipf_flushlist(softc, nfreedp, listp)
+	ipf_main_softc_t *softc;
+	int *nfreedp;
+	frentry_t **listp;
 {
 	int freed = 0;
 	frentry_t *fp;
@@ -3523,18 +3739,27 @@
 			continue;
 		}
 		*listp = fp->fr_next;
-		if (fp->fr_grp != NULL) {
-			(void) frflushlist(set, unit, nfreedp, fp->fr_grp);
+		if (fp->fr_next != NULL)
+			fp->fr_next->fr_pnext = fp->fr_pnext;
+		fp->fr_pnext = NULL;
+
+		if (fp->fr_grphead != NULL) {
+			freed += ipf_group_flush(softc, fp->fr_grphead);
+			fp->fr_names[fp->fr_grhead] = '\0';
 		}
 
-		if (fp->fr_grhead != NULL) {
-			fr_delgroup(fp->fr_grhead, unit, set);
-			*fp->fr_grhead = '\0';
+		if (fp->fr_icmpgrp != NULL) {
+			freed += ipf_group_flush(softc, fp->fr_icmpgrp);
+			fp->fr_names[fp->fr_icmphead] = '\0';
 		}
 
+		if (fp->fr_srctrack.ht_max_nodes)
+			ipf_rb_ht_flush(&fp->fr_srctrack);
+
+		fp->fr_next = NULL;
+
 		ASSERT(fp->fr_ref > 0);
-		fp->fr_next = NULL;
-		if (fr_derefrule(&fp) == 0)
+		if (ipf_derefrule(softc, &fp) == 0)
 			freed++;
 	}
 	*nfreedp += freed;
@@ -3543,61 +3768,47 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    frflush                                                     */
+/* Function:    ipf_flush                                                   */
 /* Returns:     int - >= 0 - number of flushed rules                        */
-/* Parameters:  unit(I)  - device for which to flush rules                  */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              unit(I)  - device for which to flush rules                  */
 /*              flags(I) - which set of rules to flush                      */
 /*                                                                          */
 /* Calls flushlist() for all filter rules (accounting, firewall - both IPv4 */
 /* and IPv6) as defined by the value of flags.                              */
 /* ------------------------------------------------------------------------ */
-int frflush(unit, proto, flags)
-minor_t unit;
-int proto, flags;
+int
+ipf_flush(softc, unit, flags)
+	ipf_main_softc_t *softc;
+	minor_t unit;
+	int flags;
 {
 	int flushed = 0, set;
 
-	WRITE_ENTER(&ipf_mutex);
-	bzero((char *)frcache, sizeof(frcache));
+	WRITE_ENTER(&softc->ipf_mutex);
 
-	set = fr_active;
+	set = softc->ipf_active;
 	if ((flags & FR_INACTIVE) == FR_INACTIVE)
 		set = 1 - set;
 
 	if (flags & FR_OUTQUE) {
-		if (proto == 0 || proto == 6) {
-			(void) frflushlist(set, unit,
-			    &flushed, &ipfilter6[1][set]);
-			(void) frflushlist(set, unit,
-			    &flushed, &ipacct6[1][set]);
-		}
-		if (proto == 0 || proto == 4) {
-			(void) frflushlist(set, unit,
-			    &flushed, &ipfilter[1][set]);
-			(void) frflushlist(set, unit,
-			    &flushed, &ipacct[1][set]);
-		}
+		ipf_flushlist(softc, &flushed, &softc->ipf_rules[1][set]);
+		ipf_flushlist(softc, &flushed, &softc->ipf_acct[1][set]);
 	}
 	if (flags & FR_INQUE) {
-		if (proto == 0 || proto == 6) {
-			(void) frflushlist(set, unit,
-			    &flushed, &ipfilter6[0][set]);
-			(void) frflushlist(set, unit,
-			    &flushed, &ipacct6[0][set]);
-		}
-		if (proto == 0 || proto == 4) {
-			(void) frflushlist(set, unit,
-			    &flushed, &ipfilter[0][set]);
-			(void) frflushlist(set, unit,
-			    &flushed, &ipacct[0][set]);
-		}
+		ipf_flushlist(softc, &flushed, &softc->ipf_rules[0][set]);
+		ipf_flushlist(softc, &flushed, &softc->ipf_acct[0][set]);
 	}
-	RWLOCK_EXIT(&ipf_mutex);
 
+	flushed += ipf_flush_groups(softc, &softc->ipf_groups[unit][set],
+				    flags & (FR_INQUE|FR_OUTQUE));
+
+	RWLOCK_EXIT(&softc->ipf_mutex);
+
 	if (unit == IPL_LOGIPF) {
 		int tmp;
 
-		tmp = frflush(IPL_LOGCOUNT, proto, flags);
+		tmp = ipf_flush(softc, IPL_LOGCOUNT, flags);
 		if (tmp >= 0)
 			flushed += tmp;
 	}
@@ -3606,6 +3817,59 @@
 
 
 /* ------------------------------------------------------------------------ */
+/* Function:    ipf_flush_groups                                            */
+/* Returns:     int - >= 0 - number of flushed rules                        */
+/* Parameters:  softc(I)  - soft context pointerto work with                */
+/*              grhead(I) - pointer to the start of the group list to flush */
+/*              flags(I)  - which set of rules to flush                     */
+/*                                                                          */
+/* Walk through all of the groups under the given group head and remove all */
+/* of those that match the flags passed in. The for loop here is bit more   */
+/* complicated than usual because the removal of a rule with ipf_derefrule  */
+/* may end up removing not only the structure pointed to by "fg" but also   */
+/* what is fg_next and fg_next after that. So if a filter rule is actually  */
+/* removed from the group then it is necessary to start again.              */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_flush_groups(softc, grhead, flags)
+	ipf_main_softc_t *softc;
+	frgroup_t **grhead;
+	int flags;
+{
+	frentry_t *fr, **frp;
+	frgroup_t *fg, **fgp;
+	int flushed = 0;
+	int removed = 0;
+
+	for (fgp = grhead; (fg = *fgp) != NULL; ) {
+		while ((fg != NULL) && ((fg->fg_flags & flags) == 0))
+			fg = fg->fg_next;
+		if (fg == NULL)
+			break;
+		removed = 0;
+		frp = &fg->fg_start;
+		while ((removed == 0) && ((fr = *frp) != NULL)) {
+			if ((fr->fr_flags & flags) == 0) {
+				frp = &fr->fr_next;
+			} else {
+				if (fr->fr_next != NULL)
+					fr->fr_next->fr_pnext = fr->fr_pnext;
+				*frp = fr->fr_next;
+				fr->fr_pnext = NULL;
+				fr->fr_next = NULL;
+				(void) ipf_derefrule(softc, &fr);
+				flushed++;
+				removed++;
+			}
+		}
+		if (removed == 0)
+			fgp = &fg->fg_next;
+	}
+	return flushed;
+}
+
+
+/* ------------------------------------------------------------------------ */
 /* Function:    memstr                                                      */
 /* Returns:     char *  - NULL if failed, != NULL pointer to matching bytes */
 /* Parameters:  src(I)  - pointer to byte sequence to match                 */
@@ -3616,10 +3880,11 @@
 /* Search dst for a sequence of bytes matching those at src and extend for  */
 /* slen bytes.                                                              */
 /* ------------------------------------------------------------------------ */
-char *memstr(src, dst, slen, dlen)
-const char *src;
-char *dst;
-size_t slen, dlen;
+char *
+memstr(src, dst, slen, dlen)
+	const char *src;
+	char *dst;
+	size_t slen, dlen;
 {
 	char *s = NULL;
 
@@ -3634,7 +3899,7 @@
 	return s;
 }
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_fixskip                                                  */
+/* Function:    ipf_fixskip                                                 */
 /* Returns:     Nil                                                         */
 /* Parameters:  listp(IO)    - pointer to start of list with skip rule      */
 /*              rp(I)        - rule added/removed with skip in it.          */
@@ -3645,9 +3910,10 @@
 /* Adjust all the rules in a list which would have skip'd past the position */
 /* where we are inserting to skip to the right place given the change.      */
 /* ------------------------------------------------------------------------ */
-void fr_fixskip(listp, rp, addremove)
-frentry_t **listp, *rp;
-int addremove;
+void
+ipf_fixskip(listp, rp, addremove)
+	frentry_t **listp, *rp;
+	int addremove;
 {
 	int rules, rn;
 	frentry_t *fp;
@@ -3676,8 +3942,9 @@
 /* consecutive 1's is different to that passed, return -1, else return #    */
 /* of bits.                                                                 */
 /* ------------------------------------------------------------------------ */
-int	count4bits(ip)
-u_32_t	ip;
+int
+count4bits(ip)
+	u_32_t	ip;
 {
 	u_32_t	ipn;
 	int	cnt = 0, i, j;
@@ -3700,7 +3967,6 @@
 }
 
 
-# if 0
 /* ------------------------------------------------------------------------ */
 /* Function:    count6bits                                                  */
 /* Returns:     int - >= 0 - number of consecutive bits in input            */
@@ -3709,8 +3975,10 @@
 /* IPv6 ONLY                                                                */
 /* count consecutive 1's in bit mask.                                       */
 /* ------------------------------------------------------------------------ */
-int count6bits(msk)
-u_32_t *msk;
+# ifdef USE_INET6
+int
+count6bits(msk)
+	u_32_t *msk;
 {
 	int i = 0, k;
 	u_32_t j;
@@ -3730,8 +3998,8 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    frsynclist                                                  */
-/* Returns:     void                                                        */
+/* Function:    ipf_synclist                                                */
+/* Returns:     int    - 0 = no failures, else indication of first failure  */
 /* Parameters:  fr(I)  - start of filter list to sync interface names for   */
 /*              ifp(I) - interface pointer for limiting sync lookups        */
 /* Write Locks: ipf_mutex                                                   */
@@ -3740,16 +4008,33 @@
 /* pointers.  Where dynamic addresses are used, also update the IP address  */
 /* used in the rule.  The interface pointer is used to limit the lookups to */
 /* a specific set of matching names if it is non-NULL.                      */
+/* Errors can occur when resolving the destination name of to/dup-to fields */
+/* when the name points to a pool and that pool doest not exist. If this    */
+/* does happen then it is necessary to check if there are any lookup refs   */
+/* that need to be dropped before returning with an error.                  */
 /* ------------------------------------------------------------------------ */
-static void frsynclist(fr, ifp)
-frentry_t *fr;
-void *ifp;
+static int
+ipf_synclist(softc, fr, ifp)
+	ipf_main_softc_t *softc;
+	frentry_t *fr;
+	void *ifp;
 {
+	frentry_t *frt, *start = fr;
 	frdest_t *fdp;
+	char *name;
+	int error;
+	void *ifa;
 	int v, i;
 
+	error = 0;
+
 	for (; fr; fr = fr->fr_next) {
-		v = fr->fr_v;
+		if (fr->fr_family == AF_INET)
+			v = 4;
+		else if (fr->fr_family == AF_INET6)
+			v = 6;
+		else
+			v = 0;
 
 		/*
 		 * Lookup all the interface names that are part of the rule.
@@ -3757,102 +4042,124 @@
 		for (i = 0; i < 4; i++) {
 			if ((ifp != NULL) && (fr->fr_ifas[i] != ifp))
 				continue;
-			fr->fr_ifas[i] = fr_resolvenic(fr->fr_ifnames[i], v);
+			if (fr->fr_ifnames[i] == -1)
+				continue;
+			name = FR_NAME(fr, fr_ifnames[i]);
+			fr->fr_ifas[i] = ipf_resolvenic(softc, name, v);
 		}
 
-		if (fr->fr_type == FR_T_IPF) {
+		if ((fr->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) {
 			if (fr->fr_satype != FRI_NORMAL &&
 			    fr->fr_satype != FRI_LOOKUP) {
-				(void)fr_ifpaddr(v, fr->fr_satype,
-						 fr->fr_ifas[fr->fr_sifpidx],
-						 &fr->fr_src, &fr->fr_smsk);
+				ifa = ipf_resolvenic(softc, fr->fr_names +
+						     fr->fr_sifpidx, v);
+				ipf_ifpaddr(softc, v, fr->fr_satype, ifa,
+					    &fr->fr_src6, &fr->fr_smsk6);
 			}
 			if (fr->fr_datype != FRI_NORMAL &&
 			    fr->fr_datype != FRI_LOOKUP) {
-				(void)fr_ifpaddr(v, fr->fr_datype,
-						 fr->fr_ifas[fr->fr_difpidx],
-						 &fr->fr_dst, &fr->fr_dmsk);
+				ifa = ipf_resolvenic(softc, fr->fr_names +
+						     fr->fr_sifpidx, v);
+				ipf_ifpaddr(softc, v, fr->fr_datype, ifa,
+					    &fr->fr_dst6, &fr->fr_dmsk6);
 			}
 		}
 
 		fdp = &fr->fr_tifs[0];
-		if ((ifp == NULL) || (fdp->fd_ifp == ifp))
-			fr_resolvedest(fdp, v);
+		if ((ifp == NULL) || (fdp->fd_ptr == ifp)) {
+			error = ipf_resolvedest(softc, fr->fr_names, fdp, v);
+			if (error != 0)
+				goto unwind;
+		}
 
 		fdp = &fr->fr_tifs[1];
-		if ((ifp == NULL) || (fdp->fd_ifp == ifp))
-			fr_resolvedest(fdp, v);
+		if ((ifp == NULL) || (fdp->fd_ptr == ifp)) {
+			error = ipf_resolvedest(softc, fr->fr_names, fdp, v);
+			if (error != 0)
+				goto unwind;
+		}
 
 		fdp = &fr->fr_dif;
-		if ((ifp == NULL) || (fdp->fd_ifp == ifp)) {
-			fr_resolvedest(fdp, v);
-
-			fr->fr_flags &= ~FR_DUP;
-			if ((fdp->fd_ifp != (void *)-1) &&
-			    (fdp->fd_ifp != NULL))
-				fr->fr_flags |= FR_DUP;
+		if ((ifp == NULL) || (fdp->fd_ptr == ifp)) {
+			error = ipf_resolvedest(softc, fr->fr_names, fdp, v);
+			if (error != 0)
+				goto unwind;
 		}
 
-#ifdef	IPFILTER_LOOKUP
-		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_srcsubtype,
-							 &fr->fr_slookup,
-							 &fr->fr_srcfunc);
+		if (((fr->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) &&
+		    (fr->fr_satype == FRI_LOOKUP) && (fr->fr_srcptr == NULL)) {
+			fr->fr_srcptr = ipf_lookup_res_num(softc,
+							   fr->fr_srctype,
+							   IPL_LOGIPF,
+							   fr->fr_srcnum,
+							   &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_dstsubtype,
-							 &fr->fr_dlookup,
-							 &fr->fr_dstfunc);
+		if (((fr->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) &&
+		    (fr->fr_datype == FRI_LOOKUP) && (fr->fr_dstptr == NULL)) {
+			fr->fr_dstptr = ipf_lookup_res_num(softc,
+							   fr->fr_dsttype,
+							   IPL_LOGIPF,
+							   fr->fr_dstnum,
+							   &fr->fr_dstfunc);
 		}
-#endif
 	}
+	return 0;
+
+unwind:
+	for (frt = start; frt != fr; fr = fr->fr_next) {
+		if (((frt->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) &&
+		    (frt->fr_satype == FRI_LOOKUP) && (frt->fr_srcptr != NULL))
+				ipf_lookup_deref(softc, frt->fr_srctype,
+						 frt->fr_srcptr);
+		if (((frt->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) &&
+		    (frt->fr_datype == FRI_LOOKUP) && (frt->fr_dstptr != NULL))
+				ipf_lookup_deref(softc, frt->fr_dsttype,
+						 frt->fr_dstptr);
+	}
+	return error;
 }
 
 
-#ifdef	_KERNEL
 /* ------------------------------------------------------------------------ */
-/* Function:    frsync                                                      */
+/* Function:    ipf_sync                                                    */
 /* Returns:     void                                                        */
 /* Parameters:  Nil                                                         */
 /*                                                                          */
-/* frsync() is called when we suspect that the interface list or            */
+/* ipf_sync() is called when we suspect that the interface list or          */
 /* information about interfaces (like IP#) has changed.  Go through all     */
 /* filter rules, NAT entries and the state table and check if anything      */
 /* needs to be changed/updated.                                             */
 /* ------------------------------------------------------------------------ */
-void frsync(ifp)
-void *ifp;
+int
+ipf_sync(softc, ifp)
+	ipf_main_softc_t *softc;
+	void *ifp;
 {
 	int i;
 
 # if !SOLARIS
-	fr_natsync(ifp);
-	fr_statesync(ifp);
+	ipf_nat_sync(softc, ifp);
+	ipf_state_sync(softc, ifp);
+	ipf_lookup_sync(softc, ifp);
 # endif
 
-	WRITE_ENTER(&ipf_mutex);
-	frsynclist(ipacct[0][fr_active], ifp);
-	frsynclist(ipacct[1][fr_active], ifp);
-	frsynclist(ipfilter[0][fr_active], ifp);
-	frsynclist(ipfilter[1][fr_active], ifp);
-	frsynclist(ipacct6[0][fr_active], ifp);
-	frsynclist(ipacct6[1][fr_active], ifp);
-	frsynclist(ipfilter6[0][fr_active], ifp);
-	frsynclist(ipfilter6[1][fr_active], ifp);
+	WRITE_ENTER(&softc->ipf_mutex);
+	(void) ipf_synclist(softc, softc->ipf_acct[0][softc->ipf_active], ifp);
+	(void) ipf_synclist(softc, softc->ipf_acct[1][softc->ipf_active], ifp);
+	(void) ipf_synclist(softc, softc->ipf_rules[0][softc->ipf_active], ifp);
+	(void) ipf_synclist(softc, softc->ipf_rules[1][softc->ipf_active], ifp);
 
 	for (i = 0; i < IPL_LOGSIZE; i++) {
 		frgroup_t *g;
 
-		for (g = ipfgroups[i][0]; g != NULL; g = g->fg_next)
-			frsynclist(g->fg_start, ifp);
-		for (g = ipfgroups[i][1]; g != NULL; g = g->fg_next)
-			frsynclist(g->fg_start, ifp);
+		for (g = softc->ipf_groups[i][0]; g != NULL; g = g->fg_next)
+			(void) ipf_synclist(softc, g->fg_start, ifp);
+		for (g = softc->ipf_groups[i][1]; g != NULL; g = g->fg_next)
+			(void) ipf_synclist(softc, g->fg_start, ifp);
 	}
-	RWLOCK_EXIT(&ipf_mutex);
+	RWLOCK_EXIT(&softc->ipf_mutex);
+
+	return 0;
 }
 
 
@@ -3872,9 +4179,11 @@
 /* to start copying from (src) and a pointer to where to store it (dst).    */
 /* NB: src - pointer to user space pointer, dst - kernel space pointer      */
 /* ------------------------------------------------------------------------ */
-int copyinptr(src, dst, size)
-void *src, *dst;
-size_t size;
+int
+copyinptr(softc, src, dst, size)
+	ipf_main_softc_t *softc;
+	void *src, *dst;
+	size_t size;
 {
 	caddr_t ca;
 	int error;
@@ -3887,8 +4196,10 @@
 	bcopy(src, (caddr_t)&ca, sizeof(ca));
 # endif
 	error = COPYIN(ca, dst, size);
-	if (error != 0)
+	if (error != 0) {
+		IPFERROR(3);
 		error = EFAULT;
+	}
 	return error;
 }
 
@@ -3904,9 +4215,11 @@
 /* to start copying from (src) and a pointer to where to store it (dst).    */
 /* NB: src - kernel space pointer, dst - pointer to user space pointer.     */
 /* ------------------------------------------------------------------------ */
-int copyoutptr(src, dst, size)
-void *src, *dst;
-size_t size;
+int
+copyoutptr(softc, src, dst, size)
+	ipf_main_softc_t *softc;
+	void *src, *dst;
+	size_t size;
 {
 	caddr_t ca;
 	int error;
@@ -3913,15 +4226,18 @@
 
 	bcopy(dst, (caddr_t)&ca, sizeof(ca));
 	error = COPYOUT(src, ca, size);
-	if (error != 0)
+	if (error != 0) {
+		IPFERROR(4);
 		error = EFAULT;
+	}
 	return error;
 }
+#ifdef	_KERNEL
 #endif
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_lock                                                     */
+/* Function:    ipf_lock                                                    */
 /* 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      */
@@ -3929,9 +4245,10 @@
 /* Get the new value for the lock integer, set it and return the old value  */
 /* in *lockp.                                                               */
 /* ------------------------------------------------------------------------ */
-int fr_lock(data, lockp)
-caddr_t data;
-int *lockp;
+int
+ipf_lock(data, lockp)
+	caddr_t data;
+	int *lockp;
 {
 	int arg, err;
 
@@ -3947,51 +4264,78 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_getstat                                                  */
+/* Function:    ipf_getstat                                                 */
 /* Returns:     Nil                                                         */
-/* Parameters:  fiop(I)  - pointer to ipfilter stats structure              */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              fiop(I)  - pointer to ipfilter stats structure              */
+/*              rev(I)   - version claim by program doing ioctl             */
 /*                                                                          */
 /* Stores a copy of current pointers, counters, etc, in the friostat        */
 /* structure.                                                               */
+/* If IPFILTER_COMPAT is compiled, we pretend to be whatever version the    */
+/* program is looking for. This ensure that validation of the version it    */
+/* expects will always succeed. Thus kernels with IPFILTER_COMPAT will      */
+/* allow older binaries to work but kernels without it will not.            */
 /* ------------------------------------------------------------------------ */
-void fr_getstat(fiop)
-friostat_t *fiop;
+/*ARGSUSED*/
+static void
+ipf_getstat(softc, fiop, rev)
+	ipf_main_softc_t *softc;
+	friostat_t *fiop;
+	int rev;
 {
-	int i, j;
+	int i;
 
-	bcopy((char *)frstats, (char *)fiop->f_st, sizeof(filterstats_t) * 2);
-	fiop->f_locks[IPL_LOGSTATE] = fr_state_lock;
-	fiop->f_locks[IPL_LOGNAT] = fr_nat_lock;
-	fiop->f_locks[IPL_LOGIPF] = fr_frag_lock;
-	fiop->f_locks[IPL_LOGAUTH] = fr_auth_lock;
+	bcopy((char *)softc->ipf_stats, (char *)fiop->f_st,
+	      sizeof(ipf_statistics_t) * 2);
+	fiop->f_locks[IPL_LOGSTATE] = -1;
+	fiop->f_locks[IPL_LOGNAT] = -1;
+	fiop->f_locks[IPL_LOGIPF] = -1;
+	fiop->f_locks[IPL_LOGAUTH] = -1;
 
-	for (i = 0; i < 2; i++)
-		for (j = 0; j < 2; j++) {
-			fiop->f_ipf[i][j] = ipfilter[i][j];
-			fiop->f_acct[i][j] = ipacct[i][j];
-			fiop->f_ipf6[i][j] = ipfilter6[i][j];
-			fiop->f_acct6[i][j] = ipacct6[i][j];
-		}
+	fiop->f_ipf[0][0] = softc->ipf_rules[0][0];
+	fiop->f_acct[0][0] = softc->ipf_acct[0][0];
+	fiop->f_ipf[0][1] = softc->ipf_rules[0][1];
+	fiop->f_acct[0][1] = softc->ipf_acct[0][1];
+	fiop->f_ipf[1][0] = softc->ipf_rules[1][0];
+	fiop->f_acct[1][0] = softc->ipf_acct[1][0];
+	fiop->f_ipf[1][1] = softc->ipf_rules[1][1];
+	fiop->f_acct[1][1] = softc->ipf_acct[1][1];
 
-	fiop->f_ticks = fr_ticks;
-	fiop->f_active = fr_active;
-	fiop->f_froute[0] = fr_frouteok[0];
-	fiop->f_froute[1] = fr_frouteok[1];
+	fiop->f_ticks = softc->ipf_ticks;
+	fiop->f_active = softc->ipf_active;
+	fiop->f_froute[0] = softc->ipf_frouteok[0];
+	fiop->f_froute[1] = softc->ipf_frouteok[1];
+	fiop->f_rb_no_mem = softc->ipf_rb_no_mem;
+	fiop->f_rb_node_max = softc->ipf_rb_node_max;
 
-	fiop->f_running = fr_running;
+	fiop->f_running = softc->ipf_running;
 	for (i = 0; i < IPL_LOGSIZE; i++) {
-		fiop->f_groups[i][0] = ipfgroups[i][0];
-		fiop->f_groups[i][1] = ipfgroups[i][1];
+		fiop->f_groups[i][0] = softc->ipf_groups[i][0];
+		fiop->f_groups[i][1] = softc->ipf_groups[i][1];
 	}
 #ifdef  IPFILTER_LOG
+	fiop->f_log_ok = ipf_log_logok(softc, IPL_LOGIPF);
+	fiop->f_log_fail = ipf_log_failures(softc, IPL_LOGIPF);
 	fiop->f_logging = 1;
 #else
+	fiop->f_log_ok = 0;
+	fiop->f_log_fail = 0;
 	fiop->f_logging = 0;
 #endif
-	fiop->f_defpass = fr_pass;
-	fiop->f_features = fr_features;
+	fiop->f_defpass = softc->ipf_pass;
+	fiop->f_features = ipf_features;
+
+#ifdef IPFILTER_COMPAT
+	sprintf(fiop->f_version, "IP Filter: v%d.%d.%d",
+		(rev / 1000000) % 100,
+		(rev / 10000) % 100,
+		(rev / 100) % 100);
+#else
+	rev = rev;
 	(void) strncpy(fiop->f_version, ipfilter_version,
 		       sizeof(fiop->f_version));
+#endif
 }
 
 
@@ -4042,7 +4386,7 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_matchicmpqueryreply                                      */
+/* Function:    ipf_matchicmpqueryreply                                     */
 /* Returns:     int - 1 if "icmp" is a valid reply to "ic" else 0.          */
 /* Parameters:  v(I)    - IP protocol version (4 or 6)                      */
 /*              ic(I)   - ICMP information                                  */
@@ -4053,11 +4397,12 @@
 /* reply to one as described by what's in ic.  If it is a match, return 1,  */
 /* else return 0 for no match.                                              */
 /* ------------------------------------------------------------------------ */
-int fr_matchicmpqueryreply(v, ic, icmp, rev)
-int v;
-icmpinfo_t *ic;
-icmphdr_t *icmp;
-int rev;
+int
+ipf_matchicmpqueryreply(v, ic, icmp, rev)
+	int v;
+	icmpinfo_t *ic;
+	icmphdr_t *icmp;
+	int rev;
 {
 	int ictype;
 
@@ -4091,86 +4436,37 @@
 }
 
 
-#ifdef	IPFILTER_LOOKUP
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_resolvelookup                                            */
-/* Returns:     void * - NULL = failure, else success.                      */
-/* Parameters:  type(I)     - type of lookup these parameters are for.      */
-/*              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.                            */
+/* Function:    ipf_rule_compare                                            */
+/* Parameters:  fr1(I) - first rule structure to compare                    */
+/*              fr2(I) - second rule structure to compare                   */
+/* Returns:     int    - 0 == rules are the same, else mismatch             */
 /*                                                                          */
-/* Search for the "table" number passed in amongst those configured for     */
-/* that particular type.  If the type is recognised then the function to    */
-/* call to do the IP address search will be change, regardless of whether   */
-/* or not the "table" number exists.                                        */
+/* Compare two rules and return 0 if they match or a number indicating      */
+/* which of the individual checks failed.                                   */
 /* ------------------------------------------------------------------------ */
-static void *fr_resolvelookup(type, subtype, info, funcptr)
-u_int type, subtype;
-i6addr_t *info;
-lookupfunc_t *funcptr;
+static int
+ipf_rule_compare(frentry_t *fr1, frentry_t *fr2)
 {
-	char label[FR_GROUPLEN], *name;
-	iphtable_t *iph;
-	ip_pool_t *ipo;
-	void *ptr;
-
-	if (subtype == 0) {
-#if defined(SNPRINTF) && defined(_KERNEL)
-		SNPRINTF(label, sizeof(label), "%u", info->iplookupnum);
-#else
-		(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;
+	if (fr1->fr_cksum != fr2->fr_cksum)
+		return 1;
+	if (fr1->fr_size != fr2->fr_size)
+		return 2;
+	if (fr1->fr_dsize != fr2->fr_dsize)
+		return 3;
+	if (bcmp((char *)&fr1->fr_func, (char *)&fr2->fr_func,
+		 fr1->fr_size - offsetof(struct frentry, fr_func)) != 0)
+		return 4;
+	if (fr1->fr_data && !fr2->fr_data)
+		return 5;
+	if (!fr1->fr_data && fr2->fr_data)
+		return 6;
+	if (fr1->fr_data) {
+		if (bcmp(fr1->fr_caddr, fr2->fr_caddr, fr1->fr_dsize))
+			return 7;
 	}
-
-	READ_ENTER(&ip_poolrw);
-
-	switch (type)
-	{
-	case IPLT_POOL :
-# if (defined(__osf__) && defined(_KERNEL))
-		ptr = NULL;
-		*funcptr = NULL;
-# else
-		ipo = ip_pool_find(IPL_LOGIPF, name);
-		ptr = ipo;
-		if (ipo != NULL) {
-			ATOMIC_INC32(ipo->ipo_ref);
-		}
-		*funcptr = ip_pool_search;
-# endif
-		break;
-	case IPLT_HASH :
-		iph = fr_findhtable(IPL_LOGIPF, name);
-		ptr = iph;
-		if (iph != NULL) {
-			ATOMIC_INC32(iph->iph_ref);
-		}
-		*funcptr = fr_iphmfindip;
-		break;
-	default:
-		ptr = NULL;
-		*funcptr = NULL;
-		break;
-	}
-	RWLOCK_EXIT(&ip_poolrw);
-
-	return ptr;
+	return 0;
 }
-#endif
 
 
 /* ------------------------------------------------------------------------ */
@@ -4190,54 +4486,106 @@
 /* of the rule structure being loaded.  If a rule has user defined timeouts */
 /* then make sure they are created and initialised before exiting.          */
 /* ------------------------------------------------------------------------ */
-int frrequest(unit, req, data, set, makecopy)
-int unit;
-ioctlcmd_t req;
-int set, makecopy;
-caddr_t data;
+int
+frrequest(softc, unit, req, data, set, makecopy)
+	ipf_main_softc_t *softc;
+	int unit;
+	ioctlcmd_t req;
+	int set, makecopy;
+	caddr_t data;
 {
+	int error = 0, in, family, addrem, need_free = 0;
 	frentry_t frd, *fp, *f, **fprev, **ftail;
-	int error = 0, in, v;
-	void *ptr, *uptr;
+	void *ptr, *uptr, *cptr;
 	u_int *p, *pp;
 	frgroup_t *fg;
 	char *group;
 
+	ptr = NULL;
+	cptr = NULL;
 	fg = NULL;
 	fp = &frd;
 	if (makecopy != 0) {
-		error = fr_inobj(data, fp, IPFOBJ_FRENTRY);
-		if (error)
-			return EFAULT;
-		if ((fp->fr_flags & FR_T_BUILTIN) != 0)
+		bzero(fp, sizeof(frd));
+		error = ipf_inobj(softc, data, NULL, fp, IPFOBJ_FRENTRY);
+		if (error) {
+			return error;
+		}
+		if ((fp->fr_type & FR_T_BUILTIN) != 0) {
+			IPFERROR(6);
 			return EINVAL;
+		}
+		KMALLOCS(f, frentry_t *, fp->fr_size);
+		if (f == NULL) {
+			IPFERROR(131);
+			return ENOMEM;
+		}
+		bzero(f, fp->fr_size);
+		error = ipf_inobjsz(softc, data, f, IPFOBJ_FRENTRY,
+				    fp->fr_size);
+		if (error) {
+			KFREES(f, fp->fr_size);
+			return error;
+		}
+
+		fp = f;
+		f = NULL;
+		fp->fr_next = NULL;
+		fp->fr_dnext = NULL;
+		fp->fr_pnext = NULL;
+		fp->fr_pdnext = NULL;
+		fp->fr_grp = NULL;
+		fp->fr_grphead = NULL;
+		fp->fr_icmpgrp = NULL;
+		fp->fr_isc = (void *)-1;
+		fp->fr_ptr = NULL;
 		fp->fr_ref = 0;
 		fp->fr_flags |= FR_COPIED;
 	} else {
 		fp = (frentry_t *)data;
-		if ((fp->fr_type & FR_T_BUILTIN) == 0)
+		if ((fp->fr_type & FR_T_BUILTIN) == 0) {
+			IPFERROR(7);
 			return EINVAL;
+		}
 		fp->fr_flags &= ~FR_COPIED;
 	}
 
 	if (((fp->fr_dsize == 0) && (fp->fr_data != NULL)) ||
-	    ((fp->fr_dsize != 0) && (fp->fr_data == NULL)))
-		return EINVAL;
+	    ((fp->fr_dsize != 0) && (fp->fr_data == NULL))) {
+		IPFERROR(8);
+		error = EINVAL;
+		goto donenolock;
+	}
 
-	v = fp->fr_v;
+	family = fp->fr_family;
 	uptr = fp->fr_data;
 
+	if (req == (ioctlcmd_t)SIOCINAFR || req == (ioctlcmd_t)SIOCINIFR ||
+	    req == (ioctlcmd_t)SIOCADAFR || req == (ioctlcmd_t)SIOCADIFR)
+		addrem = 0;
+	else if (req == (ioctlcmd_t)SIOCRMAFR || req == (ioctlcmd_t)SIOCRMIFR)
+		addrem = 1;
+	else if (req == (ioctlcmd_t)SIOCZRLST)
+		addrem = 2;
+	else {
+		IPFERROR(9);
+		error = EINVAL;
+		goto donenolock;
+	}
+
 	/*
 	 * Only filter rules for IPv4 or IPv6 are accepted.
 	 */
-	if (v == 4)
+	if (family == AF_INET) {
 		/*EMPTY*/;
 #ifdef	USE_INET6
-	else if (v == 6)
+	} else if (family == AF_INET6) {
 		/*EMPTY*/;
 #endif
-	else {
-		return EINVAL;
+	} else if (family != 0) {
+		IPFERROR(10);
+		error = EINVAL;
+		goto donenolock;
 	}
 
 	/*
@@ -4246,37 +4594,110 @@
 	 * rule.
 	 */
 	if ((makecopy == 1) && (fp->fr_func != NULL)) {
-		if (fr_findfunc(fp->fr_func) == NULL)
-			return ESRCH;
-		error = fr_funcinit(fp);
-		if (error != 0)
-			return error;
+		if (ipf_findfunc(fp->fr_func) == NULL) {
+			IPFERROR(11);
+			error = ESRCH;
+			goto donenolock;
+		}
+
+		if (addrem == 0) {
+			error = ipf_funcinit(softc, fp);
+			if (error != 0)
+				goto donenolock;
+		}
 	}
+	if ((fp->fr_flags & FR_CALLNOW) &&
+	    ((fp->fr_func == NULL) || (fp->fr_func == (ipfunc_t)-1))) {
+		IPFERROR(142);
+		error = ESRCH;
+		goto donenolock;
+	}
+	if (((fp->fr_flags & FR_CMDMASK) == FR_CALL) &&
+	    ((fp->fr_func == NULL) || (fp->fr_func == (ipfunc_t)-1))) {
+		IPFERROR(143);
+		error = ESRCH;
+		goto donenolock;
+	}
 
 	ptr = NULL;
-	/*
-	 * Check that the group number does exist and that its use (in/out)
-	 * matches what the rule is.
-	 */
-	if (!strncmp(fp->fr_grhead, "0", FR_GROUPLEN))
-		*fp->fr_grhead = '\0';
-	group = fp->fr_group;
-	if (!strncmp(group, "0", FR_GROUPLEN))
-		*group = '\0';
+	cptr = NULL;
 
 	if (FR_ISACCOUNT(fp->fr_flags))
 		unit = IPL_LOGCOUNT;
 
-	if ((req != (int)SIOCZRLST) && (*group != '\0')) {
-		fg = fr_findgroup(group, unit, set, NULL);
-		if (fg == NULL)
-			return ESRCH;
-		if (fg->fg_flags == 0)
-			fg->fg_flags = fp->fr_flags & FR_INOUT;
-		else if (fg->fg_flags != (fp->fr_flags & FR_INOUT))
-			return ESRCH;
+	/*
+	 * Check that each group name in the rule has a start index that
+	 * is valid.
+	 */
+	if (fp->fr_icmphead != -1) {
+		if ((fp->fr_icmphead < 0) ||
+		    (fp->fr_icmphead >= fp->fr_namelen)) {
+			IPFERROR(136);
+			error = EINVAL;
+			goto donenolock;
+		}
+		if (!strcmp(FR_NAME(fp, fr_icmphead), "0"))
+			fp->fr_names[fp->fr_icmphead] = '\0';
 	}
 
+	if (fp->fr_grhead != -1) {
+		if ((fp->fr_grhead < 0) ||
+		    (fp->fr_grhead >= fp->fr_namelen)) {
+			IPFERROR(137);
+			error = EINVAL;
+			goto donenolock;
+		}
+		if (!strcmp(FR_NAME(fp, fr_grhead), "0"))
+			fp->fr_names[fp->fr_grhead] = '\0';
+	}
+
+	if (fp->fr_group != -1) {
+		if ((fp->fr_group < 0) ||
+		    (fp->fr_group >= fp->fr_namelen)) {
+			IPFERROR(138);
+			error = EINVAL;
+			goto donenolock;
+		}
+		if ((req != (int)SIOCZRLST) && (fp->fr_group != -1)) {
+			/*
+			 * Allow loading rules that are in groups to cause
+			 * them to be created if they don't already exit.
+			 */
+			group = FR_NAME(fp, fr_group);
+			if (addrem == 0) {
+				fg = ipf_group_add(softc, group, NULL,
+						   fp->fr_flags, unit, set);
+				fp->fr_grp = fg;
+			} else {
+				fg = ipf_findgroup(softc, group, unit,
+						   set, NULL);
+				if (fg == NULL) {
+					IPFERROR(12);
+					error = ESRCH;
+					goto donenolock;
+				}
+			}
+
+			if (fg->fg_flags == 0) {
+				fg->fg_flags = fp->fr_flags & FR_INOUT;
+			} else if (fg->fg_flags != (fp->fr_flags & FR_INOUT)) {
+				IPFERROR(13);
+				error = ESRCH;
+				goto donenolock;
+			}
+		}
+	} else {
+		/*
+		 * If a rule is going to be part of a group then it does
+		 * not matter whether it is an in or out rule, but if it
+		 * isn't in a group, then it does...
+		 */
+		if ((fp->fr_flags & (FR_INQUE|FR_OUTQUE)) == 0) {
+			IPFERROR(14);
+			error = EINVAL;
+			goto donenolock;
+		}
+	}
 	in = (fp->fr_flags & FR_INQUE) ? 0 : 1;
 
 	/*
@@ -4284,27 +4705,30 @@
 	 */
 	ftail = NULL;
 	fprev = NULL;
-	if (unit == IPL_LOGAUTH)
-		fprev = &ipauth;
-	else if (v == 4) {
+	if (unit == IPL_LOGAUTH) {
+                if ((fp->fr_tifs[0].fd_ptr != NULL) ||
+		    (fp->fr_tifs[1].fd_ptr != NULL) ||
+		    (fp->fr_dif.fd_ptr != NULL) ||
+		    (fp->fr_flags & FR_FASTROUTE)) {
+			softc->ipf_interror = 145;
+			error = EINVAL;
+			goto donenolock;
+		}
+		fprev = ipf_auth_rulehead(softc);
+	} else {
 		if (FR_ISACCOUNT(fp->fr_flags))
-			fprev = &ipacct[in][set];
+			fprev = &softc->ipf_acct[in][set];
 		else if ((fp->fr_flags & (FR_OUTQUE|FR_INQUE)) != 0)
-			fprev = &ipfilter[in][set];
-	} else if (v == 6) {
-		if (FR_ISACCOUNT(fp->fr_flags))
-			fprev = &ipacct6[in][set];
-		else if ((fp->fr_flags & (FR_OUTQUE|FR_INQUE)) != 0)
-			fprev = &ipfilter6[in][set];
+			fprev = &softc->ipf_rules[in][set];
 	}
-	if (fprev == NULL)
-		return ESRCH;
+	if (fprev == NULL) {
+		IPFERROR(15);
+		error = ESRCH;
+		goto donenolock;
+	}
 
-	if (*group != '\0') {
-		if (!fg && !(fg = fr_findgroup(group, unit, set, NULL)))
-			return ESRCH;
+	if (fg != NULL)
 		fprev = &fg->fg_start;
-	}
 
 	/*
 	 * Copy in extra data for the rule.
@@ -4312,51 +4736,82 @@
 	if (fp->fr_dsize != 0) {
 		if (makecopy != 0) {
 			KMALLOCS(ptr, void *, fp->fr_dsize);
-			if (!ptr)
-				return ENOMEM;
-			error = COPYIN(uptr, ptr, fp->fr_dsize);
-			if (error != 0)
-				error = EFAULT;
+			if (ptr == NULL) {
+				IPFERROR(16);
+				error = ENOMEM;
+				goto donenolock;
+			}
+
+			/*
+			 * The bcopy case is for when the data is appended
+			 * to the rule by ipf_in_compat().
+			 */
+			if (uptr >= (void *)fp &&
+			    uptr < (void *)((char *)fp + fp->fr_size)) {
+				bcopy(uptr, ptr, fp->fr_dsize);
+				error = 0;
+			} else {
+				error = COPYIN(uptr, ptr, fp->fr_dsize);
+				if (error != 0) {
+					IPFERROR(17);
+					error = EFAULT;
+					goto donenolock;
+				}
+			}
 		} else {
 			ptr = uptr;
-			error = 0;
 		}
-		if (error != 0) {
-			KFREES(ptr, fp->fr_dsize);
-			return ENOMEM;
-		}
 		fp->fr_data = ptr;
-	} else
+	} else {
 		fp->fr_data = NULL;
+	}
 
 	/*
 	 * Perform per-rule type sanity checks of their members.
+	 * All code after this needs to be aware that allocated memory
+	 * may need to be free'd before exiting.
 	 */
 	switch (fp->fr_type & ~FR_T_BUILTIN)
 	{
 #if defined(IPFILTER_BPF)
 	case FR_T_BPFOPC :
-		if (fp->fr_dsize == 0)
-			return EINVAL;
+		if (fp->fr_dsize == 0) {
+			IPFERROR(19);
+			error = EINVAL;
+			break;
+		}
 		if (!bpf_validate(ptr, fp->fr_dsize/sizeof(struct bpf_insn))) {
-			if (makecopy && fp->fr_data != NULL) {
-				KFREES(fp->fr_data, fp->fr_dsize);
-			}
-			return EINVAL;
+			IPFERROR(20);
+			error = EINVAL;
+			break;
 		}
 		break;
 #endif
 	case FR_T_IPF :
-		if (fp->fr_dsize != sizeof(fripf_t))
-			return EINVAL;
+		/*
+		 * Preparation for error case at the bottom of this function.
+		 */
+		if (fp->fr_datype == FRI_LOOKUP)
+			fp->fr_dstptr = NULL;
+		if (fp->fr_satype == FRI_LOOKUP)
+			fp->fr_srcptr = NULL;
 
+		if (fp->fr_dsize != sizeof(fripf_t)) {
+			IPFERROR(21);
+			error = EINVAL;
+			break;
+		}
+
 		/*
 		 * Allowing a rule with both "keep state" and "with oow" is
 		 * pointless because adding a state entry to the table will
 		 * fail with the out of window (oow) flag set.
 		 */
-		if ((fp->fr_flags & FR_KEEPSTATE) && (fp->fr_flx & FI_OOW))
-			return EINVAL;
+		if ((fp->fr_flags & FR_KEEPSTATE) && (fp->fr_flx & FI_OOW)) {
+			IPFERROR(22);
+			error = EINVAL;
+			break;
+		}
 
 		switch (fp->fr_satype)
 		{
@@ -4365,26 +4820,30 @@
 		case FRI_NETWORK :
 		case FRI_NETMASKED :
 		case FRI_PEERADDR :
-			if (fp->fr_sifpidx < 0 || fp->fr_sifpidx > 3) {
-				if (makecopy && fp->fr_data != NULL) {
-					KFREES(fp->fr_data, fp->fr_dsize);
-				}
-				return EINVAL;
+			if (fp->fr_sifpidx < 0) {
+				IPFERROR(23);
+				error = EINVAL;
 			}
 			break;
-#ifdef	IPFILTER_LOOKUP
 		case FRI_LOOKUP :
-			fp->fr_srcptr = fr_resolvelookup(fp->fr_srctype,
-							 fp->fr_srcsubtype,
-							 &fp->fr_slookup,
-							 &fp->fr_srcfunc);
-			if (fp->fr_srcptr == NULL)
-				return ESRCH;
+			fp->fr_srcptr = ipf_findlookup(softc, unit, fp,
+						       &fp->fr_src6,
+						       &fp->fr_smsk6);
+			if (fp->fr_srcfunc == NULL) {
+				IPFERROR(132);
+				error = ESRCH;
+				break;
+			}
 			break;
-#endif
+		case FRI_NORMAL :
+			break;
 		default :
+			IPFERROR(133);
+			error = EINVAL;
 			break;
 		}
+		if (error != 0)
+			break;
 
 		switch (fp->fr_datype)
 		{
@@ -4393,45 +4852,84 @@
 		case FRI_NETWORK :
 		case FRI_NETMASKED :
 		case FRI_PEERADDR :
-			if (fp->fr_difpidx < 0 || fp->fr_difpidx > 3) {
-				if (makecopy && fp->fr_data != NULL) {
-					KFREES(fp->fr_data, fp->fr_dsize);
-				}
-				return EINVAL;
+			if (fp->fr_difpidx < 0) {
+				IPFERROR(24);
+				error = EINVAL;
 			}
 			break;
-#ifdef	IPFILTER_LOOKUP
 		case FRI_LOOKUP :
-			fp->fr_dstptr = fr_resolvelookup(fp->fr_dsttype,
-							 fp->fr_dstsubtype,
-							 &fp->fr_dlookup,
-							 &fp->fr_dstfunc);
-			if (fp->fr_dstptr == NULL)
-				return ESRCH;
+			fp->fr_dstptr = ipf_findlookup(softc, unit, fp,
+						       &fp->fr_dst6,
+						       &fp->fr_dmsk6);
+			if (fp->fr_dstfunc == NULL) {
+				IPFERROR(134);
+				error = ESRCH;
+			}
 			break;
-#endif
+		case FRI_NORMAL :
+			break;
 		default :
-			break;
+			IPFERROR(135);
+			error = EINVAL;
 		}
 		break;
+
 	case FR_T_NONE :
-		break;
 	case FR_T_CALLFUNC :
-		break;
 	case FR_T_COMPIPF :
 		break;
+
+	case FR_T_IPFEXPR :
+		if (ipf_matcharray_verify(fp->fr_data, fp->fr_dsize) == -1) {
+			IPFERROR(25);
+			error = EINVAL;
+		}
+		break;
+
 	default :
-		if (makecopy && fp->fr_data != NULL) {
-			KFREES(fp->fr_data, fp->fr_dsize);
+		IPFERROR(26);
+		error = EINVAL;
+		break;
+	}
+	if (error != 0)
+		goto donenolock;
+
+	if (fp->fr_tif.fd_name != -1) {
+		if ((fp->fr_tif.fd_name < 0) ||
+		    (fp->fr_tif.fd_name >= fp->fr_namelen)) {
+			IPFERROR(139);
+			error = EINVAL;
+			goto donenolock;
 		}
-		return EINVAL;
 	}
 
+	if (fp->fr_dif.fd_name != -1) {
+		if ((fp->fr_dif.fd_name < 0) ||
+		    (fp->fr_dif.fd_name >= fp->fr_namelen)) {
+			IPFERROR(140);
+			error = EINVAL;
+			goto donenolock;
+		}
+	}
+
+	if (fp->fr_rif.fd_name != -1) {
+		if ((fp->fr_rif.fd_name < 0) ||
+		    (fp->fr_rif.fd_name >= fp->fr_namelen)) {
+			IPFERROR(141);
+			error = EINVAL;
+			goto donenolock;
+		}
+	}
+
 	/*
 	 * Lookup all the interface names that are part of the rule.
 	 */
-	frsynclist(fp, NULL);
+	error = ipf_synclist(softc, fp, NULL);
+	if (error != 0)
+		goto donenolock;
 	fp->fr_statecnt = 0;
+	if (fp->fr_srctrack.ht_max_nodes != 0)
+		ipf_rb_ht_init(&fp->fr_srctrack);
 
 	/*
 	 * Look for an existing matching filter rule, but don't include the
@@ -4447,7 +4945,7 @@
 	for (p = (u_int *)fp->fr_data; p < pp; p++)
 		fp->fr_cksum += *p;
 
-	WRITE_ENTER(&ipf_mutex);
+	WRITE_ENTER(&softc->ipf_mutex);
 
 	/*
 	 * Now that the filter rule lists are locked, we can walk the
@@ -4462,17 +4960,9 @@
 		}
 		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))
-			continue;
-		if ((!ptr && !f->fr_data) ||
-		    (ptr && f->fr_data &&
-		     !bcmp((char *)ptr, (char *)f->fr_data, f->fr_dsize)))
+		if (ipf_rule_compare(fp, f) == 0)
 			break;
 	}
 
@@ -4479,10 +4969,11 @@
 	/*
 	 * If zero'ing statistics, copy current to caller and zero.
 	 */
-	if (req == (ioctlcmd_t)SIOCZRLST) {
-		if (f == NULL)
+	if (addrem == 2) {
+		if (f == NULL) {
+			IPFERROR(27);
 			error = ESRCH;
-		else {
+		} else {
 			/*
 			 * Copy and reduce lock because of impending copyout.
 			 * Well we should, but if we do then the atomicity of
@@ -4491,8 +4982,8 @@
 			 * only resets them to 0 if they are successfully
 			 * copied out into user space.
 			 */
-			bcopy((char *)f, (char *)fp, sizeof(*f));
-			/* MUTEX_DOWNGRADE(&ipf_mutex); */
+			bcopy((char *)f, (char *)fp, f->fr_size);
+			/* MUTEX_DOWNGRADE(&softc->ipf_mutex); */
 
 			/*
 			 * When we copy this rule back out, set the data
@@ -4499,14 +4990,16 @@
 			 * pointer to be what it was in user space.
 			 */
 			fp->fr_data = uptr;
-			error = fr_outobj(data, fp, IPFOBJ_FRENTRY);
+			error = ipf_outobj(softc, data, fp, IPFOBJ_FRENTRY);
 
 			if (error == 0) {
 				if ((f->fr_dsize != 0) && (uptr != NULL))
 					error = COPYOUT(f->fr_data, uptr,
 							f->fr_dsize);
-					if (error != 0)
+					if (error != 0) {
+						IPFERROR(28);
 						error = EFAULT;
+					}
 				if (error == 0) {
 					f->fr_hits = 0;
 					f->fr_bytes = 0;
@@ -4514,14 +5007,17 @@
 			}
 		}
 
-		if ((ptr != NULL) && (makecopy != 0)) {
-			KFREES(ptr, fp->fr_dsize);
+		if (makecopy != 0) {
+			if (ptr != NULL) {
+				KFREES(ptr, fp->fr_dsize);
+			}
+			KFREES(fp, fp->fr_size);
 		}
-		RWLOCK_EXIT(&ipf_mutex);
+		RWLOCK_EXIT(&softc->ipf_mutex);
 		return error;
 	}
 
-	if (!f) {
+  	if (!f) {
 		/*
 		 * At the end of this, ftail must point to the place where the
 		 * new rule is to be saved/inserted/added.
@@ -4536,10 +5032,11 @@
 				if (f->fr_collect > fp->fr_collect)
 					break;
 				ftail = &f->fr_next;
+				fprev = ftail;
 			}
+			ftail = fprev;
 			f = NULL;
 			ptr = NULL;
-			error = 0;
 		} else if (req == (ioctlcmd_t)SIOCINAFR ||
 			   req == (ioctlcmd_t)SIOCINIFR) {
 			while ((f = *fprev) != NULL) {
@@ -4547,19 +5044,18 @@
 					break;
 				fprev = &f->fr_next;
 			}
-			ftail = fprev;
-			if (fp->fr_hits != 0) {
+  			ftail = fprev;
+  			if (fp->fr_hits != 0) {
 				while (fp->fr_hits && (f = *ftail)) {
 					if (f->fr_collect != fp->fr_collect)
 						break;
 					fprev = ftail;
-					ftail = &f->fr_next;
+  					ftail = &f->fr_next;
 					fp->fr_hits--;
 				}
-			}
-			f = NULL;
-			ptr = NULL;
-			error = 0;
+  			}
+  			f = NULL;
+  			ptr = NULL;
 		}
 	}
 
@@ -4566,15 +5062,17 @@
 	/*
 	 * Request to remove a rule.
 	 */
-	if (req == (ioctlcmd_t)SIOCRMAFR || req == (ioctlcmd_t)SIOCRMIFR) {
-		if (!f)
+	if (addrem == 1) {
+		if (!f) {
+			IPFERROR(29);
 			error = ESRCH;
-		else {
+		} else {
 			/*
 			 * Do not allow activity from user space to interfere
 			 * with rules not loaded that way.
 			 */
 			if ((makecopy == 1) && !(f->fr_flags & FR_COPIED)) {
+				IPFERROR(30);
 				error = EPERM;
 				goto done;
 			}
@@ -4584,75 +5082,93 @@
 			 * something else (eg state information.)
 			 */
 			if (f->fr_ref > 1) {
+				IPFERROR(31);
 				error = EBUSY;
 				goto done;
 			}
 #ifdef	IPFILTER_SCAN
-			if (f->fr_isctag[0] != '\0' &&
+			if (f->fr_isctag != -1 &&
 			    (f->fr_isc != (struct ipscan *)-1))
-				ipsc_detachfr(f);
+				ipf_scan_detachfr(f);
 #endif
+
 			if (unit == IPL_LOGAUTH) {
-				error = fr_preauthcmd(req, f, ftail);
+				error = ipf_auth_precmd(softc, req, f, ftail);
 				goto done;
 			}
-			if (*f->fr_grhead != '\0')
-				fr_delgroup(f->fr_grhead, unit, set);
-			fr_fixskip(ftail, f, -1);
-			*ftail = f->fr_next;
-			f->fr_next = NULL;
-			(void) fr_derefrule(&f);
+
+			ipf_rule_delete(softc, f, unit, set);
+
+			need_free = makecopy;
 		}
 	} else {
 		/*
 		 * Not removing, so we must be adding/inserting a rule.
 		 */
-		if (f)
+		if (f != NULL) {
+			IPFERROR(32);
 			error = EEXIST;
-		else {
-			if (unit == IPL_LOGAUTH) {
-				error = fr_preauthcmd(req, fp, ftail);
-				goto done;
-			}
-			if (makecopy) {
-				KMALLOC(f, frentry_t *);
-			} else
-				f = fp;
-			if (f != NULL) {
-				if (fp != f)
-					bcopy((char *)fp, (char *)f,
-					      sizeof(*f));
-				MUTEX_NUKE(&f->fr_lock);
-				MUTEX_INIT(&f->fr_lock, "filter rule lock");
-#ifdef	IPFILTER_SCAN
-				if (f->fr_isctag[0] != '\0' &&
-				    ipsc_attachfr(f))
-					f->fr_isc = (struct ipscan *)-1;
-#endif
-				f->fr_hits = 0;
-				if (makecopy != 0)
-					f->fr_ref = 1;
-				f->fr_next = *ftail;
-				*ftail = f;
-				if (req == (ioctlcmd_t)SIOCINIFR ||
-				    req == (ioctlcmd_t)SIOCINAFR)
-					fr_fixskip(ftail, f, 1);
-				f->fr_grp = NULL;
-				group = f->fr_grhead;
-				if (*group != '\0') {
-					fg = fr_addgroup(group, f, f->fr_flags,
-							 unit, set);
-					if (fg != NULL)
-						f->fr_grp = &fg->fg_start;
-				}
-			} else
-				error = ENOMEM;
+			goto done;
 		}
+		if (unit == IPL_LOGAUTH) {
+			error = ipf_auth_precmd(softc, req, fp, ftail);
+			goto done;
+		}
+
+		MUTEX_NUKE(&fp->fr_lock);
+		MUTEX_INIT(&fp->fr_lock, "filter rule lock");
+		if (fp->fr_die != 0)
+			ipf_rule_expire_insert(softc, fp, set);
+
+		fp->fr_hits = 0;
+		if (makecopy != 0)
+			fp->fr_ref = 1;
+		fp->fr_pnext = ftail;
+		fp->fr_next = *ftail;
+		if (fp->fr_next != NULL)
+			fp->fr_next->fr_pnext = &fp->fr_next;
+		*ftail = fp;
+		if (addrem == 0)
+			ipf_fixskip(ftail, fp, 1);
+
+		fp->fr_icmpgrp = NULL;
+		if (fp->fr_icmphead != -1) {
+			group = FR_NAME(fp, fr_icmphead);
+			fg = ipf_group_add(softc, group, fp, 0, unit, set);
+			fp->fr_icmpgrp = fg;
+		}
+
+		fp->fr_grphead = NULL;
+		if (fp->fr_grhead != -1) {
+			group = FR_NAME(fp, fr_grhead);
+			fg = ipf_group_add(softc, group, fp, fp->fr_flags,
+					   unit, set);
+			fp->fr_grphead = fg;
+		}
 	}
 done:
-	RWLOCK_EXIT(&ipf_mutex);
-	if ((ptr != NULL) && (error != 0) && (makecopy != 0)) {
-		KFREES(ptr, fp->fr_dsize);
+	RWLOCK_EXIT(&softc->ipf_mutex);
+donenolock:
+	if (need_free || (error != 0)) {
+		if ((fp->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) {
+			if ((fp->fr_satype == FRI_LOOKUP) &&
+			    (fp->fr_srcptr != NULL))
+				ipf_lookup_deref(softc, fp->fr_srctype,
+						 fp->fr_srcptr);
+			if ((fp->fr_datype == FRI_LOOKUP) &&
+			    (fp->fr_dstptr != NULL))
+				ipf_lookup_deref(softc, fp->fr_dsttype,
+						 fp->fr_dstptr);
+		}
+		if (fp->fr_grp != NULL) {
+			WRITE_ENTER(&softc->ipf_mutex);
+			ipf_group_del(softc, fp->fr_grp, fp);
+			RWLOCK_EXIT(&softc->ipf_mutex);
+		}
+		if ((ptr != NULL) && (makecopy != 0)) {
+			KFREES(ptr, fp->fr_dsize);
+		}
+		KFREES(fp, fp->fr_size);
 	}
 	return (error);
 }
@@ -4659,26 +5175,174 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_funcinit                                                 */
+/* Function:   ipf_rule_delete                                              */
+/* Returns:    Nil                                                          */
+/* Parameters: softc(I) - pointer to soft context main structure            */
+/*             f(I)     - pointer to the rule being deleted                 */
+/*             ftail(I) - pointer to the pointer to f                       */
+/*             unit(I)  - device for which this is for                      */
+/*             set(I)   - 1 or 0 (filter set)                               */
+/*                                                                          */
+/* This function attempts to do what it can to delete a filter rule: remove */
+/* it from any linked lists and remove any groups it is responsible for.    */
+/* But in the end, removing a rule can only drop the reference count - we   */
+/* must use that as the guide for whether or not it can be freed.           */
+/* ------------------------------------------------------------------------ */
+static void
+ipf_rule_delete(softc, f, unit, set)
+	ipf_main_softc_t *softc;
+	frentry_t *f;
+	int unit, set;
+{
+
+	/*
+	 * If fr_pdnext is set, then the rule is on the expire list, so
+	 * remove it from there.
+	 */
+	if (f->fr_pdnext != NULL) {
+		*f->fr_pdnext = f->fr_dnext;
+		if (f->fr_dnext != NULL)
+			f->fr_dnext->fr_pdnext = f->fr_pdnext;
+		f->fr_pdnext = NULL;
+		f->fr_dnext = NULL;
+	}
+
+	ipf_fixskip(f->fr_pnext, f, -1);
+	if (f->fr_pnext != NULL)
+		*f->fr_pnext = f->fr_next;
+	if (f->fr_next != NULL)
+		f->fr_next->fr_pnext = f->fr_pnext;
+	f->fr_pnext = NULL;
+	f->fr_next = NULL;
+
+	(void) ipf_derefrule(softc, &f);
+}
+
+/* ------------------------------------------------------------------------ */
+/* Function:   ipf_rule_expire_insert                                       */
+/* Returns:    Nil                                                          */
+/* Parameters: softc(I) - pointer to soft context main structure            */
+/*             f(I)     - pointer to rule to be added to expire list        */
+/*             set(I)   - 1 or 0 (filter set)                               */
+/*                                                                          */
+/* If the new rule has a given expiration time, insert it into the list of  */
+/* expiring rules with the ones to be removed first added to the front of   */
+/* the list. The insertion is O(n) but it is kept sorted for quick scans at */
+/* expiration interval checks.                                              */
+/* ------------------------------------------------------------------------ */
+static void
+ipf_rule_expire_insert(softc, f, set)
+	ipf_main_softc_t *softc;
+	frentry_t *f;
+	int set;
+{
+	frentry_t *fr;
+
+	/*
+	 */
+
+	f->fr_die = softc->ipf_ticks + IPF_TTLVAL(f->fr_die);
+	for (fr = softc->ipf_rule_explist[set]; fr != NULL;
+	     fr = fr->fr_dnext) {
+		if (f->fr_die < fr->fr_die)
+			break;
+		if (fr->fr_dnext == NULL) {
+			/*
+			 * We've got to the last rule and everything
+			 * wanted to be expired before this new node,
+			 * so we have to tack it on the end...
+			 */
+			fr->fr_dnext = f;
+			f->fr_pdnext = &fr->fr_dnext;
+			fr = NULL;
+			break;
+		}
+	}
+
+	if (softc->ipf_rule_explist[set] == NULL) {
+		softc->ipf_rule_explist[set] = f;
+		f->fr_pdnext = &softc->ipf_rule_explist[set];
+	} else if (fr != NULL) {
+		f->fr_dnext = fr;
+		f->fr_pdnext = fr->fr_pdnext;
+		fr->fr_pdnext = &f->fr_dnext;
+	}
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:   ipf_findlookup                                               */
+/* Returns:    NULL = failure, else success                                 */
+/* Parameters: softc(I) - pointer to soft context main structure            */
+/*             unit(I)  - ipf device we want to find match for              */
+/*             fp(I)    - rule for which lookup is for                      */
+/*             addrp(I) - pointer to lookup information in address struct   */
+/*             maskp(O) - pointer to lookup information for storage         */
+/*                                                                          */
+/* When using pools and hash tables to store addresses for matching in      */
+/* rules, it is necessary to resolve both the object referred to by the     */
+/* name or address (and return that pointer) and also provide the means by  */
+/* which to determine if an address belongs to that object to make the      */
+/* packet matching quicker.                                                 */
+/* ------------------------------------------------------------------------ */
+static void *
+ipf_findlookup(softc, unit, fr, addrp, maskp)
+	ipf_main_softc_t *softc;
+	int unit;
+	frentry_t *fr;
+	i6addr_t *addrp, *maskp;
+{
+	void *ptr = NULL;
+
+	switch (addrp->iplookupsubtype)
+	{
+	case 0 :
+		ptr = ipf_lookup_res_num(softc, unit, addrp->iplookuptype,
+					 addrp->iplookupnum,
+					 &maskp->iplookupfunc);
+		break;
+	case 1 :
+		if (addrp->iplookupname < 0)
+			break;
+		if (addrp->iplookupname >= fr->fr_namelen)
+			break;
+		ptr = ipf_lookup_res_name(softc, unit, addrp->iplookuptype,
+					  fr->fr_names + addrp->iplookupname,
+					  &maskp->iplookupfunc);
+		break;
+	default :
+		break;
+	}
+
+	return ptr;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_funcinit                                                */
 /* Returns:     int - 0 == success, else ESRCH: cannot resolve rule details */
-/* Parameters:  fr(I) - pointer to filter rule                              */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              fr(I)    - pointer to filter rule                           */
 /*                                                                          */
 /* If a rule is a call rule, then check if the function it points to needs  */
 /* an init function to be called now the rule has been loaded.              */
 /* ------------------------------------------------------------------------ */
-static int fr_funcinit(fr)
-frentry_t *fr;
+static int
+ipf_funcinit(softc, fr)
+	ipf_main_softc_t *softc;
+	frentry_t *fr;
 {
 	ipfunc_resolve_t *ft;
 	int err;
 
+	IPFERROR(34);
 	err = ESRCH;
 
-	for (ft = fr_availfuncs; ft->ipfu_addr != NULL; ft++)
+	for (ft = ipf_availfuncs; ft->ipfu_addr != NULL; ft++)
 		if (ft->ipfu_addr == fr->fr_func) {
 			err = 0;
 			if (ft->ipfu_init != NULL)
-				err = (*ft->ipfu_init)(fr);
+				err = (*ft->ipfu_init)(softc, fr);
 			break;
 		}
 	return err;
@@ -4686,18 +5350,45 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_findfunc                                                 */
+/* Function:    ipf_funcfini                                                */
+/* Returns:     Nil                                                         */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              fr(I)    - pointer to filter rule                           */
+/*                                                                          */
+/* For a given filter rule, call the matching "fini" function if the rule   */
+/* is using a known function that would have resulted in the "init" being   */
+/* called for ealier.                                                       */
+/* ------------------------------------------------------------------------ */
+static void
+ipf_funcfini(softc, fr)
+	ipf_main_softc_t *softc;
+	frentry_t *fr;
+{
+	ipfunc_resolve_t *ft;
+
+	for (ft = ipf_availfuncs; ft->ipfu_addr != NULL; ft++)
+		if (ft->ipfu_addr == fr->fr_func) {
+			if (ft->ipfu_fini != NULL)
+				(void) (*ft->ipfu_fini)(softc, fr);
+			break;
+		}
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_findfunc                                                */
 /* Returns:     ipfunc_t - pointer to function if found, else NULL          */
 /* Parameters:  funcptr(I) - function pointer to lookup                     */
 /*                                                                          */
 /* Look for a function in the table of known functions.                     */
 /* ------------------------------------------------------------------------ */
-static ipfunc_t fr_findfunc(funcptr)
-ipfunc_t funcptr;
+static ipfunc_t
+ipf_findfunc(funcptr)
+	ipfunc_t funcptr;
 {
 	ipfunc_resolve_t *ft;
 
-	for (ft = fr_availfuncs; ft->ipfu_addr != NULL; ft++)
+	for (ft = ipf_availfuncs; ft->ipfu_addr != NULL; ft++)
 		if (ft->ipfu_addr == funcptr)
 			return funcptr;
 	return NULL;
@@ -4705,7 +5396,7 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_resolvefunc                                              */
+/* Function:    ipf_resolvefunc                                             */
 /* Returns:     int - 0 == success, else error                              */
 /* Parameters:  data(IO) - ioctl data pointer to ipfunc_resolve_t struct    */
 /*                                                                          */
@@ -4714,46 +5405,55 @@
 /* function pointer if the name is set.  When found, fill in the other one  */
 /* so that the entire, complete, structure can be copied back to user space.*/
 /* ------------------------------------------------------------------------ */
-int fr_resolvefunc(data)
-void *data;
+int
+ipf_resolvefunc(softc, data)
+	ipf_main_softc_t *softc;
+	void *data;
 {
 	ipfunc_resolve_t res, *ft;
-	int err;
+	int error;
 
-	err = BCOPYIN(data, &res, sizeof(res));
-	if (err != 0)
+	error = BCOPYIN(data, &res, sizeof(res));
+	if (error != 0) {
+		IPFERROR(123);
 		return EFAULT;
+	}
 
 	if (res.ipfu_addr == NULL && res.ipfu_name[0] != '\0') {
-		for (ft = fr_availfuncs; ft->ipfu_addr != NULL; ft++)
+		for (ft = ipf_availfuncs; ft->ipfu_addr != NULL; ft++)
 			if (strncmp(res.ipfu_name, ft->ipfu_name,
 				    sizeof(res.ipfu_name)) == 0) {
 				res.ipfu_addr = ft->ipfu_addr;
 				res.ipfu_init = ft->ipfu_init;
-				if (COPYOUT(&res, data, sizeof(res)) != 0)
+				if (COPYOUT(&res, data, sizeof(res)) != 0) {
+					IPFERROR(35);
 					return EFAULT;
+				}
 				return 0;
 			}
 	}
 	if (res.ipfu_addr != NULL && res.ipfu_name[0] == '\0') {
-		for (ft = fr_availfuncs; ft->ipfu_addr != NULL; ft++)
+		for (ft = ipf_availfuncs; ft->ipfu_addr != NULL; ft++)
 			if (ft->ipfu_addr == res.ipfu_addr) {
 				(void) strncpy(res.ipfu_name, ft->ipfu_name,
 					       sizeof(res.ipfu_name));
 				res.ipfu_init = ft->ipfu_init;
-				if (COPYOUT(&res, data, sizeof(res)) != 0)
+				if (COPYOUT(&res, data, sizeof(res)) != 0) {
+					IPFERROR(36);
 					return EFAULT;
+				}
 				return 0;
 			}
 	}
+	IPFERROR(37);
 	return ESRCH;
 }
 
 
-#if !defined(_KERNEL) || (!defined(__NetBSD__) && !defined(__OpenBSD__) && !defined(__FreeBSD__)) || \
-    (defined(__FreeBSD__) && (__FreeBSD_version < 501000)) || \
-    (defined(__NetBSD__) && (__NetBSD_Version__ < 105000000)) || \
-    (defined(__OpenBSD__) && (OpenBSD < 200006))
+#if !defined(_KERNEL) || (!defined(__NetBSD__) && !defined(__OpenBSD__) && \
+     !defined(__FreeBSD__)) || \
+    FREEBSD_LT_REV(501000) || NETBSD_LT_REV(105000000) || \
+    OPENBSD_LT_REV(200006)
 /*
  * From: NetBSD
  * ppsratecheck(): packets (or events) per second limitation.
@@ -4803,7 +5503,7 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_derefrule                                                */
+/* Function:    ipf_derefrule                                               */
 /* Returns:     int   - 0 == rule freed up, else rule not freed             */
 /* Parameters:  fr(I) - pointer to filter rule                              */
 /*                                                                          */
@@ -4810,10 +5510,13 @@
 /* Decrement the reference counter to a rule by one.  If it reaches zero,   */
 /* free it and any associated storage space being used by it.               */
 /* ------------------------------------------------------------------------ */
-int fr_derefrule(frp)
-frentry_t **frp;
+int
+ipf_derefrule(softc, frp)
+	ipf_main_softc_t *softc;
+	frentry_t **frp;
 {
 	frentry_t *fr;
+	frdest_t *fdp;
 
 	fr = *frp;
 	*frp = NULL;
@@ -4824,18 +5527,41 @@
 		MUTEX_EXIT(&fr->fr_lock);
 		MUTEX_DESTROY(&fr->fr_lock);
 
-#ifdef IPFILTER_LOOKUP
-		if (fr->fr_type == FR_T_IPF && fr->fr_satype == FRI_LOOKUP)
-			ip_lookup_deref(fr->fr_srctype, fr->fr_srcptr);
-		if (fr->fr_type == FR_T_IPF && fr->fr_datype == FRI_LOOKUP)
-			ip_lookup_deref(fr->fr_dsttype, fr->fr_dstptr);
-#endif
+		ipf_funcfini(softc, fr);
 
-		if (fr->fr_dsize) {
-			KFREES(fr->fr_data, fr->fr_dsize);
-		}
+		fdp = &fr->fr_tif;
+		if (fdp->fd_type == FRD_DSTLIST)
+			ipf_lookup_deref(softc, IPLT_DSTLIST, fdp->fd_ptr);
+
+		fdp = &fr->fr_rif;
+		if (fdp->fd_type == FRD_DSTLIST)
+			ipf_lookup_deref(softc, IPLT_DSTLIST, fdp->fd_ptr);
+
+		fdp = &fr->fr_dif;
+		if (fdp->fd_type == FRD_DSTLIST)
+			ipf_lookup_deref(softc, IPLT_DSTLIST, fdp->fd_ptr);
+
+		if ((fr->fr_type & ~FR_T_BUILTIN) == FR_T_IPF &&
+		    fr->fr_satype == FRI_LOOKUP)
+			ipf_lookup_deref(softc, fr->fr_srctype, fr->fr_srcptr);
+		if ((fr->fr_type & ~FR_T_BUILTIN) == FR_T_IPF &&
+		    fr->fr_datype == FRI_LOOKUP)
+			ipf_lookup_deref(softc, fr->fr_dsttype, fr->fr_dstptr);
+
+		if (fr->fr_grp != NULL)
+			ipf_group_del(softc, fr->fr_grp, fr);
+
+		if (fr->fr_grphead != NULL)
+			ipf_group_del(softc, fr->fr_grphead, fr);
+
+		if (fr->fr_icmpgrp != NULL)
+			ipf_group_del(softc, fr->fr_icmpgrp, fr);
+
 		if ((fr->fr_flags & FR_COPIED) != 0) {
-			KFREE(fr);
+			if (fr->fr_dsize) {
+				KFREES(fr->fr_data, fr->fr_dsize);
+			}
+			KFREES(fr, fr->fr_size);
 			return 0;
 		}
 		return 1;
@@ -4846,17 +5572,18 @@
 }
 
 
-#ifdef	IPFILTER_LOOKUP
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_grpmapinit                                               */
+/* Function:    ipf_grpmapinit                                              */
 /* Returns:     int - 0 == success, else ESRCH because table entry not found*/
 /* Parameters:  fr(I) - pointer to rule to find hash table for              */
 /*                                                                          */
 /* Looks for group hash table fr_arg and stores a pointer to it in fr_ptr.  */
-/* fr_ptr is later used by fr_srcgrpmap and fr_dstgrpmap.                   */
+/* fr_ptr is later used by ipf_srcgrpmap and ipf_dstgrpmap.                 */
 /* ------------------------------------------------------------------------ */
-static int fr_grpmapinit(fr)
-frentry_t *fr;
+static int
+ipf_grpmapinit(softc, fr)
+	ipf_main_softc_t *softc;
+	frentry_t *fr;
 {
 	char name[FR_GROUPLEN];
 	iphtable_t *iph;
@@ -4866,11 +5593,16 @@
 #else
 	(void) sprintf(name, "%d", fr->fr_arg);
 #endif
-	iph = fr_findhtable(IPL_LOGIPF, name);
-	if (iph == NULL)
+	iph = ipf_lookup_find_htable(softc, IPL_LOGIPF, name);
+	if (iph == NULL) {
+		IPFERROR(38);
 		return ESRCH;
-	if ((iph->iph_flags & FR_INOUT) != (fr->fr_flags & FR_INOUT))
+	}
+	if ((iph->iph_flags & FR_INOUT) != (fr->fr_flags & FR_INOUT)) {
+		IPFERROR(39);
 		return ESRCH;
+	}
+	iph->iph_ref++;
 	fr->fr_ptr = iph;
 	return 0;
 }
@@ -4877,7 +5609,29 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_srcgrpmap                                                */
+/* Function:    ipf_grpmapfini                                              */
+/* Returns:     int - 0 == success, else ESRCH because table entry not found*/
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              fr(I)    - pointer to rule to release hash table for        */
+/*                                                                          */
+/* For rules that have had ipf_grpmapinit called, ipf_lookup_deref needs to */
+/* be called to undo what ipf_grpmapinit caused to be done.                 */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_grpmapfini(softc, fr)
+	ipf_main_softc_t *softc;
+	frentry_t *fr;
+{
+	iphtable_t *iph;
+	iph = fr->fr_ptr;
+	if (iph != NULL)
+		ipf_lookup_deref(softc, IPLT_HASH, iph);
+	return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_srcgrpmap                                               */
 /* Returns:     frentry_t * - pointer to "new last matching" rule or NULL   */
 /* Parameters:  fin(I)    - pointer to packet information                   */
 /*              passp(IO) - pointer to current/new filter decision (unused) */
@@ -4886,26 +5640,28 @@
 /* the key, and descend into that group and continue matching rules against */
 /* the packet.                                                              */
 /* ------------------------------------------------------------------------ */
-frentry_t *fr_srcgrpmap(fin, passp)
-fr_info_t *fin;
-u_32_t *passp;
+frentry_t *
+ipf_srcgrpmap(fin, passp)
+	fr_info_t *fin;
+	u_32_t *passp;
 {
 	frgroup_t *fg;
 	void *rval;
 
-	rval = fr_iphmfindgroup(fin->fin_fr->fr_ptr, &fin->fin_src);
+	rval = ipf_iphmfindgroup(fin->fin_main_soft, fin->fin_fr->fr_ptr,
+				 &fin->fin_src);
 	if (rval == NULL)
 		return NULL;
 
 	fg = rval;
 	fin->fin_fr = fg->fg_start;
-	(void) fr_scanlist(fin, *passp);
+	(void) ipf_scanlist(fin, *passp);
 	return fin->fin_fr;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_dstgrpmap                                                */
+/* Function:    ipf_dstgrpmap                                               */
 /* Returns:     frentry_t * - pointer to "new last matching" rule or NULL   */
 /* Parameters:  fin(I)    - pointer to packet information                   */
 /*              passp(IO) - pointer to current/new filter decision (unused) */
@@ -4914,37 +5670,39 @@
 /* address as the key, and descend into that group and continue matching    */
 /* rules against  the packet.                                               */
 /* ------------------------------------------------------------------------ */
-frentry_t *fr_dstgrpmap(fin, passp)
-fr_info_t *fin;
-u_32_t *passp;
+frentry_t *
+ipf_dstgrpmap(fin, passp)
+	fr_info_t *fin;
+	u_32_t *passp;
 {
 	frgroup_t *fg;
 	void *rval;
 
-	rval = fr_iphmfindgroup(fin->fin_fr->fr_ptr, &fin->fin_dst);
+	rval = ipf_iphmfindgroup(fin->fin_main_soft, fin->fin_fr->fr_ptr,
+				 &fin->fin_dst);
 	if (rval == NULL)
 		return NULL;
 
 	fg = rval;
 	fin->fin_fr = fg->fg_start;
-	(void) fr_scanlist(fin, *passp);
+	(void) ipf_scanlist(fin, *passp);
 	return fin->fin_fr;
 }
-#endif /* IPFILTER_LOOKUP */
 
 /*
  * Queue functions
  * ===============
- * These functions manage objects on queues for efficient timeouts.  There are
- * a number of system defined queues as well as user defined timeouts.  It is
- * expected that a lock is held in the domain in which the queue belongs
- * (i.e. either state or NAT) when calling any of these functions that prevents
- * fr_freetimeoutqueue() from being called at the same time as any other.
+ * These functions manage objects on queues for efficient timeouts.  There
+ * are a number of system defined queues as well as user defined timeouts.
+ * It is expected that a lock is held in the domain in which the queue
+ * belongs (i.e. either state or NAT) when calling any of these functions
+ * that prevents ipf_freetimeoutqueue() from being called at the same time
+ * as any other.
  */
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_addtimeoutqueue                                          */
+/* Function:    ipf_addtimeoutqueue                                         */
 /* Returns:     struct ifqtq * - NULL if malloc fails, else pointer to      */
 /*                               timeout queue with given interval.         */
 /* Parameters:  parent(I)  - pointer to pointer to parent node of this list */
@@ -4960,9 +5718,11 @@
 /* It is assumed that the caller of this function has an appropriate lock   */
 /* held (exclusively) in the domain that encompases 'parent'.               */
 /* ------------------------------------------------------------------------ */
-ipftq_t *fr_addtimeoutqueue(parent, seconds)
-ipftq_t **parent;
-u_int seconds;
+ipftq_t *
+ipf_addtimeoutqueue(softc, parent, seconds)
+	ipf_main_softc_t *softc;
+	ipftq_t **parent;
+	u_int seconds;
 {
 	ipftq_t *ifq;
 	u_int period;
@@ -4969,7 +5729,7 @@
 
 	period = seconds * IPF_HZ_DIVIDE;
 
-	MUTEX_ENTER(&ipf_timeoutlock);
+	MUTEX_ENTER(&softc->ipf_timeoutlock);
 	for (ifq = *parent; ifq != NULL; ifq = ifq->ifq_next) {
 		if (ifq->ifq_ttl == period) {
 			/*
@@ -4980,7 +5740,7 @@
 			ifq->ifq_flags &= ~IFQF_DELETE;
 			ifq->ifq_ref++;
 			MUTEX_EXIT(&ifq->ifq_lock);
-			MUTEX_EXIT(&ipf_timeoutlock);
+			MUTEX_EXIT(&softc->ipf_timeoutlock);
 
 			return ifq;
 		}
@@ -4988,25 +5748,22 @@
 
 	KMALLOC(ifq, ipftq_t *);
 	if (ifq != NULL) {
-		ifq->ifq_ttl = period;
-		ifq->ifq_head = NULL;
-		ifq->ifq_tail = &ifq->ifq_head;
+		MUTEX_NUKE(&ifq->ifq_lock);
+		IPFTQ_INIT(ifq, period, "ipftq mutex");
 		ifq->ifq_next = *parent;
 		ifq->ifq_pnext = parent;
-		ifq->ifq_ref = 1;
 		ifq->ifq_flags = IFQF_USER;
+		ifq->ifq_ref++;
 		*parent = ifq;
-		fr_userifqs++;
-		MUTEX_NUKE(&ifq->ifq_lock);
-		MUTEX_INIT(&ifq->ifq_lock, "ipftq mutex");
+		softc->ipf_userifqs++;
 	}
-	MUTEX_EXIT(&ipf_timeoutlock);
+	MUTEX_EXIT(&softc->ipf_timeoutlock);
 	return ifq;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_deletetimeoutqueue                                       */
+/* Function:    ipf_deletetimeoutqueue                                      */
 /* Returns:     int    - new reference count value of the timeout queue     */
 /* Parameters:  ifq(I) - timeout queue which is losing a reference.         */
 /* Locks:       ifq->ifq_lock                                               */
@@ -5020,8 +5777,9 @@
 /* way because the locking may not be sufficient to safely do a free when   */
 /* this function is called.                                                 */
 /* ------------------------------------------------------------------------ */
-int fr_deletetimeoutqueue(ifq)
-ipftq_t *ifq;
+int
+ipf_deletetimeoutqueue(ifq)
+	ipftq_t *ifq;
 {
 
 	ifq->ifq_ref--;
@@ -5034,7 +5792,7 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_freetimeoutqueue                                         */
+/* Function:    ipf_freetimeoutqueue                                        */
 /* Parameters:  ifq(I) - timeout queue which is losing a reference.         */
 /* Returns:     Nil                                                         */
 /*                                                                          */
@@ -5043,17 +5801,18 @@
 /* held (exclusively) in the domain that encompases the callers "domain".   */
 /* The ifq_lock for this structure should not be held.                      */
 /*                                                                          */
-/* Remove a user definde timeout queue from the list of queues it is in and */
+/* Remove a user defined timeout queue from the list of queues it is in and */
 /* tidy up after this is done.                                              */
 /* ------------------------------------------------------------------------ */
-void fr_freetimeoutqueue(ifq)
-ipftq_t *ifq;
+void
+ipf_freetimeoutqueue(softc, ifq)
+	ipf_main_softc_t *softc;
+	ipftq_t *ifq;
 {
 
-
 	if (((ifq->ifq_flags & IFQF_DELETE) == 0) || (ifq->ifq_ref != 0) ||
 	    ((ifq->ifq_flags & IFQF_USER) == 0)) {
-		printf("fr_freetimeoutqueue(%lx) flags 0x%x ttl %d ref %d\n",
+		printf("ipf_freetimeoutqueue(%lx) flags 0x%x ttl %d ref %d\n",
 		       (u_long)ifq, ifq->ifq_flags, ifq->ifq_ttl,
 		       ifq->ifq_ref);
 		return;
@@ -5065,26 +5824,28 @@
 	*ifq->ifq_pnext = ifq->ifq_next;
 	if (ifq->ifq_next != NULL)
 		ifq->ifq_next->ifq_pnext = ifq->ifq_pnext;
+	ifq->ifq_next = NULL;
+	ifq->ifq_pnext = NULL;
 
 	MUTEX_DESTROY(&ifq->ifq_lock);
-	ATOMIC_DEC(fr_userifqs);
+	ATOMIC_DEC(softc->ipf_userifqs);
 	KFREE(ifq);
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_deletequeueentry                                         */
+/* Function:    ipf_deletequeueentry                                        */
 /* Returns:     Nil                                                         */
 /* Parameters:  tqe(I) - timeout queue entry to delete                      */
-/*              ifq(I) - timeout queue to remove entry from                 */
 /*                                                                          */
 /* Remove a tail queue entry from its queue and make it an orphan.          */
-/* fr_deletetimeoutqueue is called to make sure the reference count on the  */
-/* queue is correct.  We can't, however, call fr_freetimeoutqueue because   */
+/* ipf_deletetimeoutqueue is called to make sure the reference count on the */
+/* queue is correct.  We can't, however, call ipf_freetimeoutqueue because  */
 /* the correct lock(s) may not be held that would make it safe to do so.    */
 /* ------------------------------------------------------------------------ */
-void fr_deletequeueentry(tqe)
-ipftqent_t *tqe;
+void
+ipf_deletequeueentry(tqe)
+	ipftqent_t *tqe;
 {
 	ipftq_t *ifq;
 
@@ -5103,7 +5864,8 @@
 		tqe->tqe_ifq = NULL;
 	}
 
-	(void) fr_deletetimeoutqueue(ifq);
+	(void) ipf_deletetimeoutqueue(ifq);
+	ASSERT(ifq->ifq_ref > 0);
 
 	MUTEX_EXIT(&ifq->ifq_lock);
 }
@@ -5110,14 +5872,15 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_queuefront                                               */
+/* Function:    ipf_queuefront                                              */
 /* Returns:     Nil                                                         */
 /* Parameters:  tqe(I) - pointer to timeout queue entry                     */
 /*                                                                          */
 /* Move a queue entry to the front of the queue, if it isn't already there. */
 /* ------------------------------------------------------------------------ */
-void fr_queuefront(tqe)
-ipftqent_t *tqe;
+void
+ipf_queuefront(tqe)
+	ipftqent_t *tqe;
 {
 	ipftq_t *ifq;
 
@@ -5143,14 +5906,19 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_queueback                                                */
+/* Function:    ipf_queueback                                               */
 /* Returns:     Nil                                                         */
-/* Parameters:  tqe(I) - pointer to timeout queue entry                     */
+/* Parameters:  ticks(I) - ipf tick time to use with this call              */
+/*              tqe(I)   - pointer to timeout queue entry                   */
 /*                                                                          */
 /* Move a queue entry to the back of the queue, if it isn't already there.  */
+/* We use use ticks to calculate the expiration and mark for when we last   */
+/* touched the structure.                                                   */
 /* ------------------------------------------------------------------------ */
-void fr_queueback(tqe)
-ipftqent_t *tqe;
+void
+ipf_queueback(ticks, tqe)
+	u_long ticks;
+	ipftqent_t *tqe;
 {
 	ipftq_t *ifq;
 
@@ -5157,7 +5925,8 @@
 	ifq = tqe->tqe_ifq;
 	if (ifq == NULL)
 		return;
-	tqe->tqe_die = fr_ticks + ifq->ifq_ttl;
+	tqe->tqe_die = ticks + ifq->ifq_ttl;
+	tqe->tqe_touched = ticks;
 
 	MUTEX_ENTER(&ifq->ifq_lock);
 	if (tqe->tqe_next != NULL) {		/* at the end already ? */
@@ -5180,18 +5949,23 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_queueappend                                              */
+/* Function:    ipf_queueappend                                             */
 /* Returns:     Nil                                                         */
-/* Parameters:  tqe(I)    - pointer to timeout queue entry                  */
+/* Parameters:  ticks(I)  - ipf tick time to use with this call             */
+/*              tqe(I)    - pointer to timeout queue entry                  */
 /*              ifq(I)    - pointer to timeout queue                        */
 /*              parent(I) - owing object pointer                            */
 /*                                                                          */
 /* Add a new item to this queue and put it on the very end.                 */
+/* We use use ticks to calculate the expiration and mark for when we last   */
+/* touched the structure.                                                   */
 /* ------------------------------------------------------------------------ */
-void fr_queueappend(tqe, ifq, parent)
-ipftqent_t *tqe;
-ipftq_t *ifq;
-void *parent;
+void
+ipf_queueappend(ticks, tqe, ifq, parent)
+	u_long ticks;
+	ipftqent_t *tqe;
+	ipftq_t *ifq;
+	void *parent;
 {
 
 	MUTEX_ENTER(&ifq->ifq_lock);
@@ -5201,7 +5975,8 @@
 	ifq->ifq_tail = &tqe->tqe_next;
 	tqe->tqe_next = NULL;
 	tqe->tqe_ifq = ifq;
-	tqe->tqe_die = fr_ticks + ifq->ifq_ttl;
+	tqe->tqe_die = ticks + ifq->ifq_ttl;
+	tqe->tqe_touched = ticks;
 	ifq->ifq_ref++;
 	MUTEX_EXIT(&ifq->ifq_lock);
 }
@@ -5208,7 +5983,7 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_movequeue                                                */
+/* Function:    ipf_movequeue                                               */
 /* Returns:     Nil                                                         */
 /* Parameters:  tq(I)   - pointer to timeout queue information              */
 /*              oifp(I) - old timeout queue entry was on                    */
@@ -5218,58 +5993,82 @@
 /* If it notices that the current entry is already last and does not need   */
 /* to move queue, the return.                                               */
 /* ------------------------------------------------------------------------ */
-void fr_movequeue(tqe, oifq, nifq)
-ipftqent_t *tqe;
-ipftq_t *oifq, *nifq;
+void
+ipf_movequeue(ticks, tqe, oifq, nifq)
+	u_long ticks;
+	ipftqent_t *tqe;
+	ipftq_t *oifq, *nifq;
 {
+
 	/*
-	 * Is the operation here going to be a no-op ?
+	 * If the queue hasn't changed and we last touched this entry at the
+	 * same ipf time, then we're not going to achieve anything by either
+	 * changing the ttl or moving it on the queue.
 	 */
+	if (oifq == nifq && tqe->tqe_touched == ticks)
+		return;
+
+	/*
+	 * For any of this to be outside the lock, there is a risk that two
+	 * packets entering simultaneously, with one changing to a different
+	 * queue and one not, could end up with things in a bizarre state.
+	 */
 	MUTEX_ENTER(&oifq->ifq_lock);
-	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;
 
-		/*
-		 * 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;
+	tqe->tqe_touched = ticks;
+	tqe->tqe_die = ticks + nifq->ifq_ttl;
+	/*
+	 * Is the operation here going to be a no-op ?
+	 */
+	if (oifq == nifq) {
+		if ((tqe->tqe_next == NULL) ||
+		    (tqe->tqe_next->tqe_die == tqe->tqe_die)) {
+			MUTEX_EXIT(&oifq->ifq_lock);
+			return;
+		}
+	}
 
-			(void) fr_deletetimeoutqueue(oifq);
+	/*
+	 * 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;
 
-			MUTEX_EXIT(&oifq->ifq_lock);
+	/*
+	 * 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;
 
-			MUTEX_ENTER(&nifq->ifq_lock);
+		(void) ipf_deletetimeoutqueue(oifq);
 
-			tqe->tqe_ifq = nifq;
-			nifq->ifq_ref++;
-		}
+		MUTEX_EXIT(&oifq->ifq_lock);
 
-		/*
-		 * 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_ENTER(&nifq->ifq_lock);
+
+		tqe->tqe_ifq = nifq;
+		nifq->ifq_ref++;
 	}
+
+	/*
+	 * Add to the bottom of the new queue
+	 */
+	tqe->tqe_pnext = nifq->ifq_tail;
+	*nifq->ifq_tail = tqe;
+	nifq->ifq_tail = &tqe->tqe_next;
 	MUTEX_EXIT(&nifq->ifq_lock);
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_updateipid                                               */
+/* Function:    ipf_updateipid                                              */
 /* Returns:     int - 0 == success, -1 == error (packet should be droppped) */
 /* Parameters:  fin(I) - pointer to packet information                      */
 /*                                                                          */
@@ -5280,8 +6079,9 @@
 /* the fragment cache for non-leading fragments.  If a non-leading fragment */
 /* has no match in the cache, return an error.                              */
 /* ------------------------------------------------------------------------ */
-static int fr_updateipid(fin)
-fr_info_t *fin;
+static int
+ipf_updateipid(fin)
+	fr_info_t *fin;
 {
 	u_short id, ido, sums;
 	u_32_t sumd, sum;
@@ -5288,15 +6088,15 @@
 	ip_t *ip;
 
 	if (fin->fin_off != 0) {
-		sum = fr_ipid_knownfrag(fin);
+		sum = ipf_frag_ipidknown(fin);
 		if (sum == 0xffffffff)
 			return -1;
 		sum &= 0xffff;
 		id = (u_short)sum;
 	} else {
-		id = fr_nextipid(fin);
+		id = ipf_nextipid(fin);
 		if (fin->fin_off == 0 && (fin->fin_flx & FI_FRAG) != 0)
-			(void) fr_ipid_newfrag(fin, (u_32_t)id);
+			(void) ipf_frag_ipidnew(fin, (u_32_t)id);
 	}
 
 	ip = fin->fin_ip;
@@ -5317,7 +6117,7 @@
 
 #ifdef	NEED_FRGETIFNAME
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_getifname                                                */
+/* Function:    ipf_getifname                                               */
 /* Returns:     char *    - pointer to interface name                       */
 /* Parameters:  ifp(I)    - pointer to network interface                    */
 /*              buffer(O) - pointer to where to store interface name        */
@@ -5326,9 +6126,10 @@
 /* expected to be at least LIFNAMSIZ in bytes big.  If buffer is passed in  */
 /* as a NULL pointer then return a pointer to a static array.               */
 /* ------------------------------------------------------------------------ */
-char *fr_getifname(ifp, buffer)
-struct ifnet *ifp;
-char *buffer;
+char *
+ipf_getifname(ifp, buffer)
+	struct ifnet *ifp;
+	char *buffer;
 {
 	static char namebuf[LIFNAMSIZ];
 # if defined(MENTAT) || defined(__FreeBSD__) || defined(__osf__) || \
@@ -5350,7 +6151,7 @@
 		;
 	unit = ifp->if_unit;
 	space = LIFNAMSIZ - (s - buffer);
-	if (space > 0) {
+	if ((space > 0) && (unit >= 0)) {
 #  if defined(SNPRINTF) && defined(_KERNEL)
 		SNPRINTF(temp, sizeof(temp), "%d", unit);
 #  else
@@ -5365,7 +6166,7 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_ioctlswitch                                              */
+/* Function:    ipf_ioctlswitch                                             */
 /* Returns:     int     - -1 continue processing, else ioctl return value   */
 /* Parameters:  unit(I) - device unit opened                                */
 /*              data(I) - pointer to ioctl data                             */
@@ -5376,63 +6177,99 @@
 /*                                                                          */
 /* 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.                            */
+/* for the device in order to execute the ioctl.  A special case is made    */
+/* SIOCIPFINTERROR so that the same code isn't required in every handler.   */
+/* The context data pointer is passed through as this is used as the key    */
+/* for locating a matching token for continued access for walking lists,    */
+/* etc.                                                                     */
 /* ------------------------------------------------------------------------ */
-int fr_ioctlswitch(unit, data, cmd, mode, uid, ctx)
-int unit, mode, uid;
-ioctlcmd_t cmd;
-void *data, *ctx;
+int
+ipf_ioctlswitch(softc, unit, data, cmd, mode, uid, ctx)
+	ipf_main_softc_t *softc;
+	int unit, mode, uid;
+	ioctlcmd_t cmd;
+	void *data, *ctx;
 {
 	int error = 0;
 
+	switch (cmd)
+	{
+	case SIOCIPFINTERROR :
+		error = BCOPYOUT(&softc->ipf_interror, data,
+				 sizeof(softc->ipf_interror));
+		if (error != 0) {
+			IPFERROR(40);
+			error = EFAULT;
+		}
+		return error;
+	default :
+		break;
+	}
+
 	switch (unit)
 	{
 	case IPL_LOGIPF :
-		error = fr_ipf_ioctl(data, cmd, mode, uid, ctx);
+		error = ipf_ipf_ioctl(softc, data, cmd, mode, uid, ctx);
 		break;
 	case IPL_LOGNAT :
-		if (fr_running > 0)
-			error = fr_nat_ioctl(data, cmd, mode, uid, ctx);
-		else
+		if (softc->ipf_running > 0) {
+			error = ipf_nat_ioctl(softc, data, cmd, mode,
+					      uid, ctx);
+		} else {
+			IPFERROR(42);
 			error = EIO;
+		}
 		break;
 	case IPL_LOGSTATE :
-		if (fr_running > 0)
-			error = fr_state_ioctl(data, cmd, mode, uid, ctx);
-		else
+		if (softc->ipf_running > 0) {
+			error = ipf_state_ioctl(softc, data, cmd, mode,
+						uid, ctx);
+		} else {
+			IPFERROR(43);
 			error = EIO;
+		}
 		break;
 	case IPL_LOGAUTH :
-		if (fr_running > 0)
-			error = fr_auth_ioctl(data, cmd, mode, uid, ctx);
-		else
+		if (softc->ipf_running > 0) {
+			error = ipf_auth_ioctl(softc, data, cmd, mode,
+					       uid, ctx);
+		} else {
+			IPFERROR(44);
 			error = EIO;
+		}
 		break;
 	case IPL_LOGSYNC :
-#ifdef IPFILTER_SYNC
-		if (fr_running > 0)
-			error = fr_sync_ioctl(data, cmd, mode, uid, ctx);
-		else
-#endif
+		if (softc->ipf_running > 0) {
+			error = ipf_sync_ioctl(softc, data, cmd, mode,
+					       uid, ctx);
+		} else {
 			error = EIO;
+			IPFERROR(45);
+		}
 		break;
 	case IPL_LOGSCAN :
 #ifdef IPFILTER_SCAN
-		if (fr_running > 0)
-			error = fr_scan_ioctl(data, cmd, mode, uid, ctx);
+		if (softc->ipf_running > 0)
+			error = ipf_scan_ioctl(softc, data, cmd, mode,
+					       uid, ctx);
 		else
 #endif
+		{
 			error = EIO;
+			IPFERROR(46);
+		}
 		break;
 	case IPL_LOGLOOKUP :
-#ifdef IPFILTER_LOOKUP
-		if (fr_running > 0)
-			error = ip_lookup_ioctl(data, cmd, mode, uid, ctx);
-		else
-#endif
+		if (softc->ipf_running > 0) {
+			error = ipf_lookup_ioctl(softc, data, cmd, mode,
+						 uid, ctx);
+		} else {
 			error = EIO;
+			IPFERROR(47);
+		}
 		break;
 	default :
+		IPFERROR(48);
 		error = EIO;
 		break;
 	}
@@ -5443,147 +6280,181 @@
 
 /*
  * This array defines the expected size of objects coming into the kernel
- * for the various recognised object types.
+ * for the various recognised object types. The first column is flags (see
+ * below), 2nd column is current size, 3rd column is the version number of
+ * when the current size became current.
+ * Flags:
+ * 1 = minimum size, not absolute size
  */
-static	int	fr_objbytes[IPFOBJ_COUNT][2] = {
-	{ 1,	sizeof(struct frentry) },		/* frentry */
-	{ 0,	sizeof(struct friostat) },
-	{ 0,	sizeof(struct fr_info) },
-	{ 0,	sizeof(struct fr_authstat) },
-	{ 0,	sizeof(struct ipfrstat) },
-	{ 0,	sizeof(struct ipnat) },
-	{ 0,	sizeof(struct natstat) },
-	{ 0,	sizeof(struct ipstate_save) },
-	{ 1,	sizeof(struct nat_save) },		/* nat_save */
-	{ 0,	sizeof(struct natlookup) },
-	{ 1,	sizeof(struct ipstate) },		/* ipstate */
-	{ 0,	sizeof(struct ips_stat) },
-	{ 0,	sizeof(struct frauth) },
-	{ 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) },
+static	int	ipf_objbytes[IPFOBJ_COUNT][3] = {
+	{ 1,	sizeof(struct frentry),		5010000 },	/* 0 */
+	{ 1,	sizeof(struct friostat),	5010000 },
+	{ 0,	sizeof(struct fr_info),		5010000 },
+	{ 0,	sizeof(struct ipf_authstat),	4010100 },
+	{ 0,	sizeof(struct ipfrstat),	5010000 },
+	{ 1,	sizeof(struct ipnat),		5010000 },	/* 5 */
+	{ 0,	sizeof(struct natstat),		5010000 },
+	{ 0,	sizeof(struct ipstate_save),	5010000 },
+	{ 1,	sizeof(struct nat_save),	5010000 },
+	{ 0,	sizeof(struct natlookup),	5010000 },
+	{ 1,	sizeof(struct ipstate),		5010000 },	/* 10 */
+	{ 0,	sizeof(struct ips_stat),	5010000 },
+	{ 0,	sizeof(struct frauth),		5010000 },
+	{ 0,	sizeof(struct ipftune),		4010100 },
+	{ 0,	sizeof(struct nat),		5010000 },
+	{ 0,	sizeof(struct ipfruleiter),	4011400 },	/* 15 */
+	{ 0,	sizeof(struct ipfgeniter),	4011400 },
+	{ 0,	sizeof(struct ipftable),	4011400 },
+	{ 0,	sizeof(struct ipflookupiter),	4011400 },
 	{ 0,	sizeof(struct ipftq) * IPF_TCP_NSTATES },
+	{ 1,	0,				0	}, /* IPFEXPR */
+	{ 0,	0,				0	}, /* PROXYCTL */
+	{ 0,	sizeof (struct fripf),		5010000	}
 };
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_inobj                                                    */
+/* Function:    ipf_inobj                                                   */
 /* Returns:     int     - 0 = success, else failure                         */
-/* Parameters:  data(I) - pointer to ioctl data                             */
-/*              ptr(I)  - pointer to store real data in                     */
-/*              type(I) - type of structure being moved                     */
+/* Parameters:  softc(I) - soft context pointerto work with                 */
+/*              data(I)  - pointer to ioctl data                            */
+/*              objp(O)  - where to store ipfobj structure                  */
+/*              ptr(I)   - pointer to data to copy out                      */
+/*              type(I)  - type of structure being moved                    */
 /*                                                                          */
 /* Copy in the contents of what the ipfobj_t points to.  In future, we      */
 /* add things to check for version numbers, sizes, etc, to make it backward */
 /* compatible at the ABI for user land.                                     */
+/* If objp is not NULL then we assume that the caller wants to see what is  */
+/* in the ipfobj_t structure being copied in. As an example, this can tell  */
+/* the caller what version of ipfilter the ioctl program was written to.    */
 /* ------------------------------------------------------------------------ */
-int fr_inobj(data, ptr, type)
-void *data;
-void *ptr;
-int type;
+int
+ipf_inobj(softc, data, objp, ptr, type)
+	ipf_main_softc_t *softc;
+	void *data;
+	ipfobj_t *objp;
+	void *ptr;
+	int type;
 {
 	ipfobj_t obj;
-	int error = 0;
+	int error;
+	int size;
 
-	if ((type < 0) || (type >= IPFOBJ_COUNT))
+	if ((type < 0) || (type >= IPFOBJ_COUNT)) {
+		IPFERROR(49);
 		return EINVAL;
+	}
 
-	error = BCOPYIN(data, &obj, sizeof(obj));
-	if (error != 0)
+	if (objp == NULL)
+		objp = &obj;
+	error = BCOPYIN(data, objp, sizeof(*objp));
+	if (error != 0) {
+		IPFERROR(124);
 		return EFAULT;
+	}
 
-	if (obj.ipfo_type != type)
+	if (objp->ipfo_type != type) {
+		IPFERROR(50);
 		return EINVAL;
+	}
 
-#ifndef	IPFILTER_COMPAT
-	if ((fr_objbytes[type][0] & 1) != 0) {
-		if (obj.ipfo_size < fr_objbytes[type][1])
+	if (objp->ipfo_rev >= ipf_objbytes[type][2]) {
+		if ((ipf_objbytes[type][0] & 1) != 0) {
+			if (objp->ipfo_size < ipf_objbytes[type][1]) {
+				IPFERROR(51);
+				return EINVAL;
+			}
+			size =  ipf_objbytes[type][1];
+		} else if (objp->ipfo_size == ipf_objbytes[type][1]) {
+			size =  objp->ipfo_size;
+		} else {
+			IPFERROR(52);
 			return EINVAL;
-	} else if (obj.ipfo_size != fr_objbytes[type][1]) {
-		return EINVAL;
-	}
+		}
+		error = COPYIN(objp->ipfo_ptr, ptr, size);
+		if (error != 0) {
+			IPFERROR(55);
+			error = EFAULT;
+		}
+	} else {
+#ifdef  IPFILTER_COMPAT
+		error = ipf_in_compat(softc, objp, ptr, 0);
 #else
-	if (obj.ipfo_rev != IPFILTER_VERSION)
-		/* XXX compatibility hook here */
-		;
-	if ((fr_objbytes[type][0] & 1) != 0) {
-		if (obj.ipfo_size < fr_objbytes[type][1])
-			/* XXX compatibility hook here */
-			return EINVAL;
-	} else if (obj.ipfo_size != fr_objbytes[type][1])
-		/* XXX compatibility hook here */
-		return EINVAL;
+		IPFERROR(54);
+		error = EINVAL;
 #endif
-
-	if ((fr_objbytes[type][0] & 1) != 0) {
-		error = COPYIN(obj.ipfo_ptr, ptr, fr_objbytes[type][1]);
-	} else {
-		error = COPYIN(obj.ipfo_ptr, ptr, obj.ipfo_size);
 	}
-	if (error != 0)
-		error = EFAULT;
 	return error;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_inobjsz                                                  */
+/* Function:    ipf_inobjsz                                                 */
 /* Returns:     int     - 0 = success, else failure                         */
-/* Parameters:  data(I) - pointer to ioctl data                             */
-/*              ptr(I)  - pointer to store real data in                     */
-/*              type(I) - type of structure being moved                     */
-/*              sz(I)   - size of data to copy                              */
+/* Parameters:  softc(I) - soft context pointerto work with                 */
+/*              data(I)  - pointer to ioctl data                            */
+/*              ptr(I)   - pointer to store real data in                    */
+/*              type(I)  - type of structure being moved                    */
+/*              sz(I)    - size of data to copy                             */
 /*                                                                          */
-/* As per fr_inobj, except the size of the object to copy in is passed in   */
+/* As per ipf_inobj, except the size of the object to copy in is passed in  */
 /* but it must not be smaller than the size defined for the type and the    */
 /* type must allow for varied sized objects.  The extra requirement here is */
 /* that sz must match the size of the object being passed in - this is not  */
-/* not possible nor required in fr_inobj().                                 */
+/* not possible nor required in ipf_inobj().                                */
 /* ------------------------------------------------------------------------ */
-int fr_inobjsz(data, ptr, type, sz)
-void *data;
-void *ptr;
-int type, sz;
+int
+ipf_inobjsz(softc, data, ptr, type, sz)
+	ipf_main_softc_t *softc;
+	void *data;
+	void *ptr;
+	int type, sz;
 {
 	ipfobj_t obj;
 	int error;
 
-	if ((type < 0) || (type >= IPFOBJ_COUNT))
+	if ((type < 0) || (type >= IPFOBJ_COUNT)) {
+		IPFERROR(56);
 		return EINVAL;
-	if (((fr_objbytes[type][0] & 1) == 0) || (sz < fr_objbytes[type][1]))
-		return EINVAL;
+	}
 
 	error = BCOPYIN(data, &obj, sizeof(obj));
-	if (error != 0)
+	if (error != 0) {
+		IPFERROR(125);
 		return EFAULT;
+	}
 
-	if (obj.ipfo_type != type)
+	if (obj.ipfo_type != type) {
+		IPFERROR(58);
 		return EINVAL;
+	}
 
-#ifndef	IPFILTER_COMPAT
-	if (obj.ipfo_size != sz)
-		return EINVAL;
+	if (obj.ipfo_rev >= ipf_objbytes[type][2]) {
+		if (((ipf_objbytes[type][0] & 1) == 0) ||
+		    (sz < ipf_objbytes[type][1])) {
+			IPFERROR(57);
+			return EINVAL;
+		}
+		error = COPYIN(obj.ipfo_ptr, ptr, sz);
+		if (error != 0) {
+			IPFERROR(61);
+			error = EFAULT;
+		}
+	} else {
+#ifdef	IPFILTER_COMPAT
+		error = ipf_in_compat(softc, &obj, ptr, sz);
 #else
-	if (obj.ipfo_rev != IPFILTER_VERSION)
-		/* XXX compatibility hook here */
-		;
-	if (obj.ipfo_size != sz)
-		/* XXX compatibility hook here */
-		return EINVAL;
+		IPFERROR(60);
+		error = EINVAL;
 #endif
-
-	error = COPYIN(obj.ipfo_ptr, ptr, sz);
-	if (error != 0)
-		error = EFAULT;
+	}
 	return error;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_outobjsz                                                 */
+/* Function:    ipf_outobjsz                                                */
 /* Returns:     int     - 0 = success, else failure                         */
 /* Parameters:  data(I) - pointer to ioctl data                             */
 /*              ptr(I)  - pointer to store real data in                     */
@@ -5590,53 +6461,63 @@
 /*              type(I) - type of structure being moved                     */
 /*              sz(I)   - size of data to copy                              */
 /*                                                                          */
-/* As per fr_outobj, except the size of the object to copy out is passed in */
+/* As per ipf_outobj, except the size of the object to copy out is passed in*/
 /* but it must not be smaller than the size defined for the type and the    */
 /* type must allow for varied sized objects.  The extra requirement here is */
 /* that sz must match the size of the object being passed in - this is not  */
-/* not possible nor required in fr_outobj().                                */
+/* not possible nor required in ipf_outobj().                               */
 /* ------------------------------------------------------------------------ */
-int fr_outobjsz(data, ptr, type, sz)
-void *data;
-void *ptr;
-int type, sz;
+int
+ipf_outobjsz(softc, data, ptr, type, sz)
+	ipf_main_softc_t *softc;
+	void *data;
+	void *ptr;
+	int type, sz;
 {
 	ipfobj_t obj;
 	int error;
 
-	if ((type < 0) || (type >= IPFOBJ_COUNT) ||
-	    ((fr_objbytes[type][0] & 1) == 0) ||
-	    (sz < fr_objbytes[type][1]))
+	if ((type < 0) || (type >= IPFOBJ_COUNT)) {
+		IPFERROR(62);
 		return EINVAL;
+	}
 
 	error = BCOPYIN(data, &obj, sizeof(obj));
-	if (error != 0)
+	if (error != 0) {
+		IPFERROR(127);
 		return EFAULT;
+	}
 
-	if (obj.ipfo_type != type)
+	if (obj.ipfo_type != type) {
+		IPFERROR(63);
 		return EINVAL;
+	}
 
-#ifndef	IPFILTER_COMPAT
-	if (obj.ipfo_size != sz)
-		return EINVAL;
+	if (obj.ipfo_rev >= ipf_objbytes[type][2]) {
+		if (((ipf_objbytes[type][0] & 1) == 0) ||
+		    (sz < ipf_objbytes[type][1])) {
+			IPFERROR(146);
+			return EINVAL;
+		}
+		error = COPYOUT(ptr, obj.ipfo_ptr, sz);
+		if (error != 0) {
+			IPFERROR(66);
+			error = EFAULT;
+		}
+	} else {
+#ifdef	IPFILTER_COMPAT
+		error = ipf_out_compat(softc, &obj, ptr);
 #else
-	if (obj.ipfo_rev != IPFILTER_VERSION)
-		/* XXX compatibility hook here */
-		;
-	if (obj.ipfo_size != sz)
-		/* XXX compatibility hook here */
-		return EINVAL;
+		IPFERROR(65);
+		error = EINVAL;
 #endif
-
-	error = COPYOUT(ptr, obj.ipfo_ptr, sz);
-	if (error != 0)
-		error = EFAULT;
+	}
 	return error;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_outobj                                                   */
+/* Function:    ipf_outobj                                                  */
 /* Returns:     int     - 0 = success, else failure                         */
 /* Parameters:  data(I) - pointer to ioctl data                             */
 /*              ptr(I)  - pointer to store real data in                     */
@@ -5646,75 +6527,134 @@
 /* future, we add things to check for version numbers, sizes, etc, to make  */
 /* it backward  compatible at the ABI for user land.                        */
 /* ------------------------------------------------------------------------ */
-int fr_outobj(data, ptr, type)
-void *data;
-void *ptr;
-int type;
+int
+ipf_outobj(softc, data, ptr, type)
+	ipf_main_softc_t *softc;
+	void *data;
+	void *ptr;
+	int type;
 {
 	ipfobj_t obj;
 	int error;
 
-	if ((type < 0) || (type >= IPFOBJ_COUNT))
+	if ((type < 0) || (type >= IPFOBJ_COUNT)) {
+		IPFERROR(67);
 		return EINVAL;
+	}
 
 	error = BCOPYIN(data, &obj, sizeof(obj));
-	if (error != 0)
+	if (error != 0) {
+		IPFERROR(126);
 		return EFAULT;
+	}
 
-	if (obj.ipfo_type != type)
+	if (obj.ipfo_type != type) {
+		IPFERROR(68);
 		return EINVAL;
+	}
 
-#ifndef	IPFILTER_COMPAT
-	if ((fr_objbytes[type][0] & 1) != 0) {
-		if (obj.ipfo_size < fr_objbytes[type][1])
+	if (obj.ipfo_rev >= ipf_objbytes[type][2]) {
+		if ((ipf_objbytes[type][0] & 1) != 0) {
+			if (obj.ipfo_size < ipf_objbytes[type][1]) {
+				IPFERROR(69);
+				return EINVAL;
+			}
+		} else if (obj.ipfo_size != ipf_objbytes[type][1]) {
+			IPFERROR(70);
 			return EINVAL;
-	} else if (obj.ipfo_size != fr_objbytes[type][1])
+		}
+
+		error = COPYOUT(ptr, obj.ipfo_ptr, obj.ipfo_size);
+		if (error != 0) {
+			IPFERROR(73);
+			error = EFAULT;
+		}
+	} else {
+#ifdef	IPFILTER_COMPAT
+		error = ipf_out_compat(softc, &obj, ptr);
+#else
+		IPFERROR(72);
+		error = EINVAL;
+#endif
+	}
+	return error;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_outobjk                                                 */
+/* Returns:     int     - 0 = success, else failure                         */
+/* Parameters:  obj(I)  - pointer to data description structure             */
+/*              ptr(I)  - pointer to kernel data to copy out                */
+/*                                                                          */
+/* In the above functions, the ipfobj_t structure is copied into the kernel,*/
+/* telling ipfilter how to copy out data. In this instance, the ipfobj_t is */
+/* already populated with information and now we just need to use it.       */
+/* There is no need for this function to have a "type" parameter as there   */
+/* is no point in validating information that comes from the kernel with    */
+/* itself.                                                                  */
+/* ------------------------------------------------------------------------ */
+int
+ipf_outobjk(softc, obj, ptr)
+	ipf_main_softc_t *softc;
+	ipfobj_t *obj;
+	void *ptr;
+{
+	int type = obj->ipfo_type;
+	int error;
+
+	if ((type < 0) || (type >= IPFOBJ_COUNT)) {
+		IPFERROR(147);
 		return EINVAL;
+	}
+
+	if (obj->ipfo_rev >= ipf_objbytes[type][2]) {
+		if ((ipf_objbytes[type][0] & 1) != 0) {
+			if (obj->ipfo_size < ipf_objbytes[type][1]) {
+				IPFERROR(148);
+				return EINVAL;
+			}
+
+		} else if (obj->ipfo_size != ipf_objbytes[type][1]) {
+			IPFERROR(149);
+			return EINVAL;
+		}
+
+		error = COPYOUT(ptr, obj->ipfo_ptr, obj->ipfo_size);
+		if (error != 0) {
+			IPFERROR(150);
+			error = EFAULT;
+		}
+	} else {
+#ifdef  IPFILTER_COMPAT
+		error = ipf_out_compat(softc, obj, ptr);
 #else
-	if (obj.ipfo_rev != IPFILTER_VERSION)
-		/* XXX compatibility hook here */
-		;
-	if ((fr_objbytes[type][0] & 1) != 0) {
-		if (obj.ipfo_size < fr_objbytes[type][1])
-			/* XXX compatibility hook here */
-			return EINVAL;
-	} else if (obj.ipfo_size != fr_objbytes[type][1])
-		/* XXX compatibility hook here */
-		return EINVAL;
+		IPFERROR(151);
+		error = EINVAL;
 #endif
-
-	error = COPYOUT(ptr, obj.ipfo_ptr, obj.ipfo_size);
-	if (error != 0)
-		error = EFAULT;
+	}
 	return error;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_checkl4sum                                               */
+/* Function:    ipf_checkl4sum                                              */
 /* Returns:     int     - 0 = good, -1 = bad, 1 = cannot check              */
 /* Parameters:  fin(I) - pointer to packet information                      */
 /*                                                                          */
 /* If possible, calculate the layer 4 checksum for the packet.  If this is  */
 /* not possible, return without indicating a failure or success but in a    */
-/* way that is ditinguishable.                                              */
+/* way that is ditinguishable. This function should only be called by the   */
+/* ipf_checkv6sum() for each platform.                                      */
 /* ------------------------------------------------------------------------ */
-int fr_checkl4sum(fin)
-fr_info_t *fin;
+INLINE int
+ipf_checkl4sum(fin)
+	fr_info_t *fin;
 {
 	u_short sum, hdrsum, *csump;
 	udphdr_t *udp;
 	int dosum;
 
-	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
@@ -5728,48 +6668,44 @@
 	dosum = 0;
 	sum = 0;
 
-#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) && defined(ICK_VALID)
-	if (dohwcksum && ((*fin->fin_mp)->b_ick_flag == ICK_VALID)) {
-		hdrsum = 0;
-		sum = 0;
-	} else {
-#endif
-		switch (fin->fin_p)
-		{
-		case IPPROTO_TCP :
-			csump = &((tcphdr_t *)fin->fin_dp)->th_sum;
+	switch (fin->fin_p)
+	{
+	case IPPROTO_TCP :
+		csump = &((tcphdr_t *)fin->fin_dp)->th_sum;
+		dosum = 1;
+		break;
+
+	case IPPROTO_UDP :
+		udp = fin->fin_dp;
+		if (udp->uh_sum != 0) {
+			csump = &udp->uh_sum;
 			dosum = 1;
-			break;
+		}
+		break;
 
-		case IPPROTO_UDP :
-			udp = fin->fin_dp;
-			if (udp->uh_sum != 0) {
-				csump = &udp->uh_sum;
-				dosum = 1;
-			}
-			break;
+#ifdef USE_INET6
+	case IPPROTO_ICMPV6 :
+		csump = &((struct icmp6_hdr *)fin->fin_dp)->icmp6_cksum;
+		dosum = 1;
+		break;
+#endif
 
-		case IPPROTO_ICMP :
-			csump = &((struct icmp *)fin->fin_dp)->icmp_cksum;
-			dosum = 1;
-			break;
+	case IPPROTO_ICMP :
+		csump = &((struct icmp *)fin->fin_dp)->icmp_cksum;
+		dosum = 1;
+		break;
 
-		default :
-			return 1;
-			/*NOTREACHED*/
-		}
+	default :
+		return 1;
+		/*NOTREACHED*/
+	}
 
-		if (csump != NULL)
-			hdrsum = *csump;
+	if (csump != NULL)
+		hdrsum = *csump;
 
-		if (dosum) {
-			sum = fr_cksum(fin->fin_m, fin->fin_ip,
-				       fin->fin_p, fin->fin_dp,
-				       fin->fin_dlen + fin->fin_hlen);
-		}
-#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) && defined(ICK_VALID)
+	if (dosum) {
+		sum = fr_cksum(fin, fin->fin_ip, fin->fin_p, fin->fin_dp);
 	}
-#endif
 #if !defined(_KERNEL)
 	if (sum == hdrsum) {
 		FR_DEBUG(("checkl4sum: %hx == %hx\n", sum, hdrsum));
@@ -5777,17 +6713,18 @@
 		FR_DEBUG(("checkl4sum: %hx != %hx\n", sum, hdrsum));
 	}
 #endif
+	DT2(l4sums, u_short, hdrsum, u_short, sum);
 	if (hdrsum == sum) {
-		fin->fin_cksum = 1;
+		fin->fin_cksum = FI_CK_SUMOK;
 		return 0;
 	}
-	fin->fin_cksum = -1;
+	fin->fin_cksum = FI_CK_BAD;
 	return -1;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_ifpfillv4addr                                            */
+/* Function:    ipf_ifpfillv4addr                                           */
 /* Returns:     int     - 0 = address update, -1 = address not updated      */
 /* Parameters:  atype(I)   - type of network address update to perform      */
 /*              sin(I)     - pointer to source of address information       */
@@ -5802,10 +6739,11 @@
 /* FRI_NETMASKED, if inpmask is non-NULL then the mask is set to an all 1s  */
 /* value.                                                                   */
 /* ------------------------------------------------------------------------ */
-int fr_ifpfillv4addr(atype, sin, mask, inp, inpmask)
-int atype;
-struct sockaddr_in *sin, *mask;
-struct in_addr *inp, *inpmask;
+int
+ipf_ifpfillv4addr(atype, sin, mask, inp, inpmask)
+	int atype;
+	struct sockaddr_in *sin, *mask;
+	struct in_addr *inp, *inpmask;
 {
 	if (inpmask != NULL && atype != FRI_NETMASKED)
 		inpmask->s_addr = 0xffffffff;
@@ -5826,7 +6764,7 @@
 
 #ifdef	USE_INET6
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_ifpfillv6addr                                            */
+/* Function:    ipf_ifpfillv6addr                                           */
 /* Returns:     int     - 0 = address update, -1 = address not updated      */
 /* Parameters:  atype(I)   - type of network address update to perform      */
 /*              sin(I)     - pointer to source of address information       */
@@ -5841,23 +6779,22 @@
 /* FRI_NETMASKED, if inpmask is non-NULL then the mask is set to an all 1s  */
 /* value.                                                                   */
 /* ------------------------------------------------------------------------ */
-int fr_ifpfillv6addr(atype, sin, mask, inp, inpmask)
-int atype;
-struct sockaddr_in6 *sin, *mask;
-struct in_addr *inp, *inpmask;
+int
+ipf_ifpfillv6addr(atype, sin, mask, inp, inpmask)
+	int atype;
+	struct sockaddr_in6 *sin, *mask;
+	i6addr_t *inp, *inpmask;
 {
-	i6addr_t *src, *dst, *and, *dmask;
+	i6addr_t *src, *and;
 
 	src = (i6addr_t *)&sin->sin6_addr;
 	and = (i6addr_t *)&mask->sin6_addr;
-	dst = (i6addr_t *)inp;
-	dmask = (i6addr_t *)inpmask;
 
 	if (inpmask != NULL && atype != FRI_NETMASKED) {
-		dmask->i6[0] = 0xffffffff;
-		dmask->i6[1] = 0xffffffff;
-		dmask->i6[2] = 0xffffffff;
-		dmask->i6[3] = 0xffffffff;
+		inpmask->i6[0] = 0xffffffff;
+		inpmask->i6[1] = 0xffffffff;
+		inpmask->i6[2] = 0xffffffff;
+		inpmask->i6[3] = 0xffffffff;
 	}
 
 	if (atype == FRI_NETWORK || atype == FRI_NETMASKED) {
@@ -5864,21 +6801,21 @@
 		if (atype == FRI_NETMASKED) {
 			if (inpmask == NULL)
 				return -1;
-			dmask->i6[0] = and->i6[0];
-			dmask->i6[1] = and->i6[1];
-			dmask->i6[2] = and->i6[2];
-			dmask->i6[3] = and->i6[3];
+			inpmask->i6[0] = and->i6[0];
+			inpmask->i6[1] = and->i6[1];
+			inpmask->i6[2] = and->i6[2];
+			inpmask->i6[3] = and->i6[3];
 		}
 
-		dst->i6[0] = src->i6[0] & and->i6[0];
-		dst->i6[1] = src->i6[1] & and->i6[1];
-		dst->i6[2] = src->i6[2] & and->i6[2];
-		dst->i6[3] = src->i6[3] & and->i6[3];
+		inp->i6[0] = src->i6[0] & and->i6[0];
+		inp->i6[1] = src->i6[1] & and->i6[1];
+		inp->i6[2] = src->i6[2] & and->i6[2];
+		inp->i6[3] = src->i6[3] & and->i6[3];
 	} else {
-		dst->i6[0] = src->i6[0];
-		dst->i6[1] = src->i6[1];
-		dst->i6[2] = src->i6[2];
-		dst->i6[3] = src->i6[3];
+		inp->i6[0] = src->i6[0];
+		inp->i6[1] = src->i6[1];
+		inp->i6[2] = src->i6[2];
+		inp->i6[3] = src->i6[3];
 	}
 	return 0;
 }
@@ -5886,7 +6823,7 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_matchtag                                                 */
+/* Function:    ipf_matchtag                                                */
 /* Returns:     0 == mismatch, 1 == match.                                  */
 /* Parameters:  tag1(I) - pointer to first tag to compare                   */
 /*              tag2(I) - pointer to second tag to compare                  */
@@ -5898,8 +6835,9 @@
 /* comparison.  This function should only be called with both tag1 and tag2 */
 /* as non-NULL pointers.                                                    */
 /* ------------------------------------------------------------------------ */
-int fr_matchtag(tag1, tag2)
-ipftag_t *tag1, *tag2;
+int
+ipf_matchtag(tag1, tag2)
+	ipftag_t *tag1, *tag2;
 {
 	if (tag1 == tag2)
 		return 1;
@@ -5917,7 +6855,7 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_coalesce                                                 */
+/* Function:    ipf_coalesce                                                */
 /* Returns:     1 == success, -1 == failure, 0 == no change                 */
 /* Parameters:  fin(I) - pointer to packet information                      */
 /*                                                                          */
@@ -5924,9 +6862,11 @@
 /* Attempt to get all of the packet data into a single, contiguous buffer.  */
 /* If this call returns a failure then the buffers have also been freed.    */
 /* ------------------------------------------------------------------------ */
-int fr_coalesce(fin)
-fr_info_t *fin;
+int
+ipf_coalesce(fin)
+	fr_info_t *fin;
 {
+
 	if ((fin->fin_flx & FI_COALESCE) != 0)
 		return 1;
 
@@ -5938,11 +6878,15 @@
 		return 0;
 
 #if defined(_KERNEL)
-	if (fr_pullup(fin->fin_m, fin, fin->fin_plen) == NULL) {
-		ATOMIC_INCL(fr_badcoalesces[fin->fin_out]);
+	if (ipf_pullup(fin->fin_m, fin, fin->fin_plen) == NULL) {
+		ipf_main_softc_t *softc = fin->fin_main_soft;
+
+		DT1(frb_coalesce, fr_info_t *, fin);
+		LBUMP(ipf_stats[fin->fin_out].fr_badcoalesces);
 # ifdef MENTAT
 		FREE_MB_T(*fin->fin_mp);
 # endif
+		fin->fin_reason = FRB_COALESCE;
 		*fin->fin_mp = NULL;
 		fin->fin_m = NULL;
 		return -1;
@@ -5967,114 +6911,10 @@
  * The obvious implication is if neither of these are set then the value can be
  * changed at any time without harm.
  */
-ipftuneable_t ipf_tuneables[] = {
-	/* filtering */
-	{ { &fr_flags },	"fr_flags",		0,	0xffffffff,
-		sizeof(fr_flags),		0,	NULL },
-	{ { &fr_active },	"fr_active",		0,	0,
-		sizeof(fr_active),		IPFT_RDONLY,	NULL },
-	{ { &fr_control_forwarding },	"fr_control_forwarding",	0, 1,
-		sizeof(fr_control_forwarding),	0,	NULL },
-	{ { &fr_update_ipid },	"fr_update_ipid",	0,	1,
-		sizeof(fr_update_ipid),		0,	NULL },
-	{ { &fr_chksrc },	"fr_chksrc",		0,	1,
-		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,	NULL },
-	/* state */
-	{ { &fr_tcpidletimeout }, "fr_tcpidletimeout",	1,	0x7fffffff,
-		sizeof(fr_tcpidletimeout),	IPFT_WRDISABLED,	NULL },
-	{ { &fr_tcpclosewait },	"fr_tcpclosewait",	1,	0x7fffffff,
-		sizeof(fr_tcpclosewait),	IPFT_WRDISABLED,	NULL },
-	{ { &fr_tcplastack },	"fr_tcplastack",	1,	0x7fffffff,
-		sizeof(fr_tcplastack),		IPFT_WRDISABLED,	NULL },
-	{ { &fr_tcptimeout },	"fr_tcptimeout",	1,	0x7fffffff,
-		sizeof(fr_tcptimeout),		IPFT_WRDISABLED,	NULL },
-	{ { &fr_tcpclosed },	"fr_tcpclosed",		1,	0x7fffffff,
-		sizeof(fr_tcpclosed),		IPFT_WRDISABLED,	NULL },
-	{ { &fr_tcphalfclosed }, "fr_tcphalfclosed",	1,	0x7fffffff,
-		sizeof(fr_tcphalfclosed),	IPFT_WRDISABLED,	NULL },
-	{ { &fr_udptimeout },	"fr_udptimeout",	1,	0x7fffffff,
-		sizeof(fr_udptimeout),		IPFT_WRDISABLED,	NULL },
-	{ { &fr_udpacktimeout }, "fr_udpacktimeout",	1,	0x7fffffff,
-		sizeof(fr_udpacktimeout),	IPFT_WRDISABLED,	NULL },
-	{ { &fr_icmptimeout },	"fr_icmptimeout",	1,	0x7fffffff,
-		sizeof(fr_icmptimeout),		IPFT_WRDISABLED,	NULL },
-	{ { &fr_icmpacktimeout }, "fr_icmpacktimeout",	1,	0x7fffffff,
-		sizeof(fr_icmpacktimeout),	IPFT_WRDISABLED,	NULL },
-	{ { &fr_iptimeout }, "fr_iptimeout",		1,	0x7fffffff,
-		sizeof(fr_iptimeout),		IPFT_WRDISABLED,	NULL },
-	{ { &fr_statemax },	"fr_statemax",		1,	0x7fffffff,
-		sizeof(fr_statemax),		0,	NULL },
-	{ { &fr_statesize },	"fr_statesize",		1,	0x7fffffff,
-		sizeof(fr_statesize),		IPFT_WRDISABLED,	NULL },
-	{ { &fr_state_lock },	"fr_state_lock",	0,	1,
-		sizeof(fr_state_lock),		IPFT_RDONLY,	NULL },
-	{ { &fr_state_maxbucket }, "fr_state_maxbucket", 1,	0x7fffffff,
-		sizeof(fr_state_maxbucket),	IPFT_WRDISABLED,	NULL },
-	{ { &fr_state_maxbucket_reset }, "fr_state_maxbucket_reset",	0, 1,
-		sizeof(fr_state_maxbucket_reset), IPFT_WRDISABLED,	NULL },
-	{ { &ipstate_logging },	"ipstate_logging",	0,	1,
-		sizeof(ipstate_logging),	0,	NULL },
-	/* nat */
-	{ { &fr_nat_lock },		"fr_nat_lock",		0,	1,
-		sizeof(fr_nat_lock),		IPFT_RDONLY,	NULL },
-	{ { &ipf_nattable_sz },	"ipf_nattable_sz",	1,	0x7fffffff,
-		sizeof(ipf_nattable_sz),	IPFT_WRDISABLED,	NULL },
-	{ { &ipf_nattable_max }, "ipf_nattable_max",	1,	0x7fffffff,
-		sizeof(ipf_nattable_max),	0,	NULL },
-	{ { &ipf_natrules_sz },	"ipf_natrules_sz",	1,	0x7fffffff,
-		sizeof(ipf_natrules_sz),	IPFT_WRDISABLED,	NULL },
-	{ { &ipf_rdrrules_sz },	"ipf_rdrrules_sz",	1,	0x7fffffff,
-		sizeof(ipf_rdrrules_sz),	IPFT_WRDISABLED,	NULL },
-	{ { &ipf_hostmap_sz },	"ipf_hostmap_sz",	1,	0x7fffffff,
-		sizeof(ipf_hostmap_sz),		IPFT_WRDISABLED,	NULL },
-	{ { &fr_nat_maxbucket }, "fr_nat_maxbucket",	1,	0x7fffffff,
-		sizeof(fr_nat_maxbucket),	0,			NULL },
-	{ { &fr_nat_maxbucket_reset },	"fr_nat_maxbucket_reset",	0, 1,
-		sizeof(fr_nat_maxbucket_reset),	IPFT_WRDISABLED,	NULL },
-	{ { &nat_logging },		"nat_logging",		0,	1,
-		sizeof(nat_logging),		0,	NULL },
-	{ { &fr_defnatage },	"fr_defnatage",		1,	0x7fffffff,
-		sizeof(fr_defnatage),		IPFT_WRDISABLED,	NULL },
-	{ { &fr_defnatipage },	"fr_defnatipage",	1,	0x7fffffff,
-		sizeof(fr_defnatipage),		IPFT_WRDISABLED,	NULL },
-	{ { &fr_defnaticmpage }, "fr_defnaticmpage",	1,	0x7fffffff,
-		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,	NULL },
-	{ { &fr_ipfrttl },	"fr_ipfrttl",		1,	0x7fffffff,
-		sizeof(fr_ipfrttl),		IPFT_WRDISABLED,	NULL },
-#ifdef IPFILTER_LOG
-	/* log */
-	{ { &ipl_suppress },	"ipl_suppress",		0,	1,
-		sizeof(ipl_suppress),		0,	NULL },
-	{ { &ipl_logmax },	"ipl_logmax",		0,	0x7fffffff,
-		sizeof(ipl_logmax),		IPFT_WRDISABLED,	NULL },
-	{ { &ipl_logall },	"ipl_logall",		0,	1,
-		sizeof(ipl_logall),		0,	NULL },
-	{ { &ipl_logsize },	"ipl_logsize",		0,	0x80000,
-		sizeof(ipl_logsize),		0,	NULL },
-#endif
-	{ { NULL },		NULL,			0,	0,
-		0,				0,	NULL }
-};
 
-static ipftuneable_t *ipf_tunelist = NULL;
 
-
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_findtunebycookie                                         */
+/* Function:    ipf_tune_findbycookie                                       */
 /* Returns:     NULL = search failed, else pointer to tune struct           */
 /* Parameters:  cookie(I) - cookie value to search for amongst tuneables    */
 /*              next(O)   - pointer to place to store the cookie for the    */
@@ -6085,12 +6925,14 @@
 /* a matching value for "cookie" - ie its address.  When returning a match, */
 /* the next one to be found may be returned inside next.                    */
 /* ------------------------------------------------------------------------ */
-static ipftuneable_t *fr_findtunebycookie(cookie, next)
-void *cookie, **next;
+static ipftuneable_t *
+ipf_tune_findbycookie(ptop, cookie, next)
+	ipftuneable_t **ptop;
+	void *cookie, **next;
 {
 	ipftuneable_t *ta, **tap;
 
-	for (ta = ipf_tuneables; ta->ipft_name != NULL; ta++)
+	for (ta = *ptop; ta->ipft_name != NULL; ta++)
 		if (ta == cookie) {
 			if (next != NULL) {
 				/*
@@ -6104,12 +6946,12 @@
 				if ((ta + 1)->ipft_name != NULL)
 					*next = ta + 1;
 				else
-					*next = &ipf_tunelist;
+					*next = ptop;
 			}
 			return ta;
 		}
 
-	for (tap = &ipf_tunelist; (ta = *tap) != NULL; tap = &ta->ipft_next)
+	for (tap = ptop; (ta = *tap) != NULL; tap = &ta->ipft_next)
 		if (tap == cookie) {
 			if (next != NULL)
 				*next = &ta->ipft_next;
@@ -6123,7 +6965,7 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_findtunebyname                                           */
+/* Function:    ipf_tune_findbyname                                         */
 /* Returns:     NULL = search failed, else pointer to tune struct           */
 /* Parameters:  name(I) - name of the tuneable entry to find.               */
 /*                                                                          */
@@ -6131,44 +6973,192 @@
 /* for an entry with a matching name.  If we can find one, return a pointer */
 /* to the matching structure.                                               */
 /* ------------------------------------------------------------------------ */
-static ipftuneable_t *fr_findtunebyname(name)
-const char *name;
+static ipftuneable_t *
+ipf_tune_findbyname(top, name)
+	ipftuneable_t *top;
+	const char *name;
 {
 	ipftuneable_t *ta;
 
-	for (ta = ipf_tuneables; ta->ipft_name != NULL; ta++)
+	for (ta = top; ta != NULL; ta = ta->ipft_next)
 		if (!strcmp(ta->ipft_name, name)) {
 			return ta;
 		}
 
-	for (ta = ipf_tunelist; ta != NULL; ta = ta->ipft_next)
-		if (!strcmp(ta->ipft_name, name)) {
-			return ta;
+	return NULL;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_tune_add_array                                          */
+/* Returns:     int - 0 == success, else failure                            */
+/* Parameters:  newtune - pointer to new tune array to add to tuneables     */
+/*                                                                          */
+/* Appends tune structures from the array passed in (newtune) to the end of */
+/* the current list of "dynamic" tuneable parameters.                       */
+/* If any entry to be added is already present (by name) then the operation */
+/* is aborted - entries that have been added are removed before returning.  */
+/* An entry with no name (NULL) is used as the indication that the end of   */
+/* the array has been reached.                                              */
+/* ------------------------------------------------------------------------ */
+int
+ipf_tune_add_array(softc, newtune)
+	ipf_main_softc_t *softc;
+	ipftuneable_t *newtune;
+{
+	ipftuneable_t *nt, *dt;
+	int error = 0;
+
+	for (nt = newtune; nt->ipft_name != NULL; nt++) {
+		error = ipf_tune_add(softc, nt);
+		if (error != 0) {
+			for (dt = newtune; dt != nt; dt++) {
+				(void) ipf_tune_del(softc, dt);
+			}
 		}
+	}
 
-	return NULL;
+	return error;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_addipftune                                               */
+/* Function:    ipf_tune_array_link                                         */
+/* Returns:     0 == success, -1 == failure                                 */
+/* Parameters:  softc(I) - soft context pointerto work with                 */
+/*              array(I) - pointer to an array of tuneables                 */
+/*                                                                          */
+/* Given an array of tunables (array), append them to the current list of   */
+/* tuneables for this context (softc->ipf_tuners.) To properly prepare the  */
+/* the array for being appended to the list, initialise all of the next     */
+/* pointers so we don't need to walk parts of it with ++ and others with    */
+/* next. The array is expected to have an entry with a NULL name as the     */
+/* terminator. Trying to add an array with no non-NULL names will return as */
+/* a failure.                                                               */
+/* ------------------------------------------------------------------------ */
+int
+ipf_tune_array_link(softc, array)
+	ipf_main_softc_t *softc;
+	ipftuneable_t *array;
+{
+	ipftuneable_t *t, **p;
+
+	t = array;
+	if (t->ipft_name == NULL)
+		return -1;
+
+	for (; t[1].ipft_name != NULL; t++)
+		t[0].ipft_next = &t[1];
+	t->ipft_next = NULL;
+
+	/*
+	 * Since a pointer to the last entry isn't kept, we need to find it
+	 * each time we want to add new variables to the list.
+	 */
+	for (p = &softc->ipf_tuners; (t = *p) != NULL; p = &t->ipft_next)
+		if (t->ipft_name == NULL)
+			break;
+	*p = array;
+
+	return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_tune_array_unlink                                       */
+/* Returns:     0 == success, -1 == failure                                 */
+/* Parameters:  softc(I) - soft context pointerto work with                 */
+/*              array(I) - pointer to an array of tuneables                 */
+/*                                                                          */
+/* ------------------------------------------------------------------------ */
+int
+ipf_tune_array_unlink(softc, array)
+	ipf_main_softc_t *softc;
+	ipftuneable_t *array;
+{
+	ipftuneable_t *t, **p;
+
+	for (p = &softc->ipf_tuners; (t = *p) != NULL; p = &t->ipft_next)
+		if (t == array)
+			break;
+	if (t == NULL)
+		return -1;
+
+	for (; t[1].ipft_name != NULL; t++)
+		;
+
+	*p = t->ipft_next;
+
+	return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:   ipf_tune_array_copy                                          */
+/* Returns:    NULL = failure, else pointer to new array                    */
+/* Parameters: base(I)     - pointer to structure base                      */
+/*             size(I)     - size of the array at template                  */
+/*             template(I) - original array to copy                         */
+/*                                                                          */
+/* Allocate memory for a new set of tuneable values and copy everything     */
+/* from template into the new region of memory.  The new region is full of  */
+/* uninitialised pointers (ipft_next) so set them up.  Now, ipftp_offset... */
+/*                                                                          */
+/* NOTE: the following assumes that sizeof(long) == sizeof(void *)          */
+/* In the array template, ipftp_offset is the offset (in bytes) of the      */
+/* location of the tuneable value inside the structure pointed to by base.  */
+/* As ipftp_offset is a union over the pointers to the tuneable values, if  */
+/* we add base to the copy's ipftp_offset, copy ends up with a pointer in   */
+/* ipftp_void that points to the stored value.                              */
+/* ------------------------------------------------------------------------ */
+ipftuneable_t *
+ipf_tune_array_copy(base, size, template)
+	void *base;
+	size_t size;
+	ipftuneable_t *template;
+{
+	ipftuneable_t *copy;
+	int i;
+
+
+	KMALLOCS(copy, ipftuneable_t *, size);
+	if (copy == NULL) {
+		return NULL;
+	}
+	bcopy(template, copy, size);
+
+	for (i = 0; copy[i].ipft_name; i++) {
+		copy[i].ipft_una.ipftp_offset += (u_long)base;
+		copy[i].ipft_next = copy + i + 1;
+	}
+
+	return copy;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_tune_add                                                */
 /* Returns:     int - 0 == success, else failure                            */
-/* Parameters:  newtune - pointer to new tune struct to add to tuneables    */
+/* Parameters:  newtune - pointer to new tune entry to add to tuneables     */
 /*                                                                          */
-/* Appends the tune structure pointer to by "newtune" to the end of the     */
-/* current list of "dynamic" tuneable parameters.  Once added, the owner    */
-/* of the object is not expected to ever change "ipft_next".                */
+/* Appends tune structures from the array passed in (newtune) to the end of */
+/* the current list of "dynamic" tuneable parameters.  Once added, the      */
+/* owner of the object is not expected to ever change "ipft_next".          */
 /* ------------------------------------------------------------------------ */
-int fr_addipftune(newtune)
-ipftuneable_t *newtune;
+int
+ipf_tune_add(softc, newtune)
+	ipf_main_softc_t *softc;
+	ipftuneable_t *newtune;
 {
 	ipftuneable_t *ta, **tap;
 
-	ta = fr_findtunebyname(newtune->ipft_name);
-	if (ta != NULL)
+	ta = ipf_tune_findbyname(softc->ipf_tuners, newtune->ipft_name);
+	if (ta != NULL) {
+		IPFERROR(74);
 		return EEXIST;
+	}
 
-	for (tap = &ipf_tunelist; *tap != NULL; tap = &(*tap)->ipft_next)
+	for (tap = &softc->ipf_tuners; *tap != NULL; tap = &(*tap)->ipft_next)
 		;
 
 	newtune->ipft_next = NULL;
@@ -6178,9 +7168,9 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_delipftune                                               */
+/* Function:    ipf_tune_del                                                */
 /* Returns:     int - 0 == success, else failure                            */
-/* Parameters:  oldtune - pointer to tune struct to remove from the list of */
+/* Parameters:  oldtune - pointer to tune entry to remove from the list of  */
 /*                        current dynamic tuneables                         */
 /*                                                                          */
 /* Search for the tune structure, by pointer, in the list of those that are */
@@ -6187,25 +7177,64 @@
 /* dynamically added at run time.  If found, adjust the list so that this   */
 /* structure is no longer part of it.                                       */
 /* ------------------------------------------------------------------------ */
-int fr_delipftune(oldtune)
-ipftuneable_t *oldtune;
+int
+ipf_tune_del(softc, oldtune)
+	ipf_main_softc_t *softc;
+	ipftuneable_t *oldtune;
 {
 	ipftuneable_t *ta, **tap;
+	int error = 0;
 
-	for (tap = &ipf_tunelist; (ta = *tap) != NULL; tap = &ta->ipft_next)
+	for (tap = &softc->ipf_tuners; (ta = *tap) != NULL;
+	     tap = &ta->ipft_next) {
 		if (ta == oldtune) {
 			*tap = oldtune->ipft_next;
 			oldtune->ipft_next = NULL;
-			return 0;
+			break;
 		}
+	}
 
-	return ESRCH;
+	if (ta == NULL) {
+		error = ESRCH;
+		IPFERROR(75);
+	}
+	return error;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_ipftune                                                  */
+/* Function:    ipf_tune_del_array                                          */
 /* Returns:     int - 0 == success, else failure                            */
+/* Parameters:  oldtune - pointer to tuneables array                        */
+/*                                                                          */
+/* Remove each tuneable entry in the array from the list of "dynamic"       */
+/* tunables.  If one entry should fail to be found, an error will be        */
+/* returned and no further ones removed.                                    */
+/* An entry with a NULL name is used as the indicator of the last entry in  */
+/* the array.                                                               */
+/* ------------------------------------------------------------------------ */
+int
+ipf_tune_del_array(softc, oldtune)
+	ipf_main_softc_t *softc;
+	ipftuneable_t *oldtune;
+{
+	ipftuneable_t *ot;
+	int error = 0;
+
+	for (ot = oldtune; ot->ipft_name != NULL; ot++) {
+		error = ipf_tune_del(softc, ot);
+		if (error != 0)
+			break;
+	}
+
+	return error;
+
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_tune                                                    */
+/* Returns:     int - 0 == success, else failure                            */
 /* Parameters:  cmd(I)  - ioctl command number                              */
 /*              data(I) - pointer to ioctl data structure                   */
 /*                                                                          */
@@ -6216,9 +7245,11 @@
 /* and 'destruction' routines of the various components of ipfilter are all */
 /* each responsible for handling their own values being too big.            */
 /* ------------------------------------------------------------------------ */
-int fr_ipftune(cmd, data)
-ioctlcmd_t cmd;
-void *data;
+int
+ipf_ipftune(softc, cmd, data)
+	ipf_main_softc_t *softc;
+	ioctlcmd_t cmd;
+	void *data;
 {
 	ipftuneable_t *ta;
 	ipftune_t tu;
@@ -6225,7 +7256,7 @@
 	void *cookie;
 	int error;
 
-	error = fr_inobj(data, &tu, IPFOBJ_TUNEABLE);
+	error = ipf_inobj(softc, data, NULL, &tu, IPFOBJ_TUNEABLE);
 	if (error != 0)
 		return error;
 
@@ -6246,9 +7277,10 @@
 		 * at the front of the list.
 		 */
 		if (cookie != NULL) {
-			ta = fr_findtunebycookie(cookie, &tu.ipft_cookie);
+			ta = ipf_tune_findbycookie(&softc->ipf_tuners,
+						   cookie, &tu.ipft_cookie);
 		} else {
-			ta = ipf_tuneables;
+			ta = softc->ipf_tuners;
 			tu.ipft_cookie = ta + 1;
 		}
 		if (ta != NULL) {
@@ -6256,8 +7288,10 @@
 			 * Entry found, but does the data pointed to by that
 			 * row fit in what we can return?
 			 */
-			if (ta->ipft_sz > sizeof(tu.ipft_un))
+			if (ta->ipft_sz > sizeof(tu.ipft_un)) {
+				IPFERROR(76);
 				return EINVAL;
+			}
 
 			tu.ipft_vlong = 0;
 			if (ta->ipft_sz == sizeof(u_long))
@@ -6277,7 +7311,7 @@
 			      MIN(sizeof(tu.ipft_name),
 				  strlen(ta->ipft_name) + 1));
 		}
-		error = fr_outobj(data, &tu, IPFOBJ_TUNEABLE);
+		error = ipf_outobj(softc, data, &tu, IPFOBJ_TUNEABLE);
 		break;
 
 	case SIOCIPFGET :
@@ -6286,13 +7320,16 @@
 		 * Search by name or by cookie value for a particular entry
 		 * in the tuning paramter table.
 		 */
+		IPFERROR(77);
 		error = ESRCH;
 		if (cookie != NULL) {
-			ta = fr_findtunebycookie(cookie, NULL);
+			ta = ipf_tune_findbycookie(&softc->ipf_tuners,
+						   cookie, NULL);
 			if (ta != NULL)
 				error = 0;
 		} else if (tu.ipft_name[0] != '\0') {
-			ta = fr_findtunebyname(tu.ipft_name);
+			ta = ipf_tune_findbyname(softc->ipf_tuners,
+						 tu.ipft_name);
 			if (ta != NULL)
 				error = 0;
 		}
@@ -6317,7 +7354,7 @@
 			tu.ipft_min = ta->ipft_min;
 			tu.ipft_max = ta->ipft_max;
 			tu.ipft_flags = ta->ipft_flags;
-			error = fr_outobj(data, &tu, IPFOBJ_TUNEABLE);
+			error = ipf_outobj(softc, data, &tu, IPFOBJ_TUNEABLE);
 
 		} else if (cmd == (ioctlcmd_t)SIOCIPFSET) {
 			/*
@@ -6328,7 +7365,8 @@
 			u_long in;
 
 			if (((ta->ipft_flags & IPFT_WRDISABLED) != 0) &&
-			    (fr_running > 0)) {
+			    (softc->ipf_running > 0)) {
+				IPFERROR(78);
 				error = EBUSY;
 				break;
 			}
@@ -6335,28 +7373,41 @@
 
 			in = tu.ipft_vlong;
 			if (in < ta->ipft_min || in > ta->ipft_max) {
+				IPFERROR(79);
 				error = EINVAL;
 				break;
 			}
 
-			if (ta->ipft_sz == sizeof(u_long)) {
+			if (ta->ipft_func != NULL) {
+				SPL_INT(s);
+
+				SPL_NET(s);
+				error = (*ta->ipft_func)(softc, ta,
+							 &tu.ipft_un);
+				SPL_X(s);
+
+			} else if (ta->ipft_sz == sizeof(u_long)) {
 				tu.ipft_vlong = *ta->ipft_plong;
 				*ta->ipft_plong = in;
+
 			} else if (ta->ipft_sz == sizeof(u_int)) {
 				tu.ipft_vint = *ta->ipft_pint;
 				*ta->ipft_pint = (u_int)(in & 0xffffffff);
+
 			} else if (ta->ipft_sz == sizeof(u_short)) {
 				tu.ipft_vshort = *ta->ipft_pshort;
 				*ta->ipft_pshort = (u_short)(in & 0xffff);
+
 			} else if (ta->ipft_sz == sizeof(u_char)) {
 				tu.ipft_vchar = *ta->ipft_pchar;
 				*ta->ipft_pchar = (u_char)(in & 0xff);
 			}
-			error = fr_outobj(data, &tu, IPFOBJ_TUNEABLE);
+			error = ipf_outobj(softc, data, &tu, IPFOBJ_TUNEABLE);
 		}
 		break;
 
 	default :
+		IPFERROR(80);
 		error = EINVAL;
 		break;
 	}
@@ -6366,109 +7417,7 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_initialise                                               */
-/* Returns:     int - 0 == success,  < 0 == failure                         */
-/* Parameters:  None.                                                       */
-/*                                                                          */
-/* Call of the initialise functions for all the various subsystems inside   */
-/* of IPFilter.  If any of them should fail, return immeadiately a failure  */
-/* BUT do not try to recover from the error here.                           */
-/* ------------------------------------------------------------------------ */
-int fr_initialise()
-{
-	int i;
-
-	bzero(&frstats, sizeof(frstats));
-
-#ifdef IPFILTER_LOG
-	i = fr_loginit();
-	if (i < 0)
-		return -10 + i;
-#endif
-	i = fr_natinit();
-	if (i < 0)
-		return -20 + i;
-
-	i = fr_stateinit();
-	if (i < 0)
-		return -30 + i;
-
-	i = fr_authinit();
-	if (i < 0)
-		return -40 + i;
-
-	i = fr_fraginit();
-	if (i < 0)
-		return -50 + i;
-
-	i = appr_init();
-	if (i < 0)
-		return -60 + i;
-
-#ifdef IPFILTER_SYNC
-	i = ipfsync_init();
-	if (i < 0)
-		return -70 + i;
-#endif
-#ifdef IPFILTER_SCAN
-	i = ipsc_init();
-	if (i < 0)
-		return -80 + i;
-#endif
-#ifdef IPFILTER_LOOKUP
-	i = ip_lookup_init();
-	if (i < 0)
-		return -90 + i;
-#endif
-#ifdef IPFILTER_COMPILED
-	ipfrule_add();
-#endif
-	return 0;
-}
-
-
-/* ------------------------------------------------------------------------ */
-/* Function:    fr_deinitialise                                             */
-/* Returns:     None.                                                       */
-/* Parameters:  None.                                                       */
-/*                                                                          */
-/* Call all the various subsystem cleanup routines to deallocate memory or  */
-/* destroy locks or whatever they've done that they need to now undo.       */
-/* The order here IS important as there are some cross references of        */
-/* internal data structures.                                                */
-/* ------------------------------------------------------------------------ */
-void fr_deinitialise()
-{
-	fr_fragunload();
-	fr_authunload();
-	fr_natunload();
-	fr_stateunload();
-#ifdef IPFILTER_SCAN
-	fr_scanunload();
-#endif
-	appr_unload();
-
-#ifdef IPFILTER_COMPILED
-	ipfrule_remove();
-#endif
-
-	(void) frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE|FR_INACTIVE);
-	(void) frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE);
-	(void) frflush(IPL_LOGCOUNT, 0, FR_INQUE|FR_OUTQUE|FR_INACTIVE);
-	(void) frflush(IPL_LOGCOUNT, 0, FR_INQUE|FR_OUTQUE);
-
-#ifdef IPFILTER_LOOKUP
-	ip_lookup_unload();
-#endif
-
-#ifdef IPFILTER_LOG
-	fr_logunload();
-#endif
-}
-
-
-/* ------------------------------------------------------------------------ */
-/* Function:    fr_zerostats                                                */
+/* Function:    ipf_zerostats                                               */
 /* Returns:     int - 0 = success, else failure                             */
 /* Parameters:  data(O) - pointer to pointer for copying data back to       */
 /*                                                                          */
@@ -6476,20 +7425,26 @@
 /* current ones in the kernel. The lock is only held across the bzero() as  */
 /* the copyout may result in paging (ie network activity.)                  */
 /* ------------------------------------------------------------------------ */
-int	fr_zerostats(data)
-void	*data;
+int
+ipf_zerostats(softc, data)
+	ipf_main_softc_t *softc;
+	caddr_t	data;
 {
 	friostat_t fio;
+	ipfobj_t obj;
 	int error;
 
-	fr_getstat(&fio);
-	error = fr_outobj(data, &fio, IPFOBJ_IPFSTAT);
-	if (error)
-		return EFAULT;
+	error = ipf_inobj(softc, data, &obj, &fio, IPFOBJ_IPFSTAT);
+	if (error != 0)
+		return error;
+	ipf_getstat(softc, &fio, obj.ipfo_rev);
+	error = ipf_outobj(softc, data, &fio, IPFOBJ_IPFSTAT);
+	if (error != 0)
+		return error;
 
-	WRITE_ENTER(&ipf_mutex);
-	bzero(&frstats, sizeof(frstats));
-	RWLOCK_EXIT(&ipf_mutex);
+	WRITE_ENTER(&softc->ipf_mutex);
+	bzero(&softc->ipf_stats, sizeof(softc->ipf_stats));
+	RWLOCK_EXIT(&softc->ipf_mutex);
 
 	return 0;
 }
@@ -6496,10 +7451,12 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_resolvedest                                              */
+/* Function:    ipf_resolvedest                                             */
 /* Returns:     Nil                                                         */
-/* Parameters:  fdp(IO) - pointer to destination information to resolve     */
-/*              v(I)    - IP protocol version to match                      */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              base(I)  - where strings are stored                         */
+/*              fdp(IO)  - pointer to destination information to resolve    */
+/*              v(I)     - IP protocol version to match                     */
 /*                                                                          */
 /* Looks up an interface name in the frdest structure pointed to by fdp and */
 /* if a matching name can be found for the particular IP protocol version   */
@@ -6507,29 +7464,50 @@
 /* found, then set the interface pointer to be -1 as NULL is considered to  */
 /* indicate there is no information at all in the structure.                */
 /* ------------------------------------------------------------------------ */
-void fr_resolvedest(fdp, v)
-frdest_t *fdp;
-int v;
+int
+ipf_resolvedest(softc, base, fdp, v)
+	ipf_main_softc_t *softc;
+	char *base;
+	frdest_t *fdp;
+	int v;
 {
+	int errval = 0;
 	void *ifp;
 
 	ifp = NULL;
-	v = v;		/* LINT */
 
-	if (*fdp->fd_ifname != '\0') {
-		ifp = GETIFP(fdp->fd_ifname, v);
-		if (ifp == NULL)
-			ifp = (void *)-1;
+	if (fdp->fd_name != -1) {
+		if (fdp->fd_type == FRD_DSTLIST) {
+			ifp = ipf_lookup_res_name(softc, IPL_LOGIPF,
+						  IPLT_DSTLIST,
+						  base + fdp->fd_name,
+						  NULL);
+			if (ifp == NULL) {
+				IPFERROR(144);
+				errval = ESRCH;
+			}
+		} else {
+			ifp = GETIFP(base + fdp->fd_name, v);
+			if (ifp == NULL)
+				ifp = (void *)-1;
+		}
 	}
-	fdp->fd_ifp = ifp;
+	fdp->fd_ptr = ifp;
+
+	if ((ifp != NULL) && (ifp != (void *)-1)) {
+		fdp->fd_local = ipf_deliverlocal(softc, v, ifp, &fdp->fd_ip6);
+	}
+
+	return errval;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_resolvenic                                               */
+/* Function:    ipf_resolvenic                                              */
 /* Returns:     void* - NULL = wildcard name, -1 = failed to find NIC, else */
 /*                      pointer to interface structure for NIC              */
-/* Parameters:  name(I) - complete interface name                           */
+/* Parameters:  softc(I)- pointer to soft context main structure            */
+/*              name(I) - complete interface name                           */
 /*              v(I)    - IP protocol version                               */
 /*                                                                          */
 /* Look for a network interface structure that firstly has a matching name  */
@@ -6536,23 +7514,16 @@
 /* to that passed in and that is also being used for that IP protocol       */
 /* version (necessary on some platforms where there are separate listings   */
 /* for both IPv4 and IPv6 on the same physical NIC.                         */
-/*                                                                          */
-/* One might wonder why name gets terminated with a \0 byte in here.  The   */
-/* reason is an interface name could get into the kernel structures of ipf  */
-/* in any number of ways and so long as they all use the same sized array   */
-/* to put the name in, it makes sense to ensure it gets null terminated     */
-/* before it is used for its intended purpose - finding its match in the    */
-/* kernel's list of configured interfaces.                                  */
-/*                                                                          */
-/* NOTE: This SHOULD ONLY be used with IPFilter structures that have an     */
-/*       array for the name that is LIFNAMSIZ bytes (at least) in length.   */
 /* ------------------------------------------------------------------------ */
-void *fr_resolvenic(name, v)
-char *name;
-int v;
+void *
+ipf_resolvenic(softc, name, v)
+	ipf_main_softc_t *softc;
+	char *name;
+	int v;
 {
 	void *nic;
 
+	softc = softc;	/* gcc -Wextra */
 	if (name[0] == '\0')
 		return NULL;
 
@@ -6560,8 +7531,6 @@
 		return NULL;
 	}
 
-	name[LIFNAMSIZ - 1] = '\0';
-
 	nic = GETIFP(name, v);
 	if (nic == NULL)
 		nic = (void *)-1;
@@ -6569,59 +7538,95 @@
 }
 
 
-ipftoken_t *ipftokenhead = NULL, **ipftokentail = &ipftokenhead;
-
-
 /* ------------------------------------------------------------------------ */
-/* Function:    ipf_expiretokens                                            */
+/* Function:    ipf_token_expire                                            */
 /* Returns:     None.                                                       */
-/* Parameters:  None.                                                       */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
 /*                                                                          */
 /* 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()
+void
+ipf_token_expire(softc)
+	ipf_main_softc_t *softc;
 {
 	ipftoken_t *it;
 
-	WRITE_ENTER(&ipf_tokens);
-	while ((it = ipftokenhead) != NULL) {
-		if (it->ipt_die > fr_ticks)
+	WRITE_ENTER(&softc->ipf_tokens);
+	while ((it = softc->ipf_token_head) != NULL) {
+		if (it->ipt_die > softc->ipf_ticks)
 			break;
 
-		ipf_freetoken(it);
+		ipf_token_deref(softc, it);
 	}
-	RWLOCK_EXIT(&ipf_tokens);
+	RWLOCK_EXIT(&softc->ipf_tokens);
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    ipf_deltoken                                                */
+/* Function:    ipf_token_flush                                             */
+/* Returns:     None.                                                       */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*                                                                          */
+/* Loop through all of the existing tokens and call deref to see if they    */
+/* can be freed. Normally a function like this might just loop on           */
+/* ipf_token_head but there is a chance that a token might have a ref count */
+/* of greater than one and in that case the the reference would drop twice  */
+/* by code that is only entitled to drop it once.                           */
+/* ------------------------------------------------------------------------ */
+static void
+ipf_token_flush(softc)
+	ipf_main_softc_t *softc;
+{
+	ipftoken_t *it, *next;
+
+	WRITE_ENTER(&softc->ipf_tokens);
+	for (it = softc->ipf_token_head; it != NULL; it = next) {
+		next = it->ipt_next;
+		(void) ipf_token_deref(softc, it);
+	}
+	RWLOCK_EXIT(&softc->ipf_tokens);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_token_del                                               */
 /* Returns:     int     - 0 = success, else error                           */
-/* Parameters:  type(I) - the token type to match                           */
+/* Parameters:  softc(I)- pointer to soft context main structure            */
+/*              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.                         */
+/* call ipf_token_dewref() to remove it from the list. In the event that    */
+/* the token has a reference held elsewhere, setting ipt_complete to 2      */
+/* enables debugging to distinguish between the two paths that ultimately   */
+/* lead to a token to be deleted.                                           */
 /* ------------------------------------------------------------------------ */
-int ipf_deltoken(type, uid, ptr)
-int type, uid;
-void *ptr;
+int
+ipf_token_del(softc, type, uid, ptr)
+	ipf_main_softc_t *softc;
+	int type, uid;
+	void *ptr;
 {
 	ipftoken_t *it;
-	int error = ESRCH;
+	int error;
 
-	WRITE_ENTER(&ipf_tokens);
-	for (it = ipftokenhead; it != NULL; it = it->ipt_next)
+	IPFERROR(82);
+	error = ESRCH;
+
+	WRITE_ENTER(&softc->ipf_tokens);
+	for (it = softc->ipf_token_head; it != NULL; it = it->ipt_next) {
 		if (ptr == it->ipt_ctx && type == it->ipt_type &&
 		    uid == it->ipt_uid) {
-			ipf_freetoken(it);
+			it->ipt_complete = 2;
+			ipf_token_deref(softc, it);
 			error = 0;
 			break;
+		}
 	}
-	RWLOCK_EXIT(&ipf_tokens);
+	RWLOCK_EXIT(&softc->ipf_tokens);
 
 	return error;
 }
@@ -6628,9 +7633,26 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    ipf_findtoken                                               */
+/* Function:    ipf_token_mark_complete                                     */
+/* Returns:     None.                                                       */
+/* Parameters:  token(I) - pointer to token structure                       */
+/*                                                                          */
+/* Mark a token as being ineligable for being found with ipf_token_find.    */
+/* ------------------------------------------------------------------------ */
+void
+ipf_token_mark_complete(token)
+	ipftoken_t *token;
+{
+	if (token->ipt_complete == 0)
+		token->ipt_complete = 1;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_token_find                                               */
 /* Returns:     ipftoken_t * - NULL if no memory, else pointer to token     */
-/* Parameters:  type(I) - the token type to match                           */
+/* Parameters:  softc(I)- pointer to soft context main structure            */
+/*              type(I) - the token type to match                           */
 /*              uid(I)  - uid owning the token                              */
 /*              ptr(I)  - context pointer for the token                     */
 /*                                                                          */
@@ -6638,24 +7660,23 @@
 /* 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 *
+ipf_token_find(softc, type, uid, ptr)
+	ipf_main_softc_t *softc;
+	int type, uid;
+	void *ptr;
 {
 	ipftoken_t *it, *new;
 
 	KMALLOC(new, ipftoken_t *);
+	if (new != NULL)
+		bzero((char *)new, sizeof(*new));
 
-	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)
+	WRITE_ENTER(&softc->ipf_tokens);
+	for (it = softc->ipf_token_head; it != NULL; it = it->ipt_next) {
+		if ((ptr == it->ipt_ctx) && (type == it->ipt_type) &&
+		    (uid == it->ipt_uid) && (it->ipt_complete < 2))
 			break;
 	}
 
@@ -6662,14 +7683,14 @@
 	if (it == NULL) {
 		it = new;
 		new = NULL;
-		if (it == NULL)
+		if (it == NULL) {
+			RWLOCK_EXIT(&softc->ipf_tokens);
 			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;
+		it->ipt_ref = 1;
 	} else {
 		if (new != NULL) {
 			KFREE(new);
@@ -6676,59 +7697,78 @@
 			new = NULL;
 		}
 
-		ipf_unlinktoken(it);
+		if (it->ipt_complete > 0)
+			it = NULL;
+		else
+			ipf_token_unlink(softc, it);
 	}
-	it->ipt_pnext = ipftokentail;
-	*ipftokentail = it;
-	ipftokentail = &it->ipt_next;
-	it->ipt_next = NULL;
 
-	it->ipt_die = fr_ticks + 2;
+	if (it != NULL) {
+		it->ipt_pnext = softc->ipf_token_tail;
+		*softc->ipf_token_tail = it;
+		softc->ipf_token_tail = &it->ipt_next;
+		it->ipt_next = NULL;
+		it->ipt_ref++;
 
-	MUTEX_DOWNGRADE(&ipf_tokens);
+		it->ipt_die = softc->ipf_ticks + 20;
+	}
 
+	RWLOCK_EXIT(&softc->ipf_tokens);
+
 	return it;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    ipf_unlinktoken                                             */
+/* Function:    ipf_token_unlink                                            */
 /* Returns:     None.                                                       */
-/* Parameters:  token(I) - pointer to token structure                       */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              token(I) - pointer to token structure                       */
+/* Write Locks: ipf_tokens                                                  */
 /*                                                                          */
 /* 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;
+static void
+ipf_token_unlink(softc, token)
+	ipf_main_softc_t *softc;
+	ipftoken_t *token;
 {
 
-	if (ipftokentail == &token->ipt_next)
-		ipftokentail = token->ipt_pnext;
+	if (softc->ipf_token_tail == &token->ipt_next)
+		softc->ipf_token_tail = token->ipt_pnext;
 
 	*token->ipt_pnext = token->ipt_next;
 	if (token->ipt_next != NULL)
 		token->ipt_next->ipt_pnext = token->ipt_pnext;
+	token->ipt_next = NULL;
+	token->ipt_pnext = NULL;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    ipf_freetoken                                               */
-/* Returns:     None.                                                       */
-/* Parameters:  token(I) - pointer to token structure                       */
+/* Function:    ipf_token_deref                                             */
+/* Returns:     int      - 0 == token freed, else reference count           */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              token(I) - pointer to token structure                       */
+/* Write Locks: ipf_tokens                                                  */
 /*                                                                          */
-/* 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.                                                  */
+/* Drop the reference count on the token structure and if it drops to zero, */
+/* call the dereference function for the token type because it is then      */
+/* possible to free the token data structure.                               */
 /* ------------------------------------------------------------------------ */
-void ipf_freetoken(token)
-ipftoken_t *token;
+int
+ipf_token_deref(softc, token)
+	ipf_main_softc_t *softc;
+	ipftoken_t *token;
 {
 	void *data, **datap;
 
-	ipf_unlinktoken(token);
+	ASSERT(token->ipt_ref > 0);
+	token->ipt_ref--;
+	if (token->ipt_ref > 0)
+		return token->ipt_ref;
 
 	data = token->ipt_data;
 	datap = &data;
@@ -6737,54 +7777,96 @@
 		switch (token->ipt_type)
 		{
 		case IPFGENITER_IPF :
-			(void) fr_derefrule((frentry_t **)datap);
+			(void) ipf_derefrule(softc, (frentry_t **)datap);
 			break;
 		case IPFGENITER_IPNAT :
-			WRITE_ENTER(&ipf_nat);
-			fr_ipnatderef((ipnat_t **)datap);
-			RWLOCK_EXIT(&ipf_nat);
+			WRITE_ENTER(&softc->ipf_nat);
+			ipf_nat_rule_deref(softc, (ipnat_t **)datap);
+			RWLOCK_EXIT(&softc->ipf_nat);
 			break;
 		case IPFGENITER_NAT :
-			fr_natderef((nat_t **)datap);
+			ipf_nat_deref(softc, (nat_t **)datap);
 			break;
 		case IPFGENITER_STATE :
-			fr_statederef((ipstate_t **)datap);
+			ipf_state_deref(softc, (ipstate_t **)datap);
 			break;
 		case IPFGENITER_FRAG :
-#ifdef USE_MUTEXES
-			fr_fragderef((ipfr_t **)datap, &ipf_frag);
-#else
-			fr_fragderef((ipfr_t **)datap);
-#endif
+			ipf_frag_pkt_deref(softc, (ipfr_t **)datap);
 			break;
 		case IPFGENITER_NATFRAG :
-#ifdef USE_MUTEXES
-			fr_fragderef((ipfr_t **)datap, &ipf_natfrag);
-#else
-			fr_fragderef((ipfr_t **)datap);
-#endif
+			ipf_frag_nat_deref(softc, (ipfr_t **)datap);
 			break;
 		case IPFGENITER_HOSTMAP :
-			WRITE_ENTER(&ipf_nat);
-			fr_hostmapdel((hostmap_t **)datap);
-			RWLOCK_EXIT(&ipf_nat);
+			WRITE_ENTER(&softc->ipf_nat);
+			ipf_nat_hostmapdel(softc, (hostmap_t **)datap);
+			RWLOCK_EXIT(&softc->ipf_nat);
 			break;
 		default :
-#ifdef IPFILTER_LOOKUP
-			ip_lookup_iterderef(token->ipt_type, data);
-#endif
+			ipf_lookup_iterderef(softc, token->ipt_type, data);
 			break;
 		}
 	}
 
+	ipf_token_unlink(softc, token);
 	KFREE(token);
+	return 0;
 }
 
 
 /* ------------------------------------------------------------------------ */
+/* Function:    ipf_nextrule                                                */
+/* Returns:     frentry_t * - NULL == no more rules, else pointer to next   */
+/* Parameters:  softc(I)    - pointer to soft context main structure        */
+/*              fr(I)       - pointer to filter rule                        */
+/*              out(I)      - 1 == out rules, 0 == input rules              */
+/*                                                                          */
+/* Starting with "fr", find the next rule to visit. This includes visiting  */
+/* the list of rule groups if either fr is NULL (empty list) or it is the   */
+/* last rule in the list. When walking rule lists, it is either input or    */
+/* output rules that are returned, never both.                              */
+/* ------------------------------------------------------------------------ */
+static frentry_t *
+ipf_nextrule(softc, active, unit, fr, out)
+	ipf_main_softc_t *softc;
+	int active, unit;
+	frentry_t *fr;
+	int out;
+{
+	frentry_t *next;
+	frgroup_t *fg;
+
+	if (fr != NULL && fr->fr_group != -1) {
+		fg = ipf_findgroup(softc, fr->fr_names + fr->fr_group,
+				   unit, active, NULL);
+		if (fg != NULL)
+			fg = fg->fg_next;
+	} else {
+		fg = softc->ipf_groups[unit][active];
+	}
+
+	while (fg != NULL) {
+		next = fg->fg_start;
+		while (next != NULL) {
+			if (out) {
+				if (next->fr_flags & FR_OUTQUE)
+					return next;
+			} else if (next->fr_flags & FR_INQUE) {
+				return next;
+			}
+			next = next->fr_next;
+		}
+		if (next == NULL)
+			fg = fg->fg_next;
+	}
+
+	return NULL;
+}
+
+/* ------------------------------------------------------------------------ */
 /* Function:    ipf_getnextrule                                             */
 /* Returns:     int - 0 = success, else error                               */
-/* Parameters:  t(I)   - pointer to destination information to resolve      */
+/* Parameters:  softc(I)- pointer to soft context main structure            */
+/*              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 */
@@ -6795,47 +7877,72 @@
 /* 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)
+int
+ipf_getnextrule(softc, t, ptr)
+	ipf_main_softc_t *softc;
+	ipftoken_t *t;
+	void *ptr;
 {
 	frentry_t *fr, *next, zero;
-	int error, count, out;
 	ipfruleiter_t it;
+	int error, out;
 	frgroup_t *fg;
+	ipfobj_t obj;
+	int predict;
 	char *dst;
+	int unit;
 
-	if (t == NULL || ptr == NULL)
+	if (t == NULL || ptr == NULL) {
+		IPFERROR(84);
 		return EFAULT;
-	error = fr_inobj(ptr, &it, IPFOBJ_IPFITER);
+	}
+
+	error = ipf_inobj(softc, ptr, &obj, &it, IPFOBJ_IPFITER);
 	if (error != 0)
 		return error;
-	if ((it.iri_inout < 0) || (it.iri_inout > 3))
+
+	if ((it.iri_inout < 0) || (it.iri_inout > 3)) {
+		IPFERROR(85);
 		return EINVAL;
-	if ((it.iri_active != 0) && (it.iri_active != 1))
+	}
+	if ((it.iri_active != 0) && (it.iri_active != 1)) {
+		IPFERROR(86);
 		return EINVAL;
-	if (it.iri_nrules == 0)
+	}
+	if (it.iri_nrules == 0) {
+		IPFERROR(87);
 		return ENOSPC;
-	if (it.iri_rule == NULL)
+	}
+	if (it.iri_rule == NULL) {
+		IPFERROR(88);
 		return EFAULT;
+	}
 
-	out = it.iri_inout & F_OUT;
+	fg = NULL;
 	fr = t->ipt_data;
-	READ_ENTER(&ipf_mutex);
+	if ((it.iri_inout & F_OUT) != 0)
+		out = 1;
+	else
+		out = 0;
+	if ((it.iri_inout & F_ACIN) != 0)
+		unit = IPL_LOGCOUNT;
+	else
+		unit = IPL_LOGIPF;
+
+	READ_ENTER(&softc->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];
+			if (unit == IPL_LOGCOUNT) {
+				next = softc->ipf_acct[out][it.iri_active];
 			} else {
-				if (it.iri_v == 4)
-					next = ipfilter[out][it.iri_active];
-				else
-					next = ipfilter6[out][it.iri_active];
+				next = softc->ipf_rules[out][it.iri_active];
 			}
+			if (next == NULL)
+				next = ipf_nextrule(softc, it.iri_active,
+						    unit, NULL, out);
 		} else {
-			fg = fr_findgroup(it.iri_group, IPL_LOGIPF,
-					  it.iri_active, NULL);
+			fg = ipf_findgroup(softc, it.iri_group, unit,
+					   it.iri_active, NULL);
 			if (fg != NULL)
 				next = fg->fg_start;
 			else
@@ -6843,55 +7950,62 @@
 		}
 	} else {
 		next = fr->fr_next;
+		if (next == NULL)
+			next = ipf_nextrule(softc, it.iri_active, unit,
+					    fr, out);
 	}
 
+	if (next != NULL && next->fr_next != NULL)
+		predict = 1;
+	else if (ipf_nextrule(softc, it.iri_active, unit, next, out) != NULL)
+		predict = 1;
+	else
+		predict = 0;
+
+	if (fr != NULL)
+		(void) ipf_derefrule(softc, &fr);
+
+	obj.ipfo_type = IPFOBJ_FRENTRY;
 	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 != NULL) {
+		obj.ipfo_size = next->fr_size;
+		MUTEX_ENTER(&next->fr_lock);
+		next->fr_ref++;
+		MUTEX_EXIT(&next->fr_lock);
+		t->ipt_data = next;
+	} else {
+		obj.ipfo_size = sizeof(frentry_t);
+		bzero(&zero, sizeof(zero));
+		next = &zero;
+		t->ipt_data = NULL;
+	}
+	it.iri_rule = predict ? next : NULL;
+	if (predict == 0)
+		ipf_token_mark_complete(t);
 
+	RWLOCK_EXIT(&softc->ipf_mutex);
+
+	obj.ipfo_ptr = dst;
+	error = ipf_outobjk(softc, &obj, next);
+	if (error == 0 && t->ipt_data != NULL) {
+		dst += obj.ipfo_size;
 		if (next->fr_data != NULL) {
-			dst += sizeof(*next);
-			error = COPYOUT(next->fr_data, dst, next->fr_dsize);
-			if (error != 0)
-				error = EFAULT;
+			ipfobj_t dobj;
+
+			if (next->fr_type == FR_T_IPFEXPR)
+				dobj.ipfo_type = IPFOBJ_IPFEXPR;
 			else
-				dst += next->fr_dsize;
+				dobj.ipfo_type = IPFOBJ_FRIPF;
+			dobj.ipfo_size = next->fr_dsize;
+			dobj.ipfo_rev = obj.ipfo_rev;
+			dobj.ipfo_ptr = dst;
+			error = ipf_outobjk(softc, &dobj, next->fr_data);
 		}
-
-		if ((count == 1) || (error != 0))
-			break;
-
-		count--;
-
-		READ_ENTER(&ipf_mutex);
-		next = next->fr_next;
 	}
 
-	if (fr != NULL) {
-		(void) fr_derefrule(&fr);
-	}
+	if ((fr != NULL) && (next == &zero))
+		(void) ipf_derefrule(softc, &fr);
 
 	return error;
 }
@@ -6898,29 +8012,41 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_frruleiter                                               */
+/* Function:    ipf_frruleiter                                              */
 /* Returns:     int - 0 = success, else error                               */
-/* Parameters:  data(I) - the token type to match                           */
+/* Parameters:  softc(I)- pointer to soft context main structure            */
+/*              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        */
+/* This function serves as a stepping stone between ipf_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;
+static int
+ipf_frruleiter(softc, data, uid, ctx)
+	ipf_main_softc_t *softc;
+	void *data, *ctx;
+	int uid;
 {
 	ipftoken_t *token;
+	ipfruleiter_t it;
+	ipfobj_t obj;
 	int error;
 
-	token = ipf_findtoken(IPFGENITER_IPF, uid, ctx);
-	if (token != NULL)
-		error = ipf_getnextrule(token, data);
-	else
-		error = EFAULT;
-	RWLOCK_EXIT(&ipf_tokens);
+	token = ipf_token_find(softc, IPFGENITER_IPF, uid, ctx);
+	if (token != NULL) {
+		error = ipf_getnextrule(softc, token, data);
+		WRITE_ENTER(&softc->ipf_tokens);
+		ipf_token_deref(softc, token);
+		RWLOCK_EXIT(&softc->ipf_tokens);
+	} else {
+		error = ipf_inobj(softc, data, &obj, &it, IPFOBJ_IPFITER);
+		if (error != 0)
+			return error;
+		it.iri_rule = NULL;
+		error = ipf_outobj(softc, data, &it, IPFOBJ_IPFITER);
+	}
 
 	return error;
 }
@@ -6927,15 +8053,20 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_geniter                                                  */
+/* Function:    ipf_geniter                                                 */
 /* Returns:     int - 0 = success, else error                               */
-/* Parameters:  token(I) - pointer to ipftoken_t structure                  */
-/*              itp(I)   -                                                  */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              token(I) - pointer to ipftoken_t structure                  */
+/*              itp(I)   - pointer to iterator data                         */
 /*                                                                          */
+/* Decide which iterator function to call using information passed through  */
+/* the ipfgeniter_t structure at itp.                                       */
 /* ------------------------------------------------------------------------ */
-static int ipf_geniter(token, itp)
-ipftoken_t *token;
-ipfgeniter_t *itp;
+static int
+ipf_geniter(softc, token, itp)
+	ipf_main_softc_t *softc;
+	ipftoken_t *token;
+	ipfgeniter_t *itp;
 {
 	int error;
 
@@ -6942,14 +8073,10 @@
 	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
+		error = ipf_frag_pkt_next(softc, token, itp);
 		break;
 	default :
+		IPFERROR(92);
 		error = EINVAL;
 		break;
 	}
@@ -6959,32 +8086,40 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_genericiter                                              */
+/* Function:    ipf_genericiter                                             */
 /* Returns:     int - 0 = success, else error                               */
-/* Parameters:  data(I) - the token type to match                           */
+/* Parameters:  softc(I)- pointer to soft context main structure            */
+/*              data(I) - the token type to match                           */
 /*              uid(I)  - uid owning the token                              */
 /*              ptr(I)  - context pointer for the token                     */
 /*                                                                          */
+/* Handle the SIOCGENITER ioctl for the ipfilter device. The primary role   */
 /* ------------------------------------------------------------------------ */
-int ipf_genericiter(data, uid, ctx)
-void *data, *ctx;
-int uid;
+int
+ipf_genericiter(softc, data, uid, ctx)
+	ipf_main_softc_t *softc;
+	void *data, *ctx;
+	int uid;
 {
 	ipftoken_t *token;
 	ipfgeniter_t iter;
 	int error;
 
-	error = fr_inobj(data, &iter, IPFOBJ_GENITER);
+	error = ipf_inobj(softc, data, NULL, &iter, IPFOBJ_GENITER);
 	if (error != 0)
 		return error;
 
-	token = ipf_findtoken(iter.igi_type, uid, ctx);
+	token = ipf_token_find(softc, 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);
+		error = ipf_geniter(softc, token, &iter);
+		WRITE_ENTER(&softc->ipf_tokens);
+		ipf_token_deref(softc, token);
+		RWLOCK_EXIT(&softc->ipf_tokens);
+	} else {
+		IPFERROR(93);
+		error = 0;
+	}
 
 	return error;
 }
@@ -6991,9 +8126,10 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_ipf_ioctl                                                */
+/* Function:    ipf_ipf_ioctl                                               */
 /* Returns:     int - 0 = success, else error                               */
-/* Parameters:  data(I) - the token type to match                           */
+/* Parameters:  softc(I)- pointer to soft context main structure           */
+/*              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                              */
@@ -7002,49 +8138,58 @@
 /* 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;
+int
+ipf_ipf_ioctl(softc, data, cmd, mode, uid, ctx)
+	ipf_main_softc_t *softc;
+	caddr_t data;
+	ioctlcmd_t cmd;
+	int mode, uid;
+	void *ctx;
 {
 	friostat_t fio;
 	int error, tmp;
+	ipfobj_t obj;
 	SPL_INT(s);
 
 	switch (cmd)
 	{
 	case SIOCFRENB :
-		if (!(mode & FWRITE))
+		if (!(mode & FWRITE)) {
+			IPFERROR(94);
 			error = EPERM;
-		else {
+		} else {
 			error = BCOPYIN(data, &tmp, sizeof(tmp));
 			if (error != 0) {
+				IPFERROR(95);
 				error = EFAULT;
 				break;
 			}
 
-			WRITE_ENTER(&ipf_global);
+			WRITE_ENTER(&softc->ipf_global);
 			if (tmp) {
-				if (fr_running > 0)
+				if (softc->ipf_running > 0)
 					error = 0;
 				else
-					error = ipfattach();
+					error = ipfattach(softc);
 				if (error == 0)
-					fr_running = 1;
+					softc->ipf_running = 1;
 				else
-					(void) ipfdetach();
+					(void) ipfdetach(softc);
 			} else {
-				error = ipfdetach();
+				if (softc->ipf_running == 1)
+					error = ipfdetach(softc);
+				else
+					error = 0;
 				if (error == 0)
-					fr_running = -1;
+					softc->ipf_running = -1;
 			}
-			RWLOCK_EXIT(&ipf_global);
+			RWLOCK_EXIT(&softc->ipf_global);
 		}
 		break;
 
 	case SIOCIPFSET :
 		if (!(mode & FWRITE)) {
+			IPFERROR(96);
 			error = EPERM;
 			break;
 		}
@@ -7051,27 +8196,34 @@
 		/* FALLTHRU */
 	case SIOCIPFGETNEXT :
 	case SIOCIPFGET :
-		error = fr_ipftune(cmd, (void *)data);
+		error = ipf_ipftune(softc, cmd, (void *)data);
 		break;
 
 	case SIOCSETFF :
-		if (!(mode & FWRITE))
+		if (!(mode & FWRITE)) {
+			IPFERROR(97);
 			error = EPERM;
-		else {
-			error = BCOPYIN(data, &fr_flags, sizeof(fr_flags));
-			if (error != 0)
+		} else {
+			error = BCOPYIN(data, &softc->ipf_flags,
+					sizeof(softc->ipf_flags));
+			if (error != 0) {
+				IPFERROR(98);
 				error = EFAULT;
+			}
 		}
 		break;
 
 	case SIOCGETFF :
-		error = BCOPYOUT(&fr_flags, data, sizeof(fr_flags));
-		if (error != 0)
+		error = BCOPYOUT(&softc->ipf_flags, data,
+				 sizeof(softc->ipf_flags));
+		if (error != 0) {
+			IPFERROR(99);
 			error = EFAULT;
+		}
 		break;
 
 	case SIOCFUNCL :
-		error = fr_resolvefunc((void *)data);
+		error = ipf_resolvefunc(softc, (void *)data);
 		break;
 
 	case SIOCINAFR :
@@ -7078,130 +8230,164 @@
 	case SIOCRMAFR :
 	case SIOCADAFR :
 	case SIOCZRLST :
-		if (!(mode & FWRITE))
+		if (!(mode & FWRITE)) {
+			IPFERROR(100);
 			error = EPERM;
-		else
-			error = frrequest(IPL_LOGIPF, cmd, data, fr_active, 1);
+		} else {
+			error = frrequest(softc, IPL_LOGIPF, cmd, (caddr_t)data,
+					  softc->ipf_active, 1);
+		}
 		break;
 
 	case SIOCINIFR :
 	case SIOCRMIFR :
 	case SIOCADIFR :
-		if (!(mode & FWRITE))
+		if (!(mode & FWRITE)) {
+			IPFERROR(101);
 			error = EPERM;
-		else
-			error = frrequest(IPL_LOGIPF, cmd, data,
-					  1 - fr_active, 1);
+		} else {
+			error = frrequest(softc, IPL_LOGIPF, cmd, (caddr_t)data,
+					  1 - softc->ipf_active, 1);
+		}
 		break;
 
 	case SIOCSWAPA :
-		if (!(mode & FWRITE))
+		if (!(mode & FWRITE)) {
+			IPFERROR(102);
 			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)
+		} else {
+			WRITE_ENTER(&softc->ipf_mutex);
+			error = BCOPYOUT(&softc->ipf_active, data,
+					 sizeof(softc->ipf_active));
+			if (error != 0) {
+				IPFERROR(103);
 				error = EFAULT;
-			else
-				fr_active = 1 - fr_active;
-			RWLOCK_EXIT(&ipf_mutex);
+			} else {
+				softc->ipf_active = 1 - softc->ipf_active;
+			}
+			RWLOCK_EXIT(&softc->ipf_mutex);
 		}
 		break;
 
 	case SIOCGETFS :
-		fr_getstat(&fio);
-		error = fr_outobj((void *)data, &fio, IPFOBJ_IPFSTAT);
+		error = ipf_inobj(softc, (void *)data, &obj, &fio,
+				  IPFOBJ_IPFSTAT);
+		if (error != 0)
+			break;
+		ipf_getstat(softc, &fio, obj.ipfo_rev);
+		error = ipf_outobj(softc, (void *)data, &fio, IPFOBJ_IPFSTAT);
 		break;
 
 	case SIOCFRZST :
-		if (!(mode & FWRITE))
+		if (!(mode & FWRITE)) {
+			IPFERROR(104);
 			error = EPERM;
-		else
-			error = fr_zerostats(data);
+		} else
+			error = ipf_zerostats(softc, (caddr_t)data);
 		break;
 
 	case SIOCIPFFL :
-		if (!(mode & FWRITE))
+		if (!(mode & FWRITE)) {
+			IPFERROR(105);
 			error = EPERM;
-		else {
+		} else {
 			error = BCOPYIN(data, &tmp, sizeof(tmp));
 			if (!error) {
-				tmp = frflush(IPL_LOGIPF, 4, tmp);
+				tmp = ipf_flush(softc, IPL_LOGIPF, tmp);
 				error = BCOPYOUT(&tmp, data, sizeof(tmp));
-				if (error != 0)
+				if (error != 0) {
+					IPFERROR(106);
 					error = EFAULT;
-			} else
+				}
+			} else {
+				IPFERROR(107);
 				error = EFAULT;
+			}
 		}
 		break;
 
 #ifdef USE_INET6
 	case SIOCIPFL6 :
-		if (!(mode & FWRITE))
+		if (!(mode & FWRITE)) {
+			IPFERROR(108);
 			error = EPERM;
-		else {
+		} else {
 			error = BCOPYIN(data, &tmp, sizeof(tmp));
 			if (!error) {
-				tmp = frflush(IPL_LOGIPF, 6, tmp);
+				tmp = ipf_flush(softc, IPL_LOGIPF, tmp);
 				error = BCOPYOUT(&tmp, data, sizeof(tmp));
-				if (error != 0)
+				if (error != 0) {
+					IPFERROR(109);
 					error = EFAULT;
-			} else
+				}
+			} else {
+				IPFERROR(110);
 				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;
+		if (!(mode & FWRITE)) {
+			IPFERROR(122);
+			error = EPERM;
+		} else {
+			error = BCOPYIN(data, &tmp, sizeof(tmp));
+			if (error == 0) {
+				ipf_state_setlock(softc->ipf_state_soft, tmp);
+				ipf_nat_setlock(softc->ipf_nat_soft, tmp);
+				ipf_frag_setlock(softc->ipf_frag_soft, tmp);
+				ipf_auth_setlock(softc->ipf_auth_soft, tmp);
+			} else {
+				IPFERROR(111);
+				error = EFAULT;
+			}
+		}
 		break;
 
 #ifdef	IPFILTER_LOG
 	case SIOCIPFFB :
-		if (!(mode & FWRITE))
+		if (!(mode & FWRITE)) {
+			IPFERROR(112);
 			error = EPERM;
-		else {
-			tmp = ipflog_clear(IPL_LOGIPF);
+		} else {
+			tmp = ipf_log_clear(softc, IPL_LOGIPF);
 			error = BCOPYOUT(&tmp, data, sizeof(tmp));
-			if (error)
+			if (error) {
+				IPFERROR(113);
 				error = EFAULT;
+			}
 		}
 		break;
 #endif /* IPFILTER_LOG */
 
 	case SIOCFRSYN :
-		if (!(mode & FWRITE))
+		if (!(mode & FWRITE)) {
+			IPFERROR(114);
 			error = EPERM;
-		else {
-			WRITE_ENTER(&ipf_global);
-#ifdef MENTAT
+		} else {
+			WRITE_ENTER(&softc->ipf_global);
+#if (defined(MENTAT) && defined(_KERNEL)) && !defined(INSTANCES)
 			error = ipfsync();
 #else
-			frsync(NULL);
+			ipf_sync(softc, NULL);
 			error = 0;
 #endif
-			RWLOCK_EXIT(&ipf_global);
+			RWLOCK_EXIT(&softc->ipf_global);
 
 		}
 		break;
 
 	case SIOCGFRST :
-		error = fr_outobj((void *)data, fr_fragstats(),
-				  IPFOBJ_FRAGSTAT);
+		error = ipf_outobj(softc, (void *)data,
+				   ipf_frag_stats(softc->ipf_frag_soft),
+				   IPFOBJ_FRAGSTAT);
 		break;
 
 #ifdef	IPFILTER_LOG
 	case FIONREAD :
-		tmp = (int)iplused[IPL_LOGIPF];
-
+		tmp = ipf_log_bytesused(softc, IPL_LOGIPF);
 		error = BCOPYOUT(&tmp, data, sizeof(tmp));
 		break;
 #endif
@@ -7208,25 +8394,27 @@
 
 	case SIOCIPFITER :
 		SPL_SCHED(s);
-		error = ipf_frruleiter(data, uid, ctx);
+		error = ipf_frruleiter(softc, data, uid, ctx);
 		SPL_X(s);
 		break;
 
 	case SIOCGENITER :
 		SPL_SCHED(s);
-		error = ipf_genericiter(data, uid, ctx);
+		error = ipf_genericiter(softc, 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);
+		if (error == 0) {
+			SPL_SCHED(s);
+			error = ipf_token_del(softc, tmp, uid, ctx);
+			SPL_X(s);
+		}
 		break;
 
 	default :
+		IPFERROR(115);
 		error = EINVAL;
 		break;
 	}
@@ -7236,21 +8424,518 @@
 
 
 /* ------------------------------------------------------------------------ */
+/* Function:    ipf_decaps                                                  */
+/* Returns:     int        - -1 == decapsulation failed, else bit mask of   */
+/*                           flags indicating packet filtering decision.    */
+/* Parameters:  fin(I)     - pointer to packet information                  */
+/*              pass(I)    - IP protocol version to match                   */
+/*              l5proto(I) - layer 5 protocol to decode UDP data as.        */
+/*                                                                          */
+/* This function is called for packets that are wrapt up in other packets,  */
+/* for example, an IP packet that is the entire data segment for another IP */
+/* packet.  If the basic constraints for this are satisfied, change the     */
+/* buffer to point to the start of the inner packet and start processing    */
+/* rules belonging to the head group this rule specifies.                   */
+/* ------------------------------------------------------------------------ */
+u_32_t
+ipf_decaps(fin, pass, l5proto)
+	fr_info_t *fin;
+	u_32_t pass;
+	int l5proto;
+{
+	fr_info_t fin2, *fino = NULL;
+	int elen, hlen, nh;
+	grehdr_t gre;
+	ip_t *ip;
+	mb_t *m;
+
+	if ((fin->fin_flx & FI_COALESCE) == 0)
+		if (ipf_coalesce(fin) == -1)
+			goto cantdecaps;
+
+	m = fin->fin_m;
+	hlen = fin->fin_hlen;
+
+	switch (fin->fin_p)
+	{
+	case IPPROTO_UDP :
+		/*
+		 * In this case, the specific protocol being decapsulated
+		 * inside UDP frames comes from the rule.
+		 */
+		nh = fin->fin_fr->fr_icode;
+		break;
+
+	case IPPROTO_GRE :	/* 47 */
+		bcopy(fin->fin_dp, (char *)&gre, sizeof(gre));
+		hlen += sizeof(grehdr_t);
+		if (gre.gr_R|gre.gr_s)
+			goto cantdecaps;
+		if (gre.gr_C)
+			hlen += 4;
+		if (gre.gr_K)
+			hlen += 4;
+		if (gre.gr_S)
+			hlen += 4;
+
+		nh = IPPROTO_IP;
+
+		/*
+		 * If the routing options flag is set, validate that it is
+		 * there and bounce over it.
+		 */
+#if 0
+		/* This is really heavy weight and lots of room for error, */
+		/* so for now, put it off and get the simple stuff right.  */
+		if (gre.gr_R) {
+			u_char off, len, *s;
+			u_short af;
+			int end;
+
+			end = 0;
+			s = fin->fin_dp;
+			s += hlen;
+			aplen = fin->fin_plen - hlen;
+			while (aplen > 3) {
+				af = (s[0] << 8) | s[1];
+				off = s[2];
+				len = s[3];
+				aplen -= 4;
+				s += 4;
+				if (af == 0 && len == 0) {
+					end = 1;
+					break;
+				}
+				if (aplen < len)
+					break;
+				s += len;
+				aplen -= len;
+			}
+			if (end != 1)
+				goto cantdecaps;
+			hlen = s - (u_char *)fin->fin_dp;
+		}
+#endif
+		break;
+
+#ifdef IPPROTO_IPIP
+	case IPPROTO_IPIP :	/* 4 */
+#endif
+		nh = IPPROTO_IP;
+		break;
+
+	default :	/* Includes ESP, AH is special for IPv4 */
+		goto cantdecaps;
+	}
+
+	switch (nh)
+	{
+	case IPPROTO_IP :
+	case IPPROTO_IPV6 :
+		break;
+	default :
+		goto cantdecaps;
+	}
+
+	bcopy((char *)fin, (char *)&fin2, sizeof(fin2));
+	fino = fin;
+	fin = &fin2;
+	elen = hlen;
+#if defined(MENTAT) && defined(_KERNEL)
+	m->b_rptr += elen;
+#else
+	m->m_data += elen;
+	m->m_len -= elen;
+#endif
+	fin->fin_plen -= elen;
+
+	ip = (ip_t *)((char *)fin->fin_ip + elen);
+
+	/*
+	 * Make sure we have at least enough data for the network layer
+	 * header.
+	 */
+	if (IP_V(ip) == 4)
+		hlen = IP_HL(ip) << 2;
+#ifdef USE_INET6
+	else if (IP_V(ip) == 6)
+		hlen = sizeof(ip6_t);
+#endif
+	else
+		goto cantdecaps2;
+
+	if (fin->fin_plen < hlen)
+		goto cantdecaps2;
+
+	fin->fin_dp = (char *)ip + hlen;
+
+	if (IP_V(ip) == 4) {
+		/*
+		 * Perform IPv4 header checksum validation.
+		 */
+		if (ipf_cksum((u_short *)ip, hlen))
+			goto cantdecaps2;
+	}
+
+	if (ipf_makefrip(hlen, ip, fin) == -1) {
+cantdecaps2:
+		if (m != NULL) {
+#if defined(MENTAT) && defined(_KERNEL)
+			m->b_rptr -= elen;
+#else
+			m->m_data -= elen;
+			m->m_len += elen;
+#endif
+		}
+cantdecaps:
+		DT1(frb_decapfrip, fr_info_t *, fin);
+		pass &= ~FR_CMDMASK;
+		pass |= FR_BLOCK|FR_QUICK;
+		fin->fin_reason = FRB_DECAPFRIP;
+		return -1;
+	}
+
+	pass = ipf_scanlist(fin, pass);
+
+	/*
+	 * Copy the packet filter "result" fields out of the fr_info_t struct
+	 * that is local to the decapsulation processing and back into the
+	 * one we were called with.
+	 */
+	fino->fin_flx = fin->fin_flx;
+	fino->fin_rev = fin->fin_rev;
+	fino->fin_icode = fin->fin_icode;
+	fino->fin_rule = fin->fin_rule;
+	(void) strncpy(fino->fin_group, fin->fin_group, FR_GROUPLEN);
+	fino->fin_fr = fin->fin_fr;
+	fino->fin_error = fin->fin_error;
+	fino->fin_mp = fin->fin_mp;
+	fino->fin_m = fin->fin_m;
+	m = fin->fin_m;
+	if (m != NULL) {
+#if defined(MENTAT) && defined(_KERNEL)
+		m->b_rptr -= elen;
+#else
+		m->m_data -= elen;
+		m->m_len += elen;
+#endif
+	}
+	return pass;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_matcharray_load                                         */
+/* Returns:     int         - 0 = success, else error                       */
+/* Parameters:  softc(I)    - pointer to soft context main structure        */
+/*              data(I)     - pointer to ioctl data                         */
+/*              objp(I)     - ipfobj_t structure to load data into          */
+/*              arrayptr(I) - pointer to location to store array pointer    */
+/*                                                                          */
+/* This function loads in a mathing array through the ipfobj_t struct that  */
+/* describes it.  Sanity checking and array size limitations are enforced   */
+/* in this function to prevent userspace from trying to load in something   */
+/* that is insanely big.  Once the size of the array is known, the memory   */
+/* required is malloc'd and returned through changing *arrayptr.  The       */
+/* contents of the array are verified before returning.  Only in the event  */
+/* of a successful call is the caller required to free up the malloc area.  */
+/* ------------------------------------------------------------------------ */
+int
+ipf_matcharray_load(softc, data, objp, arrayptr)
+	ipf_main_softc_t *softc;
+	caddr_t data;
+	ipfobj_t *objp;
+	int **arrayptr;
+{
+	int arraysize, *array, error;
+
+	*arrayptr = NULL;
+
+	error = BCOPYIN(data, objp, sizeof(*objp));
+	if (error != 0) {
+		IPFERROR(116);
+		return EFAULT;
+	}
+
+	if (objp->ipfo_type != IPFOBJ_IPFEXPR) {
+		IPFERROR(117);
+		return EINVAL;
+	}
+
+	if (((objp->ipfo_size & 3) != 0) || (objp->ipfo_size == 0) ||
+	    (objp->ipfo_size > 1024)) {
+		IPFERROR(118);
+		return EINVAL;
+	}
+
+	arraysize = objp->ipfo_size * sizeof(*array);
+	KMALLOCS(array, int *, arraysize);
+	if (array == NULL) {
+		IPFERROR(119);
+		return ENOMEM;
+	}
+
+	error = COPYIN(objp->ipfo_ptr, array, arraysize);
+	if (error != 0) {
+		KFREES(array, arraysize);
+		IPFERROR(120);
+		return EFAULT;
+	}
+
+	if (ipf_matcharray_verify(array, arraysize) != 0) {
+		KFREES(array, arraysize);
+		IPFERROR(121);
+		return EINVAL;
+	}
+
+	*arrayptr = array;
+	return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_matcharray_verify                                       */
+/* Returns:     Nil                                                         */
+/* Parameters:  array(I)     - pointer to matching array                    */
+/*              arraysize(I) - number of elements in the array              */
+/*                                                                          */
+/* Verify the contents of a matching array by stepping through each element */
+/* in it.  The actual commands in the array are not verified for            */
+/* correctness, only that all of the sizes are correctly within limits.     */
+/* ------------------------------------------------------------------------ */
+int
+ipf_matcharray_verify(array, arraysize)
+	int *array, arraysize;
+{
+	int i, nelem, maxidx;
+	ipfexp_t *e;
+
+	nelem = arraysize / sizeof(*array);
+
+	/*
+	 * Currently, it makes no sense to have an array less than 6
+	 * elements long - the initial size at the from, a single operation
+	 * (minimum 4 in length) and a trailer, for a total of 6.
+	 */
+	if ((array[0] < 6) || (arraysize < 24) || (arraysize > 4096)) {
+		return -1;
+	}
+
+	/*
+	 * Verify the size of data pointed to by array with how long
+	 * the array claims to be itself.
+	 */
+	if (array[0] * sizeof(*array) != arraysize) {
+		return -1;
+	}
+
+	maxidx = nelem - 1;
+	/*
+	 * The last opcode in this array should be an IPF_EXP_END.
+	 */
+	if (array[maxidx] != IPF_EXP_END) {
+		return -1;
+	}
+
+	for (i = 1; i < maxidx; ) {
+		e = (ipfexp_t *)(array + i);
+
+		/*
+		 * The length of the bits to check must be at least 1
+		 * (or else there is nothing to comapre with!) and it
+		 * cannot exceed the length of the data present.
+		 */
+		if ((e->ipfe_size < 1 ) ||
+		    (e->ipfe_size + i > maxidx)) {
+			return -1;
+		}
+		i += e->ipfe_size;
+	}
+	return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_fr_matcharray                                           */
+/* Returns:     int      - 0 = match failed, else positive match            */
+/* Parameters:  fin(I)   - pointer to packet information                    */
+/*              array(I) - pointer to matching array                        */
+/*                                                                          */
+/* This function is used to apply a matching array against a packet and     */
+/* return an indication of whether or not the packet successfully matches   */
+/* all of the commands in it.                                               */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_fr_matcharray(fin, array)
+	fr_info_t *fin;
+	int *array;
+{
+	int i, n, *x, rv, p;
+	ipfexp_t *e;
+
+	rv = 0;
+	n = array[0];
+	x = array + 1;
+
+	for (; n > 0; x += 3 + x[3], rv = 0) {
+		e = (ipfexp_t *)x;
+		if (e->ipfe_cmd == IPF_EXP_END)
+			break;
+		n -= e->ipfe_size;
+
+		/*
+		 * The upper 16 bits currently store the protocol value.
+		 * This is currently used with TCP and UDP port compares and
+		 * allows "tcp.port = 80" without requiring an explicit
+		 " "ip.pr = tcp" first.
+		 */
+		p = e->ipfe_cmd >> 16;
+		if ((p != 0) && (p != fin->fin_p))
+			break;
+
+		switch (e->ipfe_cmd)
+		{
+		case IPF_EXP_IP_PR :
+			for (i = 0; !rv && i < e->ipfe_narg; i++) {
+				rv |= (fin->fin_p == e->ipfe_arg0[i]);
+			}
+			break;
+
+		case IPF_EXP_IP_SRCADDR :
+			if (fin->fin_v != 4)
+				break;
+			for (i = 0; !rv && i < e->ipfe_narg; i++) {
+				rv |= ((fin->fin_saddr &
+					e->ipfe_arg0[i * 2 + 1]) ==
+				       e->ipfe_arg0[i * 2]);
+			}
+			break;
+
+		case IPF_EXP_IP_DSTADDR :
+			if (fin->fin_v != 4)
+				break;
+			for (i = 0; !rv && i < e->ipfe_narg; i++) {
+				rv |= ((fin->fin_daddr &
+					e->ipfe_arg0[i * 2 + 1]) ==
+				       e->ipfe_arg0[i * 2]);
+			}
+			break;
+
+		case IPF_EXP_IP_ADDR :
+			if (fin->fin_v != 4)
+				break;
+			for (i = 0; !rv && i < e->ipfe_narg; i++) {
+				rv |= ((fin->fin_saddr &
+					e->ipfe_arg0[i * 2 + 1]) ==
+				       e->ipfe_arg0[i * 2]) ||
+				      ((fin->fin_daddr &
+					e->ipfe_arg0[i * 2 + 1]) ==
+				       e->ipfe_arg0[i * 2]);
+			}
+			break;
+
+#ifdef USE_INET6
+		case IPF_EXP_IP6_SRCADDR :
+			if (fin->fin_v != 6)
+				break;
+			for (i = 0; !rv && i < e->ipfe_narg; i++) {
+				rv |= IP6_MASKEQ(&fin->fin_src6,
+						 &e->ipfe_arg0[i * 8 + 4],
+						 &e->ipfe_arg0[i * 8]);
+			}
+			break;
+
+		case IPF_EXP_IP6_DSTADDR :
+			if (fin->fin_v != 6)
+				break;
+			for (i = 0; !rv && i < e->ipfe_narg; i++) {
+				rv |= IP6_MASKEQ(&fin->fin_dst6,
+						 &e->ipfe_arg0[i * 8 + 4],
+						 &e->ipfe_arg0[i * 8]);
+			}
+			break;
+
+		case IPF_EXP_IP6_ADDR :
+			if (fin->fin_v != 6)
+				break;
+			for (i = 0; !rv && i < e->ipfe_narg; i++) {
+				rv |= IP6_MASKEQ(&fin->fin_src6,
+						 &e->ipfe_arg0[i * 8 + 4],
+						 &e->ipfe_arg0[i * 8]) ||
+				      IP6_MASKEQ(&fin->fin_dst6,
+						 &e->ipfe_arg0[i * 8 + 4],
+						 &e->ipfe_arg0[i * 8]);
+			}
+			break;
+#endif
+
+		case IPF_EXP_UDP_PORT :
+		case IPF_EXP_TCP_PORT :
+			for (i = 0; !rv && i < e->ipfe_narg; i++) {
+				rv |= (fin->fin_sport == e->ipfe_arg0[i]) ||
+				      (fin->fin_dport == e->ipfe_arg0[i]);
+			}
+			break;
+
+		case IPF_EXP_UDP_SPORT :
+		case IPF_EXP_TCP_SPORT :
+			for (i = 0; !rv && i < e->ipfe_narg; i++) {
+				rv |= (fin->fin_sport == e->ipfe_arg0[i]);
+			}
+			break;
+
+		case IPF_EXP_UDP_DPORT :
+		case IPF_EXP_TCP_DPORT :
+			for (i = 0; !rv && i < e->ipfe_narg; i++) {
+				rv |= (fin->fin_dport == e->ipfe_arg0[i]);
+			}
+			break;
+
+		case IPF_EXP_TCP_FLAGS :
+			for (i = 0; !rv && i < e->ipfe_narg; i++) {
+				rv |= ((fin->fin_tcpf &
+					e->ipfe_arg0[i * 2 + 1]) ==
+				       e->ipfe_arg0[i * 2]);
+			}
+			break;
+		}
+		rv ^= e->ipfe_not;
+
+		if (rv == 0)
+			break;
+	}
+
+	return rv;
+}
+
+
+/* ------------------------------------------------------------------------ */
 /* Function:    ipf_queueflush                                              */
 /* Returns:     int - number of entries flushed (0 = none)                  */
-/* Parameters:  deletefn(I) - function to call to delete entry              */
+/* Parameters:  softc(I)    - pointer to soft context main structure        */
+/*              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.                                                          */
+/* need to try a bit harder to free up some space.  The algorithm used here */
+/* split into two parts but both halves have the same goal: to reduce the   */
+/* number of connections considered to be "active" to the low watermark.    */
+/* There are two steps in doing this:                                       */
+/* 1) Remove any TCP connections that are already considered to be "closed" */
+/*    but have not yet been removed from the state table.  The two states   */
+/*    TCPS_TIME_WAIT and TCPS_CLOSED are considered to be the perfect       */
+/*    candidates for this style of removal.  If freeing up entries in       */
+/*    CLOSED or both CLOSED and TIME_WAIT brings us to the low watermark,   */
+/*    we do not go on to step 2.                                            */
+/*                                                                          */
+/* 2) 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 (ipf_ticks.)  Anything modified in the  */
+/*    last 30 seconds is not touched.                                       */
 /*                                              touched                     */
-/*         die     fr_ticks   30*1.5    1800*1.5   |  43200*1.5             */
+/*         die     ipf_ticks  30*1.5    1800*1.5   |  43200*1.5             */
 /*           |          |        |           |     |     |                  */
 /* future <--+----------+--------+-----------+-----+-----+-----------> past */
 /*                     now        \_int=30s_/ \_int=1hr_/ \_int=12hr        */
@@ -7257,62 +8942,85 @@
 /*                                                                          */
 /* 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  */
+/* - tqe_die - ipf_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.                                */
+/* - the closer tqe_touched is to ipf_ticks, the further tqe_die will be    */
+/*   ipf_ticks 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        */
+/* - the pointer passed in as ipfqs should point to an array of timeout     */
+/*   queues representing each of the TCP states                             */
 /*                                                                          */
 /* 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.               */
+/* we start again with a new value for "iend" and "istart".  This is        */
+/* continued until we either finish the scan of 30 second intervals or the  */
+/* low water mark is reached.                                               */
 /* ------------------------------------------------------------------------ */
-int ipf_queueflush(deletefn, ipfqs, userqs)
-ipftq_delete_fn_t deletefn;
-ipftq_t *ipfqs, *userqs;
+int
+ipf_queueflush(softc, deletefn, ipfqs, userqs, activep, size, low)
+	ipf_main_softc_t *softc;
+	ipftq_delete_fn_t deletefn;
+	ipftq_t *ipfqs, *userqs;
+	u_int *activep;
+	int size, low;
 {
 	u_long interval, istart, iend;
 	ipftq_t *ifq, *ifqnext;
 	ipftqent_t *tqe, *tqn;
-	int removed;
+	int removed = 0;
 
+	for (tqn = ipfqs[IPF_TCPS_CLOSED].ifq_head; ((tqe = tqn) != NULL); ) {
+		tqn = tqe->tqe_next;
+		if ((*deletefn)(softc, tqe->tqe_parent) == 0)
+			removed++;
+	}
+	if ((*activep * 100 / size) > low) {
+		for (tqn = ipfqs[IPF_TCPS_TIME_WAIT].ifq_head;
+		     ((tqe = tqn) != NULL); ) {
+			tqn = tqe->tqe_next;
+			if ((*deletefn)(softc, tqe->tqe_parent) == 0)
+				removed++;
+		}
+	}
+
+	if ((*activep * 100 / size) <= low) {
+		return 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)) {
+	if (softc->ipf_ticks > IPF_TTLVAL(43200 * 15 / 10)) {
 		istart = IPF_TTLVAL(86400 * 4);
 		interval = IPF_TTLVAL(43200);
-	} else if (fr_ticks > IPF_TTLVAL(1800 * 15 / 10)) {
+	} else if (softc->ipf_ticks > IPF_TTLVAL(1800 * 15 / 10)) {
 		istart = IPF_TTLVAL(43200);
 		interval = IPF_TTLVAL(1800);
-	} else if (fr_ticks > IPF_TTLVAL(30 * 15 / 10)) {
+	} else if (softc->ipf_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)
+	if (istart > softc->ipf_ticks) {
+		if (softc->ipf_ticks - interval < interval)
 			istart = interval;
 		else
-			istart = (fr_ticks / interval) * interval;
+			istart = (softc->ipf_ticks / interval) * interval;
 	}
 
-	iend = fr_ticks - interval;
-	removed = 0;
+	iend = softc->ipf_ticks - interval;
 
-	for (;;) {
+	while ((*activep * 100 / size) > low) {
 		u_long try;
 
-		try = fr_ticks - istart; 
+		try = softc->ipf_ticks - istart;
 
 		for (ifq = ipfqs; ifq != NULL; ifq = ifq->ifq_next) {
 			for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); ) {
@@ -7319,7 +9027,7 @@
 				if (try < tqe->tqe_touched)
 					break;
 				tqn = tqe->tqe_next;
-				if ((*deletefn)(tqe->tqe_parent) == 0)
+				if ((*deletefn)(softc, tqe->tqe_parent) == 0)
 					removed++;
 			}
 		}
@@ -7331,14 +9039,12 @@
 				if (try < tqe->tqe_touched)
 					break;
 				tqn = tqe->tqe_next;
-				if ((*deletefn)(tqe->tqe_parent) == 0)
+				if ((*deletefn)(softc, 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)) {
@@ -7346,10 +9052,10 @@
 			} else {
 				break;
 			}
-			if (interval >= fr_ticks)
+			if (interval >= softc->ipf_ticks)
 				break;
 
-			iend = fr_ticks - interval;
+			iend = softc->ipf_ticks - interval;
 		}
 		istart -= interval;
 	}
@@ -7356,3 +9062,1190 @@
 
 	return removed;
 }
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_deliverlocal                                            */
+/* Returns:     int - 1 = local address, 0 = non-local address              */
+/* Parameters:  softc(I)     - pointer to soft context main structure       */
+/*              ipversion(I) - IP protocol version (4 or 6)                 */
+/*              ifp(I)       - network interface pointer                    */
+/*              ipaddr(I)    - IPv4/6 destination address                   */
+/*                                                                          */
+/* This fucntion is used to determine in the address "ipaddr" belongs to    */
+/* the network interface represented by ifp.                                */
+/* ------------------------------------------------------------------------ */
+int
+ipf_deliverlocal(softc, ipversion, ifp, ipaddr)
+	ipf_main_softc_t *softc;
+	int ipversion;
+	void *ifp;
+	i6addr_t *ipaddr;
+{
+	i6addr_t addr;
+	int islocal = 0;
+
+	if (ipversion == 4) {
+		if (ipf_ifpaddr(softc, 4, FRI_NORMAL, ifp, &addr, NULL) == 0) {
+			if (addr.in4.s_addr == ipaddr->in4.s_addr)
+				islocal = 1;
+		}
+
+#ifdef USE_INET6
+	} else if (ipversion == 6) {
+		if (ipf_ifpaddr(softc, 6, FRI_NORMAL, ifp, &addr, NULL) == 0) {
+			if (IP6_EQ(&addr, ipaddr))
+				islocal = 1;
+		}
+#endif
+	}
+
+	return islocal;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_settimeout                                              */
+/* Returns:     int - 0 = success, -1 = failure                             */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              t(I)     - pointer to tuneable array entry                  */
+/*              p(I)     - pointer to values passed in to apply             */
+/*                                                                          */
+/* This function is called to set the timeout values for each distinct      */
+/* queue timeout that is available.  When called, it calls into both the    */
+/* state and NAT code, telling them to update their timeout queues.         */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_settimeout(softc, t, p)
+	struct ipf_main_softc_s *softc;
+	ipftuneable_t *t;
+	ipftuneval_t *p;
+{
+
+	/*
+	 * ipf_interror should be set by the functions called here, not
+	 * by this function - it's just a middle man.
+	 */
+	if (ipf_state_settimeout(softc, t, p) == -1)
+		return -1;
+	if (ipf_nat_settimeout(softc, t, p) == -1)
+		return -1;
+	return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_apply_timeout                                           */
+/* Returns:     int - 0 = success, -1 = failure                             */
+/* Parameters:  head(I)    - pointer to tuneable array entry                */
+/*              seconds(I) - pointer to values passed in to apply           */
+/*                                                                          */
+/* This function applies a timeout of "seconds" to the timeout queue that   */
+/* is pointed to by "head".  All entries on this list have an expiration    */
+/* set to be the current tick value of ipf plus the ttl.  Given that this   */
+/* function should only be called when the delta is non-zero, the task is   */
+/* to walk the entire list and apply the change.  The sort order will not   */
+/* change.  The only catch is that this is O(n) across the list, so if the  */
+/* queue has lots of entries (10s of thousands or 100s of thousands), it    */
+/* could take a relatively long time to work through them all.              */
+/* ------------------------------------------------------------------------ */
+void
+ipf_apply_timeout(head, seconds)
+	ipftq_t *head;
+	u_int seconds;
+{
+	u_int oldtimeout, newtimeout;
+	ipftqent_t *tqe;
+	int delta;
+
+	MUTEX_ENTER(&head->ifq_lock);
+	oldtimeout = head->ifq_ttl;
+	newtimeout = IPF_TTLVAL(seconds);
+	delta = oldtimeout - newtimeout;
+
+	head->ifq_ttl = newtimeout;
+
+	for (tqe = head->ifq_head; tqe != NULL; tqe = tqe->tqe_next) {
+		tqe->tqe_die += delta;
+	}
+	MUTEX_EXIT(&head->ifq_lock);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:   ipf_settimeout_tcp                                           */
+/* Returns:    int - 0 = successfully applied, -1 = failed                  */
+/* Parameters: t(I)   - pointer to tuneable to change                       */
+/*             p(I)   - pointer to new timeout information                  */
+/*             tab(I) - pointer to table of TCP queues                      */
+/*                                                                          */
+/* This function applies the new timeout (p) to the TCP tunable (t) and     */
+/* updates all of the entries on the relevant timeout queue by calling      */
+/* ipf_apply_timeout().                                                     */
+/* ------------------------------------------------------------------------ */
+int
+ipf_settimeout_tcp(t, p, tab)
+	ipftuneable_t *t;
+	ipftuneval_t *p;
+	ipftq_t *tab;
+{
+	if (!strcmp(t->ipft_name, "tcp_idle_timeout") ||
+	    !strcmp(t->ipft_name, "tcp_established")) {
+		ipf_apply_timeout(&tab[IPF_TCPS_ESTABLISHED], p->ipftu_int);
+	} else if (!strcmp(t->ipft_name, "tcp_close_wait")) {
+		ipf_apply_timeout(&tab[IPF_TCPS_CLOSE_WAIT], p->ipftu_int);
+	} else if (!strcmp(t->ipft_name, "tcp_last_ack")) {
+		ipf_apply_timeout(&tab[IPF_TCPS_LAST_ACK], p->ipftu_int);
+	} else if (!strcmp(t->ipft_name, "tcp_timeout")) {
+		ipf_apply_timeout(&tab[IPF_TCPS_LISTEN], p->ipftu_int);
+		ipf_apply_timeout(&tab[IPF_TCPS_HALF_ESTAB], p->ipftu_int);
+		ipf_apply_timeout(&tab[IPF_TCPS_CLOSING], p->ipftu_int);
+	} else if (!strcmp(t->ipft_name, "tcp_listen")) {
+		ipf_apply_timeout(&tab[IPF_TCPS_LISTEN], p->ipftu_int);
+	} else if (!strcmp(t->ipft_name, "tcp_half_established")) {
+		ipf_apply_timeout(&tab[IPF_TCPS_HALF_ESTAB], p->ipftu_int);
+	} else if (!strcmp(t->ipft_name, "tcp_closing")) {
+		ipf_apply_timeout(&tab[IPF_TCPS_CLOSING], p->ipftu_int);
+	} else if (!strcmp(t->ipft_name, "tcp_syn_received")) {
+		ipf_apply_timeout(&tab[IPF_TCPS_SYN_RECEIVED], p->ipftu_int);
+	} else if (!strcmp(t->ipft_name, "tcp_syn_sent")) {
+		ipf_apply_timeout(&tab[IPF_TCPS_SYN_SENT], p->ipftu_int);
+	} else if (!strcmp(t->ipft_name, "tcp_closed")) {
+		ipf_apply_timeout(&tab[IPF_TCPS_CLOSED], p->ipftu_int);
+	} else if (!strcmp(t->ipft_name, "tcp_half_closed")) {
+		ipf_apply_timeout(&tab[IPF_TCPS_CLOSED], p->ipftu_int);
+	} else if (!strcmp(t->ipft_name, "tcp_time_wait")) {
+		ipf_apply_timeout(&tab[IPF_TCPS_TIME_WAIT], p->ipftu_int);
+	} else {
+		/*
+		 * ipf_interror isn't set here because it should be set
+		 * by whatever called this function.
+		 */
+		return -1;
+	}
+	return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:   ipf_main_soft_create                                         */
+/* Returns:    NULL = failure, else success                                 */
+/* Parameters: arg(I) - pointer to soft context structure if already allocd */
+/*                                                                          */
+/* Create the foundation soft context structure. In circumstances where it  */
+/* is not required to dynamically allocate the context, a pointer can be    */
+/* passed in (rather than NULL) to a structure to be initialised.           */
+/* The main thing of interest is that a number of locks are initialised     */
+/* here instead of in the where might be expected - in the relevant create  */
+/* function elsewhere.  This is done because the current locking design has */
+/* some areas where these locks are used outside of their module.           */
+/* Possibly the most important exercise that is done here is setting of all */
+/* the timeout values, allowing them to be changed before init().           */
+/* ------------------------------------------------------------------------ */
+void *
+ipf_main_soft_create(arg)
+	void *arg;
+{
+	ipf_main_softc_t *softc;
+
+	if (arg == NULL) {
+		KMALLOC(softc, ipf_main_softc_t *);
+		if (softc == NULL)
+			return NULL;
+	} else {
+		softc = arg;
+	}
+
+	bzero((char *)softc, sizeof(*softc));
+
+	/*
+	 * This serves as a flag as to whether or not the softc should be
+	 * free'd when _destroy is called.
+	 */
+	softc->ipf_dynamic_softc = (arg == NULL) ? 1 : 0;
+
+	softc->ipf_tuners = ipf_tune_array_copy(softc,
+						sizeof(ipf_main_tuneables),
+						ipf_main_tuneables);
+	if (softc->ipf_tuners == NULL) {
+		ipf_main_soft_destroy(softc);
+		return NULL;
+	}
+
+	MUTEX_INIT(&softc->ipf_rw, "ipf rw mutex");
+	MUTEX_INIT(&softc->ipf_timeoutlock, "ipf timeout lock");
+	RWLOCK_INIT(&softc->ipf_global, "ipf filter load/unload mutex");
+	RWLOCK_INIT(&softc->ipf_mutex, "ipf filter rwlock");
+	RWLOCK_INIT(&softc->ipf_tokens, "ipf token rwlock");
+	RWLOCK_INIT(&softc->ipf_state, "ipf state rwlock");
+	RWLOCK_INIT(&softc->ipf_nat, "ipf IP NAT rwlock");
+	RWLOCK_INIT(&softc->ipf_poolrw, "ipf pool rwlock");
+	RWLOCK_INIT(&softc->ipf_frag, "ipf frag rwlock");
+
+	softc->ipf_token_head = NULL;
+	softc->ipf_token_tail = &softc->ipf_token_head;
+
+	softc->ipf_tcpidletimeout = FIVE_DAYS;
+	softc->ipf_tcpclosewait = IPF_TTLVAL(2 * TCP_MSL);
+	softc->ipf_tcplastack = IPF_TTLVAL(30);
+	softc->ipf_tcptimewait = IPF_TTLVAL(2 * TCP_MSL);
+	softc->ipf_tcptimeout = IPF_TTLVAL(2 * TCP_MSL);
+	softc->ipf_tcpsynsent = IPF_TTLVAL(2 * TCP_MSL);
+	softc->ipf_tcpsynrecv = IPF_TTLVAL(2 * TCP_MSL);
+	softc->ipf_tcpclosed = IPF_TTLVAL(30);
+	softc->ipf_tcphalfclosed = IPF_TTLVAL(2 * 3600);
+	softc->ipf_udptimeout = IPF_TTLVAL(120);
+	softc->ipf_udpacktimeout = IPF_TTLVAL(12);
+	softc->ipf_icmptimeout = IPF_TTLVAL(60);
+	softc->ipf_icmpacktimeout = IPF_TTLVAL(6);
+	softc->ipf_iptimeout = IPF_TTLVAL(60);
+
+#if defined(IPFILTER_DEFAULT_BLOCK)
+	softc->ipf_pass = FR_BLOCK|FR_NOMATCH;
+#else
+	softc->ipf_pass = (IPF_DEFAULT_PASS)|FR_NOMATCH;
+#endif
+	softc->ipf_minttl = 4;
+	softc->ipf_icmpminfragmtu = 68;
+	softc->ipf_flags = IPF_LOGGING;
+
+	return softc;
+}
+
+/* ------------------------------------------------------------------------ */
+/* Function:   ipf_main_soft_init                                           */
+/* Returns:    0 = success, -1 = failure                                    */
+/* Parameters: softc(I) - pointer to soft context main structure            */
+/*                                                                          */
+/* A null-op function that exists as a placeholder so that the flow in      */
+/* other functions is obvious.                                              */
+/* ------------------------------------------------------------------------ */
+/*ARGSUSED*/
+int
+ipf_main_soft_init(softc)
+	ipf_main_softc_t *softc;
+{
+	return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:   ipf_main_soft_destroy                                        */
+/* Returns:    void                                                         */
+/* Parameters: softc(I) - pointer to soft context main structure            */
+/*                                                                          */
+/* Undo everything that we did in ipf_main_soft_create.                     */
+/*                                                                          */
+/* The most important check that needs to be made here is whether or not    */
+/* the structure was allocated by ipf_main_soft_create() by checking what   */
+/* value is stored in ipf_dynamic_main.                                     */
+/* ------------------------------------------------------------------------ */
+/*ARGSUSED*/
+void
+ipf_main_soft_destroy(softc)
+	ipf_main_softc_t *softc;
+{
+
+	RW_DESTROY(&softc->ipf_frag);
+	RW_DESTROY(&softc->ipf_poolrw);
+	RW_DESTROY(&softc->ipf_nat);
+	RW_DESTROY(&softc->ipf_state);
+	RW_DESTROY(&softc->ipf_tokens);
+	RW_DESTROY(&softc->ipf_mutex);
+	RW_DESTROY(&softc->ipf_global);
+	MUTEX_DESTROY(&softc->ipf_timeoutlock);
+	MUTEX_DESTROY(&softc->ipf_rw);
+
+	if (softc->ipf_tuners != NULL) {
+		KFREES(softc->ipf_tuners, sizeof(ipf_main_tuneables));
+	}
+	if (softc->ipf_dynamic_softc == 1) {
+		KFREE(softc);
+	}
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:   ipf_main_soft_fini                                           */
+/* Returns:    0 = success, -1 = failure                                    */
+/* Parameters: softc(I) - pointer to soft context main structure            */
+/*                                                                          */
+/* Clean out the rules which have been added since _init was last called,   */
+/* the only dynamic part of the mainline.                                   */
+/* ------------------------------------------------------------------------ */
+int
+ipf_main_soft_fini(softc)
+	ipf_main_softc_t *softc;
+{
+	(void) ipf_flush(softc, IPL_LOGIPF, FR_INQUE|FR_OUTQUE|FR_INACTIVE);
+	(void) ipf_flush(softc, IPL_LOGIPF, FR_INQUE|FR_OUTQUE);
+	(void) ipf_flush(softc, IPL_LOGCOUNT, FR_INQUE|FR_OUTQUE|FR_INACTIVE);
+	(void) ipf_flush(softc, IPL_LOGCOUNT, FR_INQUE|FR_OUTQUE);
+
+	return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:   ipf_main_load                                                */
+/* Returns:    0 = success, -1 = failure                                    */
+/* Parameters: none                                                         */
+/*                                                                          */
+/* Handle global initialisation that needs to be done for the base part of  */
+/* IPFilter. At present this just amounts to initialising some ICMP lookup  */
+/* arrays that get used by the state/NAT code.                              */
+/* ------------------------------------------------------------------------ */
+int
+ipf_main_load()
+{
+	int i;
+
+	/* fill icmp reply type table */
+	for (i = 0; i <= ICMP_MAXTYPE; i++)
+		icmpreplytype4[i] = -1;
+	icmpreplytype4[ICMP_ECHO] = ICMP_ECHOREPLY;
+	icmpreplytype4[ICMP_TSTAMP] = ICMP_TSTAMPREPLY;
+	icmpreplytype4[ICMP_IREQ] = ICMP_IREQREPLY;
+	icmpreplytype4[ICMP_MASKREQ] = ICMP_MASKREPLY;
+
+#ifdef  USE_INET6
+	/* fill icmp reply type table */
+	for (i = 0; i <= ICMP6_MAXTYPE; i++)
+		icmpreplytype6[i] = -1;
+	icmpreplytype6[ICMP6_ECHO_REQUEST] = ICMP6_ECHO_REPLY;
+	icmpreplytype6[ICMP6_MEMBERSHIP_QUERY] = ICMP6_MEMBERSHIP_REPORT;
+	icmpreplytype6[ICMP6_NI_QUERY] = ICMP6_NI_REPLY;
+	icmpreplytype6[ND_ROUTER_SOLICIT] = ND_ROUTER_ADVERT;
+	icmpreplytype6[ND_NEIGHBOR_SOLICIT] = ND_NEIGHBOR_ADVERT;
+#endif
+
+	return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:   ipf_main_unload                                              */
+/* Returns:    0 = success, -1 = failure                                    */
+/* Parameters: none                                                         */
+/*                                                                          */
+/* A null-op function that exists as a placeholder so that the flow in      */
+/* other functions is obvious.                                              */
+/* ------------------------------------------------------------------------ */
+int
+ipf_main_unload()
+{
+	return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:   ipf_load_all                                                 */
+/* Returns:    0 = success, -1 = failure                                    */
+/* Parameters: none                                                         */
+/*                                                                          */
+/* Work through all of the subsystems inside IPFilter and call the load     */
+/* function for each in an order that won't lead to a crash :)              */
+/* ------------------------------------------------------------------------ */
+int
+ipf_load_all()
+{
+	if (ipf_main_load() == -1)
+		return -1;
+
+	if (ipf_state_main_load() == -1)
+		return -1;
+
+	if (ipf_nat_main_load() == -1)
+		return -1;
+
+	if (ipf_frag_main_load() == -1)
+		return -1;
+
+	if (ipf_auth_main_load() == -1)
+		return -1;
+
+	if (ipf_proxy_main_load() == -1)
+		return -1;
+
+	return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:   ipf_unload_all                                               */
+/* Returns:    0 = success, -1 = failure                                    */
+/* Parameters: none                                                         */
+/*                                                                          */
+/* Work through all of the subsystems inside IPFilter and call the unload   */
+/* function for each in an order that won't lead to a crash :)              */
+/* ------------------------------------------------------------------------ */
+int
+ipf_unload_all()
+{
+	if (ipf_proxy_main_unload() == -1)
+		return -1;
+
+	if (ipf_auth_main_unload() == -1)
+		return -1;
+
+	if (ipf_frag_main_unload() == -1)
+		return -1;
+
+	if (ipf_nat_main_unload() == -1)
+		return -1;
+
+	if (ipf_state_main_unload() == -1)
+		return -1;
+
+	if (ipf_main_unload() == -1)
+		return -1;
+
+	return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:   ipf_create_all                                               */
+/* Returns:    NULL = failure, else success                                 */
+/* Parameters: arg(I) - pointer to soft context main structure              */
+/*                                                                          */
+/* Work through all of the subsystems inside IPFilter and call the create   */
+/* function for each in an order that won't lead to a crash :)              */
+/* ------------------------------------------------------------------------ */
+ipf_main_softc_t *
+ipf_create_all(arg)
+	void *arg;
+{
+	ipf_main_softc_t *softc;
+
+	softc = ipf_main_soft_create(arg);
+	if (softc == NULL)
+		return NULL;
+
+#ifdef IPFILTER_LOG
+	softc->ipf_log_soft = ipf_log_soft_create(softc);
+	if (softc->ipf_log_soft == NULL) {
+		ipf_destroy_all(softc);
+		return NULL;
+	}
+#endif
+
+	softc->ipf_lookup_soft = ipf_lookup_soft_create(softc);
+	if (softc->ipf_lookup_soft == NULL) {
+		ipf_destroy_all(softc);
+		return NULL;
+	}
+
+	softc->ipf_sync_soft = ipf_sync_soft_create(softc);
+	if (softc->ipf_sync_soft == NULL) {
+		ipf_destroy_all(softc);
+		return NULL;
+	}
+
+	softc->ipf_state_soft = ipf_state_soft_create(softc);
+	if (softc->ipf_state_soft == NULL) {
+		ipf_destroy_all(softc);
+		return NULL;
+	}
+
+	softc->ipf_nat_soft = ipf_nat_soft_create(softc);
+	if (softc->ipf_nat_soft == NULL) {
+		ipf_destroy_all(softc);
+		return NULL;
+	}
+
+	softc->ipf_frag_soft = ipf_frag_soft_create(softc);
+	if (softc->ipf_frag_soft == NULL) {
+		ipf_destroy_all(softc);
+		return NULL;
+	}
+
+	softc->ipf_auth_soft = ipf_auth_soft_create(softc);
+	if (softc->ipf_auth_soft == NULL) {
+		ipf_destroy_all(softc);
+		return NULL;
+	}
+
+	softc->ipf_proxy_soft = ipf_proxy_soft_create(softc);
+	if (softc->ipf_proxy_soft == NULL) {
+		ipf_destroy_all(softc);
+		return NULL;
+	}
+
+	return softc;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:   ipf_destroy_all                                              */
+/* Returns:    void                                                         */
+/* Parameters: softc(I) - pointer to soft context main structure            */
+/*                                                                          */
+/* Work through all of the subsystems inside IPFilter and call the destroy  */
+/* function for each in an order that won't lead to a crash :)              */
+/*                                                                          */
+/* Every one of these functions is expected to succeed, so there is no      */
+/* checking of return values.                                               */
+/* ------------------------------------------------------------------------ */
+void
+ipf_destroy_all(softc)
+	ipf_main_softc_t *softc;
+{
+
+	if (softc->ipf_state_soft != NULL) {
+		ipf_state_soft_destroy(softc, softc->ipf_state_soft);
+		softc->ipf_state_soft = NULL;
+	}
+
+	if (softc->ipf_nat_soft != NULL) {
+		ipf_nat_soft_destroy(softc, softc->ipf_nat_soft);
+		softc->ipf_nat_soft = NULL;
+	}
+
+	if (softc->ipf_frag_soft != NULL) {
+		ipf_frag_soft_destroy(softc, softc->ipf_frag_soft);
+		softc->ipf_frag_soft = NULL;
+	}
+
+	if (softc->ipf_auth_soft != NULL) {
+		ipf_auth_soft_destroy(softc, softc->ipf_auth_soft);
+		softc->ipf_auth_soft = NULL;
+	}
+
+	if (softc->ipf_proxy_soft != NULL) {
+		ipf_proxy_soft_destroy(softc, softc->ipf_proxy_soft);
+		softc->ipf_proxy_soft = NULL;
+	}
+
+	if (softc->ipf_sync_soft != NULL) {
+		ipf_sync_soft_destroy(softc, softc->ipf_sync_soft);
+		softc->ipf_sync_soft = NULL;
+	}
+
+	if (softc->ipf_lookup_soft != NULL) {
+		ipf_lookup_soft_destroy(softc, softc->ipf_lookup_soft);
+		softc->ipf_lookup_soft = NULL;
+	}
+
+#ifdef IPFILTER_LOG
+	if (softc->ipf_log_soft != NULL) {
+		ipf_log_soft_destroy(softc, softc->ipf_log_soft);
+		softc->ipf_log_soft = NULL;
+	}
+#endif
+
+	ipf_main_soft_destroy(softc);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:   ipf_init_all                                                 */
+/* Returns:    0 = success, -1 = failure                                    */
+/* Parameters: softc(I) - pointer to soft context main structure            */
+/*                                                                          */
+/* Work through all of the subsystems inside IPFilter and call the init     */
+/* function for each in an order that won't lead to a crash :)              */
+/* ------------------------------------------------------------------------ */
+int
+ipf_init_all(softc)
+	ipf_main_softc_t *softc;
+{
+
+	if (ipf_main_soft_init(softc) == -1)
+		return -1;
+
+#ifdef IPFILTER_LOG
+	if (ipf_log_soft_init(softc, softc->ipf_log_soft) == -1)
+		return -1;
+#endif
+
+	if (ipf_lookup_soft_init(softc, softc->ipf_lookup_soft) == -1)
+		return -1;
+
+	if (ipf_sync_soft_init(softc, softc->ipf_sync_soft) == -1)
+		return -1;
+
+	if (ipf_state_soft_init(softc, softc->ipf_state_soft) == -1)
+		return -1;
+
+	if (ipf_nat_soft_init(softc, softc->ipf_nat_soft) == -1)
+		return -1;
+
+	if (ipf_frag_soft_init(softc, softc->ipf_frag_soft) == -1)
+		return -1;
+
+	if (ipf_auth_soft_init(softc, softc->ipf_auth_soft) == -1)
+		return -1;
+
+	if (ipf_proxy_soft_init(softc, softc->ipf_proxy_soft) == -1)
+		return -1;
+
+	return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:   ipf_fini_all                                                 */
+/* Returns:    0 = success, -1 = failure                                    */
+/* Parameters: softc(I) - pointer to soft context main structure            */
+/*                                                                          */
+/* Work through all of the subsystems inside IPFilter and call the fini     */
+/* function for each in an order that won't lead to a crash :)              */
+/* ------------------------------------------------------------------------ */
+int
+ipf_fini_all(softc)
+	ipf_main_softc_t *softc;
+{
+
+	ipf_token_flush(softc);
+
+	if (ipf_proxy_soft_fini(softc, softc->ipf_proxy_soft) == -1)
+		return -1;
+
+	if (ipf_auth_soft_fini(softc, softc->ipf_auth_soft) == -1)
+		return -1;
+
+	if (ipf_frag_soft_fini(softc, softc->ipf_frag_soft) == -1)
+		return -1;
+
+	if (ipf_nat_soft_fini(softc, softc->ipf_nat_soft) == -1)
+		return -1;
+
+	if (ipf_state_soft_fini(softc, softc->ipf_state_soft) == -1)
+		return -1;
+
+	if (ipf_sync_soft_fini(softc, softc->ipf_sync_soft) == -1)
+		return -1;
+
+	if (ipf_lookup_soft_fini(softc, softc->ipf_lookup_soft) == -1)
+		return -1;
+
+#ifdef IPFILTER_LOG
+	if (ipf_log_soft_fini(softc, softc->ipf_log_soft) == -1)
+		return -1;
+#endif
+
+	if (ipf_main_soft_fini(softc) == -1)
+		return -1;
+
+	return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_rule_expire                                             */
+/* Returns:     Nil                                                         */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*                                                                          */
+/* At present this function exists just to support temporary addition of    */
+/* firewall rules. Both inactive and active lists are scanned for items to  */
+/* purge, as by rights, the expiration is computed as soon as the rule is   */
+/* loaded in.                                                               */
+/* ------------------------------------------------------------------------ */
+void
+ipf_rule_expire(softc)
+	ipf_main_softc_t *softc;
+{
+	frentry_t *fr;
+
+	if ((softc->ipf_rule_explist[0] == NULL) &&
+	    (softc->ipf_rule_explist[1] == NULL))
+		return;
+
+	WRITE_ENTER(&softc->ipf_mutex);
+
+	while ((fr = softc->ipf_rule_explist[0]) != NULL) {
+		/*
+		 * Because the list is kept sorted on insertion, the fist
+		 * one that dies in the future means no more work to do.
+		 */
+		if (fr->fr_die > softc->ipf_ticks)
+			break;
+		ipf_rule_delete(softc, fr, IPL_LOGIPF, 0);
+	}
+
+	while ((fr = softc->ipf_rule_explist[1]) != NULL) {
+		/*
+		 * Because the list is kept sorted on insertion, the fist
+		 * one that dies in the future means no more work to do.
+		 */
+		if (fr->fr_die > softc->ipf_ticks)
+			break;
+		ipf_rule_delete(softc, fr, IPL_LOGIPF, 1);
+	}
+
+	RWLOCK_EXIT(&softc->ipf_mutex);
+}
+
+
+static int ipf_ht_node_cmp __P((struct host_node_s *, struct host_node_s *));
+static void ipf_ht_node_make_key __P((host_track_t *, host_node_t *, int,
+				      i6addr_t *));
+
+host_node_t RBI_ZERO(ipf_rb);
+RBI_CODE(ipf_rb, host_node_t, hn_entry, ipf_ht_node_cmp)
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_ht_node_cmp                                             */
+/* Returns:     int   - 0 == nodes are the same, ..                         */
+/* Parameters:  k1(I) - pointer to first key to compare                     */
+/*              k2(I) - pointer to second key to compare                    */
+/*                                                                          */
+/* The "key" for the node is a combination of two fields: the address       */
+/* family and the address itself.                                           */
+/*                                                                          */
+/* Because we're not actually interpreting the address data, it isn't       */
+/* necessary to convert them to/from network/host byte order. The mask is   */
+/* just used to remove bits that aren't significant - it doesn't matter     */
+/* where they are, as long as they're always in the same place.             */
+/*                                                                          */
+/* As with IP6_EQ, comparing IPv6 addresses starts at the bottom because    */
+/* this is where individual ones will differ the most - but not true for    */
+/* for /48's, etc.                                                          */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_ht_node_cmp(k1, k2)
+	struct host_node_s *k1, *k2;
+{
+	int i;
+
+	i = (k2->hn_addr.adf_family - k1->hn_addr.adf_family);
+	if (i != 0)
+		return i;
+
+	if (k1->hn_addr.adf_family == AF_INET)
+		return (k2->hn_addr.adf_addr.in4.s_addr -
+			k1->hn_addr.adf_addr.in4.s_addr);
+
+	i = k2->hn_addr.adf_addr.i6[3] - k1->hn_addr.adf_addr.i6[3];
+	if (i != 0)
+		return i;
+	i = k2->hn_addr.adf_addr.i6[2] - k1->hn_addr.adf_addr.i6[2];
+	if (i != 0)
+		return i;
+	i = k2->hn_addr.adf_addr.i6[1] - k1->hn_addr.adf_addr.i6[1];
+	if (i != 0)
+		return i;
+	i = k2->hn_addr.adf_addr.i6[0] - k1->hn_addr.adf_addr.i6[0];
+	return i;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_ht_node_make_key                                        */
+/* Returns:     Nil                                                         */
+/* parameters:  htp(I)    - pointer to address tracking structure           */
+/*              key(I)    - where to store masked address for lookup        */
+/*              family(I) - protocol family of address                      */
+/*              addr(I)   - pointer to network address                      */
+/*                                                                          */
+/* Using the "netmask" (number of bits) stored parent host tracking struct, */
+/* copy the address passed in into the key structure whilst masking out the */
+/* bits that we don't want.                                                 */
+/*                                                                          */
+/* Because the parser will set ht_netmask to 128 if there is no protocol    */
+/* specified (the parser doesn't know if it should be a v4 or v6 rule), we  */
+/* have to be wary of that and not allow 32-128 to happen.                  */
+/* ------------------------------------------------------------------------ */
+static void
+ipf_ht_node_make_key(htp, key, family, addr)
+	host_track_t *htp;
+	host_node_t *key;
+	int family;
+	i6addr_t *addr;
+{
+	key->hn_addr.adf_family = family;
+	if (family == AF_INET) {
+		u_32_t mask;
+		int bits;
+
+		key->hn_addr.adf_len = sizeof(key->hn_addr.adf_addr.in4);
+		bits = htp->ht_netmask;
+		if (bits >= 32) {
+			mask = 0xffffffff;
+		} else {
+			mask = htonl(0xffffffff << (32 - bits));
+		}
+		key->hn_addr.adf_addr.in4.s_addr = addr->in4.s_addr & mask;
+#ifdef USE_INET6
+	} else {
+		int bits = htp->ht_netmask;
+
+		key->hn_addr.adf_len = sizeof(key->hn_addr.adf_addr.in6);
+		if (bits > 96) {
+			key->hn_addr.adf_addr.i6[3] = addr->i6[3] &
+					     htonl(0xffffffff << (128 - bits));
+			key->hn_addr.adf_addr.i6[2] = addr->i6[2];
+			key->hn_addr.adf_addr.i6[1] = addr->i6[2];
+			key->hn_addr.adf_addr.i6[0] = addr->i6[2];
+		} else if (bits > 64) {
+			key->hn_addr.adf_addr.i6[3] = 0;
+			key->hn_addr.adf_addr.i6[2] = addr->i6[2] &
+					     htonl(0xffffffff << (96 - bits));
+			key->hn_addr.adf_addr.i6[1] = addr->i6[1];
+			key->hn_addr.adf_addr.i6[0] = addr->i6[0];
+		} else if (bits > 32) {
+			key->hn_addr.adf_addr.i6[3] = 0;
+			key->hn_addr.adf_addr.i6[2] = 0;
+			key->hn_addr.adf_addr.i6[1] = addr->i6[1] &
+					     htonl(0xffffffff << (64 - bits));
+			key->hn_addr.adf_addr.i6[0] = addr->i6[0];
+		} else {
+			key->hn_addr.adf_addr.i6[3] = 0;
+			key->hn_addr.adf_addr.i6[2] = 0;
+			key->hn_addr.adf_addr.i6[1] = 0;
+			key->hn_addr.adf_addr.i6[0] = addr->i6[0] &
+					     htonl(0xffffffff << (32 - bits));
+		}
+#endif
+	}
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_ht_node_add                                             */
+/* Returns:     int       - 0 == success,  -1 == failure                    */
+/* Parameters:  softc(I)  - pointer to soft context main structure          */
+/*              htp(I)    - pointer to address tracking structure           */
+/*              family(I) - protocol family of address                      */
+/*              addr(I)   - pointer to network address                      */
+/*                                                                          */
+/* NOTE: THIS FUNCTION MUST BE CALLED WITH AN EXCLUSIVE LOCK THAT PREVENTS  */
+/*       ipf_ht_node_del FROM RUNNING CONCURRENTLY ON THE SAME htp.         */
+/*                                                                          */
+/* After preparing the key with the address information to find, look in    */
+/* the red-black tree to see if the address is known. A successful call to  */
+/* this function can mean one of two things: a new node was added to the    */
+/* tree or a matching node exists and we're able to bump up its activity.   */
+/* ------------------------------------------------------------------------ */
+int
+ipf_ht_node_add(softc, htp, family, addr)
+	ipf_main_softc_t *softc;
+	host_track_t *htp;
+	int family;
+	i6addr_t *addr;
+{
+	host_node_t *h;
+	host_node_t k;
+
+	ipf_ht_node_make_key(htp, &k, family, addr);
+
+	h = RBI_SEARCH(ipf_rb, &htp->ht_root, &k);
+	if (h == NULL) {
+		if (htp->ht_cur_nodes >= htp->ht_max_nodes)
+			return -1;
+		KMALLOC(h, host_node_t *);
+		if (h == NULL) {
+			DT(ipf_rb_no_mem);
+			LBUMP(ipf_rb_no_mem);
+			return -1;
+		}
+
+		/*
+		 * If there was a macro to initialise the RB node then that
+		 * would get used here, but there isn't...
+		 */
+		bzero((char *)h, sizeof(*h));
+		h->hn_addr = k.hn_addr;
+		h->hn_addr.adf_family = k.hn_addr.adf_family;
+		RBI_INSERT(ipf_rb, &htp->ht_root, h);
+		htp->ht_cur_nodes++;
+	} else {
+		if ((htp->ht_max_per_node != 0) &&
+		    (h->hn_active >= htp->ht_max_per_node)) {
+			DT(ipf_rb_node_max);
+			LBUMP(ipf_rb_node_max);
+			return -1;
+		}
+	}
+
+	h->hn_active++;
+
+	return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_ht_node_del                                             */
+/* Returns:     int       - 0 == success,  -1 == failure                    */
+/* parameters:  htp(I)    - pointer to address tracking structure           */
+/*              family(I) - protocol family of address                      */
+/*              addr(I)   - pointer to network address                      */
+/*                                                                          */
+/* NOTE: THIS FUNCTION MUST BE CALLED WITH AN EXCLUSIVE LOCK THAT PREVENTS  */
+/*       ipf_ht_node_add FROM RUNNING CONCURRENTLY ON THE SAME htp.         */
+/*                                                                          */
+/* Try and find the address passed in amongst the leavese on this tree to   */
+/* be friend. If found then drop the active account for that node drops by  */
+/* one. If that count reaches 0, it is time to free it all up.              */
+/* ------------------------------------------------------------------------ */
+int
+ipf_ht_node_del(htp, family, addr)
+	host_track_t *htp;
+	int family;
+	i6addr_t *addr;
+{
+	host_node_t *h;
+	host_node_t k;
+
+	ipf_ht_node_make_key(htp, &k, family, addr);
+
+	h = RBI_SEARCH(ipf_rb, &htp->ht_root, &k);
+	if (h == NULL) {
+		return -1;
+	} else {
+		h->hn_active--;
+		if (h->hn_active == 0) {
+			(void) RBI_DELETE(ipf_rb, &htp->ht_root, h);
+			htp->ht_cur_nodes--;
+			KFREE(h);
+		}
+	}
+
+	return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_rb_ht_init                                              */
+/* Returns:     Nil                                                         */
+/* Parameters:  head(I) - pointer to host tracking structure                */
+/*                                                                          */
+/* Initialise the host tracking structure to be ready for use above.        */
+/* ------------------------------------------------------------------------ */
+void
+ipf_rb_ht_init(head)
+	host_track_t *head;
+{
+	RBI_INIT(ipf_rb, &head->ht_root);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_rb_ht_freenode                                          */
+/* Returns:     Nil                                                         */
+/* Parameters:  head(I) - pointer to host tracking structure                */
+/*              arg(I)  - additional argument from walk caller              */
+/*                                                                          */
+/* Free an actual host_node_t structure.                                    */
+/* ------------------------------------------------------------------------ */
+void
+ipf_rb_ht_freenode(node, arg)
+	host_node_t *node;
+	void *arg;
+{
+	KFREE(node);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_rb_ht_flush                                             */
+/* Returns:     Nil                                                         */
+/* Parameters:  head(I) - pointer to host tracking structure                */
+/*                                                                          */
+/* Remove all of the nodes in the tree tracking hosts by calling a walker   */
+/* and free'ing each one.                                                   */
+/* ------------------------------------------------------------------------ */
+void
+ipf_rb_ht_flush(head)
+	host_track_t *head;
+{
+	RBI_WALK(ipf_rb, &head->ht_root, ipf_rb_ht_freenode, NULL);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_slowtimer                                               */
+/* Returns:     Nil                                                         */
+/* Parameters:  ptr(I) - pointer to main ipf soft context structure         */
+/*                                                                          */
+/* Slowly expire held state for fragments.  Timeouts are set * in           */
+/* expectation of this being called twice per second.                       */
+/* ------------------------------------------------------------------------ */
+void
+ipf_slowtimer(softc)
+	ipf_main_softc_t *softc;
+{
+
+	ipf_token_expire(softc);
+	ipf_frag_expire(softc);
+	ipf_state_expire(softc);
+	ipf_nat_expire(softc);
+	ipf_auth_expire(softc);
+	ipf_lookup_expire(softc);
+	ipf_rule_expire(softc);
+	ipf_sync_expire(softc);
+	softc->ipf_ticks++;
+#   if defined(__OpenBSD__)
+	timeout_add(&ipf_slowtimer_ch, hz/2);
+#   endif
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_inet_mask_add                                           */
+/* Returns:     Nil                                                         */
+/* Parameters:  bits(I) - pointer to nat context information                */
+/*              mtab(I) - pointer to mask hash table structure              */
+/*                                                                          */
+/* When called, bits represents the mask of a new NAT rule that has just    */
+/* been added. This function inserts a bitmask into the array of masks to   */
+/* search when searching for a matching NAT rule for a packet.              */
+/* Prevention of duplicate masks is achieved by checking the use count for  */
+/* a given netmask.                                                         */
+/* ------------------------------------------------------------------------ */
+void
+ipf_inet_mask_add(bits, mtab)
+	int bits;
+	ipf_v4_masktab_t *mtab;
+{
+	u_32_t mask;
+	int i, j;
+
+	mtab->imt4_masks[bits]++;
+	if (mtab->imt4_masks[bits] > 1)
+		return;
+
+	if (bits == 0)
+		mask = 0;
+	else
+		mask = 0xffffffff << (32 - bits);
+
+	for (i = 0; i < 33; i++) {
+		if (ntohl(mtab->imt4_active[i]) < mask) {
+			for (j = 32; j > i; j--)
+				mtab->imt4_active[j] = mtab->imt4_active[j - 1];
+			mtab->imt4_active[i] = htonl(mask);
+			break;
+		}
+	}
+	mtab->imt4_max++;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_inet_mask_del                                           */
+/* Returns:     Nil                                                         */
+/* Parameters:  bits(I) - number of bits set in the netmask                 */
+/*              mtab(I) - pointer to mask hash table structure              */
+/*                                                                          */
+/* Remove the 32bit bitmask represented by "bits" from the collection of    */
+/* netmasks stored inside of mtab.                                          */
+/* ------------------------------------------------------------------------ */
+void
+ipf_inet_mask_del(bits, mtab)
+	int bits;
+	ipf_v4_masktab_t *mtab;
+{
+	u_32_t mask;
+	int i, j;
+
+	mtab->imt4_masks[bits]--;
+	if (mtab->imt4_masks[bits] > 0)
+		return;
+
+	mask = htonl(0xffffffff << (32 - bits));
+	for (i = 0; i < 33; i++) {
+		if (mtab->imt4_active[i] == mask) {
+			for (j = i + 1; j < 33; j++)
+				mtab->imt4_active[j - 1] = mtab->imt4_active[j];
+			break;
+		}
+	}
+	mtab->imt4_max--;
+	ASSERT(mtab->imt4_max >= 0);
+}
+
+
+#ifdef USE_INET6
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_inet6_mask_add                                          */
+/* Returns:     Nil                                                         */
+/* Parameters:  bits(I) - number of bits set in mask                        */
+/*              mask(I) - pointer to mask to add                            */
+/*              mtab(I) - pointer to mask hash table structure              */
+/*                                                                          */
+/* When called, bitcount represents the mask of a IPv6 NAT map rule that    */
+/* has just been added. This function inserts a bitmask into the array of   */
+/* masks to search when searching for a matching NAT rule for a packet.     */
+/* Prevention of duplicate masks is achieved by checking the use count for  */
+/* a given netmask.                                                         */
+/* ------------------------------------------------------------------------ */
+void
+ipf_inet6_mask_add(bits, mask, mtab)
+	int bits;
+	i6addr_t *mask;
+	ipf_v6_masktab_t *mtab;
+{
+	i6addr_t zero;
+	int i, j;
+
+	mtab->imt6_masks[bits]++;
+	if (mtab->imt6_masks[bits] > 1)
+		return;
+
+	if (bits == 0) {
+		mask = &zero;
+		zero.i6[0] = 0;
+		zero.i6[1] = 0;
+		zero.i6[2] = 0;
+		zero.i6[3] = 0;
+	}
+
+	for (i = 0; i < 129; i++) {
+		if (IP6_LT(&mtab->imt6_active[i], mask)) {
+			for (j = 128; j > i; j--)
+				mtab->imt6_active[j] = mtab->imt6_active[j - 1];
+			mtab->imt6_active[i] = *mask;
+			break;
+		}
+	}
+	mtab->imt6_max++;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_inet6_mask_del                                          */
+/* Returns:     Nil                                                         */
+/* Parameters:  bits(I) - number of bits set in mask                        */
+/*              mask(I) - pointer to mask to remove                         */
+/*              mtab(I) - pointer to mask hash table structure              */
+/*                                                                          */
+/* Remove the 128bit bitmask represented by "bits" from the collection of   */
+/* netmasks stored inside of mtab.                                          */
+/* ------------------------------------------------------------------------ */
+void
+ipf_inet6_mask_del(bits, mask, mtab)
+	int bits;
+	i6addr_t *mask;
+	ipf_v6_masktab_t *mtab;
+{
+	i6addr_t zero;
+	int i, j;
+
+	mtab->imt6_masks[bits]--;
+	if (mtab->imt6_masks[bits] > 0)
+		return;
+
+	if (bits == 0)
+		mask = &zero;
+	zero.i6[0] = 0;
+	zero.i6[1] = 0;
+	zero.i6[2] = 0;
+	zero.i6[3] = 0;
+
+	for (i = 0; i < 129; i++) {
+		if (IP6_EQ(&mtab->imt6_active[i], mask)) {
+			for (j = i + 1; j < 129; j++) {
+				mtab->imt6_active[j - 1] = mtab->imt6_active[j];
+				if (IP6_EQ(&mtab->imt6_active[j - 1], &zero))
+					break;
+			}
+			break;
+		}
+	}
+	mtab->imt6_max--;
+	ASSERT(mtab->imt6_max >= 0);
+}
+#endif

Modified: trunk/sys/contrib/ipfilter/netinet/ip_auth.c
===================================================================
--- trunk/sys/contrib/ipfilter/netinet/ip_auth.c	2018-05-28 18:55:30 UTC (rev 10138)
+++ trunk/sys/contrib/ipfilter/netinet/ip_auth.c	2018-05-28 18:56:30 UTC (rev 10139)
@@ -1,7 +1,8 @@
-/*	$FreeBSD$	*/
+/* $MidnightBSD$ */
+/*	$FreeBSD: stable/10/sys/contrib/ipfilter/netinet/ip_auth.c 266829 2014-05-29 02:55:07Z cy $	*/
 
 /*
- * Copyright (C) 1998-2003 by Darren Reed & Guido van Rooij.
+ * Copyright (C) 2012 by Darren Reed.
  *
  * See the IPFILTER.LICENCE file for details on licencing.
  */
@@ -19,6 +20,9 @@
 #if !defined(_KERNEL)
 # include <stdio.h>
 # include <stdlib.h>
+# ifdef _STDC_C99
+#  include <stdbool.h>
+# endif
 # include <string.h>
 # define _KERNEL
 # ifdef __OpenBSD__
@@ -52,7 +56,7 @@
 # include <sys/stream.h>
 # include <sys/kmem.h>
 #endif
-#if (defined(_BSDI_VERSION) && _BSDI_VERSION >= 199802) || \
+#if (defined(_BSDI_VERSION) && (_BSDI_VERSION >= 199802)) || \
     (defined(__FreeBSD_version) &&(__FreeBSD_version >= 400000))
 # include <sys/queue.h>
 #endif
@@ -62,22 +66,25 @@
 #if defined(_KERNEL) && defined(__NetBSD__) && (__NetBSD_Version__ >= 104000000)
 # include <sys/proc.h>
 #endif
+#if defined(__NetBSD_Version__) &&  (__NetBSD_Version__ >= 400000) && \
+     !defined(_KERNEL)
+# include <stdbool.h>
+#endif
 #include <net/if.h>
 #ifdef sun
 # include <net/af.h>
 #endif
-#include <net/route.h>
 #include <netinet/in.h>
 #include <netinet/in_systm.h>
 #include <netinet/ip.h>
+#if !defined(linux)
+# include <netinet/ip_var.h>
+#endif
 #if !defined(_KERNEL) && !defined(__osf__) && !defined(__sgi)
 # define	KERNEL
 # define	_KERNEL
 # define	NOT_KERNEL
 #endif
-#if !defined(linux)
-# include <netinet/ip_var.h>
-#endif
 #ifdef	NOT_KERNEL
 # undef	_KERNEL
 # undef	KERNEL
@@ -120,76 +127,227 @@
 /* END OF INCLUDES */
 
 #if !defined(lint)
-static const char rcsid[] = "@(#)$FreeBSD$";
-/* static const char rcsid[] = "@(#)$Id: ip_auth.c,v 1.4 2013-01-08 01:31:40 laffer1 Exp $"; */
+static const char rcsid[] = "@(#)$FreeBSD: stable/10/sys/contrib/ipfilter/netinet/ip_auth.c 266829 2014-05-29 02:55:07Z cy $";
+/* static const char rcsid[] = "@(#)$Id: ip_auth.c,v 2.73.2.24 2007/09/09 11:32:04 darrenr Exp $"; */
 #endif
 
 
-#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;
-#endif
+static void ipf_auth_deref __P((frauthent_t **));
+static void ipf_auth_deref_unlocked __P((ipf_auth_softc_t *, frauthent_t **));
+static int ipf_auth_geniter __P((ipf_main_softc_t *, ipftoken_t *,
+				 ipfgeniter_t *, ipfobj_t *));
+static int ipf_auth_reply __P((ipf_main_softc_t *, ipf_auth_softc_t *, char *));
+static int ipf_auth_wait __P((ipf_main_softc_t *, ipf_auth_softc_t *, char *));
+static int ipf_auth_flush __P((void *));
 
-int	fr_authsize = FR_NUMAUTH;
-int	fr_authused = 0;
-int	fr_defaultauthage = 600;
-int	fr_auth_lock = 0;
-int	fr_auth_init = 0;
-fr_authstat_t	fr_authstats;
-static frauth_t *fr_auth = NULL;
-mb_t	**fr_authpkts = NULL;
-int	fr_authstart = 0, fr_authend = 0, fr_authnext = 0;
-frauthent_t	*fae_list = NULL;
-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:    ipf_auth_main_load                                          */
+/* Returns:     int - 0 == success, else error                              */
+/* Parameters:  None                                                        */
+/*                                                                          */
+/* A null-op function that exists as a placeholder so that the flow in      */
+/* other functions is obvious.                                              */
+/* ------------------------------------------------------------------------ */
+int
+ipf_auth_main_load()
+{
+	return 0;
+}
 
+
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_authinit                                                 */
+/* Function:    ipf_auth_main_unload                                        */
 /* Returns:     int - 0 == success, else error                              */
 /* Parameters:  None                                                        */
 /*                                                                          */
+/* A null-op function that exists as a placeholder so that the flow in      */
+/* other functions is obvious.                                              */
+/* ------------------------------------------------------------------------ */
+int
+ipf_auth_main_unload()
+{
+	return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_auth_soft_create                                        */
+/* Returns:     int - NULL = failure, else success                          */
+/* Parameters:  softc(I) - pointer to soft context data                     */
+/*                                                                          */
+/* Create a structre to store all of the run-time data for packet auth in   */
+/* and initialise some fields to their defaults.                            */
+/* ------------------------------------------------------------------------ */
+void *
+ipf_auth_soft_create(softc)
+	ipf_main_softc_t *softc;
+{
+	ipf_auth_softc_t *softa;
+
+	KMALLOC(softa, ipf_auth_softc_t *);
+	if (softa == NULL)
+		return NULL;
+
+	bzero((char *)softa, sizeof(*softa));
+
+	softa->ipf_auth_size = FR_NUMAUTH;
+	softa->ipf_auth_defaultage = 600;
+
+	RWLOCK_INIT(&softa->ipf_authlk, "ipf IP User-Auth rwlock");
+	MUTEX_INIT(&softa->ipf_auth_mx, "ipf auth log mutex");
+#if SOLARIS && defined(_KERNEL)
+	cv_init(&softa->ipf_auth_wait, "ipf auth condvar", CV_DRIVER, NULL);
+#endif
+
+	return softa;
+}
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_auth_soft_init                                          */
+/* Returns:     int - 0 == success, else error                              */
+/* Parameters:  softc(I) - pointer to soft context data                     */
+/*              arg(I)   - opaque pointer to auth context data              */
+/*                                                                          */
 /* Allocate memory and initialise data structures used in handling auth     */
 /* rules.                                                                   */
 /* ------------------------------------------------------------------------ */
-int fr_authinit()
+int
+ipf_auth_soft_init(softc, arg)
+	ipf_main_softc_t *softc;
+	void *arg;
 {
-	KMALLOCS(fr_auth, frauth_t *, fr_authsize * sizeof(*fr_auth));
-	if (fr_auth != NULL)
-		bzero((char *)fr_auth, fr_authsize * sizeof(*fr_auth));
-	else
+	ipf_auth_softc_t *softa = arg;
+
+	KMALLOCS(softa->ipf_auth, frauth_t *,
+		 softa->ipf_auth_size * sizeof(*softa->ipf_auth));
+	if (softa->ipf_auth == NULL)
 		return -1;
+	bzero((char *)softa->ipf_auth,
+	      softa->ipf_auth_size * sizeof(*softa->ipf_auth));
 
-	KMALLOCS(fr_authpkts, mb_t **, fr_authsize * sizeof(*fr_authpkts));
-	if (fr_authpkts != NULL)
-		bzero((char *)fr_authpkts, fr_authsize * sizeof(*fr_authpkts));
-	else
+	KMALLOCS(softa->ipf_auth_pkts, mb_t **,
+		 softa->ipf_auth_size * sizeof(*softa->ipf_auth_pkts));
+	if (softa->ipf_auth_pkts == NULL)
 		return -2;
+	bzero((char *)softa->ipf_auth_pkts,
+	      softa->ipf_auth_size * sizeof(*softa->ipf_auth_pkts));
 
-	MUTEX_INIT(&ipf_authmx, "ipf auth log mutex");
-	RWLOCK_INIT(&ipf_auth, "ipf IP User-Auth rwlock");
-#if SOLARIS && defined(_KERNEL)
-	cv_init(&ipfauthwait, "ipf auth condvar", CV_DRIVER, NULL);
-#endif
 #if defined(linux) && defined(_KERNEL)
-	init_waitqueue_head(&fr_authnext_linux);
+	init_waitqueue_head(&softa->ipf_auth_next_linux);
 #endif
 
-	fr_auth_init = 1;
+	return 0;
+}
 
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_auth_soft_fini                                          */
+/* Returns:     int - 0 == success, else error                              */
+/* Parameters:  softc(I) - pointer to soft context data                     */
+/*              arg(I)   - opaque pointer to auth context data              */
+/*                                                                          */
+/* Free all network buffer memory used to keep saved packets that have been */
+/* connectedd to the soft soft context structure *but* do not free that: it */
+/* is free'd by _destroy().                                                 */
+/* ------------------------------------------------------------------------ */
+int
+ipf_auth_soft_fini(softc, arg)
+	ipf_main_softc_t *softc;
+	void *arg;
+{
+	ipf_auth_softc_t *softa = arg;
+	frauthent_t *fae, **faep;
+	frentry_t *fr, **frp;
+	mb_t *m;
+	int i;
+
+	if (softa->ipf_auth != NULL) {
+		KFREES(softa->ipf_auth,
+		       softa->ipf_auth_size * sizeof(*softa->ipf_auth));
+		softa->ipf_auth = NULL;
+	}
+
+	if (softa->ipf_auth_pkts != NULL) {
+		for (i = 0; i < softa->ipf_auth_size; i++) {
+			m = softa->ipf_auth_pkts[i];
+			if (m != NULL) {
+				FREE_MB_T(m);
+				softa->ipf_auth_pkts[i] = NULL;
+			}
+		}
+		KFREES(softa->ipf_auth_pkts,
+		       softa->ipf_auth_size * sizeof(*softa->ipf_auth_pkts));
+		softa->ipf_auth_pkts = NULL;
+	}
+
+	faep = &softa->ipf_auth_entries;
+	while ((fae = *faep) != NULL) {
+		*faep = fae->fae_next;
+		KFREE(fae);
+	}
+	softa->ipf_auth_ip = NULL;
+
+	if (softa->ipf_auth_rules != NULL) {
+		for (frp = &softa->ipf_auth_rules; ((fr = *frp) != NULL); ) {
+			if (fr->fr_ref == 1) {
+				*frp = fr->fr_next;
+				MUTEX_DESTROY(&fr->fr_lock);
+				KFREE(fr);
+			} else
+				frp = &fr->fr_next;
+		}
+	}
+
 	return 0;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_checkauth                                                */
+/* Function:    ipf_auth_soft_destroy                                       */
+/* Returns:     void                                                        */
+/* Parameters:  softc(I) - pointer to soft context data                     */
+/*              arg(I)   - opaque pointer to auth context data              */
+/*                                                                          */
+/* Undo what was done in _create() - i.e. free the soft context data.       */
+/* ------------------------------------------------------------------------ */
+void
+ipf_auth_soft_destroy(softc, arg)
+	ipf_main_softc_t *softc;
+	void *arg;
+{
+	ipf_auth_softc_t *softa = arg;
+
+# if SOLARIS && defined(_KERNEL)
+	cv_destroy(&softa->ipf_auth_wait);
+# endif
+	MUTEX_DESTROY(&softa->ipf_auth_mx);
+	RW_DESTROY(&softa->ipf_authlk);
+
+	KFREE(softa);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_auth_setlock                                            */
+/* Returns:     void                                                        */
+/* Paramters:   arg(I) - pointer to soft context data                       */
+/*              tmp(I) - value to assign to auth lock                       */
+/*                                                                          */
+/* ------------------------------------------------------------------------ */
+void
+ipf_auth_setlock(arg, tmp)
+	void *arg;
+	int tmp;
+{
+	ipf_auth_softc_t *softa = arg;
+
+	softa->ipf_auth_lock = tmp;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_auth_check                                              */
 /* 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                  */
@@ -198,10 +356,13 @@
 /* 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;
+frentry_t *
+ipf_auth_check(fin, passp)
+	fr_info_t *fin;
+	u_32_t *passp;
 {
+	ipf_main_softc_t *softc = fin->fin_main_soft;
+	ipf_auth_softc_t *softa = softc->ipf_auth_soft;
 	frentry_t *fr;
 	frauth_t *fra;
 	u_32_t pass;
@@ -209,27 +370,29 @@
 	ip_t *ip;
 	int i;
 
-	if (fr_auth_lock || !fr_authused)
+	if (softa->ipf_auth_lock || !softa->ipf_auth_used)
 		return NULL;
 
 	ip = fin->fin_ip;
 	id = ip->ip_id;
 
-	READ_ENTER(&ipf_auth);
-	for (i = fr_authstart; i != fr_authend; ) {
+	READ_ENTER(&softa->ipf_authlk);
+	for (i = softa->ipf_auth_start; i != softa->ipf_auth_end; ) {
 		/*
 		 * index becomes -2 only after an SIOCAUTHW.  Check this in
 		 * case the same packet gets sent again and it hasn't yet been
 		 * auth'd.
 		 */
-		fra = fr_auth + i;
+		fra = softa->ipf_auth + i;
 		if ((fra->fra_index == -2) && (id == fra->fra_info.fin_id) &&
 		    !bcmp((char *)fin, (char *)&fra->fra_info, FI_CSIZE)) {
 			/*
 			 * Avoid feedback loop.
 			 */
-			if (!(pass = fra->fra_pass) || (FR_ISAUTH(pass)))
+			if (!(pass = fra->fra_pass) || (FR_ISAUTH(pass))) {
 				pass = FR_BLOCK;
+				fin->fin_reason = FRB_AUTHFEEDBACK;
+			}
 			/*
 			 * Create a dummy rule for the stateful checking to
 			 * use and return.  Zero out any values we don't
@@ -249,60 +412,65 @@
 					fr->fr_ifas[1] = NULL;
 					fr->fr_ifas[2] = NULL;
 					fr->fr_ifas[3] = NULL;
+					MUTEX_INIT(&fr->fr_lock,
+						   "ipf auth rule");
 				}
 			} else
 				fr = fra->fra_info.fin_fr;
 			fin->fin_fr = fr;
-			RWLOCK_EXIT(&ipf_auth);
+			fin->fin_flx |= fra->fra_flx;
+			RWLOCK_EXIT(&softa->ipf_authlk);
 
-			WRITE_ENTER(&ipf_auth);
+			WRITE_ENTER(&softa->ipf_authlk);
 			/*
-			 * fr_authlist is populated with the rules malloc'd
+			 * ipf_auth_rules 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;
+				fr->fr_next = softa->ipf_auth_rules;
+				softa->ipf_auth_rules = fr;
 			}
-			fr_authstats.fas_hits++;
+			softa->ipf_auth_stats.fas_hits++;
 			fra->fra_index = -1;
-			fr_authused--;
-			if (i == fr_authstart) {
+			softa->ipf_auth_used--;
+			softa->ipf_auth_replies--;
+			if (i == softa->ipf_auth_start) {
 				while (fra->fra_index == -1) {
 					i++;
 					fra++;
-					if (i == fr_authsize) {
+					if (i == softa->ipf_auth_size) {
 						i = 0;
-						fra = fr_auth;
+						fra = softa->ipf_auth;
 					}
-					fr_authstart = i;
-					if (i == fr_authend)
+					softa->ipf_auth_start = i;
+					if (i == softa->ipf_auth_end)
 						break;
 				}
-				if (fr_authstart == fr_authend) {
-					fr_authnext = 0;
-					fr_authstart = fr_authend = 0;
+				if (softa->ipf_auth_start ==
+				    softa->ipf_auth_end) {
+					softa->ipf_auth_next = 0;
+					softa->ipf_auth_start = 0;
+					softa->ipf_auth_end = 0;
 				}
 			}
-			RWLOCK_EXIT(&ipf_auth);
+			RWLOCK_EXIT(&softa->ipf_authlk);
 			if (passp != NULL)
 				*passp = pass;
-			ATOMIC_INC64(fr_authstats.fas_hits);
+			softa->ipf_auth_stats.fas_hits++;
 			return fr;
 		}
 		i++;
-		if (i == fr_authsize)
+		if (i == softa->ipf_auth_size)
 			i = 0;
 	}
-	fr_authstats.fas_miss++;
-	RWLOCK_EXIT(&ipf_auth);
-	ATOMIC_INC64(fr_authstats.fas_miss);
+	RWLOCK_EXIT(&softa->ipf_authlk);
+	softa->ipf_auth_stats.fas_miss++;
 	return NULL;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_newauth                                                  */
+/* Function:    ipf_auth_new                                                */
 /* 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                      */
@@ -311,10 +479,13 @@
 /* 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;
+int
+ipf_auth_new(m, fin)
+	mb_t *m;
+	fr_info_t *fin;
 {
+	ipf_main_softc_t *softc = fin->fin_main_soft;
+	ipf_auth_softc_t *softa = softc->ipf_auth_soft;
 #if defined(_KERNEL) && defined(MENTAT)
 	qpktinfo_t *qpi = fin->fin_qpi;
 #endif
@@ -324,31 +495,33 @@
 #endif
 	int i;
 
-	if (fr_auth_lock)
+	if (softa->ipf_auth_lock)
 		return 0;
 
-	WRITE_ENTER(&ipf_auth);
-	if (((fr_authend + 1) % fr_authsize) == fr_authstart) {
-		fr_authstats.fas_nospace++;
-		RWLOCK_EXIT(&ipf_auth);
+	WRITE_ENTER(&softa->ipf_authlk);
+	if (((softa->ipf_auth_end + 1) % softa->ipf_auth_size) ==
+	    softa->ipf_auth_start) {
+		softa->ipf_auth_stats.fas_nospace++;
+		RWLOCK_EXIT(&softa->ipf_authlk);
 		return 0;
 	}
 
-	fr_authstats.fas_added++;
-	fr_authused++;
-	i = fr_authend++;
-	if (fr_authend == fr_authsize)
-		fr_authend = 0;
-	fra = fr_auth + i;
+	softa->ipf_auth_stats.fas_added++;
+	softa->ipf_auth_used++;
+	i = softa->ipf_auth_end++;
+	if (softa->ipf_auth_end == softa->ipf_auth_size)
+		softa->ipf_auth_end = 0;
+
+	fra = softa->ipf_auth + i;
 	fra->fra_index = i;
-	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;
+	fra->fra_age = softa->ipf_auth_defaultage;
 	bcopy((char *)fin, (char *)&fra->fra_info, sizeof(*fin));
+	fra->fra_flx = fra->fra_info.fin_flx & (FI_STATE|FI_NATED);
+	fra->fra_info.fin_flx &= ~(FI_STATE|FI_NATED);
 #if !defined(sparc) && !defined(m68k)
 	/*
 	 * No need to copyback here as we want to undo the changes, not keep
@@ -370,17 +543,17 @@
 #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);
+	softa->ipf_auth_pkts[i] = *(mblk_t **)fin->fin_mp;
+	RWLOCK_EXIT(&softa->ipf_authlk);
+	cv_signal(&softa->ipf_auth_wait);
+	pollwakeup(&softc->ipf_poll_head[IPL_LOGAUTH], POLLIN|POLLRDNORM);
 #else
-	fr_authpkts[i] = m;
-	WAKEUP(&fr_authnext,0);
+	softa->ipf_auth_pkts[i] = m;
+	RWLOCK_EXIT(&softa->ipf_authlk);
+	WAKEUP(&softa->ipf_auth_next, 0);
 #endif
 	return 1;
 }
@@ -387,7 +560,7 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_auth_ioctl                                               */
+/* Function:    ipf_auth_ioctl                                              */
 /* Returns:     int - 0 == success, else error                              */
 /* Parameters:  data(IO) - pointer to ioctl data                            */
 /*              cmd(I)   - ioctl command                                    */
@@ -396,14 +569,17 @@
 /*              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             */
+/* in IPFilter - ie ioctls called on an open fd for /dev/ipf_auth           */
 /* ------------------------------------------------------------------------ */
-int fr_auth_ioctl(data, cmd, mode, uid, ctx)
-caddr_t data;
-ioctlcmd_t cmd;
-int mode, uid;
-void *ctx;
+int
+ipf_auth_ioctl(softc, data, cmd, mode, uid, ctx)
+	ipf_main_softc_t *softc;
+	caddr_t data;
+	ioctlcmd_t cmd;
+	int mode, uid;
+	void *ctx;
 {
+	ipf_auth_softc_t *softa = softc->ipf_auth_soft;
 	int error = 0, i;
 	SPL_INT(s);
 
@@ -413,18 +589,23 @@
 	    {
 		ipftoken_t *token;
 		ipfgeniter_t iter;
+		ipfobj_t obj;
 
-		error = fr_inobj(data, &iter, IPFOBJ_GENITER);
+		error = ipf_inobj(softc, data, &obj, &iter, IPFOBJ_GENITER);
 		if (error != 0)
 			break;
 
 		SPL_SCHED(s);
-		token = ipf_findtoken(IPFGENITER_AUTH, uid, ctx);
+		token = ipf_token_find(softc, IPFGENITER_AUTH, uid, ctx);
 		if (token != NULL)
-			error = fr_authgeniter(token, &iter);
-		else
+			error = ipf_auth_geniter(softc, token, &iter, &obj);
+		else {
+			WRITE_ENTER(&softc->ipf_tokens);
+			ipf_token_deref(softc, token);
+			RWLOCK_EXIT(&softc->ipf_tokens);
+			IPFERROR(10001);
 			error = ESRCH;
-		RWLOCK_EXIT(&ipf_tokens);
+		}
 		SPL_X(s);
 
 		break;
@@ -432,46 +613,52 @@
 
 	case SIOCADAFR :
 	case SIOCRMAFR :
-		if (!(mode & FWRITE))
+		if (!(mode & FWRITE)) {
+			IPFERROR(10002);
 			error = EPERM;
-		else
-			error = frrequest(IPL_LOGAUTH, cmd, data,
-					  fr_active, 1);
+		} else
+			error = frrequest(softc, IPL_LOGAUTH, cmd, data,
+					  softc->ipf_active, 1);
 		break;
 
 	case SIOCSTLCK :
 		if (!(mode & FWRITE)) {
+			IPFERROR(10003);
 			error = EPERM;
-			break;
+		} else {
+			error = ipf_lock(data, &softa->ipf_auth_lock);
 		}
-		error = fr_lock(data, &fr_auth_lock);
 		break;
 
 	case SIOCATHST:
-		fr_authstats.fas_faelist = fae_list;
-		error = fr_outobj(data, &fr_authstats, IPFOBJ_AUTHSTAT);
+		softa->ipf_auth_stats.fas_faelist = softa->ipf_auth_entries;
+		error = ipf_outobj(softc, data, &softa->ipf_auth_stats,
+				   IPFOBJ_AUTHSTAT);
 		break;
 
 	case SIOCIPFFL:
 		SPL_NET(s);
-		WRITE_ENTER(&ipf_auth);
-		i = fr_authflush();
-		RWLOCK_EXIT(&ipf_auth);
+		WRITE_ENTER(&softa->ipf_authlk);
+		i = ipf_auth_flush(softa);
+		RWLOCK_EXIT(&softa->ipf_authlk);
 		SPL_X(s);
-		error = BCOPYOUT((char *)&i, data, sizeof(i));
-		if (error != 0)
+		error = BCOPYOUT(&i, data, sizeof(i));
+		if (error != 0) {
+			IPFERROR(10004);
 			error = EFAULT;
+		}
 		break;
 
 	case SIOCAUTHW:
-		error = fr_authwait(data);
+		error = ipf_auth_wait(softc, softa, data);
 		break;
 
 	case SIOCAUTHR:
-		error = fr_authreply(data);
+		error = ipf_auth_reply(softc, softa, data);
 		break;
 
 	default :
+		IPFERROR(10005);
 		error = EINVAL;
 		break;
 	}
@@ -480,75 +667,18 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_authunload                                               */
+/* Function:    ipf_auth_expire                                             */
 /* Returns:     None                                                        */
 /* Parameters:  None                                                        */
 /*                                                                          */
-/* Free all network buffer memory used to keep saved packets.               */
-/* ------------------------------------------------------------------------ */
-void fr_authunload()
-{
-	register int i;
-	register frauthent_t *fae, **faep;
-	frentry_t *fr, **frp;
-	mb_t *m;
-
-	if (fr_auth != NULL) {
-		KFREES(fr_auth, fr_authsize * sizeof(*fr_auth));
-		fr_auth = NULL;
-	}
-
-	if (fr_authpkts != NULL) {
-		for (i = 0; i < fr_authsize; i++) {
-			m = fr_authpkts[i];
-			if (m != NULL) {
-				FREE_MB_T(m);
-				fr_authpkts[i] = NULL;
-			}
-		}
-		KFREES(fr_authpkts, fr_authsize * sizeof(*fr_authpkts));
-		fr_authpkts = NULL;
-	}
-
-	faep = &fae_list;
-	while ((fae = *faep) != NULL) {
-		*faep = fae->fae_next;
-		KFREE(fae);
-	}
-	ipauth = NULL;
-
-	if (fr_authlist != NULL) {
-		for (frp = &fr_authlist; ((fr = *frp) != NULL); ) {
-			if (fr->fr_ref == 1) {
-				*frp = fr->fr_next;
-				KFREE(fr);
-			} else
-				frp = &fr->fr_next;
-		}
-	}
-
-	if (fr_auth_init == 1) {
-# if SOLARIS && defined(_KERNEL)
-		cv_destroy(&ipfauthwait);
-# endif
-		MUTEX_DESTROY(&ipf_authmx);
-		RW_DESTROY(&ipf_auth);
-
-		fr_auth_init = 0;
-	}
-}
-
-
-/* ------------------------------------------------------------------------ */
-/* 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()
+void
+ipf_auth_expire(softc)
+	ipf_main_softc_t *softc;
 {
+	ipf_auth_softc_t *softa = softc->ipf_auth_soft;
 	frauthent_t *fae, **faep;
 	frentry_t *fr, **frp;
 	frauth_t *fra;
@@ -556,19 +686,24 @@
 	int i;
 	SPL_INT(s);
 
-	if (fr_auth_lock)
+	if (softa->ipf_auth_lock)
 		return;
-
 	SPL_NET(s);
-	WRITE_ENTER(&ipf_auth);
-	for (i = 0, fra = fr_auth; i < fr_authsize; i++, fra++) {
+	WRITE_ENTER(&softa->ipf_authlk);
+	for (i = 0, fra = softa->ipf_auth; i < softa->ipf_auth_size;
+	     i++, fra++) {
 		fra->fra_age--;
-		if ((fra->fra_age == 0) && (m = fr_authpkts[i])) {
-			FREE_MB_T(m);
-			fr_authpkts[i] = NULL;
-			fr_auth[i].fra_index = -1;
-			fr_authstats.fas_expire++;
-			fr_authused--;
+		if ((fra->fra_age == 0) &&
+		    (softa->ipf_auth[i].fra_index != -1)) {
+			if ((m = softa->ipf_auth_pkts[i]) != NULL) {
+				FREE_MB_T(m);
+				softa->ipf_auth_pkts[i] = NULL;
+			} else if (softa->ipf_auth[i].fra_index == -2) {
+				softa->ipf_auth_replies--;
+			}
+			softa->ipf_auth[i].fra_index = -1;
+			softa->ipf_auth_stats.fas_expire++;
+			softa->ipf_auth_used--;
 		}
 	}
 
@@ -575,33 +710,34 @@
 	/*
 	 * Expire pre-auth rules
 	 */
-	for (faep = &fae_list; ((fae = *faep) != NULL); ) {
+	for (faep = &softa->ipf_auth_entries; ((fae = *faep) != NULL); ) {
 		fae->fae_age--;
 		if (fae->fae_age == 0) {
-			fr_authderef(&fae);
-			fr_authstats.fas_expire++;
+			ipf_auth_deref(&fae);
+			softa->ipf_auth_stats.fas_expire++;
 		} else
 			faep = &fae->fae_next;
 	}
-	if (fae_list != NULL)
-		ipauth = &fae_list->fae_fr;
+	if (softa->ipf_auth_entries != NULL)
+		softa->ipf_auth_ip = &softa->ipf_auth_entries->fae_fr;
 	else
-		ipauth = NULL;
+		softa->ipf_auth_ip = NULL;
 
-	for (frp = &fr_authlist; ((fr = *frp) != NULL); ) {
+	for (frp = &softa->ipf_auth_rules; ((fr = *frp) != NULL); ) {
 		if (fr->fr_ref == 1) {
 			*frp = fr->fr_next;
+			MUTEX_DESTROY(&fr->fr_lock);
 			KFREE(fr);
 		} else
 			frp = &fr->fr_next;
 	}
-	RWLOCK_EXIT(&ipf_auth);
+	RWLOCK_EXIT(&softa->ipf_authlk);
 	SPL_X(s);
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_preauthcmd                                               */
+/* Function:    ipf_auth_precmd                                             */
 /* Returns:     int - 0 == success, else error                              */
 /* Parameters:  cmd(I)  - ioctl command for rule                            */
 /*              fr(I)   - pointer to ipf rule                               */
@@ -608,18 +744,23 @@
 /*              fptr(I) - pointer to caller's 'fr'                          */
 /*                                                                          */
 /* ------------------------------------------------------------------------ */
-int fr_preauthcmd(cmd, fr, frptr)
-ioctlcmd_t cmd;
-frentry_t *fr, **frptr;
+int
+ipf_auth_precmd(softc, cmd, fr, frptr)
+	ipf_main_softc_t *softc;
+	ioctlcmd_t cmd;
+	frentry_t *fr, **frptr;
 {
+	ipf_auth_softc_t *softa = softc->ipf_auth_soft;
 	frauthent_t *fae, **faep;
 	int error = 0;
 	SPL_INT(s);
 
-	if ((cmd != SIOCADAFR) && (cmd != SIOCRMAFR))
+	if ((cmd != SIOCADAFR) && (cmd != SIOCRMAFR)) {
+		IPFERROR(10006);
 		return EIO;
+	}
 
-	for (faep = &fae_list; ((fae = *faep) != NULL); ) {
+	for (faep = &softa->ipf_auth_entries; ((fae = *faep) != NULL); ) {
 		if (&fae->fae_fr == fr)
 			break;
 		else
@@ -627,17 +768,22 @@
 	}
 
 	if (cmd == (ioctlcmd_t)SIOCRMAFR) {
-		if (fr == NULL || frptr == NULL)
+		if (fr == NULL || frptr == NULL) {
+			IPFERROR(10007);
 			error = EINVAL;
-		else if (fae == NULL)
+
+		} else if (fae == NULL) {
+			IPFERROR(10008);
 			error = ESRCH;
-		else {
+
+		} else {
 			SPL_NET(s);
-			WRITE_ENTER(&ipf_auth);
+			WRITE_ENTER(&softa->ipf_authlk);
 			*faep = fae->fae_next;
-			if (ipauth == &fae->fae_fr)
-				ipauth = fae_list ? &fae_list->fae_fr : NULL;
-			RWLOCK_EXIT(&ipf_auth);
+			if (softa->ipf_auth_ip == &fae->fae_fr)
+				softa->ipf_auth_ip = softa->ipf_auth_entries ?
+				    &softa->ipf_auth_entries->fae_fr : NULL;
+			RWLOCK_EXIT(&softa->ipf_authlk);
 			SPL_X(s);
 
 			KFREE(fae);
@@ -648,8 +794,8 @@
 			bcopy((char *)fr, (char *)&fae->fae_fr,
 			      sizeof(*fr));
 			SPL_NET(s);
-			WRITE_ENTER(&ipf_auth);
-			fae->fae_age = fr_defaultauthage;
+			WRITE_ENTER(&softa->ipf_authlk);
+			fae->fae_age = softa->ipf_auth_defaultage;
 			fae->fae_fr.fr_hits = 0;
 			fae->fae_fr.fr_next = *frptr;
 			fae->fae_ref = 1;
@@ -656,55 +802,66 @@
 			*frptr = &fae->fae_fr;
 			fae->fae_next = *faep;
 			*faep = fae;
-			ipauth = &fae_list->fae_fr;
-			RWLOCK_EXIT(&ipf_auth);
+			softa->ipf_auth_ip = &softa->ipf_auth_entries->fae_fr;
+			RWLOCK_EXIT(&softa->ipf_authlk);
 			SPL_X(s);
-		} else
+		} else {
+			IPFERROR(10009);
 			error = ENOMEM;
-	} else
+		}
+	} else {
+		IPFERROR(10010);
 		error = EINVAL;
+	}
 	return error;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_authflush                                                */
+/* Function:    ipf_auth_flush                                              */
 /* Returns:     int - number of auth entries flushed                        */
 /* Parameters:  None                                                        */
-/* Locks:       WRITE(ipf_auth)                                             */
+/* Locks:       WRITE(ipf_authlk)                                           */
 /*                                                                          */
-/* This function flushs the fr_authpkts array of any packet data with       */
+/* This function flushs the ipf_auth_pkts 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()
+static int
+ipf_auth_flush(arg)
+	void *arg;
 {
-	register int i, num_flushed;
+	ipf_auth_softc_t *softa = arg;
+	int i, num_flushed;
 	mb_t *m;
 
-	if (fr_auth_lock)
+	if (softa->ipf_auth_lock)
 		return -1;
 
 	num_flushed = 0;
 
-	for (i = 0 ; i < fr_authsize; i++) {
-		m = fr_authpkts[i];
-		if (m != NULL) {
-			FREE_MB_T(m);
-			fr_authpkts[i] = NULL;
-			fr_auth[i].fra_index = -1;
+	for (i = 0 ; i < softa->ipf_auth_size; i++) {
+		if (softa->ipf_auth[i].fra_index != -1) {
+			m = softa->ipf_auth_pkts[i];
+			if (m != NULL) {
+				FREE_MB_T(m);
+				softa->ipf_auth_pkts[i] = NULL;
+			}
+
+			softa->ipf_auth[i].fra_index = -1;
 			/* perhaps add & use a flush counter inst.*/
-			fr_authstats.fas_expire++;
-			fr_authused--;
+			softa->ipf_auth_stats.fas_expire++;
 			num_flushed++;
 		}
 	}
 
-	fr_authstart = 0;
-	fr_authend = 0;
-	fr_authnext = 0;
+	softa->ipf_auth_start = 0;
+	softa->ipf_auth_end = 0;
+	softa->ipf_auth_next = 0;
+	softa->ipf_auth_used = 0;
+	softa->ipf_auth_replies = 0;
 
 	return num_flushed;
 }
@@ -711,98 +868,125 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_auth_waiting                                             */
-/* Returns:     int - 0 = no pakcets wiating, 1 = packets waiting.          */
+/* Function:    ipf_auth_waiting                                            */
+/* Returns:     int - number of packets in the auth queue                   */
 /* Parameters:  None                                                        */
 /*                                                                          */
 /* Simple truth check to see if there are any packets waiting in the auth   */
 /* queue.                                                                   */
 /* ------------------------------------------------------------------------ */
-int fr_auth_waiting()
+int
+ipf_auth_waiting(softc)
+	ipf_main_softc_t *softc;
 {
-	return (fr_authused != 0);
+	ipf_auth_softc_t *softa = softc->ipf_auth_soft;
+
+	return (softa->ipf_auth_used != 0);
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_authgeniter                                              */
+/* Function:    ipf_auth_geniter                                            */
 /* Returns:     int - 0 == success, else error                              */
 /* Parameters:  token(I) - pointer to ipftoken structure                    */
 /*              itp(I)   - pointer to ipfgeniter structure                  */
+/*              objp(I)  - pointer to ipf object destription                */
 /*                                                                          */
+/* Iterate through the list of entries in the auth queue list.              */
+/* objp is used here to get the location of where to do the copy out to.    */
+/* Stomping over various fields with new information will not harm anything */
 /* ------------------------------------------------------------------------ */
-int fr_authgeniter(token, itp)
-ipftoken_t *token;
-ipfgeniter_t *itp;
+static int
+ipf_auth_geniter(softc, token, itp, objp)
+	ipf_main_softc_t *softc;
+	ipftoken_t *token;
+	ipfgeniter_t *itp;
+	ipfobj_t *objp;
 {
+	ipf_auth_softc_t *softa = softc->ipf_auth_soft;
 	frauthent_t *fae, *next, zero;
 	int error;
 
-	if (itp->igi_data == NULL)
+	if (itp->igi_data == NULL) {
+		IPFERROR(10011);
 		return EFAULT;
+	}
 
-	if (itp->igi_type != IPFGENITER_AUTH)
+	if (itp->igi_type != IPFGENITER_AUTH) {
+		IPFERROR(10012);
 		return EINVAL;
+	}
 
+	objp->ipfo_type = IPFOBJ_FRAUTH;
+	objp->ipfo_ptr = itp->igi_data;
+	objp->ipfo_size = sizeof(frauth_t);
+
+	READ_ENTER(&softa->ipf_authlk);
+
 	fae = token->ipt_data;
-	READ_ENTER(&ipf_auth);
 	if (fae == NULL) {
-		next = fae_list;
+		next = softa->ipf_auth_entries;
 	} else {
 		next = fae->fae_next;
 	}
 
+	/*
+	 * If we found an auth entry to use, bump its reference count
+	 * so that it can be used for is_next when we come back.
+	 */
 	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;
-		}
+		token->ipt_data = next;
 	} else {
 		bzero(&zero, sizeof(zero));
 		next = &zero;
+		token->ipt_data = NULL;
 	}
-	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);
-	}
+	RWLOCK_EXIT(&softa->ipf_authlk);
 
-	/*
-	 * 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;
+	error = ipf_outobjk(softc, objp, next);
+	if (fae != NULL)
+		ipf_auth_deref_unlocked(softa, &fae);
 
+	if (next->fae_next == NULL)
+		ipf_token_mark_complete(token);
 	return error;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_authderef                                                */
+/* Function:    ipf_auth_deref_unlocked                                     */
 /* Returns:     None                                                        */
 /* Parameters:  faep(IO) - pointer to caller's frauthent_t pointer          */
-/* Locks:       WRITE(ipf_auth)                                             */
 /*                                                                          */
+/* Wrapper for ipf_auth_deref for when a write lock on ipf_authlk is not    */
+/* held.                                                                    */
+/* ------------------------------------------------------------------------ */
+static void
+ipf_auth_deref_unlocked(softa, faep)
+	ipf_auth_softc_t *softa;
+	frauthent_t **faep;
+{
+	WRITE_ENTER(&softa->ipf_authlk);
+	ipf_auth_deref(faep);
+	RWLOCK_EXIT(&softa->ipf_authlk);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_auth_deref                                              */
+/* Returns:     None                                                        */
+/* Parameters:  faep(IO) - pointer to caller's frauthent_t pointer          */
+/* Locks:       WRITE(ipf_authlk)                                           */
+/*                                                                          */
 /* 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;
+static void
+ipf_auth_deref(faep)
+	frauthent_t **faep;
 {
 	frauthent_t *fae;
 
@@ -817,7 +1001,7 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_authwait                                                 */
+/* Function:    ipf_auth_wait_pkt                                           */
 /* Returns:     int - 0 == success, else error                              */
 /* Parameters:  data(I) - pointer to data from ioctl call                   */
 /*                                                                          */
@@ -824,23 +1008,23 @@
 /* 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.                                                                   */
+/* If there are no packets present in the queue (ipf_auth_pkts) then we go  */
+/* to sleep.                                                                */
 /* ------------------------------------------------------------------------ */
-int fr_authwait(data)
-char *data;
+static int
+ipf_auth_wait(softc, softa, data)
+	ipf_main_softc_t *softc;
+	ipf_auth_softc_t *softa;
+	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);
+ipf_auth_ioctlloop:
+	error = ipf_inobj(softc, data, NULL, au, IPFOBJ_FRAUTH);
 	if (error != 0)
 		return error;
 
@@ -850,23 +1034,29 @@
 	 * 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);
+	SPL_NET(s);
+	READ_ENTER(&softa->ipf_authlk);
 
 	/*
-	 * 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 ipf_auth_next is not equal to ipf_auth_end it will be because
+	 * there is a packet waiting to be delt with in the ipf_auth_pkts
+	 * 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;
+	if (softa->ipf_auth_used > 0) {
+		while (softa->ipf_auth_pkts[softa->ipf_auth_next] == NULL) {
+			softa->ipf_auth_next++;
+			if (softa->ipf_auth_next == softa->ipf_auth_size)
+				softa->ipf_auth_next = 0;
 		}
 
-		error = fr_outobj(data, &fr_auth[fr_authnext], IPFOBJ_FRAUTH);
-		if (error != 0)
+		error = ipf_outobj(softc, data,
+				   &softa->ipf_auth[softa->ipf_auth_next],
+				   IPFOBJ_FRAUTH);
+		if (error != 0) {
+			RWLOCK_EXIT(&softa->ipf_authlk);
+			SPL_X(s);
 			return error;
+		}
 
 		if (auth.fra_len != 0 && auth.fra_buf != NULL) {
 			/*
@@ -873,7 +1063,7 @@
 			 * Copy packet contents out to user space if
 			 * requested.  Bail on an error.
 			 */
-			m = fr_authpkts[fr_authnext];
+			m = softa->ipf_auth_pkts[softa->ipf_auth_next];
 			len = MSGDSIZE(m);
 			if (len > auth.fra_len)
 				len = auth.fra_len;
@@ -881,62 +1071,69 @@
 
 			for (t = auth.fra_buf; m && (len > 0); ) {
 				i = MIN(M_LEN(m), len);
-				error = copyoutptr(MTOD(m, char *), &t, i);
+				error = copyoutptr(softc, MTOD(m, char *),
+						   &t, i);
 				len -= i;
 				t += i;
-				if (error != 0)
+				if (error != 0) {
+					RWLOCK_EXIT(&softa->ipf_authlk);
+					SPL_X(s);
 					return error;
+				}
 				m = m->m_next;
 			}
 		}
-		RWLOCK_EXIT(&ipf_auth);
+		RWLOCK_EXIT(&softa->ipf_authlk);
 
 		SPL_NET(s);
-		WRITE_ENTER(&ipf_auth);
-		fr_authnext++;
-		if (fr_authnext == fr_authsize)
-			fr_authnext = 0;
-		RWLOCK_EXIT(&ipf_auth);
+		WRITE_ENTER(&softa->ipf_authlk);
+		softa->ipf_auth_next++;
+		if (softa->ipf_auth_next == softa->ipf_auth_size)
+			softa->ipf_auth_next = 0;
+		RWLOCK_EXIT(&softa->ipf_authlk);
 		SPL_X(s);
 
 		return 0;
 	}
-	RWLOCK_EXIT(&ipf_auth);
+	RWLOCK_EXIT(&softa->ipf_authlk);
+	SPL_X(s);
 
-	MUTEX_ENTER(&ipf_authmx);
+	MUTEX_ENTER(&softa->ipf_auth_mx);
 #ifdef	_KERNEL
 # if	SOLARIS
 	error = 0;
-	if (!cv_wait_sig(&ipfauthwait, &ipf_authmx.ipf_lk))
+	if (!cv_wait_sig(&softa->ipf_auth_wait, &softa->ipf_auth_mx.ipf_lk)) {
+		IPFERROR(10014);
 		error = EINTR;
+	}
 # else /* SOLARIS */
 #  ifdef __hpux
 	{
 	lock_t *l;
 
-	l = get_sleep_lock(&fr_authnext);
-	error = sleep(&fr_authnext, PZERO+1);
+	l = get_sleep_lock(&softa->ipf_auth_next);
+	error = sleep(&softa->ipf_auth_next, PZERO+1);
 	spinunlock(l);
 	}
 #  else
 #   ifdef __osf__
-	error = mpsleep(&fr_authnext, PSUSP|PCATCH, "fr_authnext", 0,
-			&ipf_authmx, MS_LOCK_SIMPLE);
+	error = mpsleep(&softa->ipf_auth_next, PSUSP|PCATCH, "ipf_auth_next",
+			0, &softa->ipf_auth_mx, MS_LOCK_SIMPLE);
 #   else
-	error = SLEEP(&fr_authnext, "fr_authnext");
+	error = SLEEP(&softa->ipf_auth_next, "ipf_auth_next");
 #   endif /* __osf__ */
 #  endif /* __hpux */
 # endif /* SOLARIS */
 #endif
-	MUTEX_EXIT(&ipf_authmx);
+	MUTEX_EXIT(&softa->ipf_auth_mx);
 	if (error == 0)
-		goto fr_authioctlloop;
+		goto ipf_auth_ioctlloop;
 	return error;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_authreply                                                */
+/* Function:    ipf_auth_reply                                              */
 /* Returns:     int - 0 == success, else error                              */
 /* Parameters:  data(I) - pointer to data from ioctl call                   */
 /*                                                                          */
@@ -945,23 +1142,27 @@
 /* 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;
+static int
+ipf_auth_reply(softc, softa, data)
+	ipf_main_softc_t *softc;
+	ipf_auth_softc_t *softa;
+	char *data;
 {
 	frauth_t auth, *au = &auth, *fra;
+	fr_info_t fin;
 	int error, i;
 	mb_t *m;
 	SPL_INT(s);
 
-	error = fr_inobj(data, &auth, IPFOBJ_FRAUTH);
+	error = ipf_inobj(softc, data, NULL, &auth, IPFOBJ_FRAUTH);
 	if (error != 0)
 		return error;
 
 	SPL_NET(s);
-	WRITE_ENTER(&ipf_auth);
+	WRITE_ENTER(&softa->ipf_authlk);
 
 	i = au->fra_index;
-	fra = fr_auth + i;
+	fra = softa->ipf_auth + i;
 	error = 0;
 
 	/*
@@ -969,19 +1170,27 @@
 	 * 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);
+	if ((i < 0) || (i >= softa->ipf_auth_size)) {
+		RWLOCK_EXIT(&softa->ipf_authlk);
 		SPL_X(s);
+		IPFERROR(10015);
 		return ESRCH;
 	}
+	if  (fra->fra_info.fin_id != au->fra_info.fin_id) {
+		RWLOCK_EXIT(&softa->ipf_authlk);
+		SPL_X(s);
+		IPFERROR(10019);
+		return ESRCH;
+	}
 
-	m = fr_authpkts[i];
+	m = softa->ipf_auth_pkts[i];
 	fra->fra_index = -2;
 	fra->fra_pass = au->fra_pass;
-	fr_authpkts[i] = NULL;
+	softa->ipf_auth_pkts[i] = NULL;
+	softa->ipf_auth_replies++;
+	bcopy(&fra->fra_info, &fin, sizeof(fin));
 
-	RWLOCK_EXIT(&ipf_auth);
+	RWLOCK_EXIT(&softa->ipf_authlk);
 
 	/*
 	 * Re-insert the packet back into the packet stream flowing through
@@ -992,22 +1201,25 @@
 	 */
 #ifdef	_KERNEL
 	if ((m != NULL) && (au->fra_info.fin_out != 0)) {
-		error = ipf_inject(&fra->fra_info, m);
+		error = ipf_inject(&fin, m);
 		if (error != 0) {
+			IPFERROR(10016);
 			error = ENOBUFS;
-			fr_authstats.fas_sendfail++;
+			softa->ipf_auth_stats.fas_sendfail++;
 		} else {
-			fr_authstats.fas_sendok++;
+			softa->ipf_auth_stats.fas_sendok++;
 		}
 	} else if (m) {
-		error = ipf_inject(&fra->fra_info, m);
+		error = ipf_inject(&fin, m);
 		if (error != 0) {
+			IPFERROR(10017);
 			error = ENOBUFS;
-			fr_authstats.fas_quefail++;
+			softa->ipf_auth_stats.fas_quefail++;
 		} else {
-			fr_authstats.fas_queok++;
+			softa->ipf_auth_stats.fas_queok++;
 		}
 	} else {
+		IPFERROR(10018);
 		error = EINVAL;
 	}
 
@@ -1016,25 +1228,26 @@
 	 * not being processed, make sure we advance to the next one.
 	 */
 	if (error == ENOBUFS) {
-		WRITE_ENTER(&ipf_auth);
-		fr_authused--;
+		WRITE_ENTER(&softa->ipf_authlk);
+		softa->ipf_auth_used--;
 		fra->fra_index = -1;
 		fra->fra_pass = 0;
-		if (i == fr_authstart) {
+		if (i == softa->ipf_auth_start) {
 			while (fra->fra_index == -1) {
 				i++;
-				if (i == fr_authsize)
+				if (i == softa->ipf_auth_size)
 					i = 0;
-				fr_authstart = i;
-				if (i == fr_authend)
+				softa->ipf_auth_start = i;
+				if (i == softa->ipf_auth_end)
 					break;
 			}
-			if (fr_authstart == fr_authend) {
-				fr_authnext = 0;
-				fr_authstart = fr_authend = 0;
+			if (softa->ipf_auth_start == softa->ipf_auth_end) {
+				softa->ipf_auth_next = 0;
+				softa->ipf_auth_start = 0;
+				softa->ipf_auth_end = 0;
 			}
 		}
-		RWLOCK_EXIT(&ipf_auth);
+		RWLOCK_EXIT(&softa->ipf_authlk);
 	}
 #endif /* _KERNEL */
 	SPL_X(s);
@@ -1041,3 +1254,28 @@
 
 	return 0;
 }
+
+
+u_32_t
+ipf_auth_pre_scanlist(softc, fin, pass)
+	ipf_main_softc_t *softc;
+	fr_info_t *fin;
+	u_32_t pass;
+{
+	ipf_auth_softc_t *softa = softc->ipf_auth_soft;
+
+	if (softa->ipf_auth_ip != NULL)
+		return ipf_scanlist(fin, softc->ipf_pass);
+
+	return pass;
+}
+
+
+frentry_t **
+ipf_auth_rulehead(softc)
+	ipf_main_softc_t *softc;
+{
+	ipf_auth_softc_t *softa = softc->ipf_auth_soft;
+
+	return &softa->ipf_auth_ip;
+}

Modified: trunk/sys/contrib/ipfilter/netinet/ip_auth.h
===================================================================
--- trunk/sys/contrib/ipfilter/netinet/ip_auth.h	2018-05-28 18:55:30 UTC (rev 10138)
+++ trunk/sys/contrib/ipfilter/netinet/ip_auth.h	2018-05-28 18:56:30 UTC (rev 10139)
@@ -1,11 +1,12 @@
-/*	$FreeBSD$	*/
+/* $MidnightBSD$ */
+/*	$FreeBSD: stable/10/sys/contrib/ipfilter/netinet/ip_auth.h 266829 2014-05-29 02:55:07Z cy $	*/
 
 /*
- * Copyright (C) 1997-2001 by Darren Reed & Guido Van Rooij.
+ * Copyright (C) 2012 by Darren Reed.
  *
  * See the IPFILTER.LICENCE file for details on licencing.
  *
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/contrib/ipfilter/netinet/ip_auth.h 266829 2014-05-29 02:55:07Z cy $
  * Id: ip_auth.h,v 2.16.2.2 2006/03/16 06:45:49 darrenr Exp $
  *
  */
@@ -21,6 +22,7 @@
 	u_32_t	fra_pass;
 	fr_info_t	fra_info;
 	char	*fra_buf;
+	u_32_t	fra_flx;
 #ifdef	MENTAT
 	queue_t	*fra_q;
 	mb_t	*fra_m;
@@ -35,7 +37,7 @@
 	int	fae_ref;
 } frauthent_t;
 
-typedef struct  fr_authstat {
+typedef struct  ipf_authstat {
 	U_QUAD_T	fas_hits;
 	U_QUAD_T	fas_miss;
 	u_long		fas_nospace;
@@ -46,26 +48,46 @@
 	u_long		fas_quefail;
 	u_long		fas_expire;
 	frauthent_t	*fas_faelist;
-} fr_authstat_t;
+} ipf_authstat_t;
 
+typedef	struct ipf_auth_softc_s {
+	ipfrwlock_t	ipf_authlk;
+	ipfmutex_t	ipf_auth_mx;
+	int		ipf_auth_size;
+	int		ipf_auth_used;
+	int		ipf_auth_replies;
+	int		ipf_auth_defaultage;
+	int		ipf_auth_lock;
+	ipf_authstat_t	ipf_auth_stats;
+	frauth_t	*ipf_auth;
+	mb_t		**ipf_auth_pkts;
+	int		ipf_auth_start;
+	int		ipf_auth_end;
+	int		ipf_auth_next;
+	frauthent_t	*ipf_auth_entries;
+	frentry_t	*ipf_auth_ip;
+	frentry_t	*ipf_auth_rules;
+} ipf_auth_softc_t;
 
-extern	frentry_t	*ipauth;
-extern	struct fr_authstat	fr_authstats;
-extern	int	fr_defaultauthage;
-extern	int	fr_authstart;
-extern	int	fr_authend;
-extern	int	fr_authsize;
-extern	int	fr_authused;
-extern	int	fr_auth_lock;
-extern	frentry_t *fr_checkauth __P((fr_info_t *, u_32_t *));
-extern	void	fr_authexpire __P((void));
-extern	int	fr_authinit __P((void));
-extern	void	fr_authunload __P((void));
-extern	int	fr_authflush __P((void));
-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, int, void *));
-extern	int	fr_auth_waiting __P((void));
+extern	frentry_t *ipf_auth_check __P((fr_info_t *, u_32_t *));
+extern	void	ipf_auth_expire __P((ipf_main_softc_t *));
+extern	int	ipf_auth_ioctl __P((ipf_main_softc_t *, caddr_t, ioctlcmd_t,
+				    int, int, void *));
+extern	int	ipf_auth_init __P((void));
+extern	int	ipf_auth_main_load __P((void));
+extern	int	ipf_auth_main_unload __P((void));
+extern	void	ipf_auth_soft_destroy __P((ipf_main_softc_t *, void *));
+extern	void	*ipf_auth_soft_create __P((ipf_main_softc_t *));
+extern	int	ipf_auth_new __P((mb_t *, fr_info_t *));
+extern	int	ipf_auth_precmd __P((ipf_main_softc_t *, ioctlcmd_t,
+				     frentry_t *, frentry_t **));
+extern	void	ipf_auth_unload __P((ipf_main_softc_t *));
+extern	int	ipf_auth_waiting __P((ipf_main_softc_t *));
+extern	void	ipf_auth_setlock __P((void *, int));
+extern	int	ipf_auth_soft_init __P((ipf_main_softc_t *, void *));
+extern	int	ipf_auth_soft_fini __P((ipf_main_softc_t *, void *));
+extern	u_32_t	ipf_auth_pre_scanlist __P((ipf_main_softc_t *, fr_info_t *,
+					   u_32_t));
+extern	frentry_t **ipf_auth_rulehead __P((ipf_main_softc_t *));
 
 #endif	/* __IP_AUTH_H__ */

Modified: trunk/sys/contrib/ipfilter/netinet/ip_compat.h
===================================================================
--- trunk/sys/contrib/ipfilter/netinet/ip_compat.h	2018-05-28 18:55:30 UTC (rev 10138)
+++ trunk/sys/contrib/ipfilter/netinet/ip_compat.h	2018-05-28 18:56:30 UTC (rev 10139)
@@ -1,10 +1,11 @@
+/* $MidnightBSD$ */
 /*
- * Copyright (C) 1993-2001, 2003 by Darren Reed.
+ * Copyright (C) 2012 by Darren Reed.
  *
  * See the IPFILTER.LICENCE file for details on licencing.
  *
  * @(#)ip_compat.h	1.8 1/14/96
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/contrib/ipfilter/netinet/ip_compat.h 314251 2017-02-25 08:07:28Z cy $
  * Id: ip_compat.h,v 2.142.2.57 2007/10/10 09:51:42 darrenr Exp $
  */
 
@@ -33,40 +34,13 @@
 #endif
 
 #ifndef	SOLARIS
-#define	SOLARIS	(defined(sun) && (defined(__svr4__) || defined(__SVR4)))
-#endif
-#if (defined(SOLARIS2) && (SOLARIS2 >= 8))
-# ifndef	USE_INET6
-#  define	USE_INET6
+# if defined(sun) && (defined(__svr4__) || defined(__SVR4))
+#  define	SOLARIS		1
+# else
+#  define	SOLARIS		0
 # endif
 #endif
-#if defined(__FreeBSD_version) && (__FreeBSD_version >= 400000) && \
-    !defined(_KERNEL) && !defined(USE_INET6) && !defined(NOINET6)
-# define	USE_INET6
-#endif
-#if defined(__NetBSD_Version__) && (__NetBSD_Version__ >= 105000000) && \
-    !defined(_KERNEL) && !defined(USE_INET6)
-# define	USE_INET6
-# define	IPFILTER_M_IPFILTER
-#endif
-#if defined(OpenBSD) && (OpenBSD >= 200206) && \
-    !defined(_KERNEL) && !defined(USE_INET6)
-# define	USE_INET6
-#endif
-#if defined(__osf__)
-# define	USE_INET6
-#endif
-#if defined(linux) && (!defined(_KERNEL) || defined(CONFIG_IPV6))
-# define	USE_INET6
-#endif
-#if defined(HPUXREV) && (HPUXREV >= 1111)
-# define	USE_INET6
-#endif
 
-#if defined(BSD) && (BSD < 199103) && defined(__osf__)
-# undef BSD
-# define BSD 199103
-#endif
 
 #if defined(__SVR4) || defined(__svr4__) || defined(__sgi)
 # define index   strchr
@@ -95,767 +69,78 @@
 };
 #endif
 
-#if defined(__sgi) && !defined(IPFILTER_LKM)
 # ifdef __STDC__
-#  define IPL_EXTERN(ep) ipfilter##ep
-# else
-#  define IPL_EXTERN(ep) ipfilter/**/ep
-# endif
-#else
-# ifdef __STDC__
 #  define IPL_EXTERN(ep) ipl##ep
 # else
 #  define IPL_EXTERN(ep) ipl/**/ep
 # endif
-#endif
 
 /*
  * This is a workaround for <sys/uio.h> troubles on FreeBSD and OpenBSD.
  */
-#ifndef linux
 # ifndef _KERNEL
 #  define ADD_KERNEL
 #  define _KERNEL
 #  define KERNEL
 # endif
-# ifdef __OpenBSD__
-struct file;
-# endif
 # include <sys/uio.h>
 # ifdef ADD_KERNEL
 #  undef _KERNEL
 #  undef KERNEL
 # endif
-#endif
 
+#define	NETBSD_GE_REV(x)	(defined(__NetBSD_Version__) && \
+				 (__NetBSD_Version__ >= (x)))
+#define	NETBSD_GT_REV(x)	(defined(__NetBSD_Version__) && \
+				 (__NetBSD_Version__ > (x)))
+#define	NETBSD_LT_REV(x)	(defined(__NetBSD_Version__) && \
+				 (__NetBSD_Version__ < (x)))
+#define	FREEBSD_GE_REV(x)	(defined(__FreeBSD_version) && \
+				 (__FreeBSD_version >= (x)))
+#define	FREEBSD_GT_REV(x)	(defined(__FreeBSD_version) && \
+				 (__FreeBSD_version > (x)))
+#define	FREEBSD_LT_REV(x)	(defined(__FreeBSD_version) && \
+				 (__FreeBSD_version < (x)))
+#define	BSDOS_GE_REV(x)		(defined(_BSDI_VERSION) && \
+				 (_BSDI_VERSION >= (x)))
+#define	BSDOS_GT_REV(x)		(defined(_BSDI_VERSION) && \
+				 (_BSDI_VERSION > (x)))
+#define	BSDOS_LT_REV(x)		(defined(_BSDI_VERSION) && \
+				 (_BSDI_VERSION < (x)))
+#define	OPENBSD_GE_REV(x)	(defined(OpenBSD) && (OpenBSD >= (x)))
+#define	OPENBSD_GT_REV(x)	(defined(OpenBSD) && (OpenBSD > (x)))
+#define	OPENBSD_LT_REV(x)	(defined(OpenBSD) && (OpenBSD < (x)))
+#define	BSD_GE_YEAR(x)		(defined(BSD) && (BSD >= (x)))
+#define	BSD_GT_YEAR(x)		(defined(BSD) && (BSD > (x)))
+#define	BSD_LT_YEAR(x)		(defined(BSD) && (BSD < (x)))
 
-/* ----------------------------------------------------------------------- */
-/*                                  S O L A R I S                          */
-/* ----------------------------------------------------------------------- */
-#if SOLARIS
-# define	MENTAT	1
-# include	<sys/cmn_err.h>
-# include	<sys/isa_defs.h>
-# include	<sys/stream.h>
-# include	<sys/ioccom.h>
-# include	<sys/sysmacros.h>
-# include	<sys/kmem.h>
-# if defined(SOLARIS2) && SOLARIS2 >= 10
-#  include	<sys/procset.h>
-#  include	<sys/proc.h>
-#  include	<sys/devops.h>
-#  include	<sys/ddi_impldefs.h>
-# endif
-/*
- * because Solaris 2 defines these in two places :-/
- */
-# ifndef	KERNEL
-#  define	_KERNEL
-#  undef	RES_INIT
-# endif /* _KERNEL */
 
-# if defined(SOLARIS2) && SOLARIS2 >= 8
-#  include <netinet/ip6.h>
-#  include <netinet/icmp6.h>
-# endif
-
-# include <inet/common.h>
-/* These 5 are defined in <inet/ip.h> and <netinet/ip.h> */
-# undef	IPOPT_EOL
-# undef	IPOPT_NOP
-# undef	IPOPT_LSRR
-# undef	IPOPT_RR
-# undef	IPOPT_SSRR
-# 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 defined(SOLARIS2) && SOLARIS2 >= 8
-#  define SNPRINTF	snprintf
-
-#  include <inet/ip_if.h>
-#  define	ipif_local_addr	ipif_lcl_addr
-/* Only defined in private include file */
-#  ifndef	V4_PART_OF_V6
-#   define	V4_PART_OF_V6(v6)	v6.s6_addr32[3]
-#  endif
-struct ip6_ext {
-	u_char	ip6e_nxt;
-	u_char	ip6e_len;
-};
-# endif /* SOLARIS2 >= 8 */
-
-# if defined(SOLARIS2) && SOLARIS2 >= 6
-#  include <sys/atomic.h>
-typedef	uint32_t	u_32_t;
-# else
-typedef unsigned int	u_32_t;
-# endif
-# define	U_32_T	1
-
-# ifdef _KERNEL
-#  define	NEED_LOCAL_RAND	1
-#  define	ipf_random		arc4random
-#  define	KRWLOCK_T		krwlock_t
-#  define	KMUTEX_T		kmutex_t
-
-#  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)
-#    define	ATOMIC_DECL(x)		atomic_add_long((uint32_t*)&(x), -1)
-#   else
-#    define	ATOMIC_INCL(x)		atomic_add_long(&(x), 1)
-#    define	ATOMIC_DECL(x)		atomic_add_long(&(x), -1)
-#   endif /* SOLARIS2 == 6 */
-#   define	ATOMIC_INC64(x)		atomic_add_64((uint64_t*)&(x), 1)
-#   define	ATOMIC_INC32(x)		atomic_add_32((uint32_t*)&(x), 1)
-#   define	ATOMIC_INC16(x)		atomic_add_16((uint16_t*)&(x), 1)
-#   define	ATOMIC_DEC64(x)		atomic_add_64((uint64_t*)&(x), -1)
-#   define	ATOMIC_DEC32(x)		atomic_add_32((uint32_t*)&(x), -1)
-#   define	ATOMIC_DEC16(x)		atomic_add_16((uint16_t*)&(x), -1)
-#  else
-#   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); }
-#  endif /* SOLARIS2 >= 6 */
-#  define	USE_MUTEXES
-#  define	MUTEX_ENTER(x)		mutex_enter(&(x)->ipf_lk)
-#  define	READ_ENTER(x)		rw_enter(&(x)->ipf_lk, RW_READER)
-#  define	WRITE_ENTER(x)		rw_enter(&(x)->ipf_lk, RW_WRITER)
-#  define	MUTEX_DOWNGRADE(x)	rw_downgrade(&(x)->ipf_lk)
-#  define	RWLOCK_INIT(x, y)	rw_init(&(x)->ipf_lk, (y),  \
-						RW_DRIVER, NULL)
-#  define	RWLOCK_EXIT(x)		rw_exit(&(x)->ipf_lk)
-#  define	RW_DESTROY(x)		rw_destroy(&(x)->ipf_lk)
-#  define	MUTEX_INIT(x, y)	mutex_init(&(x)->ipf_lk, (y), \
-						   MUTEX_DRIVER, NULL)
-#  define	MUTEX_DESTROY(x)	mutex_destroy(&(x)->ipf_lk)
-#  define	MUTEX_NUKE(x)		bzero((x), sizeof(*(x)))
-#  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)	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
-#  define	SPL_X(x)	;
-#  ifdef sparc
-#   define	ntohs(x)	(x)
-#   define	ntohl(x)	(x)
-#   define	htons(x)	(x)
-#   define	htonl(x)	(x)
-#  endif /* sparc */
-#  define	KMALLOC(a,b)	(a) = (b)kmem_alloc(sizeof(*(a)), KM_NOSLEEP)
-#  define	KMALLOCS(a,b,c)	(a) = (b)kmem_alloc((c), KM_NOSLEEP)
-#  define	GET_MINOR(x)	getminor(x)
-extern	void	*get_unit __P((char *, int));
-#  define	GETIFP(n, v)	get_unit(n, v)
-#  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)
-#  define	M_DUPLICATE(x)	dupmsg((x))
-#  define	MTOD(m,t)	((t)((m)->b_rptr))
-#  define	MTYPE(m)	((m)->b_datap->db_type)
-#  define	FREE_MB_T(m)	freemsg(m)
-#  define	m_next		b_cont
-#  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 defined(SOLARIS2) && (SOLARIS2 >= 7)
-#  ifdef lint
-#   define ALIGN32(ptr)    (ptr ? 0L : 0L)
-#   define ALIGN16(ptr)    (ptr ? 0L : 0L)
-#  else
-#   define ALIGN32(ptr)    (ptr)
-#   define ALIGN16(ptr)    (ptr)
-#  endif
-# endif
-
-# if defined(SOLARIS2) && SOLARIS2 < 6
-typedef	struct uio	uio_t;
-# endif
-typedef	int		ioctlcmd_t;
-typedef	uint8_t		u_int8_t;
-
-# define OS_RECOGNISED 1
-
-#endif /* SOLARIS */
-
 /* ----------------------------------------------------------------------- */
-/*                                  H P U X                                */
-/* ----------------------------------------------------------------------- */
-#ifdef __hpux
-# define	MENTAT	1
-# include	<sys/sysmacros.h>
-# include	<sys/spinlock.h>
-# include	<sys/lock.h>
-# include	<sys/stream.h>
-# ifdef USE_INET6
-#  include	<netinet/if_ether.h>
-#  include	<netinet/ip6.h>
-#  include	<netinet/icmp6.h>
-typedef	struct	ip6_hdr	ip6_t;
-# endif
-
-# ifdef _KERNEL
-#  define SNPRINTF	sprintf
-#  if (HPUXREV >= 1111)
-#   define	IPL_SELECT
-#   ifdef	IPL_SELECT
-#    include	<machine/sys/user.h>
-#    include	<sys/kthread_iface.h>
-#    define	READ_COLLISION	0x01
-
-typedef	struct	iplog_select_s {
-	kthread_t	*read_waiter;
-	int		state;
-} iplog_select_t;
-#   endif
-#  endif
-
-#  define	GETKTIME(x)	uniqtime((struct timeval *)x)
-
-#  if HPUXREV == 1111
-#   include	"kern_svcs.h"
-#  else
-#   include	<sys/kern_svcs.h>
-#  endif
-#  undef	ti_flags
-#  undef	TCP_NODELAY
-#  undef	TCP_MAXSEG
-#  include <sys/reg.h>
-#  include "../netinet/ip_info.h"
-/*
- * According to /usr/include/sys/spinlock.h on HP-UX 11.00, these functions
- * are available.  Attempting to use them actually results in unresolved
- * symbols when it comes time to load the module.
- * This has been fixed!  Yipee!
- */
-#  if 1
-#   ifdef __LP64__
-#    define	ATOMIC_INCL(x)		lock_and_incr_int64(&ipf_rw.ipf_lk, &(x), 1)
-#    define	ATOMIC_DECL(x)		lock_and_incr_int64(&ipf_rw.ipf_lk, &(x), -1)
-#   else
-#    define	ATOMIC_INCL(x)		lock_and_incr_int32(&ipf_rw.ipf_lk, &(x), 1)
-#    define	ATOMIC_DECL(x)		lock_and_incr_int32(&ipf_rw.ipf_lk, &(x), -1)
-#   endif
-#   define	ATOMIC_INC64(x)		lock_and_incr_int64(&ipf_rw.ipf_lk, &(x), 1)
-#   define	ATOMIC_INC32(x)		lock_and_incr_int32(&ipf_rw.ipf_lk, &(x), 1)
-#   define	ATOMIC_INC16(x)		lock_and_incr_int16(&ipf_rw.ipf_lk, &(x), 1)
-#   define	ATOMIC_DEC64(x)		lock_and_incr_int64(&ipf_rw.ipf_lk, &(x), -1)
-#   define	ATOMIC_DEC32(x)		lock_and_incr_int32(&ipf_rw.ipf_lk, &(x), -1)
-#   define	ATOMIC_DEC16(x)		lock_and_incr_int16(&ipf_rw.ipf_lk, &(x), -1)
-#  else /* 0 */
-#   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); }
-#  endif
-#  define	ip_cksum		ip_csuma
-#  define	memcpy(a,b,c)		bcopy((caddr_t)b, (caddr_t)a, c)
-#  define	USE_MUTEXES
-#  define	MUTEX_INIT(x, y)	initlock(&(x)->ipf_lk, 0, 0, (y))
-#  define	MUTEX_ENTER(x)		spinlock(&(x)->ipf_lk)
-#  define	MUTEX_EXIT(x)		spinunlock(&(x)->ipf_lk);
-#  define	MUTEX_DESTROY(x)
-#  define	MUTEX_NUKE(x)		bzero((char *)(x), sizeof(*(x)))
-#  define	KMUTEX_T		lock_t
-#  define	kmutex_t		lock_t		/* for pfil.h */
-#  define	krwlock_t		lock_t		/* for pfil.h */
-/*
- * The read-write lock implementation in HP-UX 11.0 is crippled - it can
- * only be used by threads working in a user context!
- * This has been fixed!  Yipee! (Or at least it does in 11.00, not 11.11..)
- */
-#  if HPUXREV < 1111
-#   define	MUTEX_DOWNGRADE(x)	lock_write_to_read(x)
-#   define	KRWLOCK_T		struct rw_lock
-#   define	READ_ENTER(x)		lock_read(&(x)->ipf_lk)
-#   define	WRITE_ENTER(x)		lock_write(&(x)->ipf_lk)
-#   if HPUXREV >= 1111
-#    define	RWLOCK_INIT(x, y)	rwlock_init4(&(x)->ipf_lk, 0, RWLCK_CANSLEEP, 0, y)
-#   else
-#    define	RWLOCK_INIT(x, y)	lock_init3(&(x)->ipf_lk, 0, 1, 0, 0, y)
-#   endif
-#   define	RWLOCK_EXIT(x)		lock_done(&(x)->ipf_lk)
-#  else
-#   define	KRWLOCK_T		lock_t
-#   define	KMUTEX_T		lock_t
-#   define	READ_ENTER(x)		MUTEX_ENTER(x)
-#   define	WRITE_ENTER(x)		MUTEX_ENTER(x)
-#   define	MUTEX_DOWNGRADE(x)
-#   define	RWLOCK_INIT(x, y)	initlock(&(x)->ipf_lk, 0, 0, y)
-#   define	RWLOCK_EXIT(x)		MUTEX_EXIT(x)
-#  endif
-#  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))
-#  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	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)
-#  define	SLEEP(id, n)	{ lock_t *_l = get_sleep_lock((caddr_t)id); \
-				  sleep(id, PZERO+1); \
-				  spinunlock(_l); \
-				}
-#  define	WAKEUP(id,x)	{ lock_t *_l = get_sleep_lock((caddr_t)id); \
-				  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)))
-#  define	KFREES(x,s)	kmem_free((char *)(x), (s))
-#  define	MSGDSIZE(x)	msgdsize(x)
-#  define	M_LEN(x)	((x)->b_wptr - (x)->b_rptr)
-#  define	M_DUPLICATE(x)	dupmsg((x))
-#  define	MTOD(m,t)	((t)((m)->b_rptr))
-#  define	MTYPE(m)	((m)->b_datap->db_type)
-#  define	FREE_MB_T(m)	freemsg(m)
-#  define	m_next		b_cont
-#  define	IPF_PANIC(x,y)	if (x) { printf y; panic("ipf_panic"); }
-typedef mblk_t mb_t;
-
-#  define	CACHE_HASH(x)	(((qpktinfo_t *)(x)->fin_qpi)->qpi_num & 7)
-
-#  include "qif.h"
-#  include "pfil.h"
-
-# else /* _KERNEL */
-
-typedef	unsigned char uchar_t;
-
-#  ifndef	_SYS_STREAM_INCLUDED
-typedef char * mblk_t;
-typedef void * queue_t;
-typedef	u_long ulong;
-#  endif
-#  include <netinet/ip_info.h>
-
-# endif /* _KERNEL */
-
-# ifdef lint
-#  define ALIGN32(ptr)    (ptr ? 0L : 0L)
-#  define ALIGN16(ptr)    (ptr ? 0L : 0L)
-# else
-#  define ALIGN32(ptr)    (ptr)
-#  define ALIGN16(ptr)    (ptr)
-# endif
-
-typedef	struct uio	uio_t;
-typedef	int		ioctlcmd_t;
-typedef	int		minor_t;
-typedef unsigned int	u_32_t;
-# define	U_32_T	1
-
-# define OS_RECOGNISED 1
-
-#endif /* __hpux */
-
-/* ----------------------------------------------------------------------- */
-/*                                  I R I X                                */
-/* ----------------------------------------------------------------------- */
-#ifdef __sgi
-# undef		MENTAT
-# if IRIX < 60500
-typedef	struct uio	uio_t;
-# endif
-typedef	int		ioctlcmd_t;
-typedef u_int32_t       u_32_t;
-# define	U_32_T	1
-
-# ifdef INET6
-#  define USE_INET6
-# endif
-
-# define  hz HZ
-# include <sys/ksynch.h>
-# define	IPF_LOCK_PL	plhi
-# include <sys/sema.h>
-# undef kmutex_t
-typedef struct {
-	lock_t *l;
-	int pl;
-} kmutex_t;
-
-# ifdef MUTEX_INIT
-#  define	KMUTEX_T		mutex_t
-# else
-#  define	KMUTEX_T		kmutex_t
-#  define	KRWLOCK_T		kmutex_t
-# endif
-
-# ifdef _KERNEL
-#  define	NEED_LOCAL_RAND	1
-#  define	ipf_random		arc4random
-#  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	USE_MUTEXES
-#  ifdef MUTEX_INIT
-#   include <sys/atomic_ops.h>
-#   define	ATOMIC_INCL(x)		atomicAddUlong(&(x), 1)
-#   define	ATOMIC_INC64(x)		atomicAddUint64(&(x), 1)
-#   define	ATOMIC_INC32(x)		atomicAddUint(&(x), 1)
-#   define	ATOMIC_INC16		ATOMIC_INC
-#   define	ATOMIC_DECL(x)		atomicAddUlong(&(x), -1)
-#   define	ATOMIC_DEC64(x)		atomicAddUint64(&(x), -1)
-#   define	ATOMIC_DEC32(x)		atomicAddUint(&(x), -1)
-#   define	ATOMIC_DEC16		ATOMIC_DEC
-#   undef	MUTEX_INIT
-#   define	MUTEX_INIT(x, y)	mutex_init(&(x)->ipf_lk,  \
-						   MUTEX_DEFAULT, y)
-#   undef	MUTEX_ENTER
-#   define	MUTEX_ENTER(x)		mutex_lock(&(x)->ipf_lk, 0)
-#   undef	MUTEX_EXIT
-#   define	MUTEX_EXIT(x)		mutex_unlock(&(x)->ipf_lk)
-#   undef	MUTEX_DESTROY
-#   define	MUTEX_DESTROY(x)	mutex_destroy(&(x)->ipf_lk)
-#   define	MUTEX_DOWNGRADE(x)	mrdemote(&(x)->ipf_lk)
-#   define	KRWLOCK_T		mrlock_t
-#   define	RWLOCK_INIT(x, y)	mrinit(&(x)->ipf_lk, y)
-#   undef	RW_DESTROY
-#   define	RW_DESTROY(x)		mrfree(&(x)->ipf_lk)
-#   define	READ_ENTER(x)		RW_RDLOCK(&(x)->ipf_lk)
-#   define	WRITE_ENTER(x)		RW_WRLOCK(&(x)->ipf_lk)
-#   define	RWLOCK_EXIT(x)		RW_UNLOCK(&(x)->ipf_lk)
-#  else
-#   define	READ_ENTER(x)		MUTEX_ENTER(&(x)->ipf_lk)
-#   define	WRITE_ENTER(x)		MUTEX_ENTER(&(x)->ipf_lk)
-#   define	MUTEX_DOWNGRADE(x)	;
-#   define	RWLOCK_EXIT(x)		MUTEX_EXIT(&(x)->ipf_lk)
-#   define	MUTEX_EXIT(x)		UNLOCK((x)->ipf_lk.l, (x)->ipf_lk.pl);
-#   define	MUTEX_INIT(x,y)		(x)->ipf_lk.l = LOCK_ALLOC((uchar_t)-1, IPF_LOCK_PL, (lkinfo_t *)-1, KM_NOSLEEP)
-#   define	MUTEX_DESTROY(x)	LOCK_DEALLOC((x)->ipf_lk.l)
-#   define	MUTEX_ENTER(x)		(x)->ipf_lk.pl = LOCK((x)->ipf_lk.l, \
-							      IPF_LOCK_PL);
-#  endif
-#  define	MUTEX_NUKE(x)		bzero((x), sizeof(*(x)))
-#  define	FREE_MB_T(m)	m_freem(m)
-#  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	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)
-#  include <sys/kmem.h>
-#  include <sys/ddi.h>
-#  define	KMALLOC(a,b)	(a) = (b)kmem_alloc(sizeof(*(a)), KM_NOSLEEP)
-#  define	KMALLOCS(a,b,c)	(a) = (b)kmem_alloc((c), KM_NOSLEEP)
-#  define	GET_MINOR(x)	getminor(x)
-#  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));
-#  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)	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"); }
-typedef struct mbuf mb_t;
-# else
-#  undef RW_DESTROY
-#  undef MUTEX_INIT
-#  undef MUTEX_DESTROY
-# endif /* _KERNEL */
-
-# define OS_RECOGNISED 1
-
-#endif /* __sgi */
-
-/* ----------------------------------------------------------------------- */
-/*                                  T R U 6 4                              */
-/* ----------------------------------------------------------------------- */
-#ifdef __osf__
-# undef		MENTAT
-
-# include <kern/lock.h>
-# include <sys/sysmacros.h>
-
-# ifdef _KERNEL
-#  define	NEED_LOCAL_RAND		1
-#  define	ipf_random		arc4random
-#  define	KMUTEX_T		simple_lock_data_t
-#  define	KRWLOCK_T		lock_data_t
-#  include <net/net_globals.h>
-#  define	USE_MUTEXES
-#  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_init(&(x)->ipf_lk, TRUE)
-#  define	RWLOCK_EXIT(x)		lock_done(&(x)->ipf_lk)
-#  define	RW_DESTROY(x)		lock_terminate(&(x)->ipf_lk)
-#  define	MUTEX_ENTER(x)		simple_lock(&(x)->ipf_lk)
-#  define	MUTEX_INIT(x, y)	simple_lock_init(&(x)->ipf_lk)
-#  define	MUTEX_DESTROY(x)	simple_lock_terminate(&(x)->ipf_lk)
-#  define	MUTEX_EXIT(x)		simple_unlock(&(x)->ipf_lk)
-#  define	MUTEX_NUKE(x)		bzero(x, sizeof(*(x)))
-#  define	ATOMIC_INC64(x)		atomic_incq((uint64_t*)&(x))
-#  define	ATOMIC_DEC64(x)		atomic_decq((uint64_t*)&(x))
-#  define	ATOMIC_INC32(x)		atomic_incl((uint32_t*)&(x))
-#  define	ATOMIC_DEC32(x)		atomic_decl((uint32_t*)&(x))
-#  define	ATOMIC_INC16(x)		{ simple_lock(&ipf_rw); (x)++; \
-					  simple_unlock(&ipf_rw); }
-#  define	ATOMIC_DEC16(x)		{ simple_lock(&ipf_rw); (x)--; \
-					  simple_unlock(&ipf_rw); }
-#  define	ATOMIC_INCL(x)		atomic_incl((uint32_t*)&(x))
-#  define	ATOMIC_DECL(x)		atomic_decl((uint32_t*)&(x))
-#  define	ATOMIC_INC(x)		{ simple_lock(&ipf_rw); (x)++; \
-					  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
-#  define	SPL_X(x)		;
-#  define	UIOMOVE(a,b,c,d)	uiomove((caddr_t)a, b, d)
-#  define	FREE_MB_T(m)		m_freem(m)
-#  define	MTOD(m,t)		mtod(m,t)
-#  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	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)
-#  define	KFREE(x)	FREE((x), M_PFILT)
-#  define	KFREES(x,s)	FREE((x), M_PFILT)
-#  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)	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"); }
-typedef struct mbuf mb_t;
-# endif /* _KERNEL */
-
-# if (defined(_KERNEL) || defined(_NO_BITFIELDS) || (__STDC__ == 1))
-#  define	IP_V(x)		((x)->ip_vhl >> 4)
-#  define	IP_HL(x)	((x)->ip_vhl & 0xf)
-#  define	IP_V_A(x,y)	(x)->ip_vhl |= (((y) << 4) & 0xf0)
-#  define	IP_HL_A(x,y)	(x)->ip_vhl |= ((y) & 0xf)
-#  define	TCP_X2(x)	((x)->th_xoff & 0xf)
-#  define	TCP_X2_A(x,y)	(x)->th_xoff |= ((y) & 0xf)
-#  define	TCP_OFF(x)	((x)->th_xoff >> 4)
-#  define	TCP_OFF_A(x,y)	(x)->th_xoff |= (((y) << 4) & 0xf0)
-# endif
-
-/*
- * These are from's Solaris' #defines for little endian.
- */
-#define	IP6F_MORE_FRAG		0x0100
-#define	IP6F_RESERVED_MASK	0x0600
-#define	IP6F_OFF_MASK		0xf8ff
-
-struct ip6_ext {
-	u_char	ip6e_nxt;
-	u_char	ip6e_len;
-};
-
-typedef	int		ioctlcmd_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 /* __osf__ */
-
-/* ----------------------------------------------------------------------- */
-/*                                  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)
-#   include "opt_inet.h"
-#  endif
-#  ifdef INET6
-#   define USE_INET6
-#  endif
-#  if (__NetBSD_Version__ >= 105000000)
-#   define HAVE_M_PULLDOWN 1
-#  endif
-# endif
-
-# if (__NetBSD_Version__ >= 499000000)
-typedef	char *	caddr_t;
-# endif
-
-# define	ipf_random	arc4random
-
-# 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)
-#  define	GETKTIME(x)	microtime((struct timeval *)x)
-#  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))
-typedef struct mbuf mb_t;
-# endif /* _KERNEL */
-# if (NetBSD <= 1991011) && (NetBSD >= 199606)
-#  define	IFNAME(x)	((struct ifnet *)x)->if_xname
-#  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;
-typedef	u_int32_t	u_32_t;
-# define	U_32_T	1
-
-# define OS_RECOGNISED 1
-#endif /* __NetBSD__ */
-
-
-/* ----------------------------------------------------------------------- */
 /*                                F R E E B S D                            */
 /* ----------------------------------------------------------------------- */
-#ifdef __FreeBSD__
-# if  (__FreeBSD_version < 400000)
-#  define	NEED_LOCAL_RAND	1
-# else
-#  define	ipf_random	arc4random
-# endif
+# define HAS_SYS_MD5_H	1
 # if defined(_KERNEL)
-#  if (__FreeBSD_version >= 500000)                          
 #   include "opt_bpf.h"
-#  else
-#   include "bpf.h"    
-#  endif
-#  if defined(__FreeBSD_version) && (__FreeBSD_version >= 400000)
 #   include "opt_inet6.h"
-#  endif
 #  if defined(INET6) && !defined(USE_INET6)
 #   define USE_INET6
 #  endif
+# else
+#  if !defined(USE_INET6) && !defined(NOINET6)
+#   define	USE_INET6
+#  endif
 # endif
 
 # if defined(_KERNEL)
-#  if (__FreeBSD_version >= 400000)
+#  include <netinet/ip_var.h>
+#    define	p_cred	td_ucred
+#    define	p_uid	td_ucred->cr_ruid
+
 /*
  * When #define'd, the 5.2.1 kernel panics when used with the ftp proxy.
  * There may be other, safe, kernels but this is not extensively tested yet.
  */
 #   define HAVE_M_PULLDOWN
-#  endif
 #  if !defined(IPFILTER_LKM) && (__FreeBSD_version >= 300000)
 #   include "opt_ipfilter.h"
 #  endif
@@ -862,70 +147,33 @@
 #  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 (__FreeBSD_version >= 500043)
 #   define NETBSD_PF
-#  endif
+# else
+#  include <inttypes.h>
 # endif /* _KERNEL */
 
-# if (__FreeBSD_version >= 500043)
+#  include <sys/selinfo.h>
 #  include <sys/mutex.h>
-#  if (__FreeBSD_version > 700014)
+#    define	KRWLOCK_FILL_SZ		56
+#    define	KMUTEX_FILL_SZ		56
 #   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 { \
+#   define	KMUTEX_T		struct mtx
+#   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	MUTEX_TRY_UPGRADE(x)	rw_try_upgrade(&(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_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.
- */
-#   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(v, x, b) \
@@ -932,25 +180,14 @@
 				(void) strncpy(b, \
 					       ((struct ifnet *)x)->if_xname, \
 					       LIFNAMSIZ)
-# endif
-# 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
 
 # ifdef _KERNEL
 #  define	GETKTIME(x)	microtime((struct timeval *)x)
 
-#  if (__FreeBSD_version >= 500002)
 #   include <netinet/in_systm.h>
 #   include <netinet/ip.h>
 #   include <machine/in_cksum.h>
-#  endif
 
-#  if (__FreeBSD_version >= 500043)
 #   define	USE_MUTEXES
 #   define	MUTEX_ENTER(x)		mtx_lock(&(x)->ipf_lk)
 #   define	MUTEX_EXIT(x)		mtx_unlock(&(x)->ipf_lk)
@@ -958,460 +195,47 @@
 						 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.
+ */
 #   include <machine/atomic.h>
-#   define	ATOMIC_INC(x)		{ mtx_lock(&ipf_rw.ipf_lk); (x)++; \
-					  mtx_unlock(&ipf_rw.ipf_lk); }
-#   define	ATOMIC_DEC(x)		{ mtx_lock(&ipf_rw.ipf_lk); (x)--; \
-					  mtx_unlock(&ipf_rw.ipf_lk); }
+#   define	ATOMIC_INC(x)		{ mtx_lock(&softc->ipf_rw.ipf_lk); (x)++; \
+					  mtx_unlock(&softc->ipf_rw.ipf_lk); }
+#   define	ATOMIC_DEC(x)		{ mtx_lock(&softc->ipf_rw.ipf_lk); (x)--; \
+					  mtx_unlock(&softc->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((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((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)	;
-#  else
-#   define	SPL_SCHED(x)	x = splhigh()
-#  endif /* __FreeBSD_version >= 500043 */
-#  define	MSGDSIZE(x)	mbufchainlen(x)
-#  define	M_LEN(x)	(x)->m_len
-#  define	M_DUPLICATE(x)	m_copy((x), 0, M_COPYALL)
+#   define	GET_MINOR		dev2unit
+#  define	MSGDSIZE(m)	mbufchainlen(m)
+#  define	M_LEN(m)	(m)->m_len
+#  define	M_ADJ(m,x)	m_adj(m, x)
+#  define	M_COPY(x)	m_copy((x), 0, M_COPYALL)
+#  define	M_DUP(m)	m_dup(m, M_NOWAIT)
 #  define	IPF_PANIC(x,y)	if (x) { printf y; panic("ipf_panic"); }
 typedef struct mbuf mb_t;
 # endif /* _KERNEL */
 
-# if __FreeBSD__ < 3
-#  include <machine/spl.h>
-# else
-#  if __FreeBSD__ == 3
-#   if defined(IPFILTER_LKM) && !defined(ACTUALLY_LKM_NOT_KERNEL)
-#    define	ACTUALLY_LKM_NOT_KERNEL
-#   endif
-#  endif
-# endif
 
-# if (__FreeBSD_version >= 300000)
 typedef	u_long		ioctlcmd_t;
-# else
-typedef	int		ioctlcmd_t;
-# endif
 typedef	struct uio	uio_t;
 typedef	int		minor_t;
 typedef	u_int32_t	u_32_t;
 # define	U_32_T	1
 
-# define OS_RECOGNISED 1
-#endif /* __FreeBSD__ */
 
-
 /* ----------------------------------------------------------------------- */
-/*                                O P E N B S D                            */
-/* ----------------------------------------------------------------------- */
-#ifdef __OpenBSD__
-# ifdef INET6
-#  define USE_INET6
-# endif
-
-# ifdef _KERNEL
-#  if !defined(IPFILTER_LKM)
-#   include "bpfilter.h"
-#  endif
-#  if (OpenBSD >= 200311)
-#   define SNPRINTF	snprintf
-#   if defined(USE_INET6)
-#    include "netinet6/in6_var.h"
-#    include "netinet6/nd6.h"
-#   endif
-#  endif
-#  if (OpenBSD >= 200012)
-#   define HAVE_M_PULLDOWN 1
-#  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	GETKTIME(x)	microtime((struct timeval *)x)
-#  define	MSGDSIZE(x)	mbufchainlen(x)
-#  define	M_LEN(x)	(x)->m_len
-#  define	M_DUPLICATE(x)	m_copy((x), 0, M_COPYALL)
-#  define	IPF_PANIC(x,y)	if (x) { printf y; panic("ipf_panic"); }
-typedef struct mbuf mb_t;
-# endif /* _KERNEL */
-# if (OpenBSD >= 199603)
-#  define	IFNAME(x, b)	((struct ifnet *)x)->if_xname
-#  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
-
-typedef	struct uio	uio_t;
-typedef	u_long		ioctlcmd_t;  
-typedef	int		minor_t;
-typedef	u_int32_t	u_32_t;
-# define	U_32_T	1
-
-# define OS_RECOGNISED 1
-#endif /* __OpenBSD__ */
-
-
-/* ----------------------------------------------------------------------- */
-/*                                B S D O S                                */
-/* ----------------------------------------------------------------------- */
-#ifdef _BSDI_VERSION
-# ifdef INET6
-#  define USE_INET6
-# endif
-
-# ifdef _KERNEL
-#  define	GETKTIME(x)	microtime((struct timeval *)x)
-#  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;
-# endif /* _KERNEL */
-
-# if (_BSDI_VERSION >= 199701)
-typedef	u_long		ioctlcmd_t;
-# else
-typedef	int		ioctlcmd_t;
-# endif
-typedef	u_int32_t	u_32_t;
-# define	U_32_T	1
-
-#endif /* _BSDI_VERSION */
-
-
-/* ----------------------------------------------------------------------- */
-/*                                  S U N O S 4                            */
-/* ----------------------------------------------------------------------- */
-#if defined(sun) && !defined(OS_RECOGNISED) /* SunOS4 */
-# ifdef _KERNEL
-#  include	<sys/kmem_alloc.h>
-#  define	GETKTIME(x)	uniqtime((struct timeval *)x)
-#  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)
-#  define	KFREE(x)	kmem_free((char *)(x), sizeof(*(x)))
-#  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"); }
-
-extern	void	m_copydata __P((struct mbuf *, int, int, caddr_t));
-extern	void	m_copyback __P((struct mbuf *, int, int, caddr_t));
-
-typedef struct mbuf mb_t;
-# endif
-
-typedef	struct uio	uio_t;
-typedef	int		ioctlcmd_t;  
-typedef	int		minor_t;
-typedef	unsigned int	u_32_t;
-# define	U_32_T	1
-
-# define OS_RECOGNISED 1
-
-#endif /* SunOS 4 */
-
-/* ----------------------------------------------------------------------- */
-/*                            L I N U X                                    */
-/* ----------------------------------------------------------------------- */
-#if defined(linux) && !defined(OS_RECOGNISED)
-#include <linux/config.h>
-#include <linux/version.h>
-# if (LINUX >= 20600) && defined(_KERNEL)
-#  define	 HDR_T_PRIVATE	1
-# endif
-# undef USE_INET6
-# ifdef USE_INET6
-struct ip6_ext {
-	u_char	ip6e_nxt;
-	u_char	ip6e_len;
-};
-# endif
-
-# ifdef _KERNEL
-#  define	IPF_PANIC(x,y)	if (x) { printf y; panic("ipf_panic"); }
-#  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	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
-#  define	MUTEX_INIT(x,y)		spin_lock_init(&(x)->ipf_lk)
-#  define	MUTEX_ENTER(x)		spin_lock(&(x)->ipf_lk)
-#  define	MUTEX_EXIT(x)		spin_unlock(&(x)->ipf_lk)
-#  define	MUTEX_DESTROY(x)	do { } while (0)
-#  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)	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)
-#  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_INC64(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_INC16(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_DEC32(x)		MUTEX_ENTER(&ipf_rw); (x)--; \
-					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)
-#  define	IFNAME(x)		((struct net_device*)x)->name
-#  define	CACHE_HASH(x)	((IFNAME(fin->fin_ifp)[0] + \
-			  ((struct net_device *)fin->fin_ifp)->ifindex) & 7)
-typedef	struct	sk_buff	mb_t;
-extern	void	m_copydata __P((mb_t *, int, int, caddr_t));
-extern	void	m_copyback __P((mb_t *, int, int, caddr_t));
-extern	void	m_adj __P((mb_t *, int));
-extern	mb_t	*m_pullup __P((mb_t *, int));
-#  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 : \
-								GFP_KERNEL)
-#  define	MSGDSIZE(m)	(m)->len
-#  define	M_LEN(m)	(m)->len
-
-#  define	splnet(x)	;
-#  define	printf		printk
-#  define	bcopy(s,d,z)	memmove(d, s, z)
-#  define	bzero(s,z)	memset(s, 0, z)
-#  define	bcmp(a,b,z)	memcmp(a, b, z)
-
-#  define	ifnet		net_device
-#  define	if_xname	name
-#  define	if_unit		ifindex 
-
-#  define	KMALLOC(x,t)	(x) = (t)kmalloc(sizeof(*(x)), \
-				    in_interrupt() ? GFP_ATOMIC : GFP_KERNEL)
-#  define	KFREE(x)	kfree(x)
-#  define	KMALLOCS(x,t,s)	(x) = (t)kmalloc((s), \
-				    in_interrupt() ? GFP_ATOMIC : GFP_KERNEL)
-#  define	KFREES(x,s)	kfree(x)
-
-#  define GETIFP(n,v)	dev_get_by_name(n)
-
-# else
-#  include <net/ethernet.h>
-
-struct mbuf {
-};
-
-#  ifndef _NET_ROUTE_H
-struct rtentry {
-};
-#  endif
-
-struct ifnet {
-	char	if_xname[IFNAMSIZ];
-	int	if_unit;
-	int	(* if_output) __P((struct ifnet *, struct mbuf *, struct sockaddr *, struct rtentry *));
-	struct	ifaddr	*if_addrlist;
-};
-# define	IFNAME(x)	((struct ifnet *)x)->if_xname
-
-# endif	/* _KERNEL */
-
-# define	COPYIFNAME(v, x, b) \
-				(void) strncpy(b, \
-					       ((struct ifnet *)x)->if_xname, \
-					       LIFNAMSIZ)
-
-# include <linux/fs.h>
-# define	FWRITE	FMODE_WRITE
-# define	FREAD	FMODE_READ
-
-# define	__USE_MISC	1
-# define	__FAVOR_BSD	1
-
-typedef	struct uio {
-	struct iovec	*uio_iov;
-	void	*uio_file;
-	char	*uio_buf;
-	int	uio_iovcnt;
-	int	uio_offset;
-	size_t	uio_resid;
-	int	uio_rw;
-} uio_t;
-
-extern	int	uiomove __P((caddr_t, size_t, int, struct uio *));
-
-# define	UIO_READ	1
-# define	UIO_WRITE	2
-
-typedef	u_long		ioctlcmd_t;
-typedef	int		minor_t;
-typedef u_int32_t 	u_32_t;
-# define	U_32_T	1
-
-# define OS_RECOGNISED 1
-
-#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
-
-
-/* ----------------------------------------------------------------------- */
 /*                           G E N E R I C                                 */
 /* ----------------------------------------------------------------------- */
-#ifndef OS_RECOGNISED
-#endif
 
 /*
  * For BSD kernels, if bpf is in the kernel, enable ipfilter to use bpf in
@@ -1427,6 +251,15 @@
 /*
  * Userland locking primitives
  */
+#ifndef _KERNEL
+#if !defined(KMUTEX_FILL_SZ)
+# define	KMUTEX_FILL_SZ	1
+#endif
+#if !defined(KRWLOCK_FILL_SZ)
+# define	KRWLOCK_FILL_SZ	1
+#endif
+#endif
+
 typedef	struct	{
 	char	*eMm_owner;
 	char	*eMm_heldin;
@@ -1433,9 +266,6 @@
 	u_int	eMm_magic;
 	int	eMm_held;
 	int	eMm_heldat;
-#if defined(__hpux) || defined(__linux)
-	char	eMm_fill[8];
-#endif
 } eMmutex_t;
 
 typedef	struct	{
@@ -1445,16 +275,14 @@
 	short	eMrw_read;
 	short	eMrw_write;
 	int	eMrw_heldat;
-#ifdef __hpux
-	char	eMm_fill[24];
-#endif
 } eMrwlock_t;
 
 typedef union {
+	char	_fill[KMUTEX_FILL_SZ];
 #ifdef KMUTEX_T
 	struct	{
 		KMUTEX_T	ipf_slk;
-		char		*ipf_lname;
+		const char	*ipf_lname;
 	} ipf_lkun_s;
 #endif
 	eMmutex_t	ipf_emu;
@@ -1461,10 +289,11 @@
 } ipfmutex_t;
 
 typedef union {
+	char	_fill[KRWLOCK_FILL_SZ];
 #ifdef KRWLOCK_T
 	struct	{
 		KRWLOCK_T	ipf_slk;
-		char		*ipf_lname;
+		const char	*ipf_lname;
 		int		ipf_sr;
 		int		ipf_sw;
 		u_int		ipf_magic;
@@ -1488,14 +317,12 @@
 # define	INLINE	__inline__
 #endif
 
-#if defined(linux) && defined(_KERNEL)
-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 *));
+#if defined(__FreeBSD_version) && defined(_KERNEL)
+     CTASSERT(sizeof(ipfrwlock_t) == KRWLOCK_FILL_SZ);
+     CTASSERT(sizeof(ipfmutex_t) == KMUTEX_FILL_SZ);
 #endif
 
+
 /*
  * In a non-kernel environment, there are a lot of macros that need to be
  * filled in to be null-ops or to point to some compatibility function,
@@ -1504,18 +331,40 @@
 #ifndef _KERNEL
 typedef	struct	mb_s	{
 	struct	mb_s	*mb_next;
+	char		*mb_data;
+	void		*mb_ifp;
 	int		mb_len;
+	int		mb_flags;
 	u_long		mb_buf[2048];
 } mb_t;
 # undef		m_next
 # define	m_next		mb_next
-# define	MSGDSIZE(x)	(x)->mb_len	/* XXX - from ipt.c */
-# define	M_LEN(x)	(x)->mb_len
-# define	M_DUPLICATE(x)	(x)
+# undef		m_len
+# define	m_len		mb_len
+# undef		m_flags
+# define	m_flags		mb_flags
+# undef		m_data
+# define	m_data		mb_data
+# undef		M_MCAST
+# define	M_MCAST		0x01
+# undef		M_BCAST
+# define	M_BCAST		0x02
+# undef		M_MBCAST
+# define	M_MBCAST	0x04
+# define	MSGDSIZE(m)	msgdsize(m)
+# define	M_LEN(m)	(m)->mb_len
+# define	M_ADJ(m,x)	(m)->mb_len += x
+# define	M_COPY(m)	dupmbt(m)
+# define	M_DUP(m)	dupmbt(m)
 # define	GETKTIME(x)	gettimeofday((struct timeval *)(x), NULL)
-# undef		MTOD
-# define	MTOD(m, t)	((t)(m)->mb_buf)
-# define	FREE_MB_T(x)
+# define	MTOD(m, t)	((t)(m)->mb_data)
+# define	FREE_MB_T(m)	freembt(m)
+# define	ALLOC_MB_T(m,l)	(m) = allocmbt(l)
+# define	PREP_MB_T(f, m)	do { \
+						(m)->mb_next = *(f)->fin_mp; \
+						*(fin)->fin_mp = (m); \
+						(f)->fin_m = (m); \
+					} while (0)
 # define	SLEEP(x,y)	1;
 # define	WAKEUP(x,y)	;
 # define	POLLWAKEUP(y)	;
@@ -1530,6 +379,8 @@
 # define	KFREE(x)	free(x)
 # define	KFREES(x,s)	free(x)
 # define	GETIFP(x, v)	get_unit(x,v)
+# define	GETIFMTU_4(x)	2048
+# define	GETIFMTU_6(x)	2048
 # 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), \
@@ -1541,20 +392,24 @@
 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)
-# endif
+extern	mb_t	*allocmbt __P((size_t));
+extern	mb_t	*dupmbt __P((mb_t *));
+extern	void	freembt __P((mb_t *));
 
-# define	MUTEX_DESTROY(x)	eMmutex_destroy(&(x)->ipf_emu)
+# define	MUTEX_DESTROY(x)	eMmutex_destroy(&(x)->ipf_emu, \
+							__FILE__, __LINE__)
 # define	MUTEX_ENTER(x)		eMmutex_enter(&(x)->ipf_emu, \
 						      __FILE__, __LINE__)
-# define	MUTEX_EXIT(x)		eMmutex_exit(&(x)->ipf_emu)
-# define	MUTEX_INIT(x,y)		eMmutex_init(&(x)->ipf_emu, y)
+# define	MUTEX_EXIT(x)		eMmutex_exit(&(x)->ipf_emu, \
+						     __FILE__, __LINE__)
+# define	MUTEX_INIT(x,y)		eMmutex_init(&(x)->ipf_emu, y, \
+						     __FILE__, __LINE__)
 # define	MUTEX_NUKE(x)		bzero((x), sizeof(*(x)))
 
 # define	MUTEX_DOWNGRADE(x)	eMrwlock_downgrade(&(x)->ipf_emu, \
 							   __FILE__, __LINE__)
+# define	MUTEX_TRY_UPGRADE(x)	eMrwlock_try_upgrade(&(x)->ipf_emu, \
+							   __FILE__, __LINE__)
 # define	READ_ENTER(x)		eMrwlock_read_enter(&(x)->ipf_emu, \
 							    __FILE__, __LINE__)
 # define	RWLOCK_INIT(x, y)	eMrwlock_init(&(x)->ipf_emu, y)
@@ -1566,10 +421,10 @@
 
 # define	USE_MUTEXES		1
 
-extern void eMmutex_destroy __P((eMmutex_t *));
+extern void eMmutex_destroy __P((eMmutex_t *, char *, int));
 extern void eMmutex_enter __P((eMmutex_t *, char *, int));
-extern void eMmutex_exit __P((eMmutex_t *));
-extern void eMmutex_init __P((eMmutex_t *, char *));
+extern void eMmutex_exit __P((eMmutex_t *, char *, int));
+extern void eMmutex_init __P((eMmutex_t *, char *, char *, int));
 extern void eMrwlock_destroy __P((eMrwlock_t *));
 extern void eMrwlock_exit __P((eMrwlock_t *));
 extern void eMrwlock_init __P((eMrwlock_t *, char *));
@@ -1579,6 +434,8 @@
 
 #endif
 
+extern	mb_t	*allocmbt(size_t);
+
 #define	MAX_IPV4HDR	((0xf << 2) + sizeof(struct icmp) + sizeof(ip_t) + 8)
 
 #ifndef	IP_OFFMASK
@@ -1590,13 +447,15 @@
  * On BSD's use quad_t as a guarantee for getting at least a 64bit sized
  * object.
  */
-#if (BSD > 199306)
+#if !defined(__amd64__) && BSD_GT_YEAR(199306)
 # define	USE_QUAD_T
 # define	U_QUAD_T	unsigned long long
 # define	QUAD_T		long long
 #else /* BSD > 199306 */
-# define	U_QUAD_T	u_long
-# define	QUAD_T		long
+# if !defined(U_QUAD_T)
+#  define	U_QUAD_T	u_long
+#  define	QUAD_T		long
+# endif
 #endif /* BSD > 199306 */
 
 
@@ -1605,11 +464,9 @@
      defined(__osf__) || defined(linux)
 #  include <netinet/ip6.h>
 #  include <netinet/icmp6.h>
-#  if !defined(linux)
 #   if defined(_KERNEL) && !defined(__osf__)
 #    include <netinet6/ip6_var.h>
 #   endif
-#  endif
 typedef	struct ip6_hdr	ip6_t;
 # endif
 #endif
@@ -1619,7 +476,7 @@
 #endif
 
 #if defined(_KERNEL)
-# ifdef MENTAT
+# if defined(MENTAT) && !defined(INSTANCES)
 #  define	COPYDATA	mb_copydata
 #  define	COPYBACK	mb_copyback
 # else
@@ -1626,16 +483,13 @@
 #  define	COPYDATA	m_copydata
 #  define	COPYBACK	m_copyback
 # endif
-# if (BSD >= 199306) || defined(__FreeBSD__)
 #  if (defined(__NetBSD_Version__) && (__NetBSD_Version__ < 105180000)) || \
        defined(__FreeBSD__) || (defined(OpenBSD) && (OpenBSD < 200206)) || \
        defined(_BSDI_VERSION)
 #   include <vm/vm.h>
 #  endif
-#  if !defined(__FreeBSD__) || (defined (__FreeBSD_version) && \
-      (__FreeBSD_version >= 300000))
-#   if (defined(__NetBSD_Version__) && (__NetBSD_Version__ >= 105180000)) || \
-       (defined(OpenBSD) && (OpenBSD >= 200111))
+#  if !defined(__FreeBSD__) || FREEBSD_GE_REV(300000)
+#   if NETBSD_GE_REV(105180000) || OPENBSD_GE_REV(200111)
 #    include <uvm/uvm_extern.h>
 #   else
 #    include <vm/vm_extern.h>
@@ -1661,38 +515,31 @@
 #    endif /* M_IPFILTER */
 #   endif /* M_PFIL */
 #  endif /* IPFILTER_M_IPFILTER */
-#  if defined(__FreeBSD__) && __FreeBSD_version >= 800051
-#   define	KMALLOC(a, b)	do {			\
-	a = (b)malloc(sizeof(*(a)), _M_IPF, M_NOWAIT); \
-    } while (0)
-#   define	KMALLOCS(a, b, c)	do { \
-	a = (b)malloc((c), _M_IPF, ((c) > 4096) ? M_WAITOK : M_NOWAIT); \
-    } while (0)
-#   define	KFREE(x)	free((x), _M_IPF)
-#   define	KFREES(x,s)	free((x), _M_IPF)
-#  else
+#  if !defined(KMALLOC)
 #   define	KMALLOC(a, b)	MALLOC((a), b, sizeof(*(a)), _M_IPF, M_NOWAIT)
-#   if !defined(KMALLOCS)
-#    define	KMALLOCS(a, b, c)	MALLOC((a), b, (c), _M_IPF, M_NOWAIT)
-#   endif
+#  endif
+#  if !defined(KMALLOCS)
+#   define	KMALLOCS(a, b, c)	MALLOC((a), b, (c), _M_IPF, M_NOWAIT)
+#  endif
+#  if !defined(KFREE)
 #   define	KFREE(x)	FREE((x), _M_IPF)
-#   define	KFREES(x,s)	FREE((x), _M_IPF)
 #  endif
+#   if !defined(KFREES)
+#  define	KFREES(x,s)	FREE((x), _M_IPF)
+#  endif
 #  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)
+#  if !defined(POLLWAKEUP)
+#   define	POLLWAKEUP(x)	selwakeup(softc->ipf_selwait+x)
+#  endif
 #  define	GETIFP(n, v)	ifunit(n)
-# endif /* (Free)BSD */
+#  define	GETIFMTU_4(x)	((struct ifnet *)x)->if_mtu
+#  define	GETIFMTU_6(x)	((struct ifnet *)x)->if_mtu
 
 # if !defined(USE_MUTEXES) && !defined(SPL_NET)
-#  if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199407)) || \
-      (defined(OpenBSD) && (OpenBSD >= 200006))
-#   define	SPL_NET(x)	x = splsoftnet()
-#  else
-#   define	SPL_IMP(x)	x = splimp()
-#   define	SPL_NET(x)	x = splnet()
-#  endif /* NetBSD && (NetBSD <= 1991011) && (NetBSD >= 199407) */
+#  define	SPL_IMP(x)	x = splimp()
+#  define	SPL_NET(x)	x = splnet()
 #  if !defined(SPL_SCHED)
 #   define	SPL_SCHED(x)	x = splsched()
 #  endif
@@ -1702,6 +549,45 @@
 # ifndef FREE_MB_T
 #  define	FREE_MB_T(m)	m_freem(m)
 # endif
+# ifndef ALLOC_MB_T
+#  ifdef MGETHDR
+#   define	ALLOC_MB_T(m,l)	do { \
+					MGETHDR((m), M_DONTWAIT, MT_HEADER); \
+					if ((m) != NULL) { \
+						(m)->m_len = (l); \
+						(m)->m_pkthdr.len = (l); \
+					} \
+				} while (0)
+#  else
+#   define	ALLOC_MB_T(m,l)	do { \
+					MGET((m), M_DONTWAIT, MT_HEADER); \
+					if ((m) != NULL) { \
+						(m)->m_len = (l); \
+						(m)->m_pkthdr.len = (l); \
+					} \
+				} while (0)
+#  endif
+# endif
+# ifndef PREP_MB_T
+#  define	PREP_MB_T(f, m)	do { \
+						mb_t *_o = *(f)->fin_mp; \
+						(m)->m_next = _o; \
+						*(fin)->fin_mp = (m); \
+						if (_o->m_flags & M_PKTHDR) { \
+							(m)->m_pkthdr.len += \
+							    _o->m_pkthdr.len; \
+							(m)->m_pkthdr.rcvif = \
+							  _o->m_pkthdr.rcvif; \
+						} \
+					} while (0)
+# endif
+# ifndef M_DUP
+#  ifdef M_COPYALL
+#   define	M_DUP(m)	m_dup(m, 0, M_COPYALL, 0)
+#  else
+#   define	M_DUP(m)	m_dup(m)
+#  endif
+# endif
 
 # ifndef MTOD
 #  define	MTOD(m,t)	mtod(m,t)
@@ -1725,13 +611,13 @@
 #endif /* _KERNEL */
 
 #if !defined(IFNAME) && !defined(_KERNEL)
-# define	IFNAME(x)	((struct ifnet *)x)->if_name
+# define	IFNAME(x)	get_ifname((struct ifnet *)x)
 #endif
 #ifndef	COPYIFNAME
 # define	NEED_FRGETIFNAME
-extern	char	*fr_getifname __P((struct ifnet *, char *));
+extern	char	*ipf_getifname __P((struct ifnet *, char *));
 # define	COPYIFNAME(v, x, b) \
-				fr_getifname((struct ifnet *)x, b)
+				ipf_getifname((struct ifnet *)x, b)
 #endif
 
 #ifndef ASSERT
@@ -1753,9 +639,7 @@
  */
 #define	ISALNUM(x)	isalnum((u_char)(x))
 #define	ISALPHA(x)	isalpha((u_char)(x))
-#define	ISASCII(x)	isascii((u_char)(x))
 #define	ISDIGIT(x)	isdigit((u_char)(x))
-#define	ISPRINT(x)	isprint((u_char)(x))
 #define	ISSPACE(x)	isspace((u_char)(x))
 #define	ISUPPER(x)	isupper((u_char)(x))
 #define	ISXDIGIT(x)	isxdigit((u_char)(x))
@@ -1776,6 +660,7 @@
 # define	READ_ENTER(x)		;
 # define	WRITE_ENTER(x)		;
 # define	MUTEX_DOWNGRADE(x)	;
+# define	MUTEX_TRY_UPGRADE(x)	;
 # define	RWLOCK_INIT(x, y)	;
 # define	RWLOCK_EXIT(x)		;
 # define	RW_DESTROY(x)		;
@@ -1803,11 +688,9 @@
 # define	ATOMIC_INCL		ATOMIC_INC
 # define	ATOMIC_INC64		ATOMIC_INC
 # define	ATOMIC_INC32		ATOMIC_INC
-# define	ATOMIC_INC16		ATOMIC_INC
 # define	ATOMIC_DECL		ATOMIC_DEC
 # define	ATOMIC_DEC64		ATOMIC_DEC
 # define	ATOMIC_DEC32		ATOMIC_DEC
-# define	ATOMIC_DEC16		ATOMIC_DEC
 #endif
 
 #ifndef HDR_T_PRIVATE
@@ -1824,8 +707,11 @@
 #endif
 
 #ifndef offsetof
-# define offsetof(t,m) (int)((&((t *)0L)->m))
+# define offsetof(t,m) (size_t)((&((t *)0L)->m))
 #endif
+#ifndef stsizeof
+# define stsizeof(t,m)	sizeof(((t *)0L)->m)
+#endif
 
 /*
  * This set of macros has been brought about because on Tru64 it is not
@@ -1871,9 +757,9 @@
 #define	TCPF_ALL	(TH_FIN|TH_SYN|TH_RST|TH_PUSH|TH_ACK|TH_URG|\
 			 TH_ECN|TH_CWR)
 
-#if (BSD >= 199306) && !defined(m_act)
+#if BSD_GE_YEAR(199306) && !defined(m_act)
 # define	m_act	m_nextpkt
-#endif  
+#endif
 
 /*
  * Security Options for Intenet Protocol (IPSO) as defined in RFC 1108.
@@ -1910,7 +796,7 @@
  * IP option #defines
  */
 #undef	IPOPT_RR
-#define	IPOPT_RR	7 
+#define	IPOPT_RR	7
 #undef	IPOPT_ZSU
 #define	IPOPT_ZSU	10	/* ZSU */
 #undef	IPOPT_MTUP
@@ -1958,6 +844,8 @@
 #define	IPOPT_UMP	152
 #undef	IPOPT_FINN
 #define	IPOPT_FINN	205	/* FINN */
+#undef	IPOPT_AH
+#define	IPOPT_AH	256+IPPROTO_AH
 
 #ifndef TCPOPT_EOL
 # define TCPOPT_EOL		0
@@ -2236,8 +1124,11 @@
 #ifndef	IPPROTO_HOPOPTS
 # define	IPPROTO_HOPOPTS	0
 #endif
+#ifndef	IPPROTO_IPIP
+# define	IPPROTO_IPIP	4
+#endif
 #ifndef	IPPROTO_ENCAP
-# define	IPPROTO_ENCAP	4
+# define	IPPROTO_ENCAP	98
 #endif
 #ifndef	IPPROTO_IPV6
 # define	IPPROTO_IPV6	41
@@ -2436,6 +1327,38 @@
 # define	ICMP6_NI_SUBJ_IPV4	2
 #endif
 
+#ifndef	MLD_MTRACE_RESP
+# define	MLD_MTRACE_RESP		200
+#endif
+#ifndef	MLD_MTRACE
+# define	MLD_MTRACE		201
+#endif
+#ifndef	MLD6_MTRACE_RESP
+# define	MLD6_MTRACE_RESP	MLD_MTRACE_RESP
+#endif
+#ifndef	MLD6_MTRACE
+# define	MLD6_MTRACE		MLD_MTRACE
+#endif
+
+#if !defined(IPV6_FLOWINFO_MASK)
+# if (BYTE_ORDER == BIG_ENDIAN) || defined(_BIG_ENDIAN)
+#  define IPV6_FLOWINFO_MASK	0x0fffffff	/* flow info (28 bits) */
+# else
+#  if(BYTE_ORDER == LITTLE_ENDIAN) || !defined(_BIG_ENDIAN)
+#   define IPV6_FLOWINFO_MASK	0xffffff0f	/* flow info (28 bits) */
+#  endif /* LITTLE_ENDIAN */
+# endif
+#endif
+#if !defined(IPV6_FLOWLABEL_MASK)
+# if (BYTE_ORDER == BIG_ENDIAN) || defined(_BIG_ENDIAN)
+#  define IPV6_FLOWLABEL_MASK	0x000fffff	/* flow label (20 bits) */
+# else
+#  if (BYTE_ORDER == LITTLE_ENDIAN) || !defined(_BIG_ENDIAN)
+#   define IPV6_FLOWLABEL_MASK	0xffff0f00	/* flow label (20 bits) */
+#  endif /* LITTLE_ENDIAN */
+# endif
+#endif
+
 /*
  * ECN is a new addition to TCP - RFC 2481
  */
@@ -2516,6 +1439,10 @@
 # define	MIN(a,b)	(((a)<(b))?(a):(b))
 #endif
 
+#ifdef RESCUE
+# undef IPFILTER_BPF
+#endif
+
 #ifdef IPF_DEBUG
 # define	DPRINT(x)	printf x
 #else
@@ -2522,8 +1449,40 @@
 # define	DPRINT(x)
 #endif
 
-#ifdef RESCUE
-# undef IPFILTER_BPF
+#ifndef	AF_INET6
+# define	AF_INET6	26
 #endif
 
+#ifdef DTRACE_PROBE
+# ifdef _KERNEL
+#  define	DT(_n)			DTRACE_PROBE(_n)
+#  define	DT1(_n,_a,_b)		DTRACE_PROBE1(_n,_a,_b)
+#  define	DT2(_n,_a,_b,_c,_d)	DTRACE_PROBE2(_n,_a,_b,_c,_d)
+#  define	DT3(_n,_a,_b,_c,_d,_e,_f)	\
+					DTRACE_PROBE3(_n,_a,_b,_c,_d,_e,_f)
+#  define	DT4(_n,_a,_b,_c,_d,_e,_f,_g,_h) \
+				DTRACE_PROBE4(_n,_a,_b,_c,_d,_e,_f,_g,_h)
+# else
+#  define	DT(_n)
+#  define	DT1(_n,_a,_b)
+#  define	DT2(_n,_a,_b,_c,_d)
+#  define	DT3(_n,_a,_b,_c,_d,_e,_f)
+#  define	DT4(_n,_a,_b,_c,_d,_e,_f,_g,_h)
+# endif
+#else
+# define	DT(_n)
+# define	DT1(_n,_a,_b)
+# define	DT2(_n,_a,_b,_c,_d)
+# define	DT3(_n,_a,_b,_c,_d,_e,_f)
+# define	DT4(_n,_a,_b,_c,_d,_e,_f,_g,_h)
+#endif
+
+struct ip6_routing {
+	u_char	ip6r_nxt;	/* next header */
+	u_char	ip6r_len;	/* length in units of 8 octets */
+	u_char	ip6r_type;	/* always zero */
+	u_char	ip6r_segleft;	/* segments left */
+	u_32_t	ip6r_reserved;	/* reserved field */
+};
+
 #endif	/* __IP_COMPAT_H__ */

Added: trunk/sys/contrib/ipfilter/netinet/ip_dns_pxy.c
===================================================================
--- trunk/sys/contrib/ipfilter/netinet/ip_dns_pxy.c	                        (rev 0)
+++ trunk/sys/contrib/ipfilter/netinet/ip_dns_pxy.c	2018-05-28 18:56:30 UTC (rev 10139)
@@ -0,0 +1,402 @@
+/* $MidnightBSD$ */
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id: ip_dns_pxy.c,v 1.1.2.10 2012/07/22 08:04:23 darren_r Exp $
+ */
+
+#define	IPF_DNS_PROXY
+
+/*
+ * map ... proxy port dns/udp 53 { block .cnn.com; }
+ */
+typedef	struct	ipf_dns_filter	{
+	struct	ipf_dns_filter	*idns_next;
+	char			*idns_name;
+	int			idns_namelen;
+	int			idns_pass;
+} ipf_dns_filter_t;
+
+
+typedef struct ipf_dns_softc_s {
+	ipf_dns_filter_t	*ipf_p_dns_list;
+	ipfrwlock_t		ipf_p_dns_rwlock;
+	u_long			ipf_p_dns_compress;
+	u_long			ipf_p_dns_toolong;
+	u_long			ipf_p_dns_nospace;
+} ipf_dns_softc_t;
+
+int ipf_p_dns_allow_query __P((ipf_dns_softc_t *, dnsinfo_t *));
+int ipf_p_dns_ctl __P((ipf_main_softc_t *, void *, ap_ctl_t *));
+void ipf_p_dns_del __P((ipf_main_softc_t *, ap_session_t *));
+int ipf_p_dns_get_name __P((ipf_dns_softc_t *, char *, int, char *, int));
+int ipf_p_dns_inout __P((void *, fr_info_t *, ap_session_t *, nat_t *));
+int ipf_p_dns_match __P((fr_info_t *, ap_session_t *, nat_t *));
+int ipf_p_dns_match_names __P((ipf_dns_filter_t *, char *, int));
+int ipf_p_dns_new __P((void *, fr_info_t *, ap_session_t *, nat_t *));
+void *ipf_p_dns_soft_create __P((ipf_main_softc_t *));
+void ipf_p_dns_soft_destroy __P((ipf_main_softc_t *, void *));
+
+typedef struct {
+	u_char		dns_id[2];
+	u_short		dns_ctlword;
+	u_short		dns_qdcount;
+	u_short		dns_ancount;
+	u_short		dns_nscount;
+	u_short		dns_arcount;
+} ipf_dns_hdr_t;
+
+#define	DNS_QR(x)	((ntohs(x) & 0x8000) >> 15)
+#define	DNS_OPCODE(x)	((ntohs(x) & 0x7800) >> 11)
+#define	DNS_AA(x)	((ntohs(x) & 0x0400) >> 10)
+#define	DNS_TC(x)	((ntohs(x) & 0x0200) >> 9)
+#define	DNS_RD(x)	((ntohs(x) & 0x0100) >> 8)
+#define	DNS_RA(x)	((ntohs(x) & 0x0080) >> 7)
+#define	DNS_Z(x)	((ntohs(x) & 0x0070) >> 4)
+#define	DNS_RCODE(x)	((ntohs(x) & 0x000f) >> 0)
+
+
+void *
+ipf_p_dns_soft_create(softc)
+	ipf_main_softc_t *softc;
+{
+	ipf_dns_softc_t *softd;
+
+	KMALLOC(softd, ipf_dns_softc_t *);
+	if (softd == NULL)
+		return NULL;
+
+	bzero((char *)softd, sizeof(*softd));
+	RWLOCK_INIT(&softd->ipf_p_dns_rwlock, "ipf dns rwlock");
+
+	return softd;
+}
+
+
+void
+ipf_p_dns_soft_destroy(softc, arg)
+	ipf_main_softc_t *softc;
+	void *arg;
+{
+	ipf_dns_softc_t *softd = arg;
+	ipf_dns_filter_t *idns;
+
+	while ((idns = softd->ipf_p_dns_list) != NULL) {
+		KFREES(idns->idns_name, idns->idns_namelen);
+		idns->idns_name = NULL;
+		idns->idns_namelen = 0;
+		softd->ipf_p_dns_list = idns->idns_next;
+		KFREE(idns);
+	}
+	RW_DESTROY(&softd->ipf_p_dns_rwlock);
+
+	KFREE(softd);
+}
+
+
+int
+ipf_p_dns_ctl(softc, arg, ctl)
+	ipf_main_softc_t *softc;
+	void *arg;
+	ap_ctl_t *ctl;
+{
+	ipf_dns_softc_t *softd = arg;
+	ipf_dns_filter_t *tmp, *idns, **idnsp;
+	int error = 0;
+
+	/*
+	 * To make locking easier.
+	 */
+	KMALLOC(tmp, ipf_dns_filter_t *);
+
+	WRITE_ENTER(&softd->ipf_p_dns_rwlock);
+	for (idnsp = &softd->ipf_p_dns_list; (idns = *idnsp) != NULL;
+	     idnsp = &idns->idns_next) {
+		if (idns->idns_namelen != ctl->apc_dsize)
+			continue;
+		if (!strncmp(ctl->apc_data, idns->idns_name,
+		    idns->idns_namelen))
+			break;
+	}
+
+	switch (ctl->apc_cmd)
+	{
+	case APC_CMD_DEL :
+		if (idns == NULL) {
+			IPFERROR(80006);
+			error = ESRCH;
+			break;
+		}
+		*idnsp = idns->idns_next;
+		idns->idns_next = NULL;
+		KFREES(idns->idns_name, idns->idns_namelen);
+		idns->idns_name = NULL;
+		idns->idns_namelen = 0;
+		KFREE(idns);
+		break;
+	case APC_CMD_ADD :
+		if (idns != NULL) {
+			IPFERROR(80007);
+			error = EEXIST;
+			break;
+		}
+		if (tmp == NULL) {
+			IPFERROR(80008);
+			error = ENOMEM;
+			break;
+		}
+		idns = tmp;
+		tmp = NULL;
+		idns->idns_namelen = ctl->apc_dsize;
+		idns->idns_name = ctl->apc_data;
+		idns->idns_pass = ctl->apc_arg;
+		idns->idns_next = NULL;
+		*idnsp = idns;
+		ctl->apc_data = NULL;
+		ctl->apc_dsize = 0;
+		break;
+	default :
+		IPFERROR(80009);
+		error = EINVAL;
+		break;
+	}
+	RWLOCK_EXIT(&softd->ipf_p_dns_rwlock);
+
+	if (tmp != NULL) {
+		KFREE(tmp);
+		tmp = NULL;
+	}
+
+	return error;
+}
+
+
+/* ARGSUSED */
+int
+ipf_p_dns_new(arg, fin, aps, nat)
+	void *arg;
+	fr_info_t *fin;
+	ap_session_t *aps;
+	nat_t *nat;
+{
+	dnsinfo_t *di;
+	int dlen;
+
+	if (fin->fin_v != 4)
+		return -1;
+
+	dlen = fin->fin_dlen - sizeof(udphdr_t);
+	if (dlen < sizeof(ipf_dns_hdr_t)) {
+		/*
+		 * No real DNS packet is smaller than that.
+		 */
+		return -1;
+	}
+
+	aps->aps_psiz = sizeof(dnsinfo_t);
+	KMALLOCS(di, dnsinfo_t *, sizeof(dnsinfo_t));
+	if (di == NULL) {
+		printf("ipf_dns_new:KMALLOCS(%d) failed\n", sizeof(*di));
+		return -1;
+        }
+
+	MUTEX_INIT(&di->dnsi_lock, "dns lock");
+
+	aps->aps_data = di;
+
+	dlen = fin->fin_dlen - sizeof(udphdr_t);
+	COPYDATA(fin->fin_m, fin->fin_hlen + sizeof(udphdr_t),
+		 MIN(dlen, sizeof(di->dnsi_buffer)), di->dnsi_buffer);
+	di->dnsi_id = (di->dnsi_buffer[0] << 8) | di->dnsi_buffer[1];
+	return 0;
+}
+
+
+/* ARGSUSED */
+void
+ipf_p_dns_del(softc, aps)
+	ipf_main_softc_t *softc;
+	ap_session_t *aps;
+{
+#ifdef USE_MUTEXES
+	dnsinfo_t *di = aps->aps_data;
+
+	MUTEX_DESTROY(&di->dnsi_lock);
+#endif
+	KFREES(aps->aps_data, aps->aps_psiz);
+	aps->aps_data = NULL;
+	aps->aps_psiz = 0;
+}
+
+
+/*
+ * Tries to match the base string (in our ACL) with the query from a packet.
+ */
+int
+ipf_p_dns_match_names(idns, query, qlen)
+	ipf_dns_filter_t *idns;
+	char *query;
+	int qlen;
+{
+	int blen;
+	char *base;
+
+	blen = idns->idns_namelen;
+	base = idns->idns_name;
+
+	if (blen > qlen)
+		return 1;
+
+	if (blen == qlen)
+		return strncasecmp(base, query, qlen);
+
+	/*
+	 * If the base string string is shorter than the query, allow the
+	 * tail of the base to match the same length tail of the query *if*:
+	 * - the base string starts with a '*' (*cnn.com)
+	 * - the base string represents a domain (.cnn.com)
+	 * as otherwise it would not be possible to block just "cnn.com"
+	 * without also impacting "foocnn.com", etc.
+	 */
+	if (*base == '*') {
+		base++;
+		blen--;
+	} else if (*base != '.')
+		return 1;
+
+	return strncasecmp(base, query + qlen - blen, blen);
+}
+
+
+int
+ipf_p_dns_get_name(softd, start, len, buffer, buflen)
+	ipf_dns_softc_t *softd;
+	char *start;
+	int len;
+	char *buffer;
+	int buflen;
+{
+	char *s, *t, clen;
+	int slen, blen;
+
+	s = start;
+	t = buffer;
+	slen = len;
+	blen = buflen - 1;	/* Always make room for trailing \0 */
+
+	while (*s != '\0') {
+		clen = *s;
+		if ((clen & 0xc0) == 0xc0) {	/* Doesn't do compression */
+			softd->ipf_p_dns_compress++;
+			return 0;
+		}
+		if (clen > slen) {
+			softd->ipf_p_dns_toolong++;
+			return 0;	/* Does the name run off the end? */
+		}
+		if ((clen + 1) > blen) {
+			softd->ipf_p_dns_nospace++;
+			return 0;	/* Enough room for name+.? */
+		}
+		s++;
+		bcopy(s, t, clen);
+		t += clen;
+		s += clen;
+		*t++ = '.';
+		slen -= clen;
+		blen -= (clen + 1);
+	}
+
+	*(t - 1) = '\0';
+	return s - start;
+}
+
+
+int
+ipf_p_dns_allow_query(softd, dnsi)
+	ipf_dns_softc_t *softd;
+	dnsinfo_t *dnsi;
+{
+	ipf_dns_filter_t *idns;
+	int len;
+
+	len = strlen(dnsi->dnsi_buffer);
+
+	for (idns = softd->ipf_p_dns_list; idns != NULL; idns = idns->idns_next)
+		if (ipf_p_dns_match_names(idns, dnsi->dnsi_buffer, len) == 0)
+			return idns->idns_pass;
+	return 0;
+}
+
+
+/* ARGSUSED */
+int
+ipf_p_dns_inout(arg, fin, aps, nat)
+	void *arg;
+	fr_info_t *fin;
+	ap_session_t *aps;
+	nat_t *nat;
+{
+	ipf_dns_softc_t *softd = arg;
+	ipf_dns_hdr_t *dns;
+	dnsinfo_t *di;
+	char *data;
+	int dlen, q, rc = 0;
+
+	if (fin->fin_dlen < sizeof(*dns))
+		return APR_ERR(1);
+
+	dns = (ipf_dns_hdr_t *)((char *)fin->fin_dp + sizeof(udphdr_t));
+
+	q = dns->dns_qdcount;
+
+	data = (char *)(dns + 1);
+	dlen = fin->fin_dlen - sizeof(*dns) - sizeof(udphdr_t);
+
+	di = aps->aps_data;
+
+	READ_ENTER(&softd->ipf_p_dns_rwlock);
+	MUTEX_ENTER(&di->dnsi_lock);
+
+	for (; (dlen > 0) && (q > 0); q--) {
+		int len;
+
+		len = ipf_p_dns_get_name(softd, data, dlen, di->dnsi_buffer,
+					 sizeof(di->dnsi_buffer));
+		if (len == 0) {
+			rc = 1;
+			break;
+		}
+		rc = ipf_p_dns_allow_query(softd, di);
+		if (rc != 0)
+			break;
+		data += len;
+		dlen -= len;
+	}
+	MUTEX_EXIT(&di->dnsi_lock);
+	RWLOCK_EXIT(&softd->ipf_p_dns_rwlock);
+
+	return APR_ERR(rc);
+}
+
+
+/* ARGSUSED */
+int
+ipf_p_dns_match(fin, aps, nat)
+	fr_info_t *fin;
+	ap_session_t *aps;
+	nat_t *nat;
+{
+	dnsinfo_t *di = aps->aps_data;
+	ipf_dns_hdr_t *dnh;
+
+	if ((fin->fin_dlen < sizeof(u_short)) || (fin->fin_flx & FI_FRAG))
+                return -1;
+
+	dnh = (ipf_dns_hdr_t *)((char *)fin->fin_dp + sizeof(udphdr_t));
+	if (((dnh->dns_id[0] << 8) | dnh->dns_id[1]) != di->dnsi_id)
+		return -1;
+	return 0;
+}


Property changes on: trunk/sys/contrib/ipfilter/netinet/ip_dns_pxy.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/contrib/ipfilter/netinet/ip_dstlist.c
===================================================================
--- trunk/sys/contrib/ipfilter/netinet/ip_dstlist.c	                        (rev 0)
+++ trunk/sys/contrib/ipfilter/netinet/ip_dstlist.c	2018-05-28 18:56:30 UTC (rev 10139)
@@ -0,0 +1,1352 @@
+/* $MidnightBSD$ */
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ */
+#if defined(KERNEL) || defined(_KERNEL)
+# undef KERNEL
+# undef _KERNEL
+# define        KERNEL	1
+# define        _KERNEL	1
+#endif
+#if defined(__osf__)
+# define _PROTO_NET_H_
+#endif
+#include <sys/errno.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/file.h>
+#if !defined(_KERNEL) && !defined(__KERNEL__)
+# include <stdio.h>
+# include <stdlib.h>
+# include <string.h>
+# define _KERNEL
+# ifdef __OpenBSD__
+struct file;
+# endif
+# include <sys/uio.h>
+# undef _KERNEL
+#else
+# include <sys/systm.h>
+# if defined(NetBSD) && (__NetBSD_Version__ >= 104000000)
+#  include <sys/proc.h>
+# endif
+#endif
+#include <sys/time.h>
+#if !defined(linux)
+# include <sys/protosw.h>
+#endif
+#include <sys/socket.h>
+#if defined(_KERNEL) && (!defined(__SVR4) && !defined(__svr4__))
+# include <sys/mbuf.h>
+#endif
+#if defined(__SVR4) || defined(__svr4__)
+# include <sys/filio.h>
+# include <sys/byteorder.h>
+# ifdef _KERNEL
+#  include <sys/dditypes.h>
+# endif
+# include <sys/stream.h>
+# include <sys/kmem.h>
+#endif
+#if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000)
+# include <sys/malloc.h>
+#endif
+
+#include <net/if.h>
+#include <netinet/in.h>
+
+#include "netinet/ip_compat.h"
+#include "netinet/ip_fil.h"
+#include "netinet/ip_nat.h"
+#include "netinet/ip_lookup.h"
+#include "netinet/ip_dstlist.h"
+
+/* END OF INCLUDES */
+
+#ifdef HAS_SYS_MD5_H
+# include <sys/md5.h>
+#else
+# include "md5.h"
+#endif
+
+#if !defined(lint)
+static const char rcsid[] = "@(#)$Id: ip_dstlist.c,v 1.13.2.12 2012/07/20 08:40:19 darren_r Exp $";
+#endif
+
+typedef struct ipf_dstl_softc_s {
+	ippool_dst_t	*dstlist[LOOKUP_POOL_SZ];
+	ippool_dst_t	**tails[LOOKUP_POOL_SZ];
+	ipf_dstl_stat_t	stats;
+} ipf_dstl_softc_t;
+
+
+static void *ipf_dstlist_soft_create __P((ipf_main_softc_t *));
+static void ipf_dstlist_soft_destroy __P((ipf_main_softc_t *, void *));
+static int ipf_dstlist_soft_init __P((ipf_main_softc_t *, void *));
+static void ipf_dstlist_soft_fini __P((ipf_main_softc_t *, void *));
+static int ipf_dstlist_addr_find __P((ipf_main_softc_t *, void *, int,
+				      void *, u_int));
+static size_t ipf_dstlist_flush __P((ipf_main_softc_t *, void *,
+				     iplookupflush_t *));
+static int ipf_dstlist_iter_deref __P((ipf_main_softc_t *, void *, int, int,
+				       void *));
+static int ipf_dstlist_iter_next __P((ipf_main_softc_t *, void *, ipftoken_t *,
+				      ipflookupiter_t *));
+static int ipf_dstlist_node_add __P((ipf_main_softc_t *, void *,
+				     iplookupop_t *, int));
+static int ipf_dstlist_node_del __P((ipf_main_softc_t *, void *,
+				     iplookupop_t *, int));
+static int ipf_dstlist_stats_get __P((ipf_main_softc_t *, void *,
+				      iplookupop_t *));
+static int ipf_dstlist_table_add __P((ipf_main_softc_t *, void *,
+				      iplookupop_t *));
+static int ipf_dstlist_table_del __P((ipf_main_softc_t *, void *,
+				      iplookupop_t *));
+static int ipf_dstlist_table_deref __P((ipf_main_softc_t *, void *, void *));
+static void *ipf_dstlist_table_find __P((void *, int, char *));
+static void ipf_dstlist_table_free __P((ipf_dstl_softc_t *, ippool_dst_t *));
+static void ipf_dstlist_table_remove __P((ipf_main_softc_t *,
+					  ipf_dstl_softc_t *, ippool_dst_t *));
+static void ipf_dstlist_table_clearnodes __P((ipf_dstl_softc_t *,
+					      ippool_dst_t *));
+static ipf_dstnode_t *ipf_dstlist_select __P((fr_info_t *, ippool_dst_t *));
+static void *ipf_dstlist_select_ref __P((void *, int, char *));
+static void ipf_dstlist_node_free __P((ipf_dstl_softc_t *, ippool_dst_t *, ipf_dstnode_t *));
+static int ipf_dstlist_node_deref __P((void *, ipf_dstnode_t *));
+static void ipf_dstlist_expire __P((ipf_main_softc_t *, void *));
+static void ipf_dstlist_sync __P((ipf_main_softc_t *, void *));
+
+ipf_lookup_t ipf_dstlist_backend = {
+	IPLT_DSTLIST,
+	ipf_dstlist_soft_create,
+	ipf_dstlist_soft_destroy,
+	ipf_dstlist_soft_init,
+	ipf_dstlist_soft_fini,
+	ipf_dstlist_addr_find,
+	ipf_dstlist_flush,
+	ipf_dstlist_iter_deref,
+	ipf_dstlist_iter_next,
+	ipf_dstlist_node_add,
+	ipf_dstlist_node_del,
+	ipf_dstlist_stats_get,
+	ipf_dstlist_table_add,
+	ipf_dstlist_table_del,
+	ipf_dstlist_table_deref,
+	ipf_dstlist_table_find,
+	ipf_dstlist_select_ref,
+	ipf_dstlist_select_node,
+	ipf_dstlist_expire,
+	ipf_dstlist_sync
+};
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_dstlist_soft_create                                     */
+/* Returns:     int - 0 = success, else error                               */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*                                                                          */
+/* Allocating a chunk of memory filled with 0's is enough for the current   */
+/* soft context used with destination lists.                                */
+/* ------------------------------------------------------------------------ */
+static void *
+ipf_dstlist_soft_create(softc)
+	ipf_main_softc_t *softc;
+{
+	ipf_dstl_softc_t *softd;
+	int i;
+
+	KMALLOC(softd, ipf_dstl_softc_t *);
+	if (softd == NULL) {
+		IPFERROR(120028);
+		return NULL;
+	}
+
+	bzero((char *)softd, sizeof(*softd));
+	for (i = 0; i <= IPL_LOGMAX; i++)
+		softd->tails[i] = &softd->dstlist[i];
+
+	return softd;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_dstlist_soft_destroy                                    */
+/* Returns:     Nil                                                         */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              arg(I)   - pointer to local context to use                  */
+/*                                                                          */
+/* For destination lists, the only thing we have to do when destroying the  */
+/* soft context is free it!                                                 */
+/* ------------------------------------------------------------------------ */
+static void
+ipf_dstlist_soft_destroy(softc, arg)
+	ipf_main_softc_t *softc;
+	void *arg;
+{
+	ipf_dstl_softc_t *softd = arg;
+
+	KFREE(softd);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_dstlist_soft_init                                       */
+/* Returns:     int - 0 = success, else error                               */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              arg(I)   - pointer to local context to use                  */
+/*                                                                          */
+/* There is currently no soft context for destination list management.      */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_dstlist_soft_init(softc, arg)
+	ipf_main_softc_t *softc;
+	void *arg;
+{
+	return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_dstlist_soft_fini                                       */
+/* Returns:     Nil                                                         */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              arg(I)   - pointer to local context to use                  */
+/*                                                                          */
+/* There is currently no soft context for destination list management.      */
+/* ------------------------------------------------------------------------ */
+static void
+ipf_dstlist_soft_fini(softc, arg)
+	ipf_main_softc_t *softc;
+	void *arg;
+{
+	ipf_dstl_softc_t *softd = arg;
+	int i;
+
+	for (i = -1; i <= IPL_LOGMAX; i++) {
+		while (softd->dstlist[i + 1] != NULL) {
+			ipf_dstlist_table_remove(softc, softd,
+						 softd->dstlist[i + 1]);
+		}
+	}
+
+	ASSERT(softd->stats.ipls_numderefnodes == 0);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_dstlist_addr_find                                       */
+/* Returns:     int - 0 = success, else error                               */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              arg1(I)  - pointer to local context to use                  */
+/*              arg2(I)  - pointer to local context to use                  */
+/*              arg3(I)  - pointer to local context to use                  */
+/*              arg4(I)  - pointer to local context to use                  */
+/*                                                                          */
+/* There is currently no such thing as searching a destination list for an  */
+/* address so this function becomes a no-op. Its presence is required as    */
+/* ipf_lookup_res_name() stores the "addr_find" function pointer in the     */
+/* pointer passed in to it as funcptr, although it could be a generic null- */
+/* op function rather than a specific one.                                  */
+/* ------------------------------------------------------------------------ */
+/*ARGSUSED*/
+static int
+ipf_dstlist_addr_find(softc, arg1, arg2, arg3, arg4)
+	ipf_main_softc_t *softc;
+	void *arg1, *arg3;
+	int arg2;
+	u_int arg4;
+{
+	return -1;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_dstlist_flush                                           */
+/* Returns:     int      - number of objects deleted                        */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              arg(I)   - pointer to local context to use                  */
+/*              fop(I)   - pointer to lookup flush operation data           */
+/*                                                                          */
+/* Flush all of the destination tables that match the data passed in with   */
+/* the iplookupflush_t. There are two ways to match objects: the device for */
+/* which they are to be used with and their name.                           */
+/* ------------------------------------------------------------------------ */
+static size_t
+ipf_dstlist_flush(softc, arg, fop)
+	ipf_main_softc_t *softc;
+	void *arg;
+	iplookupflush_t *fop;
+{
+	ipf_dstl_softc_t *softd = arg;
+	ippool_dst_t *node, *next;
+	int n, i;
+
+	for (n = 0, i = -1; i <= IPL_LOGMAX; i++) {
+		if (fop->iplf_unit != IPLT_ALL && fop->iplf_unit != i)
+			continue;
+		for (node = softd->dstlist[i + 1]; node != NULL; node = next) {
+			next = node->ipld_next;
+
+			if ((*fop->iplf_name != '\0') &&
+			    strncmp(fop->iplf_name, node->ipld_name,
+				    FR_GROUPLEN))
+				continue;
+
+			ipf_dstlist_table_remove(softc, softd, node);
+			n++;
+		}
+	}
+	return n;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_dstlist_iter_deref                                      */
+/* Returns:     int      - 0 = success, else error                          */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              arg(I)   - pointer to local context to use                  */
+/*              otype(I) - type of data structure to iterate through        */
+/*              unit(I)  - device we are working with                       */
+/*              data(I)  - address of object in kernel space                */
+/*                                                                          */
+/* This function is called when the iteration token is being free'd and is  */
+/* responsible for dropping the reference count of the structure it points  */
+/* to.                                                                      */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_dstlist_iter_deref(softc, arg, otype, unit, data)
+	ipf_main_softc_t *softc;
+	void *arg;
+	int otype, unit;
+	void *data;
+{
+	if (data == NULL) {
+		IPFERROR(120001);
+		return EINVAL;
+	}
+
+	if (unit < -1 || unit > IPL_LOGMAX) {
+		IPFERROR(120002);
+		return EINVAL;
+	}
+
+	switch (otype)
+	{
+	case IPFLOOKUPITER_LIST :
+		ipf_dstlist_table_deref(softc, arg, (ippool_dst_t *)data);
+		break;
+
+	case IPFLOOKUPITER_NODE :
+		ipf_dstlist_node_deref(arg, (ipf_dstnode_t *)data);
+		break;
+	}
+
+	return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_dstlist_iter_next                                       */
+/* Returns:     int - 0 = success, else error                               */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              arg(I)   - pointer to local context to use                  */
+/*              op(I)    - pointer to lookup operation data                 */
+/*              uid(I)   - uid of process doing the ioctl                   */
+/*                                                                          */
+/* This function is responsible for either selecting the next destination   */
+/* list or node on a destination list to be returned as a user process      */
+/* iterates through the list of destination lists or nodes.                 */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_dstlist_iter_next(softc, arg, token, iter)
+	ipf_main_softc_t *softc;
+	void *arg;
+	ipftoken_t *token;
+	ipflookupiter_t *iter;
+{
+	ipf_dstnode_t zn, *nextnode = NULL, *node = NULL;
+	ippool_dst_t zero, *next = NULL, *dsttab = NULL;
+	ipf_dstl_softc_t *softd = arg;
+	int err = 0;
+	void *hint;
+
+	switch (iter->ili_otype)
+	{
+	case IPFLOOKUPITER_LIST :
+		dsttab = token->ipt_data;
+		if (dsttab == NULL) {
+			next = softd->dstlist[(int)iter->ili_unit + 1];
+		} else {
+			next = dsttab->ipld_next;
+		}
+
+		if (next != NULL) {
+			ATOMIC_INC32(next->ipld_ref);
+			token->ipt_data = next;
+			hint = next->ipld_next;
+		} else {
+			bzero((char *)&zero, sizeof(zero));
+			next = &zero;
+			token->ipt_data = NULL;
+			hint = NULL;
+		}
+		break;
+
+	case IPFLOOKUPITER_NODE :
+		node = token->ipt_data;
+		if (node == NULL) {
+			dsttab = ipf_dstlist_table_find(arg, iter->ili_unit,
+							iter->ili_name);
+			if (dsttab == NULL) {
+				IPFERROR(120004);
+				err = ESRCH;
+				nextnode = NULL;
+			} else {
+				if (dsttab->ipld_dests == NULL)
+					nextnode = NULL;
+				else
+					nextnode = *dsttab->ipld_dests;
+				dsttab = NULL;
+			}
+		} else {
+			nextnode = node->ipfd_next;
+		}
+
+		if (nextnode != NULL) {
+			MUTEX_ENTER(&nextnode->ipfd_lock);
+			nextnode->ipfd_ref++;
+			MUTEX_EXIT(&nextnode->ipfd_lock);
+			token->ipt_data = nextnode;
+			hint = nextnode->ipfd_next;
+		} else {
+			bzero((char *)&zn, sizeof(zn));
+			nextnode = &zn;
+			token->ipt_data = NULL;
+			hint = NULL;
+		}
+		break;
+	default :
+		IPFERROR(120003);
+		err = EINVAL;
+		break;
+	}
+
+	if (err != 0)
+		return err;
+
+	switch (iter->ili_otype)
+	{
+	case IPFLOOKUPITER_LIST :
+		if (dsttab != NULL)
+			ipf_dstlist_table_deref(softc, arg, dsttab);
+		err = COPYOUT(next, iter->ili_data, sizeof(*next));
+		if (err != 0) {
+			IPFERROR(120005);
+			err = EFAULT;
+		}
+		break;
+
+	case IPFLOOKUPITER_NODE :
+		if (node != NULL)
+			ipf_dstlist_node_deref(arg, node);
+		err = COPYOUT(nextnode, iter->ili_data, sizeof(*nextnode));
+		if (err != 0) {
+			IPFERROR(120006);
+			err = EFAULT;
+		}
+		break;
+	}
+
+	if (hint == NULL)
+		ipf_token_mark_complete(token);
+
+	return err;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_dstlist_node_add                                        */
+/* Returns:     int - 0 = success, else error                               */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              arg(I)   - pointer to local context to use                  */
+/*              op(I)    - pointer to lookup operation data                 */
+/*              uid(I)   - uid of process doing the ioctl                   */
+/* Locks:       WRITE(ipf_poolrw)                                           */
+/*                                                                          */
+/* Add a new node to a destination list. To do this, we only copy in the    */
+/* frdest_t structure because that contains the only data required from the */
+/* application to create a new node. The frdest_t doesn't contain the name  */
+/* itself. When loading filter rules, fd_name is a 'pointer' to the name.   */
+/* In this case, the 'pointer' does not work, instead it is the length of   */
+/* the name and the name is immediately following the frdest_t structure.   */
+/* fd_name must include the trailing \0, so it should be strlen(str) + 1.   */
+/* For simple sanity checking, an upper bound on the size of fd_name is     */
+/* imposed - 128.                                                          */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_dstlist_node_add(softc, arg, op, uid)
+	ipf_main_softc_t *softc;
+	void *arg;
+	iplookupop_t *op;
+	int uid;
+{
+	ipf_dstl_softc_t *softd = arg;
+	ipf_dstnode_t *node, **nodes;
+	ippool_dst_t *d;
+	frdest_t dest;
+	int err;
+
+	if (op->iplo_size < sizeof(frdest_t)) {
+		IPFERROR(120007);
+		return EINVAL;
+	}
+
+	err = COPYIN(op->iplo_struct, &dest, sizeof(dest));
+	if (err != 0) {
+		IPFERROR(120009);
+		return EFAULT;
+	}
+
+	d = ipf_dstlist_table_find(arg, op->iplo_unit, op->iplo_name);
+	if (d == NULL) {
+		IPFERROR(120010);
+		return ESRCH;
+	}
+
+	switch (dest.fd_addr.adf_family)
+	{
+	case AF_INET :
+	case AF_INET6 :
+		break;
+	default :
+		IPFERROR(120019);
+		return EINVAL;
+	}
+
+	if (dest.fd_name < -1 || dest.fd_name > 128) {
+		IPFERROR(120018);
+		return EINVAL;
+	}
+
+	KMALLOCS(node, ipf_dstnode_t *, sizeof(*node) + dest.fd_name);
+	if (node == NULL) {
+		softd->stats.ipls_nomem++;
+		IPFERROR(120008);
+		return ENOMEM;
+	}
+	bzero((char *)node, sizeof(*node) + dest.fd_name);
+
+	bcopy(&dest, &node->ipfd_dest, sizeof(dest));
+	node->ipfd_size = sizeof(*node) + dest.fd_name;
+
+	if (dest.fd_name > 0) {
+		/*
+		 * fd_name starts out as the length of the string to copy
+		 * in (including \0) and ends up being the offset from
+		 * fd_names (0).
+		 */
+		err = COPYIN((char *)op->iplo_struct + sizeof(dest),
+			     node->ipfd_names, dest.fd_name);
+		if (err != 0) {
+			IPFERROR(120017);
+			KFREES(node, node->ipfd_size);
+			return EFAULT;
+		}
+		node->ipfd_dest.fd_name = 0;
+	} else {
+		node->ipfd_dest.fd_name = -1;
+	}
+
+	if (d->ipld_nodes == d->ipld_maxnodes) {
+		KMALLOCS(nodes, ipf_dstnode_t **,
+			 sizeof(*nodes) * (d->ipld_maxnodes + 1));
+		if (nodes == NULL) {
+			softd->stats.ipls_nomem++;
+			IPFERROR(120022);
+			KFREES(node, node->ipfd_size);
+			return ENOMEM;
+		}
+		if (d->ipld_dests != NULL) {
+			bcopy(d->ipld_dests, nodes,
+			      sizeof(*nodes) * d->ipld_maxnodes);
+			KFREES(d->ipld_dests, sizeof(*nodes) * d->ipld_nodes);
+			nodes[0]->ipfd_pnext = nodes;
+		}
+		d->ipld_dests = nodes;
+		d->ipld_maxnodes++;
+	}
+	d->ipld_dests[d->ipld_nodes] = node;
+	d->ipld_nodes++;
+
+	if (d->ipld_nodes == 1) {
+		node->ipfd_pnext = d->ipld_dests;
+	} else if (d->ipld_nodes > 1) {
+		node->ipfd_pnext = &d->ipld_dests[d->ipld_nodes - 2]->ipfd_next;
+	}
+	*node->ipfd_pnext = node;
+
+	MUTEX_INIT(&node->ipfd_lock, "ipf dst node lock");
+	node->ipfd_uid = uid;
+	node->ipfd_ref = 1;
+	if (node->ipfd_dest.fd_name == 0)
+		(void) ipf_resolvedest(softc, node->ipfd_names,
+				       &node->ipfd_dest, AF_INET);
+#ifdef USE_INET6
+	if (node->ipfd_dest.fd_name == 0 &&
+	    node->ipfd_dest.fd_ptr == (void *)-1)
+		(void) ipf_resolvedest(softc, node->ipfd_names,
+				       &node->ipfd_dest, AF_INET6);
+#endif
+
+	softd->stats.ipls_numnodes++;
+
+	return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_dstlist_node_deref                                      */
+/* Returns:     int - 0 = success, else error                               */
+/* Parameters:  arg(I)  - pointer to local context to use                   */
+/*              node(I) - pointer to destionation node to free              */
+/*                                                                          */
+/* Dereference the use count by one. If it drops to zero then we can assume */
+/* that it has been removed from any lists/tables and is ripe for freeing.  */
+/* The pointer to context is required for the purpose of maintaining        */
+/* statistics.                                                              */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_dstlist_node_deref(arg, node)
+	void *arg;
+	ipf_dstnode_t *node;
+{
+	ipf_dstl_softc_t *softd = arg;
+	int ref;
+
+	MUTEX_ENTER(&node->ipfd_lock);
+	ref = --node->ipfd_ref;
+	MUTEX_EXIT(&node->ipfd_lock);
+
+	if (ref > 0)
+		return 0;
+
+	if ((node->ipfd_flags & IPDST_DELETE) != 0)
+		softd->stats.ipls_numderefnodes--;
+	MUTEX_DESTROY(&node->ipfd_lock);
+	KFREES(node, node->ipfd_size);
+	softd->stats.ipls_numnodes--;
+
+	return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_dstlist_node_del                                        */
+/* Returns:     int      - 0 = success, else error                          */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              arg(I)   - pointer to local context to use                  */
+/*              op(I)    - pointer to lookup operation data                 */
+/*              uid(I)   - uid of process doing the ioctl                   */
+/*                                                                          */
+/* Look for a matching destination node on the named table and free it if   */
+/* found. Because the name embedded in the frdest_t is variable in length,  */
+/* it is necessary to allocate some memory locally, to complete this op.    */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_dstlist_node_del(softc, arg, op, uid)
+	ipf_main_softc_t *softc;
+	void *arg;
+	iplookupop_t *op;
+	int uid;
+{
+	ipf_dstl_softc_t *softd = arg;
+	ipf_dstnode_t *node;
+	frdest_t frd, *temp;
+	ippool_dst_t *d;
+	size_t size;
+	int err;
+
+	d = ipf_dstlist_table_find(arg, op->iplo_unit, op->iplo_name);
+	if (d == NULL) {
+		IPFERROR(120012);
+		return ESRCH;
+	}
+
+	err = COPYIN(op->iplo_struct, &frd, sizeof(frd));
+	if (err != 0) {
+		IPFERROR(120011);
+		return EFAULT;
+	}
+
+	size = sizeof(*temp) + frd.fd_name;
+	KMALLOCS(temp, frdest_t *, size);
+	if (temp == NULL) {
+		softd->stats.ipls_nomem++;
+		IPFERROR(120026);
+		return ENOMEM;
+	}
+
+	err = COPYIN(op->iplo_struct, temp, size);
+	if (err != 0) {
+		IPFERROR(120027);
+		return EFAULT;
+	}
+
+	MUTEX_ENTER(&d->ipld_lock);
+	for (node = *d->ipld_dests; node != NULL; node = node->ipfd_next) {
+		if ((uid != 0) && (node->ipfd_uid != uid))
+			continue;
+		if (node->ipfd_size != size)
+			continue;
+		if (!bcmp(&node->ipfd_dest.fd_ip6, &frd.fd_ip6,
+			  size - offsetof(frdest_t, fd_ip6))) {
+			ipf_dstlist_node_free(softd, d, node);
+			MUTEX_EXIT(&d->ipld_lock);
+			KFREES(temp, size);
+			return 0;
+		}
+	}
+	MUTEX_EXIT(&d->ipld_lock);
+	KFREES(temp, size);
+
+	return ESRCH;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_dstlist_node_free                                       */
+/* Returns:     Nil                                                         */
+/* Parameters:  softd(I) - pointer to the destination list context          */
+/*              d(I)     - pointer to destination list                      */
+/*              node(I)  - pointer to node to free                          */
+/* Locks:       MUTEX(ipld_lock) or WRITE(ipf_poolrw)                       */
+/*                                                                          */
+/* Free the destination node by first removing it from any lists and then   */
+/* checking if this was the last reference held to the object. While the    */
+/* array of pointers to nodes is compacted, its size isn't reduced (by way  */
+/* of allocating a new smaller one and copying) because the belief is that  */
+/* it is likely the array will again reach that size.                       */
+/* ------------------------------------------------------------------------ */
+static void
+ipf_dstlist_node_free(softd, d, node)
+	ipf_dstl_softc_t *softd;
+	ippool_dst_t *d;
+	ipf_dstnode_t *node;
+{
+	int i;
+
+	/*
+	 * Compact the array of pointers to nodes.
+	 */
+	for (i = 0; i < d->ipld_nodes; i++)
+		if (d->ipld_dests[i] == node)
+			break;
+	if (d->ipld_nodes - i > 1) {
+		bcopy(&d->ipld_dests[i + 1], &d->ipld_dests[i],
+		      sizeof(*d->ipld_dests) * (d->ipld_nodes - i - 1));
+	}
+	d->ipld_nodes--;
+
+	if (node->ipfd_pnext != NULL)
+		*node->ipfd_pnext = node->ipfd_next;
+	if (node->ipfd_next != NULL)
+		node->ipfd_next->ipfd_pnext = node->ipfd_pnext;
+	node->ipfd_pnext = NULL;
+	node->ipfd_next = NULL;
+
+	if ((node->ipfd_flags & IPDST_DELETE) == 0) {
+		softd->stats.ipls_numderefnodes++;
+		node->ipfd_flags |= IPDST_DELETE;
+	}
+
+	ipf_dstlist_node_deref(softd, node);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_dstlist_stats_get                                       */
+/* Returns:     int - 0 = success, else error                               */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              arg(I)   - pointer to local context to use                  */
+/*              op(I)    - pointer to lookup operation data                 */
+/*                                                                          */
+/* Return the current statistics for destination lists. This may be for all */
+/* of them or just information pertaining to a particular table.            */
+/* ------------------------------------------------------------------------ */
+/*ARGSUSED*/
+static int
+ipf_dstlist_stats_get(softc, arg, op)
+	ipf_main_softc_t *softc;
+	void *arg;
+	iplookupop_t *op;
+{
+	ipf_dstl_softc_t *softd = arg;
+	ipf_dstl_stat_t stats;
+	int unit, i, err = 0;
+
+	if (op->iplo_size != sizeof(ipf_dstl_stat_t)) {
+		IPFERROR(120023);
+		return EINVAL;
+	}
+
+	stats = softd->stats;
+	unit = op->iplo_unit;
+	if (unit == IPL_LOGALL) {
+		for (i = 0; i <= IPL_LOGMAX; i++)
+			stats.ipls_list[i] = softd->dstlist[i];
+	} else if (unit >= 0 && unit <= IPL_LOGMAX) {
+		void *ptr;
+
+		if (op->iplo_name[0] != '\0')
+			ptr = ipf_dstlist_table_find(softd, unit,
+						     op->iplo_name);
+		else
+			ptr = softd->dstlist[unit + 1];
+		stats.ipls_list[unit] = ptr;
+	} else {
+		IPFERROR(120024);
+		err = EINVAL;
+	}
+
+	if (err == 0) {
+		err = COPYOUT(&stats, op->iplo_struct, sizeof(stats));
+		if (err != 0) {
+			IPFERROR(120025);
+			return EFAULT;
+		}
+	}
+	return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_dstlist_table_add                                       */
+/* Returns:     int      - 0 = success, else error                          */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              arg(I)   - pointer to local context to use                  */
+/*              op(I)    - pointer to lookup operation data                 */
+/*                                                                          */
+/* Add a new destination table to the list of those available for the given */
+/* device. Because we seldom operate on these objects (find/add/delete),    */
+/* they are just kept in a simple linked list.                              */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_dstlist_table_add(softc, arg, op)
+	ipf_main_softc_t *softc;
+	void *arg;
+	iplookupop_t *op;
+{
+	ipf_dstl_softc_t *softd = arg;
+	ippool_dst_t user, *d, *new;
+	int unit, err;
+
+	d = ipf_dstlist_table_find(arg, op->iplo_unit, op->iplo_name);
+	if (d != NULL) {
+		IPFERROR(120013);
+		return EEXIST;
+	}
+
+	err = COPYIN(op->iplo_struct, &user, sizeof(user));
+	if (err != 0) {
+		IPFERROR(120021);
+		return EFAULT;
+	}
+
+	KMALLOC(new, ippool_dst_t *);
+	if (new == NULL) {
+		softd->stats.ipls_nomem++;
+		IPFERROR(120014);
+		return ENOMEM;
+	}
+	bzero((char *)new, sizeof(*new));
+
+	MUTEX_INIT(&new->ipld_lock, "ipf dst table lock");
+
+	strncpy(new->ipld_name, op->iplo_name, FR_GROUPLEN);
+	unit = op->iplo_unit;
+	new->ipld_unit = unit;
+	new->ipld_policy = user.ipld_policy;
+	new->ipld_seed = ipf_random();
+	new->ipld_ref = 1;
+
+	new->ipld_pnext = softd->tails[unit + 1];
+	*softd->tails[unit + 1] = new;
+	softd->tails[unit + 1] = &new->ipld_next;
+	softd->stats.ipls_numlists++;
+
+	return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_dstlist_table_del                                       */
+/* Returns:     int - 0 = success, else error                               */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              arg(I)   - pointer to local context to use                  */
+/*              op(I)    - pointer to lookup operation data                 */
+/*                                                                          */
+/* Find a named destinstion list table and delete it. If there are other    */
+/* references to it, the caller isn't told.                                 */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_dstlist_table_del(softc, arg, op)
+	ipf_main_softc_t *softc;
+	void *arg;
+	iplookupop_t *op;
+{
+	ippool_dst_t *d;
+
+	d = ipf_dstlist_table_find(arg, op->iplo_unit, op->iplo_name);
+	if (d == NULL) {
+		IPFERROR(120015);
+		return ESRCH;
+	}
+
+	if (d->ipld_dests != NULL) {
+		IPFERROR(120016);
+		return EBUSY;
+	}
+
+	ipf_dstlist_table_remove(softc, arg, d);
+
+	return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_dstlist_table_remove                                    */
+/* Returns:     Nil                                                         */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              softd(I) - pointer to the destination list context          */
+/*              d(I)     - pointer to destination list                      */
+/*                                                                          */
+/* Remove a given destination list from existance. While the IPDST_DELETE   */
+/* flag is set every time we call this function and the reference count is  */
+/* non-zero, the "numdereflists" counter is always incremented because the  */
+/* decision about whether it will be freed or not is not made here. This    */
+/* means that the only action the code can take here is to treat it as if   */
+/* it will become a detached.                                               */
+/* ------------------------------------------------------------------------ */
+static void
+ipf_dstlist_table_remove(softc, softd, d)
+	ipf_main_softc_t *softc;
+	ipf_dstl_softc_t *softd;
+	ippool_dst_t *d;
+{
+
+	if (softd->tails[d->ipld_unit + 1] == &d->ipld_next)
+		softd->tails[d->ipld_unit + 1] = d->ipld_pnext;
+
+	if (d->ipld_pnext != NULL)
+		*d->ipld_pnext = d->ipld_next;
+	if (d->ipld_next != NULL)
+		d->ipld_next->ipld_pnext = d->ipld_pnext;
+	d->ipld_pnext = NULL;
+	d->ipld_next = NULL;
+
+	ipf_dstlist_table_clearnodes(softd, d);
+
+	softd->stats.ipls_numdereflists++;
+	d->ipld_flags |= IPDST_DELETE;
+
+	ipf_dstlist_table_deref(softc, softd, d);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_dstlist_table_free                                      */
+/* Returns:     Nil                                                         */
+/* Parameters:  softd(I) - pointer to the destination list context          */
+/*              d(I)   - pointer to destination list                        */
+/*                                                                          */
+/* Free up a destination list data structure and any other memory that was  */
+/* directly allocated as part of creating it. Individual destination list   */
+/* nodes are not freed. It is assumed the caller will have already emptied  */
+/* the destination list.                                                    */
+/* ------------------------------------------------------------------------ */
+static void
+ipf_dstlist_table_free(softd, d)
+	ipf_dstl_softc_t *softd;
+	ippool_dst_t *d;
+{
+	MUTEX_DESTROY(&d->ipld_lock);
+
+	if ((d->ipld_flags & IPDST_DELETE) != 0)
+		softd->stats.ipls_numdereflists--;
+	softd->stats.ipls_numlists--;
+
+	if (d->ipld_dests != NULL) {
+		KFREES(d->ipld_dests,
+		       d->ipld_maxnodes * sizeof(*d->ipld_dests));
+	}
+
+	KFREE(d);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_dstlist_table_deref                                     */
+/* Returns:     int - 0 = success, else error                               */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              arg(I)   - pointer to local context to use                  */
+/*              op(I)    - pointer to lookup operation data                 */
+/*                                                                          */
+/* Drops the reference count on a destination list table object and free's  */
+/* it if 0 has been reached.                                                */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_dstlist_table_deref(softc, arg, table)
+	ipf_main_softc_t *softc;
+	void *arg;
+	void *table;
+{
+	ippool_dst_t *d = table;
+
+	d->ipld_ref--;
+	if (d->ipld_ref > 0)
+		return d->ipld_ref;
+
+	ipf_dstlist_table_free(arg, d);
+
+	return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_dstlist_table_clearnodes                                */
+/* Returns:     Nil                                                         */
+/* Parameters:  softd(I) - pointer to the destination list context          */
+/*              dst(I)   - pointer to destination list                      */
+/*                                                                          */
+/* Free all of the destination nodes attached to the given table.           */
+/* ------------------------------------------------------------------------ */
+static void
+ipf_dstlist_table_clearnodes(softd, dst)
+	ipf_dstl_softc_t *softd;
+	ippool_dst_t *dst;
+{
+	ipf_dstnode_t *node;
+
+	if (dst->ipld_dests == NULL)
+		return;
+
+	while ((node = *dst->ipld_dests) != NULL) {
+		ipf_dstlist_node_free(softd, dst, node);
+	}
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_dstlist_table_find                                      */
+/* Returns:     int      - 0 = success, else error                          */
+/* Parameters:  arg(I)   - pointer to local context to use                  */
+/*              unit(I)  - device we are working with                       */
+/*              name(I)  - destination table name to find                   */
+/*                                                                          */
+/* Return a pointer to a destination table that matches the unit+name that  */
+/* is passed in.                                                            */
+/* ------------------------------------------------------------------------ */
+static void *
+ipf_dstlist_table_find(arg, unit, name)
+	void *arg;
+	int unit;
+	char *name;
+{
+	ipf_dstl_softc_t *softd = arg;
+	ippool_dst_t *d;
+
+	for (d = softd->dstlist[unit + 1]; d != NULL; d = d->ipld_next) {
+		if ((d->ipld_unit == unit) &&
+		    !strncmp(d->ipld_name, name, FR_GROUPLEN)) {
+			return d;
+		}
+	}
+
+	return NULL;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_dstlist_select_ref                                      */
+/* Returns:     void *   - NULL = failure, else pointer to table            */
+/* Parameters:  arg(I)   - pointer to local context to use                  */
+/*              unit(I)  - device we are working with                       */
+/*              name(I)  - destination table name to find                   */
+/*                                                                          */
+/* Attempt to find a destination table that matches the name passed in and  */
+/* if successful, bump up the reference count on it because we intend to    */
+/* store the pointer to it somewhere else.                                  */
+/* ------------------------------------------------------------------------ */
+static void *
+ipf_dstlist_select_ref(arg, unit, name)
+	void *arg;
+	int unit;
+	char *name;
+{
+	ippool_dst_t *d;
+
+	d = ipf_dstlist_table_find(arg, unit, name);
+	if (d != NULL) {
+		MUTEX_ENTER(&d->ipld_lock);
+		d->ipld_ref++;
+		MUTEX_EXIT(&d->ipld_lock);
+	}
+	return d;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_dstlist_select                                          */
+/* Returns:     void * - NULL = failure, else pointer to table              */
+/* Parameters:  fin(I) - pointer to packet information                      */
+/*              d(I)   - pointer to destination list                        */
+/*                                                                          */
+/* Find the next node in the destination list to be used according to the   */
+/* defined policy. Of these, "connection" is the most expensive policy to   */
+/* implement as it always looks for the node with the least number of       */
+/* connections associated with it.                                          */
+/*                                                                          */
+/* The hashes exclude the port numbers so that all protocols map to the     */
+/* same destination. Otherwise, someone doing a ping would target a         */
+/* different server than their TCP connection, etc. MD-5 is used to         */
+/* transform the addressese into something random that the other end could  */
+/* not easily guess and use in an attack. ipld_seed introduces an unknown   */
+/* into the hash calculation to increase the difficult of an attacker       */
+/* guessing the bucket.                                                     */
+/*                                                                          */
+/* One final comment: mixing different address families in a single pool    */
+/* will currently result in failures as the address family of the node is   */
+/* only matched up with that in the packet as the last step. While this can */
+/* be coded around for the weighted connection and round-robin models, it   */
+/* cannot be supported for the hash/random models as they do not search and */
+/* nor is the algorithm conducive to searching.                             */
+/* ------------------------------------------------------------------------ */
+static ipf_dstnode_t *
+ipf_dstlist_select(fin, d)
+	fr_info_t *fin;
+	ippool_dst_t *d;
+{
+	ipf_dstnode_t *node, *sel;
+	int connects;
+	u_32_t hash[4];
+	MD5_CTX ctx;
+	int family;
+	int x;
+
+	if (d == NULL || d->ipld_dests == NULL || *d->ipld_dests == NULL)
+		return NULL;
+
+	family = fin->fin_family;
+
+	MUTEX_ENTER(&d->ipld_lock);
+
+	switch (d->ipld_policy)
+	{
+	case IPLDP_ROUNDROBIN:
+		sel = d->ipld_selected;
+		if (sel == NULL) {
+			sel = *d->ipld_dests;
+		} else {
+			sel = sel->ipfd_next;
+			if (sel == NULL)
+				sel = *d->ipld_dests;
+		}
+		break;
+
+	case IPLDP_CONNECTION:
+		if (d->ipld_selected == NULL) {
+			sel = *d->ipld_dests;
+			break;
+		}
+
+		sel = d->ipld_selected;
+		connects = 0x7fffffff;
+		node = sel->ipfd_next;
+		if (node == NULL)
+			node = *d->ipld_dests;
+		while (node != d->ipld_selected) {
+			if (node->ipfd_states == 0) {
+				sel = node;
+				break;
+			}
+			if (node->ipfd_states < connects) {
+				sel = node;
+				connects = node->ipfd_states;
+			}
+			node = node->ipfd_next;
+			if (node == NULL)
+				node = *d->ipld_dests;
+		}
+		break;
+
+	case IPLDP_RANDOM :
+		x = ipf_random() % d->ipld_nodes;
+		sel = d->ipld_dests[x];
+		break;
+
+	case IPLDP_HASHED :
+		MD5Init(&ctx);
+		MD5Update(&ctx, (u_char *)&d->ipld_seed, sizeof(d->ipld_seed));
+		MD5Update(&ctx, (u_char *)&fin->fin_src6,
+			  sizeof(fin->fin_src6));
+		MD5Update(&ctx, (u_char *)&fin->fin_dst6,
+			  sizeof(fin->fin_dst6));
+		MD5Final((u_char *)hash, &ctx);
+		x = ntohl(hash[0]) % d->ipld_nodes;
+		sel = d->ipld_dests[x];
+		break;
+
+	case IPLDP_SRCHASH :
+		MD5Init(&ctx);
+		MD5Update(&ctx, (u_char *)&d->ipld_seed, sizeof(d->ipld_seed));
+		MD5Update(&ctx, (u_char *)&fin->fin_src6,
+			  sizeof(fin->fin_src6));
+		MD5Final((u_char *)hash, &ctx);
+		x = ntohl(hash[0]) % d->ipld_nodes;
+		sel = d->ipld_dests[x];
+		break;
+
+	case IPLDP_DSTHASH :
+		MD5Init(&ctx);
+		MD5Update(&ctx, (u_char *)&d->ipld_seed, sizeof(d->ipld_seed));
+		MD5Update(&ctx, (u_char *)&fin->fin_dst6,
+			  sizeof(fin->fin_dst6));
+		MD5Final((u_char *)hash, &ctx);
+		x = ntohl(hash[0]) % d->ipld_nodes;
+		sel = d->ipld_dests[x];
+		break;
+
+	default :
+		sel = NULL;
+		break;
+	}
+
+	if (sel && sel->ipfd_dest.fd_addr.adf_family != family)
+		sel = NULL;
+	d->ipld_selected = sel;
+
+	MUTEX_EXIT(&d->ipld_lock);
+
+	return sel;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_dstlist_select_node                                     */
+/* Returns:     int      - -1 == failure, 0 == success                      */
+/* Parameters:  fin(I)   - pointer to packet information                    */
+/*              group(I) - destination pool to search                       */
+/*              addr(I)  - pointer to store selected address                */
+/*              pfdp(O)  - pointer to storage for selected destination node */
+/*                                                                          */
+/* This function is only responsible for obtaining the next IP address for  */
+/* use and storing it in the caller's address space (addr). "addr" is only  */
+/* used for storage if pfdp is NULL. No permanent reference is currently    */
+/* kept on the node.                                                        */
+/* ------------------------------------------------------------------------ */
+int
+ipf_dstlist_select_node(fin, group, addr, pfdp)
+	fr_info_t *fin;
+	void *group;
+	u_32_t *addr;
+	frdest_t *pfdp;
+{
+#ifdef USE_MUTEXES
+	ipf_main_softc_t *softc = fin->fin_main_soft;
+#endif
+	ippool_dst_t *d = group;
+	ipf_dstnode_t *node;
+	frdest_t *fdp;
+
+	READ_ENTER(&softc->ipf_poolrw);
+
+	node = ipf_dstlist_select(fin, d);
+	if (node == NULL) {
+		RWLOCK_EXIT(&softc->ipf_poolrw);
+		return -1;
+	}
+
+	if (pfdp != NULL) {
+		bcopy(&node->ipfd_dest, pfdp, sizeof(*pfdp));
+	} else {
+		if (fin->fin_family == AF_INET) {
+			addr[0] = node->ipfd_dest.fd_addr.adf_addr.i6[0];
+		} else if (fin->fin_family == AF_INET6) {
+			addr[0] = node->ipfd_dest.fd_addr.adf_addr.i6[0];
+			addr[1] = node->ipfd_dest.fd_addr.adf_addr.i6[1];
+			addr[2] = node->ipfd_dest.fd_addr.adf_addr.i6[2];
+			addr[3] = node->ipfd_dest.fd_addr.adf_addr.i6[3];
+		}
+	}
+
+	fdp = &node->ipfd_dest;
+	if (fdp->fd_ptr == NULL)
+		fdp->fd_ptr = fin->fin_ifp;
+
+	MUTEX_ENTER(&node->ipfd_lock);
+	node->ipfd_states++;
+	MUTEX_EXIT(&node->ipfd_lock);
+
+	RWLOCK_EXIT(&softc->ipf_poolrw);
+
+	return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_dstlist_expire                                          */
+/* Returns:     Nil                                                         */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              arg(I)   - pointer to local context to use                  */
+/*                                                                          */
+/* There are currently no objects to expire in destination lists.           */
+/* ------------------------------------------------------------------------ */
+static void
+ipf_dstlist_expire(softc, arg)
+	ipf_main_softc_t *softc;
+	void *arg;
+{
+	return;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_dstlist_sync                                            */
+/* Returns:     Nil                                                         */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              arg(I)   - pointer to local context to use                  */
+/*                                                                          */
+/* When a network interface appears or disappears, we need to revalidate    */
+/* all of the network interface names that have been configured as a target */
+/* in a destination list.                                                   */
+/* ------------------------------------------------------------------------ */
+void
+ipf_dstlist_sync(softc, arg)
+	ipf_main_softc_t *softc;
+	void *arg;
+{
+	ipf_dstl_softc_t *softd = arg;
+	ipf_dstnode_t *node;
+	ippool_dst_t *list;
+	int i;
+	int j;
+
+	for (i = 0; i < IPL_LOGMAX; i++) {
+		for (list = softd->dstlist[i]; list != NULL;
+		     list = list->ipld_next) {
+			for (j = 0; j < list->ipld_maxnodes; j++) {
+				node = list->ipld_dests[j];
+				if (node == NULL)
+					continue;
+				if (node->ipfd_dest.fd_name == -1)
+					continue;
+				(void) ipf_resolvedest(softc,
+						       node->ipfd_names,
+						       &node->ipfd_dest,
+						       AF_INET);
+			}
+		}
+	}
+}


Property changes on: trunk/sys/contrib/ipfilter/netinet/ip_dstlist.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/contrib/ipfilter/netinet/ip_dstlist.h
===================================================================
--- trunk/sys/contrib/ipfilter/netinet/ip_dstlist.h	                        (rev 0)
+++ trunk/sys/contrib/ipfilter/netinet/ip_dstlist.h	2018-05-28 18:56:30 UTC (rev 10139)
@@ -0,0 +1,69 @@
+/* $MidnightBSD$ */
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id: ip_dstlist.h,v 1.5.2.6 2012/07/22 08:04:23 darren_r Exp $
+ */
+
+#ifndef	__IP_DSTLIST_H__
+#define	__IP_DSTLIST_H__
+
+typedef struct ipf_dstnode {
+	struct ipf_dstnode	*ipfd_next;
+	struct ipf_dstnode	**ipfd_pnext;
+	ipfmutex_t		ipfd_lock;
+	frdest_t		ipfd_dest;
+	u_long			ipfd_syncat;
+	int			ipfd_flags;
+	int			ipfd_size;
+	int			ipfd_states;
+	int			ipfd_ref;
+	int			ipfd_uid;
+	char			ipfd_names[1];
+} ipf_dstnode_t;
+
+typedef enum ippool_policy_e {
+	IPLDP_NONE = 0,
+	IPLDP_ROUNDROBIN,
+	IPLDP_CONNECTION,
+	IPLDP_RANDOM,
+	IPLDP_HASHED,
+	IPLDP_SRCHASH,
+	IPLDP_DSTHASH
+} ippool_policy_t;
+
+typedef struct ippool_dst {
+	struct ippool_dst	*ipld_next;
+	struct ippool_dst	**ipld_pnext;
+	ipfmutex_t		ipld_lock;
+	int			ipld_seed;
+	int			ipld_unit;
+	int			ipld_ref;
+	int			ipld_flags;
+	int			ipld_nodes;
+	int			ipld_maxnodes;
+	ippool_policy_t		ipld_policy;
+	ipf_dstnode_t		**ipld_dests;
+	ipf_dstnode_t		*ipld_selected;
+	char			ipld_name[FR_GROUPLEN];
+} ippool_dst_t;
+
+#define	IPDST_DELETE		0x01
+
+typedef	struct dstlist_stat_s {
+	void			*ipls_list[LOOKUP_POOL_SZ];
+	int			ipls_numlists;
+	u_long			ipls_nomem;
+	int			ipls_numnodes;
+	int			ipls_numdereflists;
+	int			ipls_numderefnodes;
+} ipf_dstl_stat_t;
+
+extern ipf_lookup_t ipf_dstlist_backend;
+
+extern int ipf_dstlist_select_node __P((fr_info_t *, void *, u_32_t *,
+					frdest_t *));
+
+#endif /* __IP_DSTLIST_H__ */


Property changes on: trunk/sys/contrib/ipfilter/netinet/ip_dstlist.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Modified: trunk/sys/contrib/ipfilter/netinet/ip_fil.h
===================================================================
--- trunk/sys/contrib/ipfilter/netinet/ip_fil.h	2018-05-28 18:55:30 UTC (rev 10138)
+++ trunk/sys/contrib/ipfilter/netinet/ip_fil.h	2018-05-28 18:56:30 UTC (rev 10139)
@@ -1,10 +1,11 @@
+/* $MidnightBSD$ */
 /*
- * Copyright (C) 1993-2001, 2003 by Darren Reed.
+ * Copyright (C) 2012 by Darren Reed.
  *
  * See the IPFILTER.LICENCE file for details on licencing.
  *
  * @(#)ip_fil.h	1.35 6/5/96
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/contrib/ipfilter/netinet/ip_fil.h 319179 2017-05-30 03:33:48Z cy $
  * Id: ip_fil.h,v 2.170.2.51 2007/10/10 09:48:03 darrenr Exp $
  */
 
@@ -11,10 +12,29 @@
 #ifndef	__IP_FIL_H__
 #define	__IP_FIL_H__
 
+#if !defined(linux) || !defined(_KERNEL)
+# include <netinet/in.h>
+#endif
+
 #include "netinet/ip_compat.h"
+#include "netinet/ipf_rb.h"
+#if NETBSD_GE_REV(104040000)
+# include <sys/callout.h>
+#endif
+#if defined(BSD) && defined(_KERNEL)
+# if NETBSD_LT_REV(399000000) || defined(__osf__) || FREEBSD_LT_REV(500043)
+#  include <sys/select.h>
+# else
+#  include <sys/selinfo.h>
+# endif
+#endif
 
 #ifndef	SOLARIS
-# define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4)))
+# if defined(sun) && (defined(__svr4__) || defined(__SVR4))
+#  define	SOLARIS		1
+# else
+#  define	SOLARIS		0
+# endif
 #endif
 
 #ifndef	__P
@@ -63,6 +83,8 @@
 # define	SIOCIPFDELTOK	_IOWR('r', 94, int)
 # define	SIOCLOOKUPITER	_IOWR('r', 95, struct ipfobj)
 # define	SIOCGTQTAB	_IOWR('r', 96, struct ipfobj)
+# define	SIOCMATCHFLUSH	_IOWR('r', 97, struct ipfobj)
+# define	SIOCIPFINTERROR	_IOR('r', 98, int)
 #else
 # define	SIOCADAFR	_IOW(r, 60, struct ipfobj)
 # define	SIOCRMAFR	_IOW(r, 61, struct ipfobj)
@@ -101,6 +123,8 @@
 # define	SIOCIPFDELTOK	_IOWR(r, 94, int)
 # define	SIOCLOOKUPITER	_IOWR(r, 95, struct ipfobj)
 # define	SIOCGTQTAB	_IOWR(r, 96, struct ipfobj)
+# define	SIOCMATCHFLUSH	_IOWR(r, 97, struct ipfobj)
+# define	SIOCIPFINTERROR	_IOR(r, 98, int)
 #endif
 #define	SIOCADDFR	SIOCADAFR
 #define	SIOCDELFR	SIOCRMAFR
@@ -111,44 +135,33 @@
 
 struct ipscan;
 struct ifnet;
+struct ipf_main_softc_s;
 
+typedef	int	(* lookupfunc_t) __P((struct ipf_main_softc_s *, void *,
+				      int, void *, u_int));
 
-typedef	int	(* lookupfunc_t) __P((void *, int, void *));
-
 /*
  * i6addr is used as a container for both IPv4 and IPv6 addresses, as well
  * as other types of objects, depending on its qualifier.
  */
-#ifdef	USE_INET6
 typedef	union	i6addr	{
 	u_32_t	i6[4];
 	struct	in_addr	in4;
+#ifdef	USE_INET6
 	struct	in6_addr in6;
+#endif
 	void	*vptr[2];
 	lookupfunc_t	lptr[2];
 	struct {
 		u_short	type;
 		u_short	subtype;
-		char	label[12];
+		int	name;
 	} i6un;
 } i6addr_t;
-#else
-typedef	union	i6addr	{
-	u_32_t	i6[4];
-	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[1]
-#define	iplookupname	i6un.label
+#define	iplookupname	i6un.name
 #define	iplookuptype	i6un.type
 #define	iplookupsubtype	i6un.subtype
 /*
@@ -172,17 +185,25 @@
 			 (I61(a) != I61(b)) || (I60(a) != I60(b)))
 #define IP6_ISZERO(a)   ((I60(a) | I61(a) | I62(a) | I63(a)) == 0)
 #define IP6_NOTZERO(a)  ((I60(a) | I61(a) | I62(a) | I63(a)) != 0)
-#define	IP6_GT(a,b)	(HI60(a) > HI60(b) || (HI60(a) == HI60(b) && \
-			  (HI61(a) > HI61(b) || (HI61(a) == HI61(b) && \
-			    (HI62(a) > HI62(b) || (HI62(a) == HI62(b) && \
-			      HI63(a) > HI63(b)))))))
-#define	IP6_LT(a,b)	(HI60(a) < HI60(b) || (HI60(a) == HI60(b) && \
-			  (HI61(a) < HI61(b) || (HI61(a) == HI61(b) && \
-			    (HI62(a) < HI62(b) || (HI62(a) == HI62(b) && \
-			      HI63(a) < HI63(b)))))))
+#define	IP6_ISONES(a)	((I63(a) == 0xffffffff) && (I62(a) == 0xffffffff) && \
+			 (I61(a) == 0xffffffff) && (I60(a) == 0xffffffff))
+#define	IP6_GT(a,b)	(ntohl(HI60(a)) > ntohl(HI60(b)) || \
+			 (HI60(a) == HI60(b) && \
+			  (ntohl(HI61(a)) > ntohl(HI61(b)) || \
+			   (HI61(a) == HI61(b) && \
+			    (ntohl(HI62(a)) > ntohl(HI62(b)) || \
+			     (HI62(a) == HI62(b) && \
+			      ntohl(HI63(a)) > ntohl(HI63(b))))))))
+#define	IP6_LT(a,b)	(ntohl(HI60(a)) < ntohl(HI60(b)) || \
+			 (HI60(a) == HI60(b) && \
+			  (ntohl(HI61(a)) < ntohl(HI61(b)) || \
+			   (HI61(a) == HI61(b) && \
+			    (ntohl(HI62(a)) < ntohl(HI62(b)) || \
+			     (HI62(a) == HI62(b) && \
+			      ntohl(HI63(a)) < ntohl(HI63(b))))))))
 #define	NLADD(n,x)	htonl(ntohl(n) + (x))
 #define	IP6_INC(a)	\
-		{ u_32_t *_i6 = (u_32_t *)(a); \
+		do { u_32_t *_i6 = (u_32_t *)(a); \
 		  _i6[3] = NLADD(_i6[3], 1); \
 		  if (_i6[3] == 0) { \
 			_i6[2] = NLADD(_i6[2], 1); \
@@ -193,9 +214,9 @@
 				} \
 			} \
 		  } \
-		}
+		} while (0)
 #define	IP6_ADD(a,x,d)	\
-		{ i6addr_t *_s = (i6addr_t *)(a); \
+		do { i6addr_t *_s = (i6addr_t *)(a); \
 		  i6addr_t *_d = (i6addr_t *)(d); \
 		  _d->i6[0] = NLADD(_s->i6[0], x); \
 		  if (ntohl(_d->i6[0]) < ntohl(_s->i6[0])) { \
@@ -207,17 +228,35 @@
 				} \
 			} \
 		  } \
-		}
-#define	IP6_AND(a,b,d)	{ i6addr_t *_s1 = (i6addr_t *)(a); \
-			  i6addr_t *_s2 = (i6addr_t *)(d); \
+		} while (0)
+#define	IP6_AND(a,b,d)	do { i6addr_t *_s1 = (i6addr_t *)(a); \
+			  i6addr_t *_s2 = (i6addr_t *)(b); \
 			  i6addr_t *_d = (i6addr_t *)(d); \
 			  _d->i6[0] = _s1->i6[0] & _s2->i6[0]; \
 			  _d->i6[1] = _s1->i6[1] & _s2->i6[1]; \
 			  _d->i6[2] = _s1->i6[2] & _s2->i6[2]; \
 			  _d->i6[3] = _s1->i6[3] & _s2->i6[3]; \
-			}
+			} while (0)
+#define	IP6_ANDASSIGN(a,m) \
+			do { i6addr_t *_d = (i6addr_t *)(a); \
+			  i6addr_t *_m = (i6addr_t *)(m); \
+			  _d->i6[0] &= _m->i6[0]; \
+			  _d->i6[1] &= _m->i6[1]; \
+			  _d->i6[2] &= _m->i6[2]; \
+			  _d->i6[3] &= _m->i6[3]; \
+			} while (0)
+#define	IP6_MASKEQ(a,m,b) \
+			(((I60(a) & I60(m)) == I60(b)) && \
+			 ((I61(a) & I61(m)) == I61(b)) && \
+			 ((I62(a) & I62(m)) == I62(b)) && \
+			 ((I63(a) & I63(m)) == I63(b)))
+#define	IP6_MASKNEQ(a,m,b) \
+			(((I60(a) & I60(m)) != I60(b)) || \
+			 ((I61(a) & I61(m)) != I61(b)) || \
+			 ((I62(a) & I62(m)) != I62(b)) || \
+			 ((I63(a) & I63(m)) != I63(b)))
 #define	IP6_MERGE(a,b,c) \
-			{ i6addr_t *_d, *_s1, *_s2; \
+			do { i6addr_t *_d, *_s1, *_s2; \
 			  _d = (i6addr_t *)(a); \
 			  _s1 = (i6addr_t *)(b); \
 			  _s2 = (i6addr_t *)(c); \
@@ -224,9 +263,30 @@
 			  _d->i6[0] |= _s1->i6[0] & ~_s2->i6[0]; \
 			  _d->i6[1] |= _s1->i6[1] & ~_s2->i6[1]; \
 			  _d->i6[2] |= _s1->i6[2] & ~_s2->i6[2]; \
-			  _d->i6[2] |= _s1->i6[3] & ~_s2->i6[3]; \
-			}
+			  _d->i6[3] |= _s1->i6[3] & ~_s2->i6[3]; \
+			} while (0)
+#define	IP6_MASK(a,b,c) \
+			do { i6addr_t *_d, *_s1, *_s2; \
+			  _d = (i6addr_t *)(a); \
+			  _s1 = (i6addr_t *)(b); \
+			  _s2 = (i6addr_t *)(c); \
+			  _d->i6[0] = _s1->i6[0] & ~_s2->i6[0]; \
+			  _d->i6[1] = _s1->i6[1] & ~_s2->i6[1]; \
+			  _d->i6[2] = _s1->i6[2] & ~_s2->i6[2]; \
+			  _d->i6[3] = _s1->i6[3] & ~_s2->i6[3]; \
+			} while (0)
+#define	IP6_SETONES(a)	\
+			do { i6addr_t *_d = (i6addr_t *)(a); \
+			  _d->i6[0] = 0xffffffff; \
+			  _d->i6[1] = 0xffffffff; \
+			  _d->i6[2] = 0xffffffff; \
+			  _d->i6[3] = 0xffffffff; \
+			} while (0)
 
+typedef	union ipso_u	{
+	u_short	ipso_ripso[2];
+	u_32_t	ipso_doi;
+} ipso_t;
 
 typedef	struct	fr_ip	{
 	u_32_t	fi_v:4;		/* IP version */
@@ -237,11 +297,13 @@
 	u_32_t	fi_optmsk;	/* bitmask composed from IP options */
 	i6addr_t fi_src;	/* source address from packet */
 	i6addr_t fi_dst;	/* destination address from packet */
-	u_short	fi_secmsk;	/* bitmask composed from IP security options */
-	u_short	fi_auth;	/* authentication code from IP sec. options */
+	ipso_t	fi_ipso;	/* IP security options */
 	u_32_t	fi_flx;		/* packet flags */
 	u_32_t	fi_tcpmsk;	/* TCP options set/reset */
-	u_32_t	fi_res1;	/* RESERVED */
+	u_32_t	fi_ports[2];	/* TCP ports */
+	u_char	fi_tcpf;	/* TCP flags */
+	u_char	fi_sensitivity;
+	u_char	fi_xxx[2];	/* pad */
 } fr_ip_t;
 
 /*
@@ -263,16 +325,23 @@
 #define	FI_FRAGBODY	0x2000
 #define	FI_BADSRC	0x4000
 #define	FI_LOWTTL	0x8000
-#define	FI_CMP		0xcf03	/* Not FI_FRAG,FI_NATED,FI_FRAGTAIL,broadcast */
+#define	FI_CMP		0x5cfe3	/* Not FI_FRAG,FI_NATED,FI_FRAGTAIL */
 #define	FI_ICMPCMP	0x0003	/* Flags we can check for ICMP error packets */
-#define	FI_WITH		0xeffe	/* Not FI_TCPUDP */
+#define	FI_WITH		0x5effe	/* Not FI_TCPUDP */
 #define	FI_V6EXTHDR	0x10000
 #define	FI_COALESCE	0x20000
 #define	FI_NEWNAT	0x40000
+#define	FI_ICMPQUERY	0x80000
+#define	FI_ENCAP	0x100000	/* encap/decap with NAT */
+#define	FI_AH		0x200000	/* AH header present */
+#define	FI_DOCKSUM	0x10000000	/* Proxy wants L4 recalculation */
 #define	FI_NOCKSUM	0x20000000	/* don't do a L4 checksum validation */
-#define	FI_DONTCACHE	0x40000000	/* don't cache the result */
+#define	FI_NOWILD	0x40000000	/* Do not do wildcard searches */
 #define	FI_IGNORE	0x80000000
 
+#define	fi_secmsk	fi_ipso.ipso_ripso[0]
+#define	fi_auth		fi_ipso.ipso_ripso[1]
+#define	fi_doi		fi_ipso.ipso_doi
 #define	fi_saddr	fi_src.in4.s_addr
 #define	fi_daddr	fi_dst.in4.s_addr
 #define	fi_srcnum	fi_src.iplookupnum
@@ -303,37 +372,87 @@
 #define	SI_NEWFR	0x00001000
 #define	SI_CLONE	0x00002000
 #define	SI_CLONED	0x00004000
+#define	SI_NEWCLONE	0x00008000
 
+typedef	struct {
+	u_short	fda_ports[2];
+	u_char	fda_tcpf;		/* TCP header flags (SYN, ACK, etc) */
+} frdat_t;
 
+typedef enum fr_breasons_e {
+	FRB_BLOCKED = 0,
+	FRB_LOGFAIL = 1,
+	FRB_PPSRATE = 2,
+	FRB_JUMBO = 3,
+	FRB_MAKEFRIP = 4,
+	FRB_STATEADD = 5,
+	FRB_UPDATEIPID = 6,
+	FRB_LOGFAIL2 = 7,
+	FRB_DECAPFRIP = 8,
+	FRB_AUTHNEW = 9,
+	FRB_AUTHCAPTURE = 10,
+	FRB_COALESCE = 11,
+	FRB_PULLUP = 12,
+	FRB_AUTHFEEDBACK = 13,
+	FRB_BADFRAG = 14,
+	FRB_NATV4 = 15,
+	FRB_NATV6 = 16,
+} fr_breason_t;
+
+#define	FRB_MAX_VALUE	16
+
+typedef enum ipf_cksum_e {
+	FI_CK_BAD = -1,
+	FI_CK_NEEDED = 0,
+	FI_CK_SUMOK = 1,
+	FI_CK_L4PART = 2,
+	FI_CK_L4FULL = 4
+} ipf_cksum_t;
+
 typedef	struct	fr_info	{
+	void	*fin_main_soft;
 	void	*fin_ifp;		/* interface packet is `on' */
-	fr_ip_t	fin_fi;		/* IP Packet summary */
-	union	{
-		u_short	fid_16[2];	/* TCP/UDP ports, ICMP code/type */
-		u_32_t	fid_32;
-	} fin_dat;
+	struct	frentry *fin_fr;	/* last matching rule */
 	int	fin_out;		/* in or out ? 1 == out, 0 == in */
-	int	fin_rev;		/* state only: 1 = reverse */
+	fr_ip_t	fin_fi;			/* IP Packet summary */
+	frdat_t	fin_dat;		/* TCP/UDP ports, ICMP code/type */
+	int	fin_dlen;		/* length of data portion of packet */
+	int	fin_plen;
+	u_32_t	fin_rule;		/* rule # last matched */
 	u_short	fin_hlen;		/* length of IP header in bytes */
-	u_char	fin_tcpf;		/* TCP header flags (SYN, ACK, etc) */
-	u_char	fin_icode;		/* ICMP error to return */
-	u_32_t	fin_rule;		/* rule # last matched */
 	char	fin_group[FR_GROUPLEN];	/* group number, -1 for none */
-	struct	frentry *fin_fr;	/* last matching rule */
 	void	*fin_dp;		/* start of data past IP header */
-	int	fin_dlen;		/* length of data portion of packet */
-	int	fin_plen;
+	/*
+	 * Fields after fin_dp aren't used for compression of log records.
+	 * fin_fi contains the IP version (fin_family)
+	 * fin_rule isn't included because adding a new rule can change it but
+	 * not change fin_fr. fin_rule is the rule number reported.
+	 * It isn't necessary to include fin_crc because that is checked
+	 * for explicitly, before calling bcmp.
+	 */
+	u_32_t	fin_crc;		/* Simple calculation for logging */
+	int	fin_family;		/* AF_INET, etc. */
+	int	fin_icode;		/* ICMP error to return */
+	int	fin_mtu;		/* MTU input for ICMP need-frag */
+	int	fin_rev;		/* state only: 1 = reverse */
 	int	fin_ipoff;		/* # bytes from buffer start to hdr */
-	u_short	fin_id;			/* IP packet id field */
+	u_32_t	fin_id;			/* IP packet id field */
+	u_short	fin_l4hlen;		/* length of L4 header, if known */
 	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;
+	ipf_cksum_t	fin_cksum;	/* -1 = bad, 1 = good, 0 = not done */
+	fr_breason_t	fin_reason;	/* why auto blocked */
+	u_int	fin_pktnum;
 	void	*fin_nattag;
-	void	*fin_exthdr;
-	ip_t	*fin_ip;
+	struct frdest	*fin_dif;
+	struct frdest	*fin_tif;
+	union {
+		ip_t	*fip_ip;
+#ifdef USE_INET6
+		ip6_t	*fip_ip6;
+#endif
+	} fin_ipu;
 	mb_t	**fin_mp;		/* pointer to pointer to mbuf */
 	mb_t	*fin_m;			/* pointer to mbuf */
 #ifdef	MENTAT
@@ -344,35 +463,42 @@
 #ifdef	__sgi
 	void	*fin_hbuf;
 #endif
+	void	*fin_fraghdr;		/* pointer to start of ipv6 frag hdr */
 } fr_info_t;
 
+#define	fin_ip		fin_ipu.fip_ip
+#define	fin_ip6		fin_ipu.fip_ip6
 #define	fin_v		fin_fi.fi_v
 #define	fin_p		fin_fi.fi_p
 #define	fin_flx		fin_fi.fi_flx
 #define	fin_optmsk	fin_fi.fi_optmsk
 #define	fin_secmsk	fin_fi.fi_secmsk
+#define	fin_doi		fin_fi.fi_doi
 #define	fin_auth	fin_fi.fi_auth
 #define	fin_src		fin_fi.fi_src.in4
-#define	fin_src6	fin_fi.fi_src.in6
 #define	fin_saddr	fin_fi.fi_saddr
 #define	fin_dst		fin_fi.fi_dst.in4
-#define	fin_dst6	fin_fi.fi_dst.in6
 #define	fin_daddr	fin_fi.fi_daddr
-#define	fin_data	fin_dat.fid_16
-#define	fin_sport	fin_dat.fid_16[0]
-#define	fin_dport	fin_dat.fid_16[1]
-#define	fin_ports	fin_dat.fid_32
+#define	fin_data	fin_fi.fi_ports
+#define	fin_sport	fin_fi.fi_ports[0]
+#define	fin_dport	fin_fi.fi_ports[1]
+#define	fin_tcpf	fin_fi.fi_tcpf
+#define	fin_src6	fin_fi.fi_src
+#define	fin_dst6	fin_fi.fi_dst
+#define	fin_srcip6	fin_fi.fi_src.in6
+#define	fin_dstip6	fin_fi.fi_dst.in6
 
 #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 *));
+typedef	int		(*ipfuncinit_t) __P((struct ipf_main_softc_s *, struct frentry *));
 
 typedef	struct	ipfunc_resolve	{
 	char		ipfu_name[32];
 	ipfunc_t	ipfu_addr;
 	ipfuncinit_t	ipfu_init;
+	ipfuncinit_t	ipfu_fini;
 } ipfunc_resolve_t;
 
 /*
@@ -401,39 +527,78 @@
 #define	ipt_tag	ipt_un.iptu_tag
 #define	ipt_num	ipt_un.iptu_num
 
+/*
+ * Structure to define address for pool lookups.
+ */
+typedef	struct	{
+	u_char		adf_len;
+	sa_family_t	adf_family;
+	u_char		adf_xxx[2];
+	i6addr_t	adf_addr;
+} addrfamily_t;
 
+
+RBI_LINK(ipf_rb, host_node_s);
+
+typedef	struct	host_node_s {
+	RBI_FIELD(ipf_rb)	hn_entry;
+	addrfamily_t		hn_addr;
+	int			hn_active;
+} host_node_t;
+
+typedef RBI_HEAD(ipf_rb, host_node_s) ipf_rb_head_t;
+
+typedef	struct	host_track_s {
+	ipf_rb_head_t	ht_root;
+	int		ht_max_nodes;
+	int		ht_max_per_node;
+	int		ht_netmask;
+	int		ht_cur_nodes;
+} host_track_t;
+
+
+typedef enum fr_dtypes_e {
+	FRD_NORMAL = 0,
+	FRD_DSTLIST
+} fr_dtypes_t;
 /*
  * This structure is used to hold information about the next hop for where
  * to forward a packet.
  */
 typedef	struct	frdest	{
-	void	*fd_ifp;
-	i6addr_t	fd_ip6;
-	char	fd_ifname[LIFNAMSIZ];
+	void		*fd_ptr;
+	addrfamily_t	fd_addr;
+	fr_dtypes_t	fd_type;
+	int		fd_name;
+	int		fd_local;
 } frdest_t;
 
+#define	fd_ip6	fd_addr.adf_addr
 #define	fd_ip	fd_ip6.in4
 
 
+typedef enum fr_ctypes_e {
+	FR_NONE = 0,
+	FR_EQUAL,
+	FR_NEQUAL,
+	FR_LESST,
+	FR_GREATERT,
+	FR_LESSTE,
+	FR_GREATERTE,
+	FR_OUTRANGE,
+	FR_INRANGE,
+	FR_INCRANGE
+} fr_ctypes_t;
+
 /*
  * This structure holds information about a port comparison.
  */
 typedef	struct	frpcmp	{
-	int	frp_cmp;	/* data for port comparisons */
-	u_short	frp_port;	/* top port for <> and >< */
-	u_short	frp_top;	/* top port for <> and >< */
+	fr_ctypes_t	frp_cmp;	/* data for port comparisons */
+	u_32_t		frp_port;	/* top port for <> and >< */
+	u_32_t		frp_top;	/* top port for <> and >< */
 } frpcmp_t;
 
-#define FR_NONE 0
-#define FR_EQUAL 1
-#define FR_NEQUAL 2
-#define FR_LESST 3
-#define FR_GREATERT 4
-#define FR_LESSTE 5
-#define FR_GREATERTE 6
-#define FR_OUTRANGE 7
-#define FR_INRANGE 8
-#define FR_INCRANGE 9
 
 /*
  * Structure containing all the relevant TCP things that can be checked in
@@ -455,6 +620,20 @@
 
 #define	FR_TCPFMAX	0x3f
 
+typedef enum fr_atypes_e {
+	FRI_NONE = -1,	/* For LHS of NAT */
+	FRI_NORMAL = 0,	/* Normal address */
+	FRI_DYNAMIC,	/* dynamic address */
+	FRI_LOOKUP,	/* address is a pool # */
+	FRI_RANGE,	/* address/mask is a range */
+	FRI_NETWORK,	/* network address from if */
+	FRI_BROADCAST,	/* broadcast address from if */
+	FRI_PEERADDR,	/* Peer address for P-to-P */
+	FRI_NETMASKED,	/* network address with netmask from if */
+	FRI_SPLIT,	/* For NAT compatibility */
+	FRI_INTERFACE	/* address is based on interface name */
+} fr_atypes_t;
+
 /*
  * This structure makes up what is considered to be the IPFilter specific
  * matching components of a filter rule, as opposed to the data structures
@@ -461,17 +640,17 @@
  * used to define the result which are in frentry_t and not here.
  */
 typedef	struct	fripf	{
-	fr_ip_t	fri_ip;
-	fr_ip_t	fri_mip;	/* mask structure */
+	fr_ip_t		fri_ip;
+	fr_ip_t		fri_mip;	/* mask structure */
 
-	u_short	fri_icmpm;		/* data for ICMP packets (mask) */
-	u_short	fri_icmp;
+	u_short		fri_icmpm;	/* data for ICMP packets (mask) */
+	u_short		fri_icmp;
 
-	frtuc_t	fri_tuc;
-	int	fri_satype;		/* addres type */
-	int	fri_datype;		/* addres type */
-	int	fri_sifpidx;		/* doing dynamic addressing */
-	int	fri_difpidx;		/* index into fr_ifps[] to use when */
+	frtuc_t		fri_tuc;
+	fr_atypes_t	fri_satype;	/* addres type */
+	fr_atypes_t	fri_datype;	/* addres type */
+	int		fri_sifpidx;	/* doing dynamic addressing */
+	int		fri_difpidx;	/* index into fr_ifps[] to use when */
 } fripf_t;
 
 #define	fri_dlookup	fri_mip.fi_dst
@@ -483,15 +662,21 @@
 #define	fri_dstptr	fri_mip.fi_dstptr
 #define	fri_srcptr	fri_mip.fi_srcptr
 
-#define	FRI_NORMAL	0	/* Normal address */
-#define	FRI_DYNAMIC	1	/* dynamic address */
-#define	FRI_LOOKUP	2	/* address is a pool # */
-#define	FRI_RANGE	3	/* address/mask is a range */
-#define	FRI_NETWORK	4	/* network address from if */
-#define	FRI_BROADCAST	5	/* broadcast address from if */
-#define	FRI_PEERADDR	6	/* Peer address for P-to-P */
-#define	FRI_NETMASKED	7	/* network address with netmask from if */
 
+typedef enum fr_rtypes_e {
+	FR_T_NONE = 0,
+	FR_T_IPF,		/* IPF structures */
+	FR_T_BPFOPC,		/* BPF opcode */
+	FR_T_CALLFUNC,		/* callout to function in fr_func only */
+	FR_T_COMPIPF,			/* compiled C code */
+	FR_T_IPFEXPR,			/* IPF expression */
+	FR_T_BUILTIN = 0x40000000,	/* rule is in kernel space */
+	FR_T_IPF_BUILTIN,
+	FR_T_BPFOPC_BUILTIN,
+	FR_T_CALLFUNC_BUILTIN,
+	FR_T_COMPIPF_BUILTIN,
+	FR_T_IPFEXPR_BUILTIN
+} fr_rtypes_t;
 
 typedef	struct	frentry	* (* frentfunc_t) __P((fr_info_t *));
 
@@ -498,13 +683,21 @@
 typedef	struct	frentry {
 	ipfmutex_t	fr_lock;
 	struct	frentry	*fr_next;
-	struct	frentry	**fr_grp;
+	struct	frentry	**fr_pnext;
+	struct	frgroup	*fr_grp;
+	struct	frgroup	*fr_grphead;
+	struct	frgroup	*fr_icmpgrp;
 	struct	ipscan	*fr_isc;
+	struct	frentry	*fr_dnext;	/* 2 fr_die linked list pointers */
+	struct	frentry	**fr_pdnext;
 	void	*fr_ifas[4];
 	void	*fr_ptr;	/* for use with fr_arg */
-	char	*fr_comment;	/* text comment for rule */
-	int	fr_ref;		/* reference count - for grouping */
+	int	fr_comment;	/* text comment for rule */
+	int	fr_size;	/* size of this structure */
+	int	fr_ref;		/* reference count */
 	int	fr_statecnt;	/* state count - for limit rules */
+	u_32_t	fr_die;		/* only used on loading the rule */
+	u_int	fr_cksum;	/* checksum on filter rules for performance */
 	/*
 	 * 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 -''
@@ -521,13 +714,18 @@
 
 	/*
 	 * For PPS rate limiting
+	 * fr_lpu is used to always have the same size for this field,
+	 * allocating 64bits for seconds and 32bits for milliseconds.
 	 */
-	struct timeval	fr_lastpkt;
+	union {
+		struct timeval	frp_lastpkt;
+		char	frp_bytes[12];
+	} fr_lpu;
 	int		fr_curpps;
 
 	union	{
 		void		*fru_data;
-		caddr_t		fru_caddr;
+		char		*fru_caddr;
 		fripf_t		*fru_ipf;
 		frentfunc_t	fru_func;
 	} fr_dun;
@@ -538,29 +736,38 @@
 	ipfunc_t fr_func; 	/* call this function */
 	int	fr_dsize;
 	int	fr_pps;
-	int	fr_statemax;	/* max reference count */
-	u_32_t	fr_type;
+	fr_rtypes_t	fr_type;
 	u_32_t	fr_flags;	/* per-rule flags && options (see below) */
 	u_32_t	fr_logtag;	/* user defined log tag # */
 	u_32_t	fr_collect;	/* collection number */
-	u_int	fr_arg;		/* misc. numeric arg for rule */ 
+	u_int	fr_arg;		/* misc. numeric arg for rule */
 	u_int	fr_loglevel;	/* syslog log facility + priority */
-	u_int	fr_age[2];	/* non-TCP timeouts */
-	u_char	fr_v;
+	u_char	fr_family;
 	u_char	fr_icode;	/* return ICMP code */
-	char	fr_group[FR_GROUPLEN];	/* group to which this rule belongs */
-	char	fr_grhead[FR_GROUPLEN];	/* group # which this rule starts */
+	int	fr_group;	/* group to which this rule belongs */
+	int	fr_grhead;	/* group # which this rule starts */
+	int	fr_ifnames[4];
+	int	fr_isctag;
+	int	fr_rpc;		/* XID Filtering */ 
 	ipftag_t fr_nattag;
-	char	fr_ifnames[4][LIFNAMSIZ];
-	char	fr_isctag[16];
 	frdest_t fr_tifs[2];	/* "to"/"reply-to" interface */
 	frdest_t fr_dif;	/* duplicate packet interface */
 	/*
-	 * This must be last and will change after loaded into the kernel.
+	 * These are all options related to stateful filtering
 	 */
-	u_int	fr_cksum;	/* checksum on filter rules for performance */
+	host_track_t	fr_srctrack;
+	int	fr_nostatelog;
+	int	fr_statemax;	/* max reference count */
+	int	fr_icmphead;	/* ICMP group  for state options */
+	u_int	fr_age[2];	/* non-TCP state timeouts */
+	/*
+	 * How big is the name buffer at the end?
+	 */
+	int	fr_namelen;
+	char	fr_names[1];
 } frentry_t;
 
+#define	fr_lastpkt	fr_lpu.frp_lastpkt
 #define	fr_caddr	fr_dun.fru_caddr
 #define	fr_data		fr_dun.fru_data
 #define	fr_dfunc	fr_dun.fru_func
@@ -589,12 +796,16 @@
 #define	fr_stop		fr_tuc.ftu_stop
 #define	fr_dtop		fr_tuc.ftu_dtop
 #define	fr_dst		fr_ip.fi_dst.in4
+#define	fr_dst6		fr_ip.fi_dst
 #define	fr_daddr	fr_ip.fi_dst.in4.s_addr
 #define	fr_src		fr_ip.fi_src.in4
+#define	fr_src6		fr_ip.fi_src
 #define	fr_saddr	fr_ip.fi_src.in4.s_addr
 #define	fr_dmsk		fr_mip.fi_dst.in4
+#define	fr_dmsk6	fr_mip.fi_dst
 #define	fr_dmask	fr_mip.fi_dst.in4.s_addr
 #define	fr_smsk		fr_mip.fi_src.in4
+#define	fr_smsk6	fr_mip.fi_src
 #define	fr_smask	fr_mip.fi_src.in4.s_addr
 #define	fr_dstnum	fr_ip.fi_dstnum
 #define	fr_srcnum	fr_ip.fi_srcnum
@@ -616,10 +827,10 @@
 #define	fr_secmask	fr_mip.fi_secmsk
 #define	fr_authbits	fr_ip.fi_auth
 #define	fr_authmask	fr_mip.fi_auth
+#define	fr_doi		fr_ip.fi_doi
+#define	fr_doimask	fr_mip.fi_doi
 #define	fr_flx		fr_ip.fi_flx
 #define	fr_mflx		fr_mip.fi_flx
-#define	fr_ifname	fr_ifnames[0]
-#define	fr_oifname	fr_ifnames[2]
 #define	fr_ifa		fr_ifas[0]
 #define	fr_oifa		fr_ifas[2]
 #define	fr_tif		fr_tifs[0]
@@ -627,26 +838,14 @@
 
 #define	FR_NOLOGTAG	0
 
-#ifndef	offsetof
-#define	offsetof(t,m)	(int)((&((t *)0L)->m))
-#endif
 #define	FR_CMPSIZ	(sizeof(struct frentry) - \
 			 offsetof(struct frentry, fr_func))
+#define	FR_NAME(_f, _n)	(_f)->fr_names + (_f)->_n
 
-/*
- * fr_type
- */
-#define	FR_T_NONE	0
-#define	FR_T_IPF	1	/* IPF structures */
-#define	FR_T_BPFOPC	2	/* BPF opcode */
-#define	FR_T_CALLFUNC	3	/* callout to function in fr_func only */
-#define	FR_T_COMPIPF	4	/* compiled C code */
-#define	FR_T_BUILTIN	0x80000000	/* rule is in kernel space */
 
 /*
  * fr_flags
  */
-#define	FR_CALL		0x00000	/* call rule */
 #define	FR_BLOCK	0x00001	/* do not allow packet to pass */
 #define	FR_PASS		0x00002	/* allow packet to pass */
 #define	FR_AUTH		0x00003	/* use authentication */
@@ -653,7 +852,8 @@
 #define	FR_PREAUTH	0x00004	/* require preauthentication */
 #define	FR_ACCOUNT	0x00005	/* Accounting rule */
 #define	FR_SKIP		0x00006	/* skip rule */
-#define	FR_DIVERT	0x00007	/* divert rule */
+#define	FR_DECAPSULATE	0x00008	/* decapsulate rule */
+#define	FR_CALL		0x00009	/* call rule */
 #define	FR_CMDMASK	0x0000f
 #define	FR_LOG		0x00010	/* Log */
 #define	FR_LOGB		0x00011	/* Log-fail */
@@ -674,19 +874,19 @@
 #define	FR_LOGBODY	0x10000	/* Log the body */
 #define	FR_LOGFIRST	0x20000	/* Log the first byte if state held */
 #define	FR_LOGORBLOCK	0x40000	/* block the packet if it can't be logged */
-#define	FR_DUP		0x80000	/* duplicate packet */
+#define	FR_STLOOSE	0x80000	/* loose state checking */
 #define	FR_FRSTRICT	0x100000	/* strict frag. cache */
 #define	FR_STSTRICT	0x200000	/* strict keep state */
 #define	FR_NEWISN	0x400000	/* new ISN for outgoing TCP */
 #define	FR_NOICMPERR	0x800000	/* do not match ICMP errors in state */
 #define	FR_STATESYNC	0x1000000	/* synchronize state to slave */
+#define	FR_COPIED	0x2000000	/* copied from user space */
+#define	FR_INACTIVE	0x4000000	/* only used when flush'ing rules */
 #define	FR_NOMATCH	0x8000000	/* no match occured */
 		/*	0x10000000 	FF_LOGPASS */
 		/*	0x20000000 	FF_LOGBLOCK */
 		/*	0x40000000 	FF_LOGNOMATCH */
 		/*	0x80000000 	FF_BLOCKNONIP */
-#define	FR_COPIED	0x40000000	/* copied from user space */
-#define	FR_INACTIVE	0x80000000	/* only used when flush'ing rules */
 
 #define	FR_RETMASK	(FR_RETICMP|FR_RETRST|FR_FAKEICMP)
 #define	FR_ISBLOCK(x)	(((x) & FR_CMDMASK) == FR_BLOCK)
@@ -695,6 +895,7 @@
 #define	FR_ISPREAUTH(x)	(((x) & FR_CMDMASK) == FR_PREAUTH)
 #define	FR_ISACCOUNT(x)	(((x) & FR_CMDMASK) == FR_ACCOUNT)
 #define	FR_ISSKIP(x)	(((x) & FR_CMDMASK) == FR_SKIP)
+#define	FR_ISDECAPS(x)	(((x) & FR_CMDMASK) == FR_DECAPSULATE)
 #define	FR_ISNOMATCH(x)	((x) & FR_NOMATCH)
 #define	FR_INOUT	(FR_INQUE|FR_OUTQUE)
 
@@ -712,8 +913,8 @@
  * Structure that passes information on what/how to flush to the kernel.
  */
 typedef	struct	ipfflush	{
-	int	ipflu_how;
-	int	ipflu_arg;
+	int		ipflu_how;
+	int		ipflu_arg;
 } ipfflush_t;
 
 
@@ -721,12 +922,12 @@
  *
  */
 typedef	struct	ipfgetctl	{
-	u_int	ipfg_min;	/* min value */
-	u_int	ipfg_current;	/* current value */
-	u_int	ipfg_max;	/* max value */
-	u_int	ipfg_default;	/* default value */
-	u_int	ipfg_steps;	/* value increments */
-	char	ipfg_name[40];	/* tag name for this control */
+	u_int		ipfg_min;	/* min value */
+	u_int		ipfg_current;	/* current value */
+	u_int		ipfg_max;	/* max value */
+	u_int		ipfg_default;	/* default value */
+	u_int		ipfg_steps;	/* value increments */
+	char		ipfg_name[40];	/* tag name for this control */
 } ipfgetctl_t;
 
 typedef	struct	ipfsetctl	{
@@ -741,7 +942,43 @@
  * in this single structure so that they can all easily be collected and
  * copied back as required.
  */
-typedef	struct	filterstats {
+typedef	struct	ipf_statistics {
+	u_long	fr_icmp_coalesce;
+	u_long	fr_tcp_frag;
+	u_long	fr_tcp_pullup;
+	u_long	fr_tcp_short;
+	u_long	fr_tcp_small;
+	u_long	fr_tcp_bad_flags;
+	u_long	fr_udp_pullup;
+	u_long	fr_ip_freed;
+	u_long	fr_v6_ah_bad;
+	u_long	fr_v6_bad;
+	u_long	fr_v6_badfrag;
+	u_long	fr_v6_dst_bad;
+	u_long	fr_v6_esp_pullup;
+	u_long	fr_v6_ext_short;
+	u_long	fr_v6_ext_pullup;
+	u_long	fr_v6_ext_hlen;
+	u_long	fr_v6_frag_bad;
+	u_long	fr_v6_frag_pullup;
+	u_long	fr_v6_frag_size;
+	u_long	fr_v6_gre_pullup;
+	u_long	fr_v6_icmp6_pullup;
+	u_long	fr_v6_rh_bad;
+	u_long	fr_v6_badttl;	/* TTL in packet doesn't reach minimum */
+	u_long	fr_v4_ah_bad;
+	u_long	fr_v4_ah_pullup;
+	u_long	fr_v4_esp_pullup;
+	u_long	fr_v4_cipso_bad;
+	u_long	fr_v4_cipso_tlen;
+	u_long	fr_v4_gre_frag;
+	u_long	fr_v4_gre_pullup;
+	u_long	fr_v4_icmp_frag;
+	u_long	fr_v4_icmp_pullup;
+	u_long	fr_v4_badttl;	/* TTL in packet doesn't reach minimum */
+	u_long	fr_v4_badsrc;	/* source received doesn't match route */
+	u_long	fr_l4_badcksum;	/* layer 4 header checksum failure */
+	u_long	fr_badcoalesces;
 	u_long	fr_pass;	/* packets allowed */
 	u_long	fr_block;	/* packets denied */
 	u_long	fr_nom;		/* packets which don't match any rule */
@@ -749,8 +986,6 @@
 	u_long	fr_ppkl;	/* packets allowed and logged */
 	u_long	fr_bpkl;	/* packets denied and logged */
 	u_long	fr_npkl;	/* packets unmatched and logged */
-	u_long	fr_pkl;		/* packets logged */
-	u_long	fr_skip;	/* packets to be logged but buffer full */
 	u_long	fr_ret;		/* packets for which a return is sent */
 	u_long	fr_acct;	/* packets for which counting was performed */
 	u_long	fr_bnfr;	/* bad attempts to allocate fragment state */
@@ -759,15 +994,15 @@
 	u_long	fr_bads;	/* bad attempts to allocate packet state */
 	u_long	fr_ads;		/* new packet state kept */
 	u_long	fr_chit;	/* cached hit */
+	u_long	fr_cmiss;	/* cached miss */
 	u_long	fr_tcpbad;	/* TCP checksum check failures */
 	u_long	fr_pull[2];	/* good and bad pullup attempts */
-	u_long	fr_badsrc;	/* source received doesn't match route */
-	u_long	fr_badttl;	/* TTL in packet doesn't reach minimum */
 	u_long	fr_bad;		/* bad IP packets to the filter */
 	u_long	fr_ipv6;	/* IPv6 packets in/out */
 	u_long	fr_ppshit;	/* dropped because of pps ceiling */
 	u_long	fr_ipud;	/* IP id update failures */
-} filterstats_t;
+	u_long	fr_blocked[FRB_MAX_VALUE + 1];
+} ipf_statistics_t;
 
 /*
  * Log structure.  Each packet header logged is prepended by one of these.
@@ -777,6 +1012,7 @@
 typedef	struct	iplog	{
 	u_32_t		ipl_magic;
 	u_int		ipl_count;
+	u_32_t		ipl_seqnum;
 	struct	timeval	ipl_time;
 	size_t		ipl_dsize;
 	struct	iplog	*ipl_next;
@@ -796,18 +1032,19 @@
 #else
 	u_int	fl_unit;
 #endif
-	u_32_t	fl_rule;
-	u_32_t	fl_flags;
-	u_32_t	fl_lflags;
-	u_32_t	fl_logtag;
+	u_32_t		fl_rule;
+	u_32_t		fl_flags;
+	u_32_t		fl_lflags;
+	u_32_t		fl_logtag;
 	ipftag_t	fl_nattag;
-	u_short	fl_plen;	/* extra data after hlen */
-	u_short	fl_loglevel;	/* syslog log level */
-	char	fl_group[FR_GROUPLEN];
-	u_char	fl_hlen;	/* length of IP headers saved */
-	u_char	fl_dir;
-	u_char	fl_xxx[2];	/* pad */
-	char	fl_ifname[LIFNAMSIZ];
+	u_short		fl_plen;	/* extra data after hlen */
+	u_short		fl_loglevel;	/* syslog log level */
+	char		fl_group[FR_GROUPLEN];
+	u_char		fl_hlen;	/* length of IP headers saved */
+	u_char		fl_dir;
+	u_char		fl_breason;	/* from fin_reason */
+	u_char		fl_family;	/* address family of packet logged */
+	char		fl_ifname[LIFNAMSIZ];
 } ipflog_t;
 
 #ifndef	IPF_LOGGING
@@ -817,12 +1054,12 @@
 # define	IPF_DEFAULT_PASS	FR_PASS
 #endif
 
-#define	DEFAULT_IPFLOGSIZE	8192
+#define	DEFAULT_IPFLOGSIZE	32768
 #ifndef	IPFILTER_LOGSIZE
 # define	IPFILTER_LOGSIZE	DEFAULT_IPFLOGSIZE
 #else
-# if IPFILTER_LOGSIZE < DEFAULT_IPFLOGSIZE
-#  error IPFILTER_LOGSIZE too small.  Must be >= DEFAULT_IPFLOGSIZE
+# if IPFILTER_LOGSIZE < 8192
+#  error IPFILTER_LOGSIZE too small.  Must be >= 8192
 # endif
 #endif
 
@@ -867,34 +1104,30 @@
  * For SIOCGETFS
  */
 typedef	struct	friostat	{
-	struct	filterstats	f_st[2];
-	struct	frentry		*f_ipf[2][2];
-	struct	frentry		*f_acct[2][2];
-	struct	frentry		*f_ipf6[2][2];
-	struct	frentry		*f_acct6[2][2];
-	struct	frentry		*f_auth;
-	struct	frgroup		*f_groups[IPL_LOGSIZE][2];
-	u_long	f_froute[2];
-	u_long	f_ticks;
-	int	f_locks[IPL_LOGMAX];
-	size_t	f_kmutex_sz;
-	size_t	f_krwlock_sz;
-	int	f_defpass;	/* default pass - from fr_pass */
-	int	f_active;	/* 1 or 0 - active rule set */
-	int	f_running;	/* 1 if running, else 0 */
-	int	f_logging;	/* 1 if enabled, else 0 */
-	int	f_features;
-	char	f_version[32];	/* version string */
+	ipf_statistics_t f_st[2];
+	frentry_t	*f_ipf[2][2];
+	frentry_t	*f_acct[2][2];
+	frentry_t	*f_auth;
+	struct frgroup	*f_groups[IPL_LOGSIZE][2];
+	u_long		f_froute[2];
+	u_long		f_log_ok;
+	u_long		f_log_fail;
+	u_long		f_rb_no_mem;
+	u_long		f_rb_node_max;
+	u_32_t		f_ticks;
+	int		f_locks[IPL_LOGSIZE];
+	int		f_defpass;	/* default pass - from fr_pass */
+	int		f_active;	/* 1 or 0 - active rule set */
+	int		f_running;	/* 1 if running, else 0 */
+	int		f_logging;	/* 1 if enabled, else 0 */
+	int		f_features;
+	char		f_version[32];	/* version string */
 } friostat_t;
 
 #define	f_fin		f_ipf[0]
-#define	f_fin6		f_ipf6[0]
 #define	f_fout		f_ipf[1]
-#define	f_fout6		f_ipf6[1]
 #define	f_acctin	f_acct[0]
-#define	f_acctin6	f_acct6[0]
 #define	f_acctout	f_acct[1]
-#define	f_acctout6	f_acct6[1]
 
 #define	IPF_FEAT_LKM		0x001
 #define	IPF_FEAT_LOG		0x002
@@ -916,12 +1149,13 @@
  * Group list structure.
  */
 typedef	struct frgroup {
-	struct	frgroup	*fg_next;
-	struct	frentry	*fg_head;
-	struct	frentry	*fg_start;
-	u_32_t	fg_flags;
-	int	fg_ref;
-	char	fg_name[FR_GROUPLEN];
+	struct frgroup	*fg_next;
+	struct frentry	*fg_head;
+	struct frentry	*fg_start;
+	struct frgroup	**fg_set;
+	u_32_t		fg_flags;
+	int		fg_ref;
+	char		fg_name[FR_GROUPLEN];
 } frgroup_t;
 
 #define	FG_NAME(g)	(*(g)->fg_name == '\0' ? "" : (g)->fg_name)
@@ -931,24 +1165,24 @@
  * Used by state and NAT tables
  */
 typedef struct icmpinfo {
-	u_short	ici_id;
-	u_short	ici_seq;
-	u_char	ici_type;
+	u_short		ici_id;
+	u_short		ici_seq;
+	u_char		ici_type;
 } icmpinfo_t;
 
 typedef struct udpinfo {
-	u_short	us_sport;
-	u_short	us_dport;
+	u_short		us_sport;
+	u_short		us_dport;
 } udpinfo_t;
 
 
 typedef	struct	tcpdata	{
-	u_32_t	td_end;
-	u_32_t	td_maxend;
-	u_32_t	td_maxwin;
-	u_32_t	td_winscale;
-	u_32_t	td_maxseg;
-	int	td_winflags;
+	u_32_t		td_end;
+	u_32_t		td_maxend;
+	u_32_t		td_maxwin;
+	u_32_t		td_winscale;
+	u_32_t		td_maxseg;
+	int		td_winflags;
 } tcpdata_t;
 
 #define	TCP_WSCALE_MAX		14
@@ -959,9 +1193,9 @@
 
 
 typedef	struct tcpinfo {
-	u_short	ts_sport;
-	u_short	ts_dport;
-	tcpdata_t ts_data[2];
+	u_32_t		ts_sport;
+	u_32_t		ts_dport;
+	tcpdata_t	ts_data[2];
 } tcpinfo_t;
 
 
@@ -969,16 +1203,28 @@
  * 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;
-	u_32_t	grb_K:1;
-	u_32_t	grb_S:1;
-	u_32_t	grb_s:1;
-	u_32_t	grb_recur:1;
-	u_32_t	grb_A:1;
-	u_32_t	grb_flags:3;
-	u_32_t	grb_ver:3;
-	u_short	grb_ptype;
+#if defined(sparc)
+	u_32_t		grb_ver:3;
+	u_32_t		grb_flags:3;
+	u_32_t		grb_A:1;
+	u_32_t		grb_recur:1;
+	u_32_t		grb_s:1;
+	u_32_t		grb_S:1;
+	u_32_t		grb_K:1;
+	u_32_t		grb_R:1;
+	u_32_t		grb_C:1;
+#else
+	u_32_t		grb_C:1;
+	u_32_t		grb_R:1;
+	u_32_t		grb_K:1;
+	u_32_t		grb_S:1;
+	u_32_t		grb_s:1;
+	u_32_t		grb_recur:1;
+	u_32_t		grb_A:1;
+	u_32_t		grb_flags:3;
+	u_32_t		grb_ver:3;
+#endif
+	u_short		grb_ptype;
 };
 
 typedef	struct	grehdr	{
@@ -986,8 +1232,8 @@
 		struct	grebits	gru_bits;
 		u_short	gru_flags;
 	} gr_un;
-	u_short	gr_len;
-	u_short	gr_call;
+	u_short		gr_len;
+	u_short		gr_call;
 } grehdr_t;
 
 #define	gr_flags	gr_un.gru_flags
@@ -1006,9 +1252,9 @@
  * GRE information tracked by "keep state"
  */
 typedef	struct	greinfo	{
-	u_short	gs_call[2];
-	u_short	gs_flags;
-	u_short	gs_ptype;
+	u_short		gs_call[2];
+	u_short		gs_flags;
+	u_short		gs_ptype;
 } greinfo_t;
 
 #define	GRE_REV(x)	((ntohs(x) >> 13) & 7)
@@ -1018,11 +1264,11 @@
  * 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;
+	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;
@@ -1035,14 +1281,15 @@
 	struct ipftqent **tqe_pnext;
 	struct ipftqent *tqe_next;
 	struct	ipftq	*tqe_ifq;
-	void	*tqe_parent;		/* pointer back to NAT/state struct */
-	u_long	tqe_die;		/* when this entriy is to die */
-	u_long	tqe_touched;
-	int	tqe_flags;
-	int	tqe_state[2];		/* current state of this entry */
+	void		*tqe_parent;	/* pointer back to NAT/state struct */
+	u_32_t		tqe_die;	/* when this entriy is to die */
+	u_32_t		tqe_touched;
+	int		tqe_flags;
+	int		tqe_state[2];	/* current state of this entry */
 } ipftqent_t;
 
 #define	TQE_RULEBASED	0x00000001
+#define	TQE_DELETE	0x00000002
 
 
 /*
@@ -1050,13 +1297,13 @@
  */
 typedef struct  ipftq   {
 	ipfmutex_t	ifq_lock;
-	u_int	ifq_ttl;
+	u_int		ifq_ttl;
 	ipftqent_t	*ifq_head;
 	ipftqent_t	**ifq_tail;
-	struct	ipftq	*ifq_next;
-	struct	ipftq	**ifq_pnext;
-	int	ifq_ref;
-	u_int	ifq_flags;
+	struct ipftq	*ifq_next;
+	struct ipftq	**ifq_pnext;
+	int		ifq_ref;
+	u_int		ifq_flags;
 } ipftq_t;
 
 #define	IFQF_USER	0x01		/* User defined aging */
@@ -1063,32 +1310,33 @@
 #define	IFQF_DELETE	0x02		/* Marked for deletion */
 #define	IFQF_PROXY	0x04		/* Timeout queue in use by a proxy */
 
+#define	IPFTQ_INIT(x,y,z)	do {			\
+					(x)->ifq_ttl = (y);	\
+					(x)->ifq_head = NULL;	\
+					(x)->ifq_ref = 1;	\
+					(x)->ifq_tail = &(x)->ifq_head; \
+					MUTEX_INIT(&(x)->ifq_lock, (z)); \
+				} while (0)
+
 #define	IPF_HZ_MULT	1
 #define	IPF_HZ_DIVIDE	2		/* How many times a second ipfilter */
 					/* checks its timeout queues.       */
 #define	IPF_TTLVAL(x)	(((x) / IPF_HZ_MULT) * IPF_HZ_DIVIDE)
 
-typedef	int	(*ipftq_delete_fn_t)(void *);       
+typedef	int	(*ipftq_delete_fn_t)(struct ipf_main_softc_s *, void *);
 
-/*
- * Structure to define address for pool lookups.
- */
-typedef	struct	{
-	u_char		adf_len;
-	i6addr_t	adf_addr;
-} addrfamily_t;
 
-
 /*
  * Object structure description.  For passing through in ioctls.
  */
 typedef	struct	ipfobj	{
-	u_32_t	ipfo_rev;		/* IPFilter version number */
-	u_32_t	ipfo_size;		/* size of object at ipfo_ptr */
-	void	*ipfo_ptr;		/* pointer to object */
-	int	ipfo_type;		/* type of object being pointed to */
-	int	ipfo_offset;		/* bytes from ipfo_ptr where to start */
-	u_char	ipfo_xxxpad[32];	/* reserved for future use */
+	u_32_t		ipfo_rev;	/* IPFilter version number */
+	u_32_t		ipfo_size;	/* size of object at ipfo_ptr */
+	void		*ipfo_ptr;	/* pointer to object */
+	int		ipfo_type;	/* type of object being pointed to */
+	int		ipfo_offset;	/* bytes from ipfo_ptr where to start */
+	int		ipfo_retval;	/* return value */
+	u_char		ipfo_xxxpad[28];	/* reserved for future use */
 } ipfobj_t;
 
 #define	IPFOBJ_FRENTRY		0	/* struct frentry */
@@ -1110,18 +1358,32 @@
 #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? */
+#define	IPFOBJ_STATETQTAB	19	/* struct ipftq * NSTATES */
+#define	IPFOBJ_IPFEXPR		20
+#define	IPFOBJ_PROXYCTL		21	/* strct ap_ctl */
+#define	IPFOBJ_FRIPF		22	/* structfripf */
+#define	IPFOBJ_COUNT		23	/* How many #defines are above this? */
 
 
 typedef	union	ipftunevalptr	{
-	void	*ipftp_void;
-	u_long	*ipftp_long;
-	u_int	*ipftp_int;
-	u_short	*ipftp_short;
-	u_char	*ipftp_char;
+	void		*ipftp_void;
+	u_long		*ipftp_long;
+	u_int		*ipftp_int;
+	u_short		*ipftp_short;
+	u_char		*ipftp_char;
+	u_long		ipftp_offset;
 } ipftunevalptr_t;
 
+typedef	union	ipftuneval	{
+	u_long		ipftu_long;
+	u_int		ipftu_int;
+	u_short		ipftu_short;
+	u_char		ipftu_char;
+} ipftuneval_t;
+
+struct ipftuneable;
+typedef	int (* ipftunefunc_t) __P((struct ipf_main_softc_s *, struct ipftuneable *, ipftuneval_t *));
+
 typedef	struct	ipftuneable	{
 	ipftunevalptr_t	ipft_una;
 	const char	*ipft_name;
@@ -1130,6 +1392,7 @@
 	int		ipft_sz;
 	int		ipft_flags;
 	struct ipftuneable *ipft_next;
+	ipftunefunc_t	ipft_func;
 } ipftuneable_t;
 
 #define	ipft_addr	ipft_una.ipftp_void
@@ -1141,13 +1404,6 @@
 #define	IPFT_RDONLY	1	/* read-only */
 #define	IPFT_WRDISABLED	2	/* write when disabled only */
 
-typedef	union	ipftuneval	{
-	u_long	ipftu_long;
-	u_int	ipftu_int;
-	u_short	ipftu_short;
-	u_char	ipftu_char;
-} ipftuneval_t;
-
 typedef	struct	ipftune	{
 	void    	*ipft_cookie;
 	ipftuneval_t	ipft_un;
@@ -1164,6 +1420,53 @@
 #define	ipft_vchar	ipft_un.ipftu_char
 
 /*
+ * Hash table header
+ */
+#define	IPFHASH(x,y)	typedef struct { 			\
+				ipfrwlock_t	ipfh_lock;	\
+				struct	x	*ipfh_head;	\
+				} y
+
+/*
+** HPUX Port
+*/
+#ifdef __hpux
+/* HP-UX locking sequence deadlock detection module lock MAJOR ID */
+# define	IPF_SMAJ	0	/* temp assignment XXX, not critical */
+#endif
+
+#if !defined(CDEV_MAJOR) && defined (__FreeBSD_version) && \
+    (__FreeBSD_version >= 220000)
+# define	CDEV_MAJOR	79
+#endif
+
+/*
+ * Post NetBSD 1.2 has the PFIL interface for packet filters.  This turns
+ * on those hooks.  We don't need any special mods in non-IP Filter code
+ * with this!
+ */
+#if (defined(NetBSD) && (NetBSD > 199609) && (NetBSD <= 1991011)) || \
+    (defined(NetBSD1_2) && NetBSD1_2 > 1) || \
+    (defined(__FreeBSD__) && (__FreeBSD_version >= 500043))
+# if (defined(NetBSD) && NetBSD >= 199905)
+#  define PFIL_HOOKS
+# endif
+# ifdef PFIL_HOOKS
+#  define NETBSD_PF
+# endif
+#endif
+
+#ifdef _KERNEL
+# define	FR_VERBOSE(verb_pr)
+# define	FR_DEBUG(verb_pr)
+#else
+extern	void	ipfkdebug __P((char *, ...));
+extern	void	ipfkverbose __P((char *, ...));
+# define	FR_VERBOSE(verb_pr)	ipfkverbose verb_pr
+# define	FR_DEBUG(verb_pr)	ipfkdebug verb_pr
+#endif
+
+/*
  *
  */
 typedef	struct	ipfruleiter {
@@ -1171,7 +1474,7 @@
 	char		iri_group[FR_GROUPLEN];
 	int		iri_active;
 	int		iri_nrules;
-	int		iri_v;
+	int		iri_v;		/* No longer used (compatibility) */
 	frentry_t	*iri_rule;
 } ipfruleiter_t;
 
@@ -1210,6 +1513,19 @@
 #define	IPFTABLE_BUCKETS_NATOUT	3
 
 
+typedef struct ipf_v4_masktab_s {
+	u_32_t	imt4_active[33];
+	int	imt4_masks[33];
+	int	imt4_max;
+} ipf_v4_masktab_t;
+
+typedef struct ipf_v6_masktab_s {
+	i6addr_t	imt6_active[129];
+	int		imt6_masks[129];
+	int		imt6_max;
+} ipf_v6_masktab_t;
+
+
 /*
  *
  */
@@ -1222,190 +1538,246 @@
 	int		ipt_type;
 	int		ipt_uid;
 	int		ipt_subtype;
-	int		ipt_alive;
+	int		ipt_ref;
+	int		ipt_complete;
 } ipftoken_t;
 
 
 /*
-** HPUX Port
-*/
-#ifdef __hpux
-/* HP-UX locking sequence deadlock detection module lock MAJOR ID */
-# define	IPF_SMAJ	0	/* temp assignment XXX, not critical */
-#endif
+ *
+ */
+typedef struct ipfexp {
+	int		ipfe_cmd;
+	int		ipfe_not;
+	int		ipfe_narg;
+	int		ipfe_size;
+	int		ipfe_arg0[1];
+} ipfexp_t;
 
-#if !defined(CDEV_MAJOR) && defined (__FreeBSD_version) && \
-    (__FreeBSD_version >= 220000)
-# define	CDEV_MAJOR	79
-#endif
-
 /*
- * Post NetBSD 1.2 has the PFIL interface for packet filters.  This turns
- * on those hooks.  We don't need any special mods in non-IP Filter code
- * with this!
+ * Currently support commands (ipfe_cmd)
+ * 32bits is split up follows:
+ * aabbcccc
+ * aa = 0 = packet matching, 1 = meta data matching
+ * bb = IP protocol number
+ * cccc = command
  */
-#if (defined(NetBSD) && (NetBSD > 199609) && (NetBSD <= 1991011)) || \
-    (defined(NetBSD1_2) && NetBSD1_2 > 1) || \
-    (defined(__FreeBSD__) && (__FreeBSD_version >= 500043))
-# if defined(NetBSD) && (NetBSD >= 199905)
-#  define PFIL_HOOKS
+#define	IPF_EXP_IP_PR		0x00000001
+#define	IPF_EXP_IP_ADDR		0x00000002
+#define	IPF_EXP_IP_SRCADDR	0x00000003
+#define	IPF_EXP_IP_DSTADDR	0x00000004
+#define	IPF_EXP_IP6_ADDR	0x00000005
+#define	IPF_EXP_IP6_SRCADDR	0x00000006
+#define	IPF_EXP_IP6_DSTADDR	0x00000007
+#define	IPF_EXP_TCP_FLAGS	0x00060001
+#define	IPF_EXP_TCP_PORT	0x00060002
+#define	IPF_EXP_TCP_SPORT	0x00060003
+#define	IPF_EXP_TCP_DPORT	0x00060004
+#define	IPF_EXP_UDP_PORT	0x00110002
+#define	IPF_EXP_UDP_SPORT	0x00110003
+#define	IPF_EXP_UDP_DPORT	0x00110004
+#define	IPF_EXP_IDLE_GT		0x01000001
+#define	IPF_EXP_TCP_STATE	0x01060002
+#define	IPF_EXP_END		0xffffffff
+
+#define	ONE_DAY			IPF_TTLVAL(1 * 86400)   /* 1 day */
+#define	FIVE_DAYS		(5 * ONE_DAY)
+
+typedef struct ipf_main_softc_s {
+	struct ipf_main_softc_s *ipf_next;
+	ipfmutex_t	ipf_rw;
+	ipfmutex_t      ipf_timeoutlock;
+	ipfrwlock_t     ipf_mutex;
+	ipfrwlock_t	ipf_frag;
+	ipfrwlock_t	ipf_global;
+	ipfrwlock_t	ipf_tokens;
+	ipfrwlock_t	ipf_state;
+	ipfrwlock_t	ipf_nat;
+	ipfrwlock_t	ipf_natfrag;
+	ipfrwlock_t	ipf_poolrw;
+	int		ipf_dynamic_softc;
+	int		ipf_refcnt;
+	int		ipf_running;
+	int		ipf_flags;
+	int		ipf_active;
+	int		ipf_control_forwarding;
+	int		ipf_update_ipid;
+	int		ipf_chksrc;	/* causes a system crash if enabled */
+	int		ipf_pass;
+	int		ipf_minttl;
+	int		ipf_icmpminfragmtu;
+	int		ipf_interror;	/* Should be in a struct that is per  */
+					/* thread or process. Does not belong */
+					/* here but there's a lot more work   */
+					/* in doing that properly. For now,   */
+					/* it is squatting. */
+	u_int		ipf_tcpidletimeout;
+	u_int		ipf_tcpclosewait;
+	u_int		ipf_tcplastack;
+	u_int		ipf_tcptimewait;
+	u_int		ipf_tcptimeout;
+	u_int		ipf_tcpsynsent;
+	u_int		ipf_tcpsynrecv;
+	u_int		ipf_tcpclosed;
+	u_int		ipf_tcphalfclosed;
+	u_int		ipf_udptimeout;
+	u_int		ipf_udpacktimeout;
+	u_int		ipf_icmptimeout;
+	u_int		ipf_icmpacktimeout;
+	u_int		ipf_iptimeout;
+	u_long		ipf_ticks;
+	u_long		ipf_userifqs;
+	u_long		ipf_rb_no_mem;
+	u_long		ipf_rb_node_max;
+	u_long		ipf_frouteok[2];
+	ipftuneable_t	*ipf_tuners;
+	void		*ipf_frag_soft;
+	void		*ipf_nat_soft;
+	void		*ipf_state_soft;
+	void		*ipf_auth_soft;
+	void		*ipf_proxy_soft;
+	void		*ipf_sync_soft;
+	void		*ipf_lookup_soft;
+	void		*ipf_log_soft;
+	struct frgroup	*ipf_groups[IPL_LOGSIZE][2];
+	frentry_t	*ipf_rules[2][2];
+	frentry_t	*ipf_acct[2][2];
+	frentry_t	*ipf_rule_explist[2];
+	ipftoken_t	*ipf_token_head;
+	ipftoken_t	**ipf_token_tail;
+#if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000) && \
+    defined(_KERNEL)
+	struct callout ipf_slow_ch;
+#endif
+#if defined(linux) && defined(_KERNEL)
+	struct timer_list	ipf_timer;
+#endif
+#if NETBSD_GE_REV(104040000)
+	struct callout	ipf_slow_ch;
+#endif
+#if SOLARIS
+# if SOLARIS2 >= 7
+	timeout_id_t	ipf_slow_ch;
+# else
+	int		ipf_slow_ch;
 # endif
-# ifdef PFIL_HOOKS
-#  define NETBSD_PF
+#endif
+#if defined(_KERNEL)
+# if SOLARIS
+	struct pollhead	ipf_poll_head[IPL_LOGSIZE];
+	void		*ipf_dip;
+#  if defined(INSTANCES)
+	int		ipf_get_loopback;
+	u_long		ipf_idnum;
+	net_handle_t	ipf_nd_v4;
+	net_handle_t	ipf_nd_v6;
+	hook_t		*ipf_hk_v4_in;
+	hook_t		*ipf_hk_v4_out;
+	hook_t		*ipf_hk_v4_nic;
+	hook_t		*ipf_hk_v6_in;
+	hook_t		*ipf_hk_v6_out;
+	hook_t		*ipf_hk_v6_nic;
+	hook_t		*ipf_hk_loop_v4_in;
+	hook_t		*ipf_hk_loop_v4_out;
+	hook_t		*ipf_hk_loop_v6_in;
+	hook_t		*ipf_hk_loop_v6_out;
+#  endif
+# else
+#  if defined(linux) && defined(_KERNEL)
+	struct poll_table_struct	ipf_selwait[IPL_LOGSIZE];
+	wait_queue_head_t		iplh_linux[IPL_LOGSIZE];
+#  else
+	struct selinfo	ipf_selwait[IPL_LOGSIZE];
+#  endif
 # endif
 #endif
+	void		*ipf_slow;
+	ipf_statistics_t ipf_stats[2];
+	u_char		ipf_iss_secret[32];
+	u_short		ipf_ip_id;
+} ipf_main_softc_t;
 
-#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
+#define	IPFERROR(_e)	do { softc->ipf_interror = (_e); \
+			     DT1(user_error, int, _e); \
+			} while (0)
 
-
 #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 **));
-extern	int	ipf_log __P((void));
+extern	int	ipf_check __P((void *, struct ip *, int, void *, int, mb_t **));
+extern	int	(*ipf_checkp) __P((ip_t *, int, void *, int, mb_t **));
 extern	struct	ifnet *get_unit __P((char *, int));
 extern	char	*get_ifname __P((struct ifnet *));
-# if defined(__NetBSD__) || defined(__OpenBSD__) || \
-	  (_BSDI_VERSION >= 199701) || (__FreeBSD_version >= 300000)
-extern	int	iplioctl __P((int, ioctlcmd_t, caddr_t, int));
-# else
-extern	int	iplioctl __P((int, ioctlcmd_t, caddr_t, int));
-# endif
-extern	int	iplopen __P((dev_t, int));
-extern	int	iplclose __P((dev_t, int));
+extern	int	ipfioctl __P((ipf_main_softc_t *, int, ioctlcmd_t,
+			      caddr_t, int));
 extern	void	m_freem __P((mb_t *));
+extern	size_t	msgdsize __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 **));
+extern	int	ipf_check __P((void *, struct ip *, int, void *, int, void *,
+			       mblk_t **));
 #  if SOLARIS
+extern	void	ipf_prependmbt(fr_info_t *, mblk_t *);
 #   if SOLARIS2 >= 7
-extern	int	iplioctl __P((dev_t, int, intptr_t, int, cred_t *, int *));
+extern	int	ipfioctl __P((dev_t, int, intptr_t, int, cred_t *, int *));
 #   else
-extern	int	iplioctl __P((dev_t, int, int *, int, cred_t *, int *));
+extern	int	ipfioctl __P((dev_t, int, int *, int, cred_t *, int *));
 #   endif
-extern	int	iplopen __P((dev_t *, int, int, cred_t *));
-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 *));
 #  endif
 #  ifdef __hpux
-extern	int	iplopen __P((dev_t, int, intptr_t, int));
-extern	int	iplclose __P((dev_t, int, int));
-extern	int	iplioctl __P((dev_t, int, caddr_t, int));
-extern	int	iplread __P((dev_t, uio_t *));
-extern	int	iplwrite __P((dev_t, uio_t *));
-extern	int	iplselect __P((dev_t, int));
+extern	int	ipfioctl __P((dev_t, int, caddr_t, int));
+extern	int	ipf_select __P((dev_t, int));
 #  endif
-extern	int	fr_qout __P((queue_t *, mblk_t *));
+extern	int	ipf_qout __P((queue_t *, mblk_t *));
 # else /* MENTAT */
-extern	int	fr_check __P((struct ip *, int, void *, int, mb_t **));
+extern	int	ipf_check __P((void *, struct ip *, int, void *, int, mb_t **));
 extern	int	(*fr_checkp) __P((ip_t *, int, void *, int, mb_t **));
 extern	size_t	mbufchainlen __P((mb_t *));
 #  ifdef	__sgi
 #   include <sys/cred.h>
-extern	int	iplioctl __P((dev_t, int, caddr_t, int, cred_t *, int *));
-extern	int	iplopen __P((dev_t *, int, int, cred_t *));
-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	ipfioctl __P((dev_t, int, caddr_t, int, cred_t *, int *));
 extern	int	ipfilter_sgi_attach __P((void));
 extern	void	ipfilter_sgi_detach __P((void));
 extern	void	ipfilter_sgi_intfsync __P((void));
 #  else
 #   ifdef	IPFILTER_LKM
-extern	int	iplidentify __P((char *));
+extern	int	ipf_identify __P((char *));
 #   endif
-#   if (defined(_BSDI_VERSION) && _BSDI_VERSION >= 199510) || \
-      (__FreeBSD_version >= 220000) || \
-      (NetBSD >= 199511) || defined(__OpenBSD__)
-#    if defined(__NetBSD__) || \
-       (defined(_BSDI_VERSION) && _BSDI_VERSION >= 199701) || \
-       defined(__OpenBSD__) || (__FreeBSD_version >= 300000)
+#   if BSDOS_GE_REV(199510) || FREEBSD_GE_REV(220000) || \
+      (defined(NetBSD) && (NetBSD >= 199511)) || defined(__OpenBSD__)
+#    if defined(__NetBSD__) || BSDOS_GE_REV(199701) || \
+       defined(__OpenBSD__) || FREEBSD_GE_REV(300000)
 #     if (__FreeBSD_version >= 500024)
 #      if (__FreeBSD_version >= 502116)
-extern	int	iplioctl __P((struct cdev*, u_long, caddr_t, int, struct thread *));
+extern	int	ipfioctl __P((struct cdev*, u_long, caddr_t, int, struct thread *));
 #      else
-extern	int	iplioctl __P((dev_t, u_long, caddr_t, int, struct thread *));
+extern	int	ipfioctl __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 *));
+#      if  NETBSD_GE_REV(499001000)
+extern	int	ipfioctl __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 *));
+#       if  NETBSD_GE_REV(399001400)
+extern	int	ipfioctl __P((dev_t, u_long, caddr_t, int, struct lwp *));
 #       else
-extern	int	iplioctl __P((dev_t, u_long, caddr_t, int, struct proc *));
+extern	int	ipfioctl __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 *));
+extern	int	ipfioctl __P((dev_t, int, caddr_t, int, struct proc *));
 #    endif
-#    if (__FreeBSD_version >= 500024)
-#      if (__FreeBSD_version >= 502116)
-extern	int	iplopen __P((struct cdev*, int, int, struct thread *));
-extern	int	iplclose __P((struct cdev*, int, int, struct thread *));
-#      else
-extern	int	iplopen __P((dev_t, int, int, struct thread *));
-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
-extern	int	iplioctl __P((struct inode *, struct file *, u_int, u_long));
+extern	int	ipfioctl __P((struct inode *, struct file *, u_int, u_long));
 #    else
-extern	int	iplopen __P((dev_t, int));
-extern	int	iplclose __P((dev_t, int));
-extern	int	iplioctl __P((dev_t, int, caddr_t, int));
+extern	int	ipfioctl __P((dev_t, int, caddr_t, int));
 #    endif
 #   endif /* (_BSDI_VERSION >= 199510) */
-#   if	BSD >= 199306
-#      if (__FreeBSD_version >= 502116)
-extern	int	iplread __P((struct cdev*, struct uio *, int));
-extern	int	iplwrite __P((struct cdev*, struct uio *, int));
-#      else
-extern	int	iplread __P((dev_t, struct uio *, int));
-extern	int	iplwrite __P((dev_t, struct uio *, int));
-#      endif /* __FreeBSD_version >= 502116 */
-#   else
-#    ifndef linux
-extern	int	iplread __P((dev_t, struct uio *));
-extern	int	iplwrite __P((dev_t, struct uio *));
-#    endif
-#   endif /* BSD >= 199306 */
 #  endif /* __ sgi */
 # endif /* MENTAT */
 
@@ -1416,153 +1788,206 @@
 extern	void	ipf_event_dereg __P((void));
 # endif
 
+# if defined(INSTANCES)
+extern	ipf_main_softc_t	*ipf_find_softc __P((u_long));
+extern	int	ipf_set_loopback __P((ipf_main_softc_t *, ipftuneable_t *,
+				      ipftuneval_t *));
+# 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((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));
+#ifdef USE_INET6
+extern	int	count6bits __P((u_32_t *));
+#endif
+extern	int	frrequest __P((ipf_main_softc_t *, int, ioctlcmd_t, caddr_t,
+			       int, int));
 extern	char	*getifname __P((struct ifnet *));
-extern	int	ipfattach __P((void));
-extern	int	ipfdetach __P((void));
+extern	int	ipfattach __P((ipf_main_softc_t *));
+extern	int	ipfdetach __P((ipf_main_softc_t *));
 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, 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));
-extern	void	*fr_pullup __P((mb_t *, fr_info_t *, int));
-extern	void	fr_resolvedest __P((struct frdest *, int));
-extern	int	fr_resolvefunc __P((void *));
-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 < 501000) || !defined(_KERNEL)
-extern	int	ppsratecheck __P((struct timeval *, int *, int));
+extern	int	copyinptr __P((ipf_main_softc_t *, void *, void *, size_t));
+extern	int	copyoutptr __P((ipf_main_softc_t *, void *, void *, size_t));
+extern	int	ipf_fastroute __P((mb_t *, mb_t **, fr_info_t *, frdest_t *));
+extern	int	ipf_inject __P((fr_info_t *, mb_t *));
+extern	int	ipf_inobj __P((ipf_main_softc_t *, void *, ipfobj_t *,
+			       void *, int));
+extern	int	ipf_inobjsz __P((ipf_main_softc_t *, void *, void *,
+				 int , int));
+extern	int	ipf_ioctlswitch __P((ipf_main_softc_t *, int, void *,
+				     ioctlcmd_t, int, int, void *));
+extern	int	ipf_ipf_ioctl __P((ipf_main_softc_t *, caddr_t, ioctlcmd_t,
+				   int, int, void *));
+extern	int	ipf_ipftune __P((ipf_main_softc_t *, ioctlcmd_t, void *));
+extern	int	ipf_matcharray_load __P((ipf_main_softc_t *, caddr_t,
+					 ipfobj_t *, int **));
+extern	int	ipf_matcharray_verify __P((int *, int));
+extern	int	ipf_outobj __P((ipf_main_softc_t *, void *, void *, int));
+extern	int	ipf_outobjk __P((ipf_main_softc_t *, ipfobj_t *, void *));
+extern	int	ipf_outobjsz __P((ipf_main_softc_t *, void *, void *,
+				  int, int));
+extern	void	*ipf_pullup __P((mb_t *, fr_info_t *, int));
+extern	int	ipf_resolvedest __P((ipf_main_softc_t *, char *,
+				     struct frdest *, int));
+extern	int	ipf_resolvefunc __P((ipf_main_softc_t *, void *));
+extern	void	*ipf_resolvenic __P((ipf_main_softc_t *, char *, int));
+extern	int	ipf_send_icmp_err __P((int, fr_info_t *, int));
+extern	int	ipf_send_reset __P((fr_info_t *));
+#if  (defined(__FreeBSD_version) && (__FreeBSD_version < 501000)) || \
+     !defined(_KERNEL) || defined(linux)
 #endif
-extern	ipftq_t	*fr_addtimeoutqueue __P((ipftq_t **, u_int));
-extern	void	fr_deletequeueentry __P((ipftqent_t *));
-extern	int	fr_deletetimeoutqueue __P((ipftq_t *));
-extern	void	fr_freetimeoutqueue __P((ipftq_t *));
-extern	void	fr_movequeue __P((ipftqent_t *, ipftq_t *, ipftq_t *));
-extern	void	fr_queueappend __P((ipftqent_t *, ipftq_t *, void *));
-extern	void	fr_queueback __P((ipftqent_t *));
-extern	void	fr_queuefront __P((ipftqent_t *));
-extern	void	fr_checkv4sum __P((fr_info_t *));
-extern	int	fr_checkl4sum __P((fr_info_t *));
-extern	int	fr_ifpfillv4addr __P((int, struct sockaddr_in *,
+extern	void	ipf_apply_timeout __P((ipftq_t *, u_int));
+extern	ipftq_t	*ipf_addtimeoutqueue __P((ipf_main_softc_t *, ipftq_t **,
+					  u_int));
+extern	void	ipf_deletequeueentry __P((ipftqent_t *));
+extern	int	ipf_deletetimeoutqueue __P((ipftq_t *));
+extern	void	ipf_freetimeoutqueue __P((ipf_main_softc_t *, ipftq_t *));
+extern	void	ipf_movequeue __P((u_long, ipftqent_t *, ipftq_t *,
+				   ipftq_t *));
+extern	void	ipf_queueappend __P((u_long, ipftqent_t *, ipftq_t *, void *));
+extern	void	ipf_queueback __P((u_long, ipftqent_t *));
+extern	int	ipf_queueflush __P((ipf_main_softc_t *, ipftq_delete_fn_t,
+				    ipftq_t *, ipftq_t *, u_int *, int, int));
+extern	void	ipf_queuefront __P((ipftqent_t *));
+extern	int	ipf_settimeout_tcp __P((ipftuneable_t *, ipftuneval_t *,
+					ipftq_t *));
+extern	int	ipf_checkv4sum __P((fr_info_t *));
+extern	int	ipf_checkl4sum __P((fr_info_t *));
+extern	int	ipf_ifpfillv4addr __P((int, struct sockaddr_in *,
 				      struct sockaddr_in *, struct in_addr *,
 				      struct in_addr *));
-extern	int	fr_coalesce __P((fr_info_t *));
+extern	int	ipf_coalesce __P((fr_info_t *));
 #ifdef	USE_INET6
-extern	void	fr_checkv6sum __P((fr_info_t *));
-extern	int	fr_ifpfillv6addr __P((int, struct sockaddr_in6 *,
-				      struct sockaddr_in6 *, struct in_addr *,
-				      struct in_addr *));
+extern	int	ipf_checkv6sum __P((fr_info_t *));
+extern	int	ipf_ifpfillv6addr __P((int, struct sockaddr_in6 *,
+				      struct sockaddr_in6 *, i6addr_t *,
+				      i6addr_t *));
 #endif
 
-extern	int		fr_addipftune __P((ipftuneable_t *));
-extern	int		fr_delipftune __P((ipftuneable_t *));
+extern	int	ipf_tune_add __P((ipf_main_softc_t *, ipftuneable_t *));
+extern	int	ipf_tune_add_array __P((ipf_main_softc_t *, ipftuneable_t *));
+extern	int	ipf_tune_del __P((ipf_main_softc_t *, ipftuneable_t *));
+extern	int	ipf_tune_del_array __P((ipf_main_softc_t *, ipftuneable_t *));
+extern	int	ipf_tune_array_link __P((ipf_main_softc_t *, ipftuneable_t *));
+extern	int	ipf_tune_array_unlink __P((ipf_main_softc_t *,
+					   ipftuneable_t *));
+extern	ipftuneable_t *ipf_tune_array_copy __P((void *, size_t,
+						ipftuneable_t *));
 
-extern	int	frflush __P((minor_t, int, int));
-extern	void	frsync __P((void *));
-extern	frgroup_t *fr_addgroup __P((char *, void *, u_32_t, minor_t, int));
-extern	int	fr_derefrule __P((frentry_t **));
-extern	void	fr_delgroup __P((char *, minor_t, int));
-extern	frgroup_t *fr_findgroup __P((char *, minor_t, int, frgroup_t ***));
+extern int	ipf_pr_pullup __P((fr_info_t *, int));
 
-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));
-extern	int	ipllog __P((int, fr_info_t *, void **, size_t *, int *, int));
-extern	void	fr_logunload __P((void));
+extern	int	ipf_flush __P((ipf_main_softc_t *, minor_t, int));
+extern	frgroup_t *ipf_group_add __P((ipf_main_softc_t *, char *, void *,
+				      u_32_t, minor_t, int));
+extern	void	ipf_group_del __P((ipf_main_softc_t *, frgroup_t *,
+				   frentry_t *));
+extern	int	ipf_derefrule __P((ipf_main_softc_t *, frentry_t **));
+extern	frgroup_t *ipf_findgroup __P((ipf_main_softc_t *, char *, minor_t,
+				      int, frgroup_t ***));
 
-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 *, 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 *));
-extern	void		fr_fixskip __P((frentry_t **, frentry_t *, int));
-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_ifpaddr __P((int, int, void *,
-				struct in_addr *, struct in_addr *));
-extern	int		fr_initialise __P((void));
-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((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 *));
-#ifndef ipf_random
-extern	u_32_t		ipf_random __P((void));
+extern	int	ipf_log_init __P((void));
+extern	int	ipf_log_bytesused __P((ipf_main_softc_t *, int));
+extern	int	ipf_log_canread __P((ipf_main_softc_t *, int));
+extern	int	ipf_log_clear __P((ipf_main_softc_t *, minor_t));
+extern	u_long  ipf_log_failures __P((ipf_main_softc_t *, int));
+extern	int	ipf_log_read __P((ipf_main_softc_t *, minor_t, uio_t *));
+extern	int	ipf_log_items __P((ipf_main_softc_t *, int, fr_info_t *,
+				   void **, size_t *, int *, int));
+extern	u_long  ipf_log_logok __P((ipf_main_softc_t *, int));
+extern	void	ipf_log_unload __P((ipf_main_softc_t *));
+extern	int 	ipf_log_pkt __P((fr_info_t *, u_int));
+
+extern	frentry_t	*ipf_acctpkt __P((fr_info_t *, u_32_t *));
+extern	u_short		fr_cksum __P((fr_info_t *, ip_t *, int, void *));
+extern	void		ipf_deinitialise __P((ipf_main_softc_t *));
+extern	int		ipf_deliverlocal __P((ipf_main_softc_t *, int, void *,
+					      i6addr_t *));
+extern	frentry_t 	*ipf_dstgrpmap __P((fr_info_t *, u_32_t *));
+extern	void		ipf_fixskip __P((frentry_t **, frentry_t *, int));
+extern	void		ipf_forgetifp __P((ipf_main_softc_t *, void *));
+extern	frentry_t 	*ipf_getrulen __P((ipf_main_softc_t *, int, char *,
+					   u_32_t));
+extern	int		ipf_ifpaddr __P((ipf_main_softc_t *, int, int, void *,
+					i6addr_t *, i6addr_t *));
+extern	void		ipf_inet_mask_add __P((int, ipf_v4_masktab_t *));
+extern	void		ipf_inet_mask_del __P((int, ipf_v4_masktab_t *));
+#ifdef	USE_INET6
+extern	void		ipf_inet6_mask_add __P((int, i6addr_t *,
+						ipf_v6_masktab_t *));
+extern	void		ipf_inet6_mask_del __P((int, i6addr_t *,
+						ipf_v6_masktab_t *));
 #endif
-#ifdef NEED_LOCAL_RAND
-extern	void		ipf_rand_push __P((void *, int));
+extern	int		ipf_initialise __P((void));
+extern	int		ipf_lock __P((caddr_t, int *));
+extern  int		ipf_makefrip __P((int, ip_t *, fr_info_t *));
+extern	int		ipf_matchtag __P((ipftag_t *, ipftag_t *));
+extern	int		ipf_matchicmpqueryreply __P((int, icmpinfo_t *,
+						     struct icmp *, int));
+extern	u_32_t		ipf_newisn __P((fr_info_t *));
+extern	u_short		ipf_nextipid __P((fr_info_t *));
+extern	u_int		ipf_pcksum __P((fr_info_t *, int, u_int));
+extern	void		ipf_rule_expire __P((ipf_main_softc_t *));
+extern	int		ipf_scanlist __P((fr_info_t *, u_32_t));
+extern	frentry_t 	*ipf_srcgrpmap __P((fr_info_t *, u_32_t *));
+extern	int		ipf_tcpudpchk __P((fr_ip_t *, frtuc_t *));
+extern	int		ipf_verifysrc __P((fr_info_t *fin));
+extern	int		ipf_zerostats __P((ipf_main_softc_t *, char *));
+extern	int		ipf_getnextrule __P((ipf_main_softc_t *, ipftoken_t *,
+					     void *));
+extern	int		ipf_sync __P((ipf_main_softc_t *, void *));
+extern	int		ipf_token_deref __P((ipf_main_softc_t *, ipftoken_t *));
+extern	void		ipf_token_expire __P((ipf_main_softc_t *));
+extern	ipftoken_t	*ipf_token_find __P((ipf_main_softc_t *, int, int,
+					    void *));
+extern	int		ipf_token_del __P((ipf_main_softc_t *, int, int,
+					  void *));
+extern	void		ipf_token_mark_complete __P((ipftoken_t *));
+extern	int		ipf_genericiter __P((ipf_main_softc_t *, void *,
+					     int, void *));
+#ifdef	IPFILTER_LOOKUP
+extern	void		*ipf_resolvelookup __P((int, u_int, u_int,
+						lookupfunc_t *));
 #endif
+extern	u_32_t		ipf_random __P((void));
 
-extern	int	fr_running;
-extern	u_long	fr_frouteok[2];
-extern	int	fr_pass;
-extern	int	fr_flags;
-extern	int	fr_active;
-extern	int	fr_chksrc;
-extern	int	fr_minttl;
-extern	int	fr_refcnt;
-extern	int	fr_control_forwarding;
-extern	int	fr_update_ipid;
-extern	int	nat_logging;
-extern	int	ipstate_logging;
-extern	int	ipl_suppress;
-extern	int	ipl_logmax;
-extern	int	ipl_logall;
-extern	int	ipl_logsize;
-extern	u_long	fr_ticks;
-extern	fr_info_t	frcache[2][8];
+extern	int		ipf_main_load __P((void));
+extern	void		*ipf_main_soft_create __P((void *));
+extern	void		ipf_main_soft_destroy __P((ipf_main_softc_t *));
+extern	int		ipf_main_soft_init __P((ipf_main_softc_t *));
+extern	int		ipf_main_soft_fini __P((ipf_main_softc_t *));
+extern	int		ipf_main_unload __P((void));
+extern	int		ipf_load_all __P((void));
+extern	int		ipf_unload_all __P((void));
+extern	void		ipf_destroy_all __P((ipf_main_softc_t *));
+extern	ipf_main_softc_t *ipf_create_all __P((void *));
+extern	int		ipf_init_all __P((ipf_main_softc_t *));
+extern	int		ipf_fini_all __P((ipf_main_softc_t *));
+extern	void		ipf_log_soft_destroy __P((ipf_main_softc_t *, void *));
+extern	void		*ipf_log_soft_create __P((ipf_main_softc_t *));
+extern	int		ipf_log_soft_init __P((ipf_main_softc_t *, void *));
+extern	int		ipf_log_soft_fini __P((ipf_main_softc_t *, void *));
+extern	int		ipf_log_main_load __P((void));
+extern	int		ipf_log_main_unload __P((void));
+
+
 extern	char	ipfilter_version[];
-extern	iplog_t	**iplh[IPL_LOGMAX+1], *iplt[IPL_LOGMAX+1];
-extern	int	iplused[IPL_LOGMAX + 1];
-extern	struct frentry *ipfilter[2][2], *ipacct[2][2];
 #ifdef	USE_INET6
-extern	struct frentry *ipfilter6[2][2], *ipacct6[2][2];
 extern	int	icmptoicmp6types[ICMP_MAXTYPE+1];
 extern	int	icmptoicmp6unreach[ICMP_MAX_UNREACH];
 extern	int	icmpreplytype6[ICMP6_MAXTYPE + 1];
 #endif
+#ifdef	IPFILTER_COMPAT
+extern	int	ipf_in_compat __P((ipf_main_softc_t *, ipfobj_t *, void *,int));
+extern	int	ipf_out_compat __P((ipf_main_softc_t *, ipfobj_t *, void *));
+#endif
 extern	int	icmpreplytype4[ICMP_MAXTYPE + 1];
-extern	struct frgroup *ipfgroups[IPL_LOGSIZE][2];
-extern	struct filterstats frstats[];
-extern	frentry_t *ipfrule_match __P((fr_info_t *));
-extern	u_char	ipf_iss_secret[32];
-extern	ipftuneable_t ipf_tuneables[];
 
+extern	int	ipf_ht_node_add __P((ipf_main_softc_t *, host_track_t *,
+				     int, i6addr_t *));
+extern	int	ipf_ht_node_del __P((host_track_t *, int, i6addr_t *));
+extern	void	ipf_rb_ht_flush __P((host_track_t *));
+extern	void	ipf_rb_ht_freenode __P((host_node_t *, void *));
+extern	void	ipf_rb_ht_init __P((host_track_t *));
+
 #endif	/* __IP_FIL_H__ */

Modified: trunk/sys/contrib/ipfilter/netinet/ip_fil_freebsd.c
===================================================================
--- trunk/sys/contrib/ipfilter/netinet/ip_fil_freebsd.c	2018-05-28 18:55:30 UTC (rev 10138)
+++ trunk/sys/contrib/ipfilter/netinet/ip_fil_freebsd.c	2018-05-28 18:56:30 UTC (rev 10139)
@@ -1,13 +1,14 @@
-/*	$FreeBSD$	*/
+/* $MidnightBSD$ */
+/*	$FreeBSD: stable/10/sys/contrib/ipfilter/netinet/ip_fil_freebsd.c 314667 2017-03-04 13:03:31Z avg $	*/
 
 /*
- * Copyright (C) 1993-2003 by Darren Reed.
+ * Copyright (C) 2012 by Darren Reed.
  *
  * See the IPFILTER.LICENCE file for details on licencing.
  */
 #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 1.7 2013-01-08 01:31:40 laffer1 Exp $";
+static const char rcsid[] = "@(#)$Id$";
 #endif
 
 #if defined(KERNEL) || defined(_KERNEL)
@@ -25,60 +26,29 @@
 # include "opt_random_ip_id.h"
 #endif
 #include <sys/param.h>
-#if defined(__FreeBSD__) && !defined(__FreeBSD_version)
-# if defined(IPFILTER_LKM)
-#  ifndef __FreeBSD_cc_version
-#   include <osreldate.h>
-#  else
-#   if __FreeBSD_cc_version < 430000
-#    include <osreldate.h>
-#   endif
-#  endif
-# endif
-#endif
 #include <sys/errno.h>
 #include <sys/types.h>
 #include <sys/file.h>
-#if __FreeBSD_version >= 220000
 # include <sys/fcntl.h>
 # include <sys/filio.h>
-#else
-# include <sys/ioctl.h>
-#endif
 #include <sys/time.h>
 #include <sys/systm.h>
-#if (__FreeBSD_version >= 300000)
 # include <sys/dirent.h>
-#else
-# include <sys/dir.h>
+#if defined(__FreeBSD_version) && (__FreeBSD_version >= 800000)
+#include <sys/jail.h>
 #endif
+# include <sys/mbuf.h>
+# include <sys/sockopt.h>
 #if !defined(__hpux)
 # include <sys/mbuf.h>
 #endif
-#include <sys/protosw.h>
 #include <sys/socket.h>
-#if __FreeBSD_version >= 500043
 # include <sys/selinfo.h>
-#else
-# include <sys/select.h>
-#endif
-#if __FreeBSD_version >= 800044
 # include <netinet/tcp_var.h>
-#else
-#define V_path_mtu_discovery path_mtu_discovery
-#define V_ipforwarding ipforwarding
-#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
-#endif
 #include <net/route.h>
 #include <netinet/in.h>
 #include <netinet/in_var.h>
@@ -86,6 +56,12 @@
 #include <netinet/ip.h>
 #include <netinet/ip_var.h>
 #include <netinet/tcp.h>
+#if defined(__FreeBSD_version) && (__FreeBSD_version >= 800000)
+#include <net/vnet.h>
+#else
+#define CURVNET_SET(arg)
+#define CURVNET_RESTORE()
+#endif
 #if defined(__osf__)
 # include <netinet/tcp_timer.h>
 #endif
@@ -92,9 +68,6 @@
 #include <netinet/udp.h>
 #include <netinet/tcpip.h>
 #include <netinet/ip_icmp.h>
-#ifndef _KERNEL
-# include "netinet/ipf.h"
-#endif
 #include "netinet/ip_compat.h"
 #ifdef USE_INET6
 # include <netinet/icmp6.h>
@@ -105,16 +78,14 @@
 #include "netinet/ip_state.h"
 #include "netinet/ip_proxy.h"
 #include "netinet/ip_auth.h"
-#ifdef	IPFILTER_SYNC
 #include "netinet/ip_sync.h"
-#endif
+#include "netinet/ip_lookup.h"
+#include "netinet/ip_dstlist.h"
 #ifdef	IPFILTER_SCAN
 #include "netinet/ip_scan.h"
 #endif
 #include "netinet/ip_pool.h"
-#if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000)
 # include <sys/malloc.h>
-#endif
 #include <sys/kernel.h>
 #ifdef CSUM_DATA_VALID
 #include <machine/in_cksum.h>
@@ -121,9 +92,6 @@
 #endif
 extern	int	ip_optcopy __P((struct ip *, struct ip *));
 
-#if (__FreeBSD_version > 460000) && (__FreeBSD_version < 800055)
-extern	int	path_mtu_discovery;
-#endif
 
 # ifdef IPFILTER_M_IPFILTER
 MALLOC_DEFINE(M_IPFILTER, "ipfilter", "IP Filter packet filter data structures");
@@ -130,60 +98,59 @@
 # endif
 
 
-#if !defined(__osf__)
-extern	struct	protosw	inetsw[];
-#endif
-
-static	int	(*fr_savep) __P((ip_t *, int, void *, int, struct mbuf **));
-static	int	fr_send_ip __P((fr_info_t *, mb_t *, mb_t **));
-# 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, ipf_frcache, ipf_tokens;
-ipfrwlock_t	ipf_frag, ipf_state, ipf_nat, ipf_natfrag, ipf_auth;
-# endif
+static	u_short	ipid = 0;
+static	int	(*ipf_savep) __P((void *, ip_t *, int, void *, int, struct mbuf **));
+static	int	ipf_send_ip __P((fr_info_t *, mb_t *));
+static void	ipf_timer_func __P((void *arg));
 int		ipf_locks_done = 0;
 
-#if (__FreeBSD_version >= 300000)
-struct callout_handle fr_slowtimer_ch;
-#endif
-struct	selinfo	ipfselwait[IPL_LOGSIZE];
+ipf_main_softc_t ipfmain;
 
-#if (__FreeBSD_version >= 500011)
 # include <sys/conf.h>
 # if defined(NETBSD_PF)
 #  include <net/pfil.h>
-#  if (__FreeBSD_version < 501108)
-#   include <netinet/ipprotosw.h>
-#  endif
+# endif /* NETBSD_PF */
 /*
- * We provide the fr_checkp name just to minimize changes later.
+ * We provide the ipf_checkp name just to minimize changes later.
  */
-int (*fr_checkp) __P((ip_t *ip, int hlen, void *ifp, int out, mb_t **mp));
-# endif /* NETBSD_PF */
-#endif /* __FreeBSD_version >= 500011 */
+int (*ipf_checkp) __P((void *, ip_t *ip, int hlen, void *ifp, int out, mb_t **mp));
 
 
-#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;
+	void *arg;
 {
-        frsync(NULL);
+        ipf_sync(arg, NULL);
 }
-#endif
 
 
-#if (__FreeBSD_version >= 501108) && defined(_KERNEL)
 
 static int
-fr_check_wrapper(void *arg, struct mbuf **mp, struct ifnet *ifp, int dir)
+ipf_check_wrapper(void *arg, struct mbuf **mp, struct ifnet *ifp, int dir)
 {
 	struct ip *ip = mtod(*mp, struct ip *);
-	return fr_check(ip, ip->ip_hl << 2, ifp, (dir == PFIL_OUT), mp);
+	int rv;
+
+	/*
+	 * IPFilter expects evreything in network byte order
+	 */
+#if (__FreeBSD_version < 1000019)
+	ip->ip_len = htons(ip->ip_len);
+	ip->ip_off = htons(ip->ip_off);
+#endif
+	rv = ipf_check(&ipfmain, ip, ip->ip_hl << 2, ifp, (dir == PFIL_OUT),
+		       mp);
+#if (__FreeBSD_version < 1000019)
+	if ((rv == 0) && (*mp != NULL)) {
+		ip = mtod(*mp, struct ip *);
+		ip->ip_len = ntohs(ip->ip_len);
+		ip->ip_off = ntohs(ip->ip_off);
+	}
+#endif
+	return rv;
 }
 
 # ifdef USE_INET6
@@ -190,16 +157,15 @@
 #  include <netinet/ip6.h>
 
 static int
-fr_check_wrapper6(void *arg, struct mbuf **mp, struct ifnet *ifp, int dir)
+ipf_check_wrapper6(void *arg, struct mbuf **mp, struct ifnet *ifp, int dir)
 {
-	return (fr_check(mtod(*mp, struct ip *), sizeof(struct ip6_hdr),
-	    ifp, (dir == PFIL_OUT), mp));
+	return (ipf_check(&ipfmain, mtod(*mp, struct ip *),
+			  sizeof(struct ip6_hdr), ifp, (dir == PFIL_OUT), mp));
 }
 # endif
-#endif /* __FreeBSD_version >= 501108 */
 #if	defined(IPFILTER_LKM)
-int iplidentify(s)
-char *s;
+int ipf_identify(s)
+	char *s;
 {
 	if (strcmp(s, "ipl") == 0)
 		return 1;
@@ -208,49 +174,74 @@
 #endif /* IPFILTER_LKM */
 
 
-int ipfattach()
+static void
+ipf_timer_func(arg)
+	void *arg;
 {
+	ipf_main_softc_t *softc = arg;
+	SPL_INT(s);
+
+	SPL_NET(s);
+	READ_ENTER(&softc->ipf_global);
+
+        if (softc->ipf_running > 0)
+		ipf_slowtimer(softc);
+
+	if (softc->ipf_running == -1 || softc->ipf_running == 1) {
+#if 0
+		softc->ipf_slow_ch = timeout(ipf_timer_func, softc, hz/2);
+#endif
+		callout_init(&softc->ipf_slow_ch, 1);
+		callout_reset(&softc->ipf_slow_ch,
+			(hz / IPF_HZ_DIVIDE) * IPF_HZ_MULT,
+			ipf_timer_func, softc);
+	}
+	RWLOCK_EXIT(&softc->ipf_global);
+	SPL_X(s);
+}
+
+
+int
+ipfattach(softc)
+	ipf_main_softc_t *softc;
+{
 #ifdef USE_SPL
 	int s;
 #endif
 
 	SPL_NET(s);
-	if (fr_running > 0) {
+	if (softc->ipf_running > 0) {
 		SPL_X(s);
 		return EBUSY;
 	}
 
-	MUTEX_INIT(&ipf_rw, "ipf rw mutex");
-	MUTEX_INIT(&ipf_timeoutlock, "ipf timeout queue mutex");
-	RWLOCK_INIT(&ipf_ipidfrag, "ipf IP NAT-Frag rwlock");
-	RWLOCK_INIT(&ipf_tokens, "ipf token rwlock");
-	ipf_locks_done = 1;
-
-	if (fr_initialise() < 0) {
+	if (ipf_init_all(softc) < 0) {
 		SPL_X(s);
 		return EIO;
 	}
 
 
-	if (fr_checkp != fr_check) {
-		fr_savep = fr_checkp;
-		fr_checkp = fr_check;
+	if (ipf_checkp != ipf_check) {
+		ipf_savep = ipf_checkp;
+		ipf_checkp = ipf_check;
 	}
 
-	bzero((char *)ipfselwait, sizeof(ipfselwait));
-	bzero((char *)frcache, sizeof(frcache));
-	fr_running = 1;
+	bzero((char *)ipfmain.ipf_selwait, sizeof(ipfmain.ipf_selwait));
+	softc->ipf_running = 1;
 
-	if (fr_control_forwarding & 1)
+	if (softc->ipf_control_forwarding & 1)
 		V_ipforwarding = 1;
 
+	ipid = 0;
+
 	SPL_X(s);
-#if (__FreeBSD_version >= 300000)
-	fr_slowtimer_ch = timeout(fr_slowtimer, NULL,
-				    (hz / IPF_HZ_DIVIDE) * IPF_HZ_MULT);
-#else
-	timeout(fr_slowtimer, NULL, (hz / IPF_HZ_DIVIDE) * IPF_HZ_MULT);
+#if 0
+	softc->ipf_slow_ch = timeout(ipf_timer_func, softc,
+				     (hz / IPF_HZ_DIVIDE) * IPF_HZ_MULT);
 #endif
+	callout_init(&softc->ipf_slow_ch, 1);
+	callout_reset(&softc->ipf_slow_ch, (hz / IPF_HZ_DIVIDE) * IPF_HZ_MULT,
+		ipf_timer_func, softc);
 	return 0;
 }
 
@@ -259,45 +250,36 @@
  * Disable the filter by removing the hooks from the IP input/output
  * stream.
  */
-int ipfdetach()
+int
+ipfdetach(softc)
+	ipf_main_softc_t *softc;
 {
 #ifdef USE_SPL
 	int s;
 #endif
-	if (fr_control_forwarding & 2)
+
+	if (softc->ipf_control_forwarding & 2)
 		V_ipforwarding = 0;
 
 	SPL_NET(s);
 
-#if (__FreeBSD_version >= 300000)
-	if (fr_slowtimer_ch.callout != NULL)
-		untimeout(fr_slowtimer, NULL, fr_slowtimer_ch);
-	bzero(&fr_slowtimer_ch, sizeof(fr_slowtimer_ch));
-#else
-	untimeout(fr_slowtimer, NULL);
-#endif /* FreeBSD */
+#if 0
+	if (softc->ipf_slow_ch.callout != NULL)
+		untimeout(ipf_timer_func, softc, softc->ipf_slow_ch);
+	bzero(&softc->ipf_slow, sizeof(softc->ipf_slow));
+#endif
+	callout_drain(&softc->ipf_slow_ch);
 
 #ifndef NETBSD_PF
-	if (fr_checkp != NULL)
-		fr_checkp = fr_savep;
-	fr_savep = NULL;
+	if (ipf_checkp != NULL)
+		ipf_checkp = ipf_savep;
+	ipf_savep = NULL;
 #endif
 
-	fr_deinitialise();
+	ipf_fini_all(softc);
 
-	fr_running = -2;
+	softc->ipf_running = -2;
 
-	(void) frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE|FR_INACTIVE);
-	(void) frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE);
-
-	if (ipf_locks_done == 1) {
-		MUTEX_DESTROY(&ipf_timeoutlock);
-		MUTEX_DESTROY(&ipf_rw);
-		RW_DESTROY(&ipf_ipidfrag);
-		RW_DESTROY(&ipf_tokens);
-		ipf_locks_done = 0;
-	}
-
 	SPL_X(s);
 
 	return 0;
@@ -307,62 +289,53 @@
 /*
  * Filter ioctl interface.
  */
-int iplioctl(dev, cmd, data, mode
-# if defined(_KERNEL) && ((BSD >= 199506) || (__FreeBSD_version >= 220000))
+int
+ipfioctl(dev, cmd, data, mode
 , p)
-#  if (__FreeBSD_version >= 500024)
-struct thread *p;
-#   if (__FreeBSD_version >= 500043)
+	struct thread *p;
 #    define	p_cred	td_ucred
 #    define	p_uid	td_ucred->cr_ruid
-#   else
-#    define	p_cred	t_proc->p_cred
-#    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
-)
-# endif
-#if defined(_KERNEL) && (__FreeBSD_version >= 502116)
-struct cdev *dev;
-#else
-dev_t dev;
-#endif
-ioctlcmd_t cmd;
-caddr_t data;
-int mode;
+	struct cdev *dev;
+	ioctlcmd_t cmd;
+	caddr_t data;
+	int mode;
 {
 	int error = 0, unit = 0;
 	SPL_INT(s);
 
-#if (BSD >= 199306) && defined(_KERNEL)
-# if (__FreeBSD_version >= 500034)
-	if (securelevel_ge(p->p_cred, 3) && (mode & FWRITE))
-# else
-	if ((securelevel >= 3) && (mode & FWRITE))
-# endif
+#if (BSD >= 199306)
+        if (securelevel_ge(p->p_cred, 3) && (mode & FWRITE))
+	{
+		ipfmain.ipf_interror = 130001;
 		return EPERM;
+	}
 #endif
 
 	unit = GET_MINOR(dev);
-	if ((IPL_LOGMAX < unit) || (unit < 0))
+	if ((IPL_LOGMAX < unit) || (unit < 0)) {
+		ipfmain.ipf_interror = 130002;
 		return ENXIO;
+	}
 
-	if (fr_running <= 0) {
-		if (unit != IPL_LOGIPF)
+	if (ipfmain.ipf_running <= 0) {
+		if (unit != IPL_LOGIPF && cmd != SIOCIPFINTERROR) {
+			ipfmain.ipf_interror = 130003;
 			return EIO;
+		}
 		if (cmd != SIOCIPFGETNEXT && cmd != SIOCIPFGET &&
 		    cmd != SIOCIPFSET && cmd != SIOCFRENB &&
-		    cmd != SIOCGETFS && cmd != SIOCGETFF)
+		    cmd != SIOCGETFS && cmd != SIOCGETFF &&
+		    cmd != SIOCIPFINTERROR) {
+			ipfmain.ipf_interror = 130004;
 			return EIO;
+		}
 	}
 
 	SPL_NET(s);
 
-	error = fr_ioctlswitch(unit, data, cmd, mode, p->p_uid, p);
+	CURVNET_SET(TD_TO_VNET(p));
+	error = ipf_ioctlswitch(&ipfmain, unit, data, cmd, mode, p->p_uid, p);
+	CURVNET_RESTORE();
 	if (error != -1) {
 		SPL_X(s);
 		return error;
@@ -374,182 +347,13 @@
 }
 
 
-#if 0
-void fr_forgetifp(ifp)
-void *ifp;
-{
-	register frentry_t *f;
-
-	WRITE_ENTER(&ipf_mutex);
-	for (f = ipacct[0][fr_active]; (f != NULL); f = f->fr_next)
-		if (f->fr_ifa == ifp)
-			f->fr_ifa = (void *)-1;
-	for (f = ipacct[1][fr_active]; (f != NULL); f = f->fr_next)
-		if (f->fr_ifa == ifp)
-			f->fr_ifa = (void *)-1;
-	for (f = ipfilter[0][fr_active]; (f != NULL); f = f->fr_next)
-		if (f->fr_ifa == ifp)
-			f->fr_ifa = (void *)-1;
-	for (f = ipfilter[1][fr_active]; (f != NULL); f = f->fr_next)
-		if (f->fr_ifa == ifp)
-			f->fr_ifa = (void *)-1;
-#ifdef USE_INET6
-	for (f = ipacct6[0][fr_active]; (f != NULL); f = f->fr_next)
-		if (f->fr_ifa == ifp)
-			f->fr_ifa = (void *)-1;
-	for (f = ipacct6[1][fr_active]; (f != NULL); f = f->fr_next)
-		if (f->fr_ifa == ifp)
-			f->fr_ifa = (void *)-1;
-	for (f = ipfilter6[0][fr_active]; (f != NULL); f = f->fr_next)
-		if (f->fr_ifa == ifp)
-			f->fr_ifa = (void *)-1;
-	for (f = ipfilter6[1][fr_active]; (f != NULL); f = f->fr_next)
-		if (f->fr_ifa == ifp)
-			f->fr_ifa = (void *)-1;
-#endif
-	RWLOCK_EXIT(&ipf_mutex);
-	fr_natsync(ifp);
-}
-#endif
-
-
 /*
- * routines below for saving IP headers to buffer
- */
-int iplopen(dev, flags
-#if ((BSD >= 199506) || (__FreeBSD_version >= 220000)) && defined(_KERNEL)
-, devtype, p)
-int devtype;
-# if (__FreeBSD_version >= 500024)
-struct thread *p;
-# else
-struct proc *p;
-# endif /* __FreeBSD_version >= 500024 */
-#else
-)
-#endif
-#if defined(_KERNEL) && (__FreeBSD_version >= 502116)
-struct cdev *dev;
-#else
-dev_t dev;
-#endif
-int flags;
-{
-	u_int min = GET_MINOR(dev);
-
-	if (IPL_LOGMAX < min)
-		min = ENXIO;
-	else
-		min = 0;
-	return min;
-}
-
-
-int iplclose(dev, flags
-#if ((BSD >= 199506) || (__FreeBSD_version >= 220000)) && defined(_KERNEL)
-, devtype, p)
-int devtype;
-# if (__FreeBSD_version >= 500024)
-struct thread *p;
-# else
-struct proc *p;
-# endif /* __FreeBSD_version >= 500024 */
-#else
-)
-#endif
-#if defined(_KERNEL) && (__FreeBSD_version >= 502116)
-struct cdev *dev;
-#else
-dev_t dev;
-#endif
-int flags;
-{
-	u_int	min = GET_MINOR(dev);
-
-	if (IPL_LOGMAX < min)
-		min = ENXIO;
-	else
-		min = 0;
-	return min;
-}
-
-/*
- * iplread/ipllog
- * both of these must operate with at least splnet() lest they be
- * called during packet processing and cause an inconsistancy to appear in
- * the filter lists.
- */
-#if (BSD >= 199306)
-int iplread(dev, uio, ioflag)
-int ioflag;
-#else
-int iplread(dev, uio)
-#endif
-#if defined(_KERNEL) && (__FreeBSD_version >= 502116)
-struct cdev *dev;
-#else
-dev_t dev;
-#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 (xmin == IPL_LOGSYNC)
-		return ipfsync_read(uio);
-# endif
-
-#ifdef IPFILTER_LOG
-	return ipflog_read(xmin, uio);
-#else
-	return ENXIO;
-#endif
-}
-
-
-/*
- * iplwrite
- * both of these must operate with at least splnet() lest they be
- * called during packet processing and cause an inconsistancy to appear in
- * the filter lists.
- */
-#if (BSD >= 199306)
-int iplwrite(dev, uio, ioflag)
-int ioflag;
-#else
-int iplwrite(dev, uio)
-#endif
-#if defined(_KERNEL) && (__FreeBSD_version >= 502116)
-struct cdev *dev;
-#else
-dev_t dev;
-#endif
-register struct uio *uio;
-{
-
-	if (fr_running < 1)
-		return EIO;
-
-#ifdef	IPFILTER_SYNC
-	if (GET_MINOR(dev) == IPL_LOGSYNC)
-		return ipfsync_write(uio);
-#endif
-	return ENXIO;
-}
-
-
-/*
- * fr_send_reset - this could conceivably be a call to tcp_respond(), but that
+ * ipf_send_reset - this could conceivably be a call to tcp_respond(), but that
  * requires a large amount of setting up and isn't any more efficient.
  */
-int fr_send_reset(fin)
-fr_info_t *fin;
+int
+ipf_send_reset(fin)
+	fr_info_t *fin;
 {
 	struct tcphdr *tcp, *tcp2;
 	int tlen = 0, hlen;
@@ -563,7 +367,7 @@
 	if (tcp->th_flags & TH_RST)
 		return -1;		/* feedback loop */
 
-	if (fr_checkl4sum(fin) == -1)
+	if (ipf_checkl4sum(fin) == -1)
 		return -1;
 
 	tlen = fin->fin_dlen - (TCP_OFF(tcp) << 2) +
@@ -628,11 +432,11 @@
 		ip6->ip6_plen = htons(sizeof(struct tcphdr));
 		ip6->ip6_nxt = IPPROTO_TCP;
 		ip6->ip6_hlim = 0;
-		ip6->ip6_src = fin->fin_dst6;
-		ip6->ip6_dst = fin->fin_src6;
+		ip6->ip6_src = fin->fin_dst6.in6;
+		ip6->ip6_dst = fin->fin_src6.in6;
 		tcp2->th_sum = in6_cksum(m, IPPROTO_TCP,
 					 sizeof(*ip6), sizeof(*tcp2));
-		return fr_send_ip(fin, m, &m);
+		return ipf_send_ip(fin, m);
 	}
 #endif
 	ip->ip_p = IPPROTO_TCP;
@@ -640,14 +444,18 @@
 	ip->ip_src.s_addr = fin->fin_daddr;
 	ip->ip_dst.s_addr = fin->fin_saddr;
 	tcp2->th_sum = in_cksum(m, hlen + sizeof(*tcp2));
-	ip->ip_len = hlen + sizeof(*tcp2);
-	return fr_send_ip(fin, m, &m);
+	ip->ip_len = htons(hlen + sizeof(*tcp2));
+	return ipf_send_ip(fin, m);
 }
 
 
-static int fr_send_ip(fin, m, mpp)
-fr_info_t *fin;
-mb_t *m, **mpp;
+/*
+ * ip_len must be in network byte order when called.
+ */
+static int
+ipf_send_ip(fin, m)
+	fr_info_t *fin;
+	mb_t *m;
 {
 	fr_info_t fnew;
 	ip_t *ip, *oip;
@@ -655,24 +463,27 @@
 
 	ip = mtod(m, ip_t *);
 	bzero((char *)&fnew, sizeof(fnew));
+	fnew.fin_main_soft = fin->fin_main_soft;
 
 	IP_V_A(ip, fin->fin_v);
 	switch (fin->fin_v)
 	{
 	case 4 :
+		oip = fin->fin_ip;
+		hlen = sizeof(*oip);
 		fnew.fin_v = 4;
-		oip = fin->fin_ip;
+		fnew.fin_p = ip->ip_p;
+		fnew.fin_plen = ntohs(ip->ip_len);
 		IP_HL_A(ip, sizeof(*oip) >> 2);
 		ip->ip_tos = oip->ip_tos;
 		ip->ip_id = fin->fin_ip->ip_id;
-#if (__FreeBSD_version > 460000)
-		ip->ip_off = V_path_mtu_discovery ? IP_DF : 0;
+#if defined(FreeBSD) && (__FreeBSD_version > 460000)
+		ip->ip_off = htons(path_mtu_discovery ? IP_DF : 0);
 #else
 		ip->ip_off = 0;
 #endif
 		ip->ip_ttl = V_ip_defttl;
 		ip->ip_sum = 0;
-		hlen = sizeof(*oip);
 		break;
 #ifdef USE_INET6
 	case 6 :
@@ -682,8 +493,10 @@
 		ip6->ip6_vfc = 0x60;
 		ip6->ip6_hlim = IPDEFTTL;
 
+		hlen = sizeof(*ip6);
+		fnew.fin_p = ip6->ip6_nxt;
 		fnew.fin_v = 6;
-		hlen = sizeof(*ip6);
+		fnew.fin_plen = ntohs(ip6->ip6_plen) + hlen;
 		break;
 	}
 #endif
@@ -698,28 +511,29 @@
 	fnew.fin_flx = FI_NOCKSUM;
 	fnew.fin_m = m;
 	fnew.fin_ip = ip;
-	fnew.fin_mp = mpp;
+	fnew.fin_mp = &m;
 	fnew.fin_hlen = hlen;
 	fnew.fin_dp = (char *)ip + hlen;
-	(void) fr_makefrip(hlen, ip, &fnew);
+	(void) ipf_makefrip(hlen, ip, &fnew);
 
-	return fr_fastroute(m, mpp, &fnew, NULL);
+	return ipf_fastroute(m, &m, &fnew, NULL);
 }
 
 
-int fr_send_icmp_err(type, fin, dst)
-int type;
-fr_info_t *fin;
-int dst;
+int
+ipf_send_icmp_err(type, fin, dst)
+	int type;
+	fr_info_t *fin;
+	int dst;
 {
 	int err, hlen, xtra, iclen, ohlen, avail, code;
 	struct in_addr dst4;
 	struct icmp *icmp;
 	struct mbuf *m;
+	i6addr_t dst6;
 	void *ifp;
 #ifdef USE_INET6
 	ip6_t *ip6;
-	struct in6_addr dst6;
 #endif
 	ip_t *ip, *ip2;
 
@@ -728,11 +542,17 @@
 
 	code = fin->fin_icode;
 #ifdef USE_INET6
-	if ((code < 0) || (code > sizeof(icmptoicmp6unreach)/sizeof(int)))
+#if 0
+	/* XXX Fix an off by one error: s/>/>=/
+	 was:
+	 if ((code < 0) || (code > sizeof(icmptoicmp6unreach)/sizeof(int)))
+	 Fix obtained from NetBSD ip_fil_netbsd.c r1.4: */
+#endif
+	if ((code < 0) || (code >= sizeof(icmptoicmp6unreach)/sizeof(int)))
 		return -1;
 #endif
 
-	if (fr_checkl4sum(fin) == -1)
+	if (ipf_checkl4sum(fin) == -1)
 		return -1;
 #ifdef MGETHDR
 	MGETHDR(m, M_DONTWAIT, MT_HEADER);
@@ -746,10 +566,10 @@
 	xtra = 0;
 	hlen = 0;
 	ohlen = 0;
+	dst4.s_addr = 0;
 	ifp = fin->fin_ifp;
 	if (fin->fin_v == 4) {
-		if ((fin->fin_p == IPPROTO_ICMP) &&
-		    !(fin->fin_flx & FI_SHORT))
+		if ((fin->fin_p == IPPROTO_ICMP) && !(fin->fin_flx & FI_SHORT))
 			switch (ntohs(fin->fin_data[0]) >> 8)
 			{
 			case ICMP_ECHO :
@@ -763,16 +583,18 @@
 			}
 
 		if (dst == 0) {
-			if (fr_ifpaddr(4, FRI_NORMAL, ifp,
-				       &dst4, NULL) == -1) {
+			if (ipf_ifpaddr(&ipfmain, 4, FRI_NORMAL, ifp,
+					&dst6, NULL) == -1) {
 				FREE_MB_T(m);
 				return -1;
 			}
+			dst4 = dst6.in4;
 		} else
 			dst4.s_addr = fin->fin_daddr;
 
 		hlen = sizeof(ip_t);
 		ohlen = fin->fin_hlen;
+		iclen = hlen + offsetof(struct icmp, icmp_ip) + ohlen;
 		if (fin->fin_hlen < fin->fin_plen)
 			xtra = MIN(fin->fin_dlen, 8);
 		else
@@ -783,12 +605,12 @@
 	else if (fin->fin_v == 6) {
 		hlen = sizeof(ip6_t);
 		ohlen = sizeof(ip6_t);
+		iclen = hlen + offsetof(struct icmp, icmp_ip) + ohlen;
 		type = icmptoicmp6types[type];
 		if (type == ICMP6_DST_UNREACH)
 			code = icmptoicmp6unreach[code];
 
-		if (hlen + sizeof(*icmp) + max_linkhdr +
-		    fin->fin_plen > avail) {
+		if (iclen + max_linkhdr + fin->fin_plen > avail) {
 			MCLGET(m, M_DONTWAIT);
 			if ((m->m_flags & M_EXT) == 0) {
 				FREE_MB_T(m);
@@ -796,11 +618,11 @@
 			}
 			avail = MCLBYTES;
 		}
-		xtra = MIN(fin->fin_plen,
-			   avail - hlen - sizeof(*icmp) - max_linkhdr);
+		xtra = MIN(fin->fin_plen, avail - iclen - max_linkhdr);
+		xtra = MIN(xtra, IPV6_MMTU - iclen);
 		if (dst == 0) {
-			if (fr_ifpaddr(6, FRI_NORMAL, ifp,
-				       (struct in_addr *)&dst6, NULL) == -1) {
+			if (ipf_ifpaddr(&ipfmain, 6, FRI_NORMAL, ifp,
+					&dst6, NULL) == -1) {
 				FREE_MB_T(m);
 				return -1;
 			}
@@ -813,7 +635,6 @@
 		return -1;
 	}
 
-	iclen = hlen + sizeof(*icmp);
 	avail -= (max_linkhdr + iclen);
 	if (avail < 0) {
 		FREE_MB_T(m);
@@ -834,9 +655,17 @@
 	icmp->icmp_code = fin->fin_icode;
 	icmp->icmp_cksum = 0;
 #ifdef icmp_nextmtu
-	if (type == ICMP_UNREACH &&
-	    fin->fin_icode == ICMP_UNREACH_NEEDFRAG && ifp)
-		icmp->icmp_nextmtu = htons(((struct ifnet *)ifp)->if_mtu);
+	if (type == ICMP_UNREACH && fin->fin_icode == ICMP_UNREACH_NEEDFRAG) {
+		if (fin->fin_mtu != 0) {
+			icmp->icmp_nextmtu = htons(fin->fin_mtu);
+
+		} else if (ifp != NULL) {
+			icmp->icmp_nextmtu = htons(GETIFMTU_4(ifp));
+
+		} else {	/* make up a number... */
+			icmp->icmp_nextmtu = htons(fin->fin_plen - 20);
+		}
+	}
 #endif
 
 	bcopy((char *)fin->fin_ip, (char *)ip2, ohlen);
@@ -848,8 +677,8 @@
 		ip6->ip6_plen = htons(iclen - hlen);
 		ip6->ip6_nxt = IPPROTO_ICMPV6;
 		ip6->ip6_hlim = 0;
-		ip6->ip6_src = dst6;
-		ip6->ip6_dst = fin->fin_src6;
+		ip6->ip6_src = dst6.in6;
+		ip6->ip6_dst = fin->fin_src6.in6;
 		if (xtra > 0)
 			bcopy((char *)fin->fin_ip + ohlen,
 			      (char *)&icmp->icmp_ip + ohlen, xtra);
@@ -858,8 +687,6 @@
 	} else
 #endif
 	{
-		ip2->ip_len = htons(ip2->ip_len);
-		ip2->ip_off = htons(ip2->ip_off);
 		ip->ip_p = IPPROTO_ICMP;
 		ip->ip_src.s_addr = dst4.s_addr;
 		ip->ip_dst.s_addr = fin->fin_saddr;
@@ -869,41 +696,25 @@
 			      (char *)&icmp->icmp_ip + ohlen, xtra);
 		icmp->icmp_cksum = ipf_cksum((u_short *)icmp,
 					     sizeof(*icmp) + 8);
-		ip->ip_len = iclen;
+		ip->ip_len = htons(iclen);
 		ip->ip_p = IPPROTO_ICMP;
 	}
-	err = fr_send_ip(fin, m, &m);
+	err = ipf_send_ip(fin, m);
 	return err;
 }
 
 
-#if !defined(IPFILTER_LKM) && (__FreeBSD_version < 300000)
-# if	(BSD < 199306)
-int iplinit __P((void));
 
-int
-# else
-void iplinit __P((void));
 
-void
-# endif
-iplinit()
-{
-	if (ipfattach() != 0)
-		printf("IP Filter failed to attach\n");
-	ip_init();
-}
-#endif /* __FreeBSD_version < 300000 */
-
-
 /*
  * m0 - pointer to mbuf where the IP packet starts
  * mpp - pointer to the mbuf pointer that is the start of the mbuf chain
  */
-int fr_fastroute(m0, mpp, fin, fdp)
-mb_t *m0, **mpp;
-fr_info_t *fin;
-frdest_t *fdp;
+int
+ipf_fastroute(m0, mpp, fin, fdp)
+	mb_t *m0, **mpp;
+	fr_info_t *fin;
+	frdest_t *fdp;
 {
 	register struct ip *ip, *mhip;
 	register struct mbuf *m = *mpp;
@@ -913,6 +724,7 @@
 	struct sockaddr_in *dst;
 	struct route iproute;
 	u_short ip_off;
+	frdest_t node;
 	frentry_t *fr;
 
 	ro = NULL;
@@ -931,7 +743,7 @@
 	*/
 	if (M_WRITABLE(m) == 0) {
 		m0 = m_dup(m, M_DONTWAIT);
-		if (m0 != 0) {
+		if (m0 != NULL) {
 			FREE_MB_T(m);
 			m = m0;
 			*mpp = m;
@@ -949,33 +761,36 @@
 		 * currently "to <if>" and "to <if>:ip#" are not supported
 		 * for IPv6
 		 */
-#if  (__FreeBSD_version >= 490000)
-		return ip6_output(m0, NULL, NULL, 0, NULL, NULL, NULL);
-#else
-		return ip6_output(m0, NULL, NULL, 0, NULL, NULL);
-#endif
+		return ip6_output(m, NULL, NULL, 0, NULL, NULL, NULL);
 	}
 #endif
 
 	hlen = fin->fin_hlen;
 	ip = mtod(m0, struct ip *);
+	ifp = NULL;
 
 	/*
 	 * Route packet.
 	 */
 	ro = &iproute;
-	bzero((caddr_t)ro, sizeof (*ro));
+	bzero(ro, sizeof (*ro));
 	dst = (struct sockaddr_in *)&ro->ro_dst;
 	dst->sin_family = AF_INET;
 	dst->sin_addr = ip->ip_dst;
 
 	fr = fin->fin_fr;
+	if ((fr != NULL) && !(fr->fr_flags & FR_KEEPSTATE) && (fdp != NULL) &&
+	    (fdp->fd_type == FRD_DSTLIST)) {
+		if (ipf_dstlist_select_node(fin, fdp->fd_ptr, NULL, &node) == 0)
+			fdp = &node;
+	}
+
 	if (fdp != NULL)
-		ifp = fdp->fd_ifp;
+		ifp = fdp->fd_ptr;
 	else
 		ifp = fin->fin_ifp;
 
-	if ((ifp == NULL) && (!fr || !(fr->fr_flags & FR_FASTROUTE))) {
+	if ((ifp == NULL) && ((fr == NULL) || !(fr->fr_flags & FR_FASTROUTE))) {
 		error = -2;
 		goto bad;
 	}
@@ -984,7 +799,7 @@
 		dst->sin_addr = fdp->fd_ip;
 
 	dst->sin_len = sizeof(*dst);
-	in_rtalloc(ro, 0);
+	in_rtalloc(ro, M_GETFIB(m0));
 
 	if ((ifp == NULL) && (ro->ro_rt != NULL))
 		ifp = ro->ro_rt->rt_ifp;
@@ -999,7 +814,7 @@
 	if (ro->ro_rt->rt_flags & RTF_GATEWAY)
 		dst = (struct sockaddr_in *)ro->ro_rt->rt_gateway;
 	if (ro->ro_rt)
-		ro->ro_rt->rt_use++;
+		counter_u64_add(ro->ro_rt->rt_pksent, 1);
 
 	/*
 	 * For input packets which are being "fastrouted", they won't
@@ -1012,21 +827,19 @@
 		sifp = fin->fin_ifp;
 		fin->fin_ifp = ifp;
 		fin->fin_out = 1;
-		(void) fr_acctpkt(fin, NULL);
+		(void) ipf_acctpkt(fin, NULL);
 		fin->fin_fr = NULL;
 		if (!fr || !(fr->fr_flags & FR_RETMASK)) {
 			u_32_t pass;
 
-			if (fr_checkstate(fin, &pass) != NULL)
-				fr_statederef((ipstate_t **)&fin->fin_state);
+			(void) ipf_state_check(fin, &pass);
 		}
 
-		switch (fr_checknatout(fin, NULL))
+		switch (ipf_nat_checkout(fin, NULL))
 		{
 		case 0 :
 			break;
 		case 1 :
-			fr_natderef((nat_t **)&fin->fin_nat);
 			ip->ip_sum = 0;
 			break;
 		case -1 :
@@ -1042,14 +855,12 @@
 	/*
 	 * If small enough for interface, can just send directly.
 	 */
-	if (ip->ip_len <= ifp->if_mtu) {
-		ip->ip_len = htons(ip->ip_len);
-		ip->ip_off = htons(ip->ip_off);
-
+	if (ntohs(ip->ip_len) <= ifp->if_mtu) {
 		if (!ip->ip_sum)
 			ip->ip_sum = in_cksum(m, hlen);
 		error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst,
-					  ro);
+			    ro
+			);
 		goto done;
 	}
 	/*
@@ -1077,13 +888,13 @@
 	 */
 	m0 = m;
 	mhlen = sizeof (struct ip);
-	for (off = hlen + len; off < ip->ip_len; off += len) {
+	for (off = hlen + len; off < ntohs(ip->ip_len); off += len) {
 #ifdef MGETHDR
 		MGETHDR(m, M_DONTWAIT, MT_HEADER);
 #else
 		MGET(m, M_DONTWAIT, MT_HEADER);
 #endif
-		if (m == 0) {
+		if (m == NULL) {
 			m = m0;
 			error = ENOBUFS;
 			goto bad;
@@ -1097,8 +908,8 @@
 		}
 		m->m_len = mhlen;
 		mhip->ip_off = ((off - hlen) >> 3) + ip_off;
-		if (off + len >= ip->ip_len)
-			len = ip->ip_len - off;
+		if (off + len >= ntohs(ip->ip_len))
+			len = ntohs(ip->ip_len) - off;
 		else
 			mhip->ip_off |= IP_MF;
 		mhip->ip_len = htons((u_short)(len + mhlen));
@@ -1130,21 +941,22 @@
 		m->m_act = 0;
 		if (error == 0)
 			error = (*ifp->if_output)(ifp, m,
-			    (struct sockaddr *)dst, ro);
+			    (struct sockaddr *)dst,
+			    ro
+			    );
 		else
 			FREE_MB_T(m);
 	}
-    }	
+    }
 done:
 	if (!error)
-		fr_frouteok[0]++;
+		ipfmain.ipf_frouteok[0]++;
 	else
-		fr_frouteok[1]++;
+		ipfmain.ipf_frouteok[1]++;
 
 	if ((ro != NULL) && (ro->ro_rt != NULL)) {
 		RTFREE(ro->ro_rt);
 	}
-	*mpp = NULL;
 	return 0;
 bad:
 	if (error == EMSGSIZE) {
@@ -1152,7 +964,7 @@
 		code = fin->fin_icode;
 		fin->fin_icode = ICMP_UNREACH_NEEDFRAG;
 		fin->fin_ifp = ifp;
-		(void) fr_send_icmp_err(ICMP_UNREACH, fin, 1);
+		(void) ipf_send_icmp_err(ICMP_UNREACH, fin, 1);
 		fin->fin_ifp = sifp;
 		fin->fin_icode = code;
 	}
@@ -1161,8 +973,9 @@
 }
 
 
-int fr_verifysrc(fin)
-fr_info_t *fin;
+int
+ipf_verifysrc(fin)
+	fr_info_t *fin;
 {
 	struct sockaddr_in *dst;
 	struct route iproute;
@@ -1182,10 +995,12 @@
 /*
  * return the first IP Address associated with an interface
  */
-int fr_ifpaddr(v, atype, ifptr, inp, inpmask)
-int v, atype;
-void *ifptr;
-struct in_addr *inp, *inpmask;
+int
+ipf_ifpaddr(softc, v, atype, ifptr, inp, inpmask)
+	ipf_main_softc_t *softc;
+	int v, atype;
+	void *ifptr;
+	i6addr_t *inp, *inpmask;
 {
 #ifdef USE_INET6
 	struct in6_addr *inp6 = NULL;
@@ -1202,16 +1017,12 @@
 	ifp = ifptr;
 
 	if (v == 4)
-		inp->s_addr = 0;
+		inp->in4.s_addr = 0;
 #ifdef USE_INET6
 	else if (v == 6)
-		bzero((char *)inp, sizeof(struct in6_addr));
+		bzero((char *)inp, sizeof(*inp));
 #endif
-#if  (__FreeBSD_version >= 300000)
 	ifa = TAILQ_FIRST(&ifp->if_addrhead);
-#else
-	ifa = ifp->if_addrlist;
-#endif /* __FreeBSD_version >= 300000 */
 
 	sock = ifa->ifa_addr;
 	while (sock != NULL && ifa != NULL) {
@@ -1226,11 +1037,7 @@
 				break;
 		}
 #endif
-#if (__FreeBSD_version >= 300000)
 		ifa = TAILQ_NEXT(ifa, ifa_link);
-#else
-		ifa = ifa->ifa_next;
-#endif /* __FreeBSD_version >= 300000 */
 		if (ifa != NULL)
 			sock = ifa->ifa_addr;
 	}
@@ -1249,79 +1056,45 @@
 
 #ifdef USE_INET6
 	if (v == 6) {
-		return fr_ifpfillv6addr(atype, (struct sockaddr_in6 *)sock,
-					(struct sockaddr_in6 *)mask,
-					inp, inpmask);
+		return ipf_ifpfillv6addr(atype, (struct sockaddr_in6 *)sock,
+					 (struct sockaddr_in6 *)mask,
+					 inp, inpmask);
 	}
 #endif
-	return fr_ifpfillv4addr(atype, (struct sockaddr_in *)sock,
-				(struct sockaddr_in *)mask, inp, inpmask);
+	return ipf_ifpfillv4addr(atype, (struct sockaddr_in *)sock,
+				 (struct sockaddr_in *)mask,
+				 &inp->in4, &inpmask->in4);
 }
 
 
-u_32_t fr_newisn(fin)
-fr_info_t *fin;
+u_32_t
+ipf_newisn(fin)
+	fr_info_t *fin;
 {
 	u_32_t newiss;
-#if  (__FreeBSD_version >= 400000)
 	newiss = arc4random();
-#else
-	static iss_seq_off = 0;
-	u_char hash[16];
-	MD5_CTX ctx;
-
-	/*
-	 * Compute the base value of the ISS.  It is a hash
-	 * of (saddr, sport, daddr, dport, secret).
-	 */
-	MD5Init(&ctx);
-
-	MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_src,
-		  sizeof(fin->fin_fi.fi_src));
-	MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_dst,
-		  sizeof(fin->fin_fi.fi_dst));
-	MD5Update(&ctx, (u_char *) &fin->fin_dat, sizeof(fin->fin_dat));
-
-	MD5Update(&ctx, ipf_iss_secret, sizeof(ipf_iss_secret));
-
-	MD5Final(hash, &ctx);
-
-	memcpy(&newiss, hash, sizeof(newiss));
-
-	/*
-	 * Now increment our "timer", and add it in to
-	 * the computed value.
-	 *
-	 * XXX Use `addin'?
-	 * XXX TCP_ISSINCR too large to use?
-	 */
-	iss_seq_off += 0x00010000;
-	newiss += iss_seq_off;
-#endif
 	return newiss;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_nextipid                                                 */
+/* Function:    ipf_nextipid                                                */
 /* Returns:     int - 0 == success, -1 == error (packet should be droppped) */
 /* Parameters:  fin(I) - pointer to packet information                      */
 /*                                                                          */
 /* Returns the next IPv4 ID to use for this packet.                         */
 /* ------------------------------------------------------------------------ */
-u_short fr_nextipid(fin)
-fr_info_t *fin;
+u_short
+ipf_nextipid(fin)
+	fr_info_t *fin;
 {
-#ifndef	RANDOM_IP_ID
-	static u_short ipid = 0;
 	u_short id;
 
-	MUTEX_ENTER(&ipf_rw);
+#ifndef	RANDOM_IP_ID
+	MUTEX_ENTER(&ipfmain.ipf_rw);
 	id = ipid++;
-	MUTEX_EXIT(&ipf_rw);
+	MUTEX_EXIT(&ipfmain.ipf_rw);
 #else
-	u_short id;
-
 	id = ip_randomid();
 #endif
 
@@ -1329,8 +1102,9 @@
 }
 
 
-INLINE void fr_checkv4sum(fin)
-fr_info_t *fin;
+INLINE int
+ipf_checkv4sum(fin)
+	fr_info_t *fin;
 {
 #ifdef CSUM_DATA_VALID
 	int manual = 0;
@@ -1339,11 +1113,14 @@
 	mb_t *m;
 
 	if ((fin->fin_flx & FI_NOCKSUM) != 0)
-		return;
+		return 0;
 
-	if (fin->fin_cksum != 0)
-		return;
+	if ((fin->fin_flx & FI_SHORT) != 0)
+		return 1;
 
+	if (fin->fin_cksum != FI_CK_NEEDED)
+		return (fin->fin_cksum > FI_CK_NEEDED) ? 0 : -1;
+
 	m = fin->fin_m;
 	if (m == NULL) {
 		manual = 1;
@@ -1351,56 +1128,102 @@
 	}
 	ip = fin->fin_ip;
 
+	if ((m->m_pkthdr.csum_flags & (CSUM_IP_CHECKED|CSUM_IP_VALID)) ==
+	    CSUM_IP_CHECKED) {
+		fin->fin_cksum = FI_CK_BAD;
+		fin->fin_flx |= FI_BAD;
+		return -1;
+	}
 	if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID) {
+		/* Depending on the driver, UDP may have zero checksum */
+		if (fin->fin_p == IPPROTO_UDP && (fin->fin_flx &
+		    (FI_FRAG|FI_SHORT|FI_BAD)) == 0) {
+			udphdr_t *udp = fin->fin_dp;
+			if (udp->uh_sum == 0) {
+				/*
+				 * we're good no matter what the hardware
+				 * checksum flags and csum_data say (handling
+				 * of csum_data for zero UDP checksum is not
+				 * consistent across all drivers)
+				 */
+				fin->fin_cksum = 1;
+				return 0;
+			}
+		}
+
 		if (m->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR)
 			sum = m->m_pkthdr.csum_data;
 		else
 			sum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr,
 					htonl(m->m_pkthdr.csum_data +
-					fin->fin_ip->ip_len -
-					(fin->fin_ip->ip_hl << 2) +
-					fin->fin_p));
+					fin->fin_dlen + fin->fin_p));
 		sum ^= 0xffff;
 		if (sum != 0) {
+			fin->fin_cksum = FI_CK_BAD;
 			fin->fin_flx |= FI_BAD;
-			fin->fin_cksum = -1;
 		} else {
-			fin->fin_cksum = 1;
+			fin->fin_cksum = FI_CK_SUMOK;
+			return 0;
 		}
-	} else
-		manual = 1;
+	} else {
+		if (m->m_pkthdr.csum_flags == CSUM_DELAY_DATA) {
+			fin->fin_cksum = FI_CK_L4FULL;
+			return 0;
+		} else if (m->m_pkthdr.csum_flags == CSUM_TCP ||
+			   m->m_pkthdr.csum_flags == CSUM_UDP) {
+			fin->fin_cksum = FI_CK_L4PART;
+			return 0;
+		} else if (m->m_pkthdr.csum_flags == CSUM_IP) {
+			fin->fin_cksum = FI_CK_L4PART;
+			return 0;
+		} else {
+			manual = 1;
+		}
+	}
 skipauto:
-# ifdef IPFILTER_CKSUM
-	if (manual != 0)
-		if (fr_checkl4sum(fin) == -1)
+	if (manual != 0) {
+		if (ipf_checkl4sum(fin) == -1) {
 			fin->fin_flx |= FI_BAD;
-# else
-	;
-# endif
+			return -1;
+		}
+	}
 #else
-# ifdef IPFILTER_CKSUM
-	if (fr_checkl4sum(fin) == -1)
+	if (ipf_checkl4sum(fin) == -1) {
 		fin->fin_flx |= FI_BAD;
-# endif
+		return -1;
+	}
 #endif
+	return 0;
 }
 
 
 #ifdef USE_INET6
-INLINE void fr_checkv6sum(fin)
-fr_info_t *fin;
+INLINE int
+ipf_checkv6sum(fin)
+	fr_info_t *fin;
 {
-# ifdef IPFILTER_CKSUM
-	if (fr_checkl4sum(fin) == -1)
+	if ((fin->fin_flx & FI_NOCKSUM) != 0)
+		return 0;
+
+	if ((fin->fin_flx & FI_SHORT) != 0)
+		return 1;
+
+	if (fin->fin_cksum != FI_CK_NEEDED)
+		return (fin->fin_cksum > FI_CK_NEEDED) ? 0 : -1;
+
+	if (ipf_checkl4sum(fin) == -1) {
 		fin->fin_flx |= FI_BAD;
-# endif
+		return -1;
+	}
+	return 0;
 }
 #endif /* USE_INET6 */
 
 
-size_t mbufchainlen(m0)
-struct mbuf *m0;
-{
+size_t
+mbufchainlen(m0)
+	struct mbuf *m0;
+	{
 	size_t len;
 
 	if ((m0->m_flags & M_PKTHDR) != 0) {
@@ -1416,9 +1239,9 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_pullup                                                   */
+/* Function:    ipf_pullup                                                  */
 /* Returns:     NULL == pullup failed, else pointer to protocol header      */
-/* Parameters:  m(I)   - pointer to buffer where data packet starts         */
+/* Parameters:  xmin(I)- pointer to buffer where data packet starts         */
 /*              fin(I) - pointer to packet information                      */
 /*              len(I) - number of bytes to pullup                          */
 /*                                                                          */
@@ -1425,20 +1248,21 @@
 /* Attempt to move at least len bytes (from the start of the buffer) into a */
 /* single buffer for ease of access.  Operating system native functions are */
 /* used to manage buffers - if necessary.  If the entire packet ends up in  */
-/* a single buffer, set the FI_COALESCE flag even though fr_coalesce() has  */
+/* a single buffer, set the FI_COALESCE flag even though ipf_coalesce() has */
 /* not been called.  Both fin_ip and fin_dp are updated before exiting _IF_ */
 /* and ONLY if the pullup succeeds.                                         */
 /*                                                                          */
-/* We assume that 'min' is a pointer to a buffer that is part of the chain  */
+/* We assume that 'xmin' is a pointer to a buffer that is part of the chain */
 /* of buffers that starts at *fin->fin_mp.                                  */
 /* ------------------------------------------------------------------------ */
-void *fr_pullup(min, fin, len)
-mb_t *min;
-fr_info_t *fin;
-int len;
+void *
+ipf_pullup(xmin, fin, len)
+	mb_t *xmin;
+	fr_info_t *fin;
+	int len;
 {
-	int out = fin->fin_out, dpoff, ipoff;
-	mb_t *m = min;
+	int dpoff, ipoff;
+	mb_t *m = xmin;
 	char *ip;
 
 	if (m == NULL)
@@ -1455,12 +1279,25 @@
 		dpoff = 0;
 
 	if (M_LEN(m) < len) {
-#ifdef MHLEN
+		mb_t *n = *fin->fin_mp;
 		/*
 		 * Assume that M_PKTHDR is set and just work with what is left
 		 * rather than check..
 		 * Should not make any real difference, anyway.
 		 */
+		if (m != n) {
+			/*
+			 * Record the mbuf that points to the mbuf that we're
+			 * about to go to work on so that we can update the
+			 * m_next appropriately later.
+			 */
+			for (; n->m_next != m; n = n->m_next)
+				;
+		} else {
+			n = NULL;
+		}
+
+#ifdef MHLEN
 		if (len > MHLEN)
 #else
 		if (len > MLEN)
@@ -1472,30 +1309,47 @@
 #else
 			FREE_MB_T(*fin->fin_mp);
 			m = NULL;
+			n = NULL;
 #endif
 		} else
 		{
 			m = m_pullup(m, len);
 		}
-		*fin->fin_mp = m;
+		if (n != NULL)
+			n->m_next = m;
 		if (m == NULL) {
+			/*
+			 * When n is non-NULL, it indicates that m pointed to
+			 * a sub-chain (tail) of the mbuf and that the head
+			 * of this chain has not yet been free'd.
+			 */
+			if (n != NULL) {
+				FREE_MB_T(*fin->fin_mp);
+			}
+
+			*fin->fin_mp = NULL;
 			fin->fin_m = NULL;
-			ATOMIC_INCL(frstats[out].fr_pull[1]);
 			return NULL;
 		}
 
+		if (n == NULL)
+			*fin->fin_mp = m;
+
 		while (M_LEN(m) == 0) {
 			m = m->m_next;
 		}
 		fin->fin_m = m;
 		ip = MTOD(m, char *) + ipoff;
+
+		fin->fin_ip = (ip_t *)ip;
+		if (fin->fin_dp != NULL)
+			fin->fin_dp = (char *)fin->fin_ip + dpoff;
+		if (fin->fin_fraghdr != NULL)
+			fin->fin_fraghdr = (char *)ip +
+					   ((char *)fin->fin_fraghdr -
+					    (char *)fin->fin_ip);
 	}
 
-	ATOMIC_INCL(frstats[out].fr_pull[0]);
-	fin->fin_ip = (ip_t *)ip;
-	if (fin->fin_dp != NULL)
-		fin->fin_dp = (char *)fin->fin_ip + dpoff;
-
 	if (len == fin->fin_plen)
 		fin->fin_flx |= FI_COALESCE;
 	return ip;
@@ -1502,45 +1356,19 @@
 }
 
 
-int ipf_inject(fin, m)
-fr_info_t *fin;
-mb_t *m;
+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;
@@ -1548,38 +1376,22 @@
 
 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_remove_hook((void *)ipf_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_remove_hook((void *)ipf_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
 
@@ -1588,17 +1400,13 @@
 
 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);
@@ -1607,28 +1415,17 @@
 #    ifdef USE_INET6
 	    && ph_inet6 == NULL
 #    endif
-	   )
+	   ) {
 		return ENODEV;
+	}
 
 	if (ph_inet != NULL)
-		pfil_add_hook((void *)fr_check_wrapper, NULL,
+		pfil_add_hook((void *)ipf_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_add_hook((void *)ipf_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);
@@ -1637,22 +1434,19 @@
 void
 ipf_event_reg(void)
 {
-#if (__FreeBSD_version >= 502103)
-	ipf_arrivetag =  EVENTHANDLER_REGISTER(ifnet_arrival_event, \
-					       ipf_ifevent, NULL, \
+	ipf_arrivetag = EVENTHANDLER_REGISTER(ifnet_arrival_event, \
+					       ipf_ifevent, &ipfmain, \
 					       EVENTHANDLER_PRI_ANY);
-	ipf_departtag =  EVENTHANDLER_REGISTER(ifnet_departure_event, \
-					       ipf_ifevent, NULL, \
+	ipf_departtag = EVENTHANDLER_REGISTER(ifnet_departure_event, \
+					       ipf_ifevent, &ipfmain, \
 					       EVENTHANDLER_PRI_ANY);
-	ipf_clonetag =  EVENTHANDLER_REGISTER(if_clone_event, ipf_ifevent, \
-					      NULL, EVENTHANDLER_PRI_ANY);
-#endif
+	ipf_clonetag  = EVENTHANDLER_REGISTER(if_clone_event, ipf_ifevent, \
+					       &ipfmain, EVENTHANDLER_PRI_ANY);
 }
 
 void
 ipf_event_dereg(void)
 {
-#if (__FreeBSD_version >= 502103)
 	if (ipf_arrivetag != NULL) {
 		EVENTHANDLER_DEREGISTER(ifnet_arrival_event, ipf_arrivetag);
 	}
@@ -1662,5 +1456,40 @@
 	if (ipf_clonetag != NULL) {
 		EVENTHANDLER_DEREGISTER(if_clone_event, ipf_clonetag);
 	}
-#endif
 }
+
+
+u_32_t
+ipf_random()
+{
+	return arc4random();
+}
+
+
+u_int
+ipf_pcksum(fin, hlen, sum)
+	fr_info_t *fin;
+	int hlen;
+	u_int sum;
+{
+	struct mbuf *m;
+	u_int sum2;
+	int off;
+
+	m = fin->fin_m;
+	off = (char *)fin->fin_dp - (char *)fin->fin_ip;
+	m->m_data += hlen;
+	m->m_len -= hlen;
+	sum2 = in_cksum(fin->fin_m, fin->fin_plen - off);
+	m->m_len += hlen;
+	m->m_data -= hlen;
+
+	/*
+	 * Both sum and sum2 are partial sums, so combine them together.
+	 */
+	sum += ~sum2 & 0xffff;
+	while (sum > 0xffff)
+		sum = (sum & 0xffff) + (sum >> 16);
+	sum2 = ~sum & 0xffff;
+	return sum2;
+}

Modified: trunk/sys/contrib/ipfilter/netinet/ip_frag.c
===================================================================
--- trunk/sys/contrib/ipfilter/netinet/ip_frag.c	2018-05-28 18:55:30 UTC (rev 10138)
+++ trunk/sys/contrib/ipfilter/netinet/ip_frag.c	2018-05-28 18:56:30 UTC (rev 10139)
@@ -1,7 +1,8 @@
-/*	$FreeBSD$	*/
+/* $MidnightBSD$ */
+/*	$FreeBSD: stable/10/sys/contrib/ipfilter/netinet/ip_frag.c 317241 2017-04-21 01:51:49Z cy $	*/
 
 /*
- * Copyright (C) 1993-2003 by Darren Reed.
+ * Copyright (C) 2012 by Darren Reed.
  *
  * See the IPFILTER.LICENCE file for details on licencing.
  */
@@ -30,7 +31,8 @@
 # include <sys/uio.h>
 # undef _KERNEL
 #endif
-#if defined(_KERNEL) && (__FreeBSD_version >= 220000)
+#if defined(_KERNEL) && \
+    defined(__FreeBSD_version) && (__FreeBSD_version >= 220000)
 # include <sys/filio.h>
 # include <sys/fcntl.h>
 #else
@@ -62,7 +64,6 @@
 #ifdef sun
 # include <net/af.h>
 #endif
-#include <net/route.h>
 #include <netinet/in.h>
 #include <netinet/in_systm.h>
 #include <netinet/ip.h>
@@ -79,208 +80,407 @@
 #include "netinet/ip_frag.h"
 #include "netinet/ip_state.h"
 #include "netinet/ip_auth.h"
+#include "netinet/ip_lookup.h"
 #include "netinet/ip_proxy.h"
-#if (__FreeBSD_version >= 300000)
-# include <sys/malloc.h>
-# if defined(_KERNEL)
-#  ifndef IPFILTER_LKM
-#   include <sys/libkern.h>
-#   include <sys/systm.h>
-#  endif
-extern struct callout_handle fr_slowtimer_ch;
-# endif
-#endif
-#if defined(__NetBSD__) && (__NetBSD_Version__ >= 104230000)
-# include <sys/callout.h>
-extern struct callout fr_slowtimer_ch;
-#endif
-#if defined(__OpenBSD__)
-# include <sys/timeout.h>
-extern struct timeout fr_slowtimer_ch;
-#endif
+#include "netinet/ip_sync.h"
 /* END OF INCLUDES */
 
 #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$";
-/* static const char rcsid[] = "@(#)$Id: ip_frag.c,v 1.4 2013-01-08 01:31:40 laffer1 Exp $"; */
+static const char rcsid[] = "@(#)$FreeBSD: stable/10/sys/contrib/ipfilter/netinet/ip_frag.c 317241 2017-04-21 01:51:49Z cy $";
+/* static const char rcsid[] = "@(#)$Id: ip_frag.c,v 2.77.2.12 2007/09/20 12:51:51 darrenr Exp $"; */
 #endif
 
 
-ipfr_t   *ipfr_list = NULL;
-ipfr_t   **ipfr_tail = &ipfr_list;
+#ifdef USE_MUTEXES
+static ipfr_t *ipfr_frag_new __P((ipf_main_softc_t *, ipf_frag_softc_t *,
+				  fr_info_t *, u_32_t, ipfr_t **,
+				  ipfrwlock_t *));
+static ipfr_t *ipf_frag_lookup __P((ipf_main_softc_t *, ipf_frag_softc_t *, fr_info_t *, ipfr_t **, ipfrwlock_t *));
+static void ipf_frag_deref __P((void *, ipfr_t **, ipfrwlock_t *));
+static int ipf_frag_next __P((ipf_main_softc_t *, ipftoken_t *, ipfgeniter_t *,
+			      ipfr_t **, ipfrwlock_t *));
+#else
+static ipfr_t *ipfr_frag_new __P((ipf_main_softc_t *, ipf_frag_softc_t *,
+				  fr_info_t *, u_32_t, ipfr_t **));
+static ipfr_t *ipf_frag_lookup __P((ipf_main_softc_t *, ipf_frag_softc_t *, fr_info_t *, ipfr_t **));
+static void ipf_frag_deref __P((void *, ipfr_t **));
+static int ipf_frag_next __P((ipf_main_softc_t *, ipftoken_t *, ipfgeniter_t *,
+			      ipfr_t **));
+#endif
+static void ipf_frag_delete __P((ipf_main_softc_t *, ipfr_t *, ipfr_t ***));
+static void ipf_frag_free __P((ipf_frag_softc_t *, ipfr_t *));
 
-ipfr_t   *ipfr_natlist = NULL;
-ipfr_t   **ipfr_nattail = &ipfr_natlist;
+static frentry_t ipfr_block;
 
-ipfr_t   *ipfr_ipidlist = NULL;
-ipfr_t   **ipfr_ipidtail = &ipfr_ipidlist;
+static ipftuneable_t ipf_frag_tuneables[] = {
+	{ { (void *)offsetof(ipf_frag_softc_t, ipfr_size) },
+		"frag_size",		1,	0x7fffffff,
+		stsizeof(ipf_frag_softc_t, ipfr_size),
+		IPFT_WRDISABLED,	NULL,	NULL },
+	{ { (void *)offsetof(ipf_frag_softc_t, ipfr_ttl) },
+		"frag_ttl",		1,	0x7fffffff,
+		stsizeof(ipf_frag_softc_t, ipfr_ttl),
+		0,			NULL,	NULL },
+	{ { NULL },
+		NULL,			0,	0,
+		0,
+		0,			NULL,	NULL }
+};
 
-static ipfr_t	**ipfr_heads;
-static ipfr_t	**ipfr_nattab;
-static ipfr_t	**ipfr_ipidtab;
+#define	FBUMP(x)	softf->ipfr_stats.x++
+#define	FBUMPD(x)	do { softf->ipfr_stats.x++; DT(x); } while (0)
 
-static ipfrstat_t ipfr_stats;
-static int	ipfr_inuse = 0;
-int		ipfr_size = IPFT_SIZE;
 
-int	fr_ipfrttl = 120;	/* 60 seconds */
-int	fr_frag_lock = 0;
-int	fr_frag_init = 0;
-u_long	fr_ticks = 0;
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_frag_main_load                                          */
+/* Returns:     int - 0 == success, -1 == error                             */
+/* Parameters:  Nil                                                         */
+/*                                                                          */
+/* Initialise the filter rule associted with blocked packets - everyone can */
+/* use it.                                                                  */
+/* ------------------------------------------------------------------------ */
+int
+ipf_frag_main_load()
+{
+	bzero((char *)&ipfr_block, sizeof(ipfr_block));
+	ipfr_block.fr_flags = FR_BLOCK|FR_QUICK;
+	ipfr_block.fr_ref = 1;
 
+	return 0;
+}
 
-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 *));
 
-
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_fraginit                                                 */
+/* Function:    ipf_frag_main_unload                                        */
 /* Returns:     int - 0 == success, -1 == error                             */
 /* Parameters:  Nil                                                         */
 /*                                                                          */
+/* A null-op function that exists as a placeholder so that the flow in      */
+/* other functions is obvious.                                              */
+/* ------------------------------------------------------------------------ */
+int
+ipf_frag_main_unload()
+{
+	return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_frag_soft_create                                        */
+/* Returns:     void *   - NULL = failure, else pointer to local context    */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*                                                                          */
+/* Allocate a new soft context structure to track fragment related info.    */
+/* ------------------------------------------------------------------------ */
+/*ARGSUSED*/
+void *
+ipf_frag_soft_create(softc)
+	ipf_main_softc_t *softc;
+{
+	ipf_frag_softc_t *softf;
+
+	KMALLOC(softf, ipf_frag_softc_t *);
+	if (softf == NULL)
+		return NULL;
+
+	bzero((char *)softf, sizeof(*softf));
+
+	RWLOCK_INIT(&softf->ipfr_ipidfrag, "frag ipid lock");
+	RWLOCK_INIT(&softf->ipfr_frag, "ipf fragment rwlock");
+	RWLOCK_INIT(&softf->ipfr_natfrag, "ipf NAT fragment rwlock");
+
+	softf->ipf_frag_tune = ipf_tune_array_copy(softf,
+						   sizeof(ipf_frag_tuneables),
+						   ipf_frag_tuneables);
+	if (softf->ipf_frag_tune == NULL) {
+		ipf_frag_soft_destroy(softc, softf);
+		return NULL;
+	}
+	if (ipf_tune_array_link(softc, softf->ipf_frag_tune) == -1) {
+		ipf_frag_soft_destroy(softc, softf);
+		return NULL;
+	}
+
+	softf->ipfr_size = IPFT_SIZE;
+	softf->ipfr_ttl = IPF_TTLVAL(60);
+	softf->ipfr_lock = 1;
+	softf->ipfr_tail = &softf->ipfr_list;
+	softf->ipfr_nattail = &softf->ipfr_natlist;
+	softf->ipfr_ipidtail = &softf->ipfr_ipidlist;
+
+	return softf;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_frag_soft_destroy                                       */
+/* Returns:     Nil                                                         */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              arg(I)   - pointer to local context to use                  */
+/*                                                                          */
 /* Initialise the hash tables for the fragment cache lookups.               */
 /* ------------------------------------------------------------------------ */
-int fr_fraginit()
+void
+ipf_frag_soft_destroy(softc, arg)
+	ipf_main_softc_t *softc;
+	void *arg;
 {
-	KMALLOCS(ipfr_heads, ipfr_t **, ipfr_size * sizeof(ipfr_t *));
-	if (ipfr_heads == NULL)
-		return -1;
-	bzero((char *)ipfr_heads, ipfr_size * sizeof(ipfr_t *));
+	ipf_frag_softc_t *softf = arg;
 
-	KMALLOCS(ipfr_nattab, ipfr_t **, ipfr_size * sizeof(ipfr_t *));
-	if (ipfr_nattab == NULL)
-		return -1;
-	bzero((char *)ipfr_nattab, ipfr_size * sizeof(ipfr_t *));
+	RW_DESTROY(&softf->ipfr_ipidfrag);
+	RW_DESTROY(&softf->ipfr_frag);
+	RW_DESTROY(&softf->ipfr_natfrag);
 
-	KMALLOCS(ipfr_ipidtab, ipfr_t **, ipfr_size * sizeof(ipfr_t *));
-	if (ipfr_ipidtab == NULL)
+	if (softf->ipf_frag_tune != NULL) {
+		ipf_tune_array_unlink(softc, softf->ipf_frag_tune);
+		KFREES(softf->ipf_frag_tune, sizeof(ipf_frag_tuneables));
+		softf->ipf_frag_tune = NULL;
+	}
+
+	KFREE(softf);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_frag_soft_init                                          */
+/* Returns:     int      - 0 == success, -1 == error                        */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              arg(I)   - pointer to local context to use                  */
+/*                                                                          */
+/* Initialise the hash tables for the fragment cache lookups.               */
+/* ------------------------------------------------------------------------ */
+/*ARGSUSED*/
+int
+ipf_frag_soft_init(softc, arg)
+	ipf_main_softc_t *softc;
+	void *arg;
+{
+	ipf_frag_softc_t *softf = arg;
+
+	KMALLOCS(softf->ipfr_heads, ipfr_t **,
+		 softf->ipfr_size * sizeof(ipfr_t *));
+	if (softf->ipfr_heads == NULL)
 		return -1;
-	bzero((char *)ipfr_ipidtab, ipfr_size * sizeof(ipfr_t *));
 
-	RWLOCK_INIT(&ipf_frag, "ipf fragment rwlock");
-	fr_frag_init = 1;
+	bzero((char *)softf->ipfr_heads, softf->ipfr_size * sizeof(ipfr_t *));
 
+	KMALLOCS(softf->ipfr_nattab, ipfr_t **,
+		 softf->ipfr_size * sizeof(ipfr_t *));
+	if (softf->ipfr_nattab == NULL)
+		return -2;
+
+	bzero((char *)softf->ipfr_nattab, softf->ipfr_size * sizeof(ipfr_t *));
+
+	KMALLOCS(softf->ipfr_ipidtab, ipfr_t **,
+		 softf->ipfr_size * sizeof(ipfr_t *));
+	if (softf->ipfr_ipidtab == NULL)
+		return -3;
+
+	bzero((char *)softf->ipfr_ipidtab,
+	      softf->ipfr_size * sizeof(ipfr_t *));
+
+	softf->ipfr_lock = 0;
+	softf->ipfr_inited = 1;
+
 	return 0;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_fragunload                                               */
-/* Returns:     Nil                                                         */
-/* Parameters:  Nil                                                         */
+/* Function:    ipf_frag_soft_fini                                          */
+/* Returns:     int      - 0 == success, -1 == error                        */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              arg(I)   - pointer to local context to use                  */
 /*                                                                          */
 /* Free all memory allocated whilst running and from initialisation.        */
 /* ------------------------------------------------------------------------ */
-void fr_fragunload()
+int
+ipf_frag_soft_fini(softc, arg)
+	ipf_main_softc_t *softc;
+	void *arg;
 {
-	if (fr_frag_init == 1) {
-		fr_fragclear();
+	ipf_frag_softc_t *softf = arg;
 
-		RW_DESTROY(&ipf_frag);
-		fr_frag_init = 0;
+	softf->ipfr_lock = 1;
+
+	if (softf->ipfr_inited == 1) {
+		ipf_frag_clear(softc);
+
+		softf->ipfr_inited = 0;
 	}
 
-	if (ipfr_heads != NULL)
-		KFREES(ipfr_heads, ipfr_size * sizeof(ipfr_t *));
-	ipfr_heads = NULL;
+	if (softf->ipfr_heads != NULL)
+		KFREES(softf->ipfr_heads,
+		       softf->ipfr_size * sizeof(ipfr_t *));
+	softf->ipfr_heads = NULL;
 
-	if (ipfr_nattab != NULL)
-		KFREES(ipfr_nattab, ipfr_size * sizeof(ipfr_t *));
-	ipfr_nattab = NULL;
+	if (softf->ipfr_nattab != NULL)
+		KFREES(softf->ipfr_nattab,
+		       softf->ipfr_size * sizeof(ipfr_t *));
+	softf->ipfr_nattab = NULL;
 
-	if (ipfr_ipidtab != NULL)
-		KFREES(ipfr_ipidtab, ipfr_size * sizeof(ipfr_t *));
-	ipfr_ipidtab = NULL;
+	if (softf->ipfr_ipidtab != NULL)
+		KFREES(softf->ipfr_ipidtab,
+		       softf->ipfr_size * sizeof(ipfr_t *));
+	softf->ipfr_ipidtab = NULL;
+
+	return 0;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_fragstats                                                */
+/* Function:    ipf_frag_set_lock                                           */
+/* Returns:     Nil                                                         */
+/* Parameters:  arg(I) - pointer to local context to use                    */
+/*              tmp(I) - new value for lock                                 */
+/*                                                                          */
+/* Stub function that allows for external manipulation of ipfr_lock         */
+/* ------------------------------------------------------------------------ */
+void
+ipf_frag_setlock(arg, tmp)
+	void *arg;
+	int tmp;
+{
+	ipf_frag_softc_t *softf = arg;
+
+	softf->ipfr_lock = tmp;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_frag_stats                                              */
 /* Returns:     ipfrstat_t* - pointer to struct with current frag stats     */
-/* Parameters:  Nil                                                         */
+/* Parameters:  arg(I) - pointer to local context to use                    */
 /*                                                                          */
 /* Updates ipfr_stats with current information and returns a pointer to it  */
 /* ------------------------------------------------------------------------ */
-ipfrstat_t *fr_fragstats()
+ipfrstat_t *
+ipf_frag_stats(arg)
+	void *arg;
 {
-	ipfr_stats.ifs_table = ipfr_heads;
-	ipfr_stats.ifs_nattab = ipfr_nattab;
-	ipfr_stats.ifs_inuse = ipfr_inuse;
-	return &ipfr_stats;
+	ipf_frag_softc_t *softf = arg;
+
+	softf->ipfr_stats.ifs_table = softf->ipfr_heads;
+	softf->ipfr_stats.ifs_nattab = softf->ipfr_nattab;
+	return &softf->ipfr_stats;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    ipfr_newfrag                                                */
+/* Function:    ipfr_frag_new                                               */
 /* Returns:     ipfr_t * - pointer to fragment cache state info or NULL     */
 /* Parameters:  fin(I)   - pointer to packet information                    */
 /*              table(I) - pointer to frag table to add to                  */
+/*              lock(I)  - pointer to lock to get a write hold of           */
 /*                                                                          */
 /* Add a new entry to the fragment cache, registering it as having come     */
 /* through this box, with the result of the filter operation.               */
+/*                                                                          */
+/* If this function succeeds, it returns with a write lock held on "lock".  */
+/* If it fails, no lock is held on return.                                  */
 /* ------------------------------------------------------------------------ */
-static ipfr_t *ipfr_newfrag(fin, pass, table)
-fr_info_t *fin;
-u_32_t pass;
-ipfr_t *table[];
+static ipfr_t *
+ipfr_frag_new(softc, softf, fin, pass, table
+#ifdef USE_MUTEXES
+, lock
+#endif
+)
+	ipf_main_softc_t *softc;
+	ipf_frag_softc_t *softf;
+	fr_info_t *fin;
+	u_32_t pass;
+	ipfr_t *table[];
+#ifdef USE_MUTEXES
+	ipfrwlock_t *lock;
+#endif
 {
-	ipfr_t *fra, frag;
+	ipfr_t *fra, frag, *fran;
 	u_int idx, off;
 	frentry_t *fr;
-	ip_t *ip;
 
-	if (ipfr_inuse >= IPFT_SIZE)
+	if (softf->ipfr_stats.ifs_inuse >= softf->ipfr_size) {
+		FBUMPD(ifs_maximum);
 		return NULL;
+	}
 
-	if ((fin->fin_flx & (FI_FRAG|FI_BAD)) != FI_FRAG)
+	if ((fin->fin_flx & (FI_FRAG|FI_BAD)) != FI_FRAG) {
+		FBUMPD(ifs_newbad);
 		return NULL;
+	}
 
-	ip = fin->fin_ip;
-
-	if (pass & FR_FRSTRICT)
-		if (fin->fin_off != 0)
+	if (pass & FR_FRSTRICT) {
+		if (fin->fin_off != 0) {
+			FBUMPD(ifs_newrestrictnot0);
 			return NULL;
+		}
+	}
 
-	frag.ipfr_p = ip->ip_p;
-	idx = ip->ip_p;
-	frag.ipfr_id = ip->ip_id;
-	idx += ip->ip_id;
-	frag.ipfr_tos = ip->ip_tos;
-	frag.ipfr_src.s_addr = ip->ip_src.s_addr;
-	idx += ip->ip_src.s_addr;
-	frag.ipfr_dst.s_addr = ip->ip_dst.s_addr;
-	idx += ip->ip_dst.s_addr;
+	frag.ipfr_v = fin->fin_v;
+	idx = fin->fin_v;
+	frag.ipfr_p = fin->fin_p;
+	idx += fin->fin_p;
+	frag.ipfr_id = fin->fin_id;
+	idx += fin->fin_id;
+	frag.ipfr_source = fin->fin_fi.fi_src;
+	idx += frag.ipfr_src.s_addr;
+	frag.ipfr_dest = fin->fin_fi.fi_dst;
+	idx += frag.ipfr_dst.s_addr;
 	frag.ipfr_ifp = fin->fin_ifp;
 	idx *= 127;
-	idx %= IPFT_SIZE;
+	idx %= softf->ipfr_size;
 
 	frag.ipfr_optmsk = fin->fin_fi.fi_optmsk & IPF_OPTCOPY;
 	frag.ipfr_secmsk = fin->fin_fi.fi_secmsk;
 	frag.ipfr_auth = fin->fin_fi.fi_auth;
 
+	off = fin->fin_off >> 3;
+	if (off == 0) {
+		char *ptr;
+		int end;
+
+#ifdef USE_INET6
+		if (fin->fin_v == 6) {
+
+			ptr = (char *)fin->fin_fraghdr +
+			      sizeof(struct ip6_frag);
+		} else
+#endif
+		{
+			ptr = fin->fin_dp;
+		}
+		end = fin->fin_plen - (ptr - (char *)fin->fin_ip);
+		frag.ipfr_firstend = end >> 3;
+	} else {
+		frag.ipfr_firstend = 0;
+	}
+
 	/*
+	 * allocate some memory, if possible, if not, just record that we
+	 * failed to do so.
+	 */
+	KMALLOC(fran, ipfr_t *);
+	if (fran == NULL) {
+		FBUMPD(ifs_nomem);
+		return NULL;
+	}
+
+	WRITE_ENTER(lock);
+
+	/*
 	 * first, make sure it isn't already there...
 	 */
 	for (fra = table[idx]; (fra != NULL); fra = fra->ipfr_hnext)
 		if (!bcmp((char *)&frag.ipfr_ifp, (char *)&fra->ipfr_ifp,
 			  IPFR_CMPSZ)) {
-			ipfr_stats.ifs_exists++;
+			RWLOCK_EXIT(lock);
+			FBUMPD(ifs_exists);
+			KFREE(fran);
 			return NULL;
 		}
 
-	/*
-	 * allocate some memory, if possible, if not, just record that we
-	 * failed to do so.
-	 */
-	KMALLOC(fra, ipfr_t *);
-	if (fra == NULL) {
-		ipfr_stats.ifs_nomem++;
-		return NULL;
-	}
-
+	fra = fran;
+	fran = NULL;
 	fr = fin->fin_fr;
 	fra->ipfr_rule = fr;
 	if (fr != NULL) {
@@ -300,56 +500,63 @@
 	fra->ipfr_data = NULL;
 	table[idx] = fra;
 	bcopy((char *)&frag.ipfr_ifp, (char *)&fra->ipfr_ifp, IPFR_CMPSZ);
-	fra->ipfr_ttl = fr_ticks + fr_ipfrttl;
+	fra->ipfr_v = fin->fin_v;
+	fra->ipfr_ttl = softc->ipf_ticks + softf->ipfr_ttl;
+	fra->ipfr_firstend = frag.ipfr_firstend;
 
 	/*
 	 * Compute the offset of the expected start of the next packet.
 	 */
-	off = ip->ip_off & IP_OFFMASK;
 	if (off == 0)
 		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++;
+	fra->ipfr_pkts = 1;
+	fra->ipfr_bytes = fin->fin_plen;
+	FBUMP(ifs_inuse);
+	FBUMP(ifs_new);
 	return fra;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_newfrag                                                  */
+/* Function:    ipf_frag_new                                                */
 /* Returns:     int - 0 == success, -1 == error                             */
 /* Parameters:  fin(I)  - pointer to packet information                     */
 /*                                                                          */
 /* Add a new entry to the fragment cache table based on the current packet  */
 /* ------------------------------------------------------------------------ */
-int fr_newfrag(fin, pass)
-u_32_t pass;
-fr_info_t *fin;
+int
+ipf_frag_new(softc, fin, pass)
+	ipf_main_softc_t *softc;
+	u_32_t pass;
+	fr_info_t *fin;
 {
+	ipf_frag_softc_t *softf = softc->ipf_frag_soft;
 	ipfr_t	*fra;
 
-	if ((fin->fin_v != 4) || (fr_frag_lock != 0))
+	if (softf->ipfr_lock != 0)
 		return -1;
 
-	WRITE_ENTER(&ipf_frag);
-	fra = ipfr_newfrag(fin, pass, ipfr_heads);
+#ifdef USE_MUTEXES
+	fra = ipfr_frag_new(softc, softf, fin, pass, softf->ipfr_heads, &softc->ipf_frag);
+#else
+	fra = ipfr_frag_new(softc, softf, fin, pass, softf->ipfr_heads);
+#endif
 	if (fra != NULL) {
-		*ipfr_tail = fra;
-		fra->ipfr_prev = ipfr_tail;
-		ipfr_tail = &fra->ipfr_next;
-		if (ipfr_list == NULL)
-			ipfr_list = fra;
+		*softf->ipfr_tail = fra;
+		fra->ipfr_prev = softf->ipfr_tail;
+		softf->ipfr_tail = &fra->ipfr_next;
 		fra->ipfr_next = NULL;
+		RWLOCK_EXIT(&softc->ipf_frag);
 	}
-	RWLOCK_EXIT(&ipf_frag);
 	return fra ? 0 : -1;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_nat_newfrag                                              */
+/* Function:    ipf_frag_natnew                                             */
 /* Returns:     int - 0 == success, -1 == error                             */
 /* Parameters:  fin(I)  - pointer to packet information                     */
 /*              nat(I)  - pointer to NAT structure                          */
@@ -357,33 +564,41 @@
 /* Create a new NAT fragment cache entry based on the current packet and    */
 /* the NAT structure for this "session".                                    */
 /* ------------------------------------------------------------------------ */
-int fr_nat_newfrag(fin, pass, nat)
-fr_info_t *fin;
-u_32_t pass;
-nat_t *nat;
+int
+ipf_frag_natnew(softc, fin, pass, nat)
+	ipf_main_softc_t *softc;
+	fr_info_t *fin;
+	u_32_t pass;
+	nat_t *nat;
 {
+	ipf_frag_softc_t *softf = softc->ipf_frag_soft;
 	ipfr_t	*fra;
 
-	if ((fin->fin_v != 4) || (fr_frag_lock != 0))
+	if (softf->ipfr_lock != 0)
 		return 0;
 
-	WRITE_ENTER(&ipf_natfrag);
-	fra = ipfr_newfrag(fin, pass, ipfr_nattab);
+#ifdef USE_MUTEXES
+	fra = ipfr_frag_new(softc, softf, fin, pass, softf->ipfr_nattab,
+			    &softf->ipfr_natfrag);
+#else
+	fra = ipfr_frag_new(softc, softf, fin, pass, softf->ipfr_nattab);
+#endif
 	if (fra != NULL) {
 		fra->ipfr_data = nat;
 		nat->nat_data = fra;
-		*ipfr_nattail = fra;
-		fra->ipfr_prev = ipfr_nattail;
-		ipfr_nattail = &fra->ipfr_next;
+		*softf->ipfr_nattail = fra;
+		fra->ipfr_prev = softf->ipfr_nattail;
+		softf->ipfr_nattail = &fra->ipfr_next;
 		fra->ipfr_next = NULL;
+		RWLOCK_EXIT(&softf->ipfr_natfrag);
+		return 0;
 	}
-	RWLOCK_EXIT(&ipf_natfrag);
-	return fra ? 0 : -1;
+	return -1;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_ipid_newfrag                                             */
+/* Function:    ipf_frag_ipidnew                                            */
 /* Returns:     int - 0 == success, -1 == error                             */
 /* Parameters:  fin(I)  - pointer to packet information                     */
 /*              ipid(I) - new IP ID for this fragmented packet              */
@@ -391,31 +606,37 @@
 /* Create a new fragment cache entry for this packet and store, as a data   */
 /* pointer, the new IP ID value.                                            */
 /* ------------------------------------------------------------------------ */
-int fr_ipid_newfrag(fin, ipid)
-fr_info_t *fin;
-u_32_t ipid;
+int
+ipf_frag_ipidnew(fin, ipid)
+	fr_info_t *fin;
+	u_32_t ipid;
 {
+	ipf_main_softc_t *softc = fin->fin_main_soft;
+	ipf_frag_softc_t *softf = softc->ipf_frag_soft;
 	ipfr_t	*fra;
 
-	if ((fin->fin_v != 4) || (fr_frag_lock))
+	if (softf->ipfr_lock)
 		return 0;
 
-	WRITE_ENTER(&ipf_ipidfrag);
-	fra = ipfr_newfrag(fin, 0, ipfr_ipidtab);
+#ifdef USE_MUTEXES
+	fra = ipfr_frag_new(softc, softf, fin, 0, softf->ipfr_ipidtab, &softf->ipfr_ipidfrag);
+#else
+	fra = ipfr_frag_new(softc, softf, fin, 0, softf->ipfr_ipidtab);
+#endif
 	if (fra != NULL) {
-		fra->ipfr_data = (void *)(uintptr_t)ipid;
-		*ipfr_ipidtail = fra;
-		fra->ipfr_prev = ipfr_ipidtail;
-		ipfr_ipidtail = &fra->ipfr_next;
+		fra->ipfr_data = (void *)(intptr_t)ipid;
+		*softf->ipfr_ipidtail = fra;
+		fra->ipfr_prev = softf->ipfr_ipidtail;
+		softf->ipfr_ipidtail = &fra->ipfr_next;
 		fra->ipfr_next = NULL;
+		RWLOCK_EXIT(&softf->ipfr_ipidfrag);
 	}
-	RWLOCK_EXIT(&ipf_ipidfrag);
 	return fra ? 0 : -1;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_fraglookup                                               */
+/* Function:    ipf_frag_lookup                                             */
 /* Returns:     ipfr_t * - pointer to ipfr_t structure if there's a         */
 /*                         matching entry in the frag table, else NULL      */
 /* Parameters:  fin(I)   - pointer to packet information                    */
@@ -423,18 +644,45 @@
 /*                                                                          */
 /* Check the fragment cache to see if there is already a record of this     */
 /* packet with its filter result known.                                     */
+/*                                                                          */
+/* If this function succeeds, it returns with a write lock held on "lock".  */
+/* If it fails, no lock is held on return.                                  */
 /* ------------------------------------------------------------------------ */
-static ipfr_t *fr_fraglookup(fin, table)
-fr_info_t *fin;
-ipfr_t *table[];
+static ipfr_t *
+ipf_frag_lookup(softc, softf, fin, table
+#ifdef USE_MUTEXES
+, lock
+#endif
+)
+	ipf_main_softc_t *softc;
+	ipf_frag_softc_t *softf;
+	fr_info_t *fin;
+	ipfr_t *table[];
+#ifdef USE_MUTEXES
+	ipfrwlock_t *lock;
+#endif
 {
 	ipfr_t *f, frag;
 	u_int idx;
-	ip_t *ip;
 
-	if ((fin->fin_flx & (FI_FRAG|FI_BAD)) != FI_FRAG)
+	/*
+	 * We don't want to let short packets match because they could be
+	 * compromising the security of other rules that want to match on
+	 * layer 4 fields (and can't because they have been fragmented off.)
+	 * Why do this check here?  The counter acts as an indicator of this
+	 * kind of attack, whereas if it was elsewhere, it wouldn't know if
+	 * other matching packets had been seen.
+	 */
+	if (fin->fin_flx & FI_SHORT) {
+		FBUMPD(ifs_short);
 		return NULL;
+	}
 
+	if ((fin->fin_flx & FI_BAD) != 0) {
+		FBUMPD(ifs_bad);
+		return NULL;
+	}
+
 	/*
 	 * For fragments, we record protocol, packet id, TOS and both IP#'s
 	 * (these should all be the same for all fragments of a packet).
@@ -441,63 +689,62 @@
 	 *
 	 * build up a hash value to index the table with.
 	 */
-	ip = fin->fin_ip;
-	frag.ipfr_p = ip->ip_p;
-	idx = ip->ip_p;
-	frag.ipfr_id = ip->ip_id;
-	idx += ip->ip_id;
-	frag.ipfr_tos = ip->ip_tos;
-	frag.ipfr_src.s_addr = ip->ip_src.s_addr;
-	idx += ip->ip_src.s_addr;
-	frag.ipfr_dst.s_addr = ip->ip_dst.s_addr;
-	idx += ip->ip_dst.s_addr;
+	frag.ipfr_v = fin->fin_v;
+	idx = fin->fin_v;
+	frag.ipfr_p = fin->fin_p;
+	idx += fin->fin_p;
+	frag.ipfr_id = fin->fin_id;
+	idx += fin->fin_id;
+	frag.ipfr_source = fin->fin_fi.fi_src;
+	idx += frag.ipfr_src.s_addr;
+	frag.ipfr_dest = fin->fin_fi.fi_dst;
+	idx += frag.ipfr_dst.s_addr;
 	frag.ipfr_ifp = fin->fin_ifp;
 	idx *= 127;
-	idx %= IPFT_SIZE;
+	idx %= softf->ipfr_size;
 
 	frag.ipfr_optmsk = fin->fin_fi.fi_optmsk & IPF_OPTCOPY;
 	frag.ipfr_secmsk = fin->fin_fi.fi_secmsk;
 	frag.ipfr_auth = fin->fin_fi.fi_auth;
 
+	READ_ENTER(lock);
+
 	/*
 	 * check the table, careful to only compare the right amount of data
 	 */
-	for (f = table[idx]; f; f = f->ipfr_hnext)
+	for (f = table[idx]; f; f = f->ipfr_hnext) {
 		if (!bcmp((char *)&frag.ipfr_ifp, (char *)&f->ipfr_ifp,
 			  IPFR_CMPSZ)) {
 			u_short	off;
 
 			/*
-			 * We don't want to let short packets match because
-			 * they could be compromising the security of other
-			 * rules that want to match on layer 4 fields (and
-			 * can't because they have been fragmented off.)
-			 * Why do this check here?  The counter acts as an
-			 * indicator of this kind of attack, whereas if it was
-			 * elsewhere, it wouldn't know if other matching
-			 * packets had been seen.
-			 */
-			if (fin->fin_flx & FI_SHORT) {
-				ATOMIC_INCL(ipfr_stats.ifs_short);
-				continue;
-			}
-
-			/*
 			 * XXX - We really need to be guarding against the
 			 * retransmission of (src,dst,id,offset-range) here
 			 * because a fragmented packet is never resent with
 			 * the same IP ID# (or shouldn't).
 			 */
-			off = ip->ip_off & IP_OFFMASK;
+			off = fin->fin_off >> 3;
 			if (f->ipfr_seen0) {
 				if (off == 0) {
-					ATOMIC_INCL(ipfr_stats.ifs_retrans0);
+					FBUMPD(ifs_retrans0);
 					continue;
 				}
+
+				/*
+				 * Case 3. See comment for frpr_fragment6.
+				 */
+				if ((f->ipfr_firstend != 0) &&
+				    (off < f->ipfr_firstend)) {
+					FBUMP(ifs_overlap);
+					DT2(ifs_overlap, u_short, off,
+					    ipfr_t *, f);
+					fin->fin_flx |= FI_BAD;
+					break;
+				}
 			} else if (off == 0)
 				f->ipfr_seen0 = 1;
 
-			if (f != table[idx]) {
+			if (f != table[idx] && MUTEX_TRY_UPGRADE(lock)) {
 				ipfr_t **fp;
 
 				/*
@@ -515,6 +762,7 @@
 				table[idx]->ipfr_hprev = &f->ipfr_hnext;
 				f->ipfr_hprev = table + idx;
 				table[idx] = f;
+				MUTEX_DOWNGRADE(lock);
 			}
 
 			/*
@@ -522,20 +770,48 @@
 			 * last (in order), shrink expiration time.
 			 */
 			if (off == f->ipfr_off) {
-				if (!(ip->ip_off & IP_MF))
-					f->ipfr_ttl = fr_ticks + 1;
 				f->ipfr_off = (fin->fin_dlen >> 3) + off;
-			} else if (f->ipfr_pass & FR_FRSTRICT)
-				continue;
-			ATOMIC_INCL(ipfr_stats.ifs_hits);
+
+				/*
+				 * Well, we could shrink the expiration time
+				 * but only if every fragment has been seen
+				 * in order upto this, the last. ipfr_badorder
+				 * is used here to count those out of order
+				 * and if it equals 0 when we get to the last
+				 * fragment then we can assume all of the
+				 * fragments have been seen and in order.
+				 */
+#if 0
+				/*
+				 * Doing this properly requires moving it to
+				 * the head of the list which is infesible.
+				 */
+				if ((more == 0) && (f->ipfr_badorder == 0))
+					f->ipfr_ttl = softc->ipf_ticks + 1;
+#endif
+			} else {
+				f->ipfr_badorder++;
+				FBUMPD(ifs_unordered);
+				if (f->ipfr_pass & FR_FRSTRICT) {
+					FBUMPD(ifs_strict);
+					continue;
+				}
+			}
+			f->ipfr_pkts++;
+			f->ipfr_bytes += fin->fin_plen;
+			FBUMP(ifs_hits);
 			return f;
 		}
+	}
+
+	RWLOCK_EXIT(lock);
+	FBUMP(ifs_miss);
 	return NULL;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_nat_knownfrag                                            */
+/* Function:    ipf_frag_natknown                                           */
 /* Returns:     nat_t* - pointer to 'parent' NAT structure if frag table    */
 /*                       match found, else NULL                             */
 /* Parameters:  fin(I)  - pointer to packet information                     */
@@ -542,34 +818,41 @@
 /*                                                                          */
 /* Functional interface for NAT lookups of the NAT fragment cache           */
 /* ------------------------------------------------------------------------ */
-nat_t *fr_nat_knownfrag(fin)
-fr_info_t *fin;
+nat_t *
+ipf_frag_natknown(fin)
+	fr_info_t *fin;
 {
+	ipf_main_softc_t *softc = fin->fin_main_soft;
+	ipf_frag_softc_t *softf = softc->ipf_frag_soft;
 	nat_t	*nat;
 	ipfr_t	*ipf;
 
-	if ((fin->fin_v != 4) || (fr_frag_lock) || !ipfr_natlist)
+	if ((softf->ipfr_lock) || !softf->ipfr_natlist)
 		return NULL;
-	READ_ENTER(&ipf_natfrag);
-	ipf = fr_fraglookup(fin, ipfr_nattab);
+#ifdef USE_MUTEXES
+	ipf = ipf_frag_lookup(softc, softf, fin, softf->ipfr_nattab,
+			      &softf->ipfr_natfrag);
+#else
+	ipf = ipf_frag_lookup(softc, softf, fin, softf->ipfr_nattab);
+#endif
 	if (ipf != NULL) {
 		nat = ipf->ipfr_data;
 		/*
 		 * This is the last fragment for this packet.
 		 */
-		if ((ipf->ipfr_ttl == fr_ticks + 1) && (nat != NULL)) {
+		if ((ipf->ipfr_ttl == softc->ipf_ticks + 1) && (nat != NULL)) {
 			nat->nat_data = NULL;
 			ipf->ipfr_data = NULL;
 		}
+		RWLOCK_EXIT(&softf->ipfr_natfrag);
 	} else
 		nat = NULL;
-	RWLOCK_EXIT(&ipf_natfrag);
 	return nat;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_ipid_knownfrag                                           */
+/* Function:    ipf_frag_ipidknown                                          */
 /* Returns:     u_32_t - IPv4 ID for this packet if match found, else       */
 /*                       return 0xfffffff to indicate no match.             */
 /* Parameters:  fin(I) - pointer to packet information                      */
@@ -576,28 +859,35 @@
 /*                                                                          */
 /* Functional interface for IP ID lookups of the IP ID fragment cache       */
 /* ------------------------------------------------------------------------ */
-u_32_t fr_ipid_knownfrag(fin)
-fr_info_t *fin;
+u_32_t
+ipf_frag_ipidknown(fin)
+	fr_info_t *fin;
 {
+	ipf_main_softc_t *softc = fin->fin_main_soft;
+	ipf_frag_softc_t *softf = softc->ipf_frag_soft;
 	ipfr_t	*ipf;
 	u_32_t	id;
 
-	if ((fin->fin_v != 4) || (fr_frag_lock) || !ipfr_ipidlist)
+	if (softf->ipfr_lock || !softf->ipfr_ipidlist)
 		return 0xffffffff;
 
-	READ_ENTER(&ipf_ipidfrag);
-	ipf = fr_fraglookup(fin, ipfr_ipidtab);
-	if (ipf != NULL)
-		id = (u_32_t)(uintptr_t)ipf->ipfr_data;
-	else
+#ifdef USE_MUTEXES
+	ipf = ipf_frag_lookup(softc, softf, fin, softf->ipfr_ipidtab,
+			      &softf->ipfr_ipidfrag);
+#else
+	ipf = ipf_frag_lookup(softc, softf, fin, softf->ipfr_ipidtab);
+#endif
+	if (ipf != NULL) {
+		id = (u_32_t)(intptr_t)ipf->ipfr_data;
+		RWLOCK_EXIT(&softf->ipfr_ipidfrag);
+	} else
 		id = 0xffffffff;
-	RWLOCK_EXIT(&ipf_ipidfrag);
 	return id;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_knownfrag                                                */
+/* Function:    ipf_frag_known                                              */
 /* Returns:     frentry_t* - pointer to filter rule if a match is found in  */
 /*                           the frag cache table, else NULL.               */
 /* Parameters:  fin(I)   - pointer to packet information                    */
@@ -607,80 +897,86 @@
 /* match is found, return the rule pointer and flags from the rule, except  */
 /* that if FR_LOGFIRST is set, reset FR_LOG.                                */
 /* ------------------------------------------------------------------------ */
-frentry_t *fr_knownfrag(fin, passp)
-fr_info_t *fin;
-u_32_t *passp;
+frentry_t *
+ipf_frag_known(fin, passp)
+	fr_info_t *fin;
+	u_32_t *passp;
 {
+	ipf_main_softc_t *softc = fin->fin_main_soft;
+	ipf_frag_softc_t *softf = softc->ipf_frag_soft;
 	frentry_t *fr = NULL;
 	ipfr_t	*fra;
 	u_32_t pass;
 
-	if ((fin->fin_v != 4) || (fr_frag_lock) || (ipfr_list == NULL))
+	if ((softf->ipfr_lock) || (softf->ipfr_list == NULL))
 		return NULL;
 
-	READ_ENTER(&ipf_frag);
-	fra = fr_fraglookup(fin, ipfr_heads);
+#ifdef USE_MUTEXES
+	fra = ipf_frag_lookup(softc, softf, fin, softf->ipfr_heads,
+			      &softc->ipf_frag);
+#else
+	fra = ipf_frag_lookup(softc, softf, fin, softf->ipfr_heads);
+#endif
 	if (fra != NULL) {
-		fr = fra->ipfr_rule;
+		if (fin->fin_flx & FI_BAD) {
+			fr = &ipfr_block;
+			fin->fin_reason = FRB_BADFRAG;
+		} else {
+			fr = fra->ipfr_rule;
+		}
 		fin->fin_fr = fr;
 		if (fr != NULL) {
 			pass = fr->fr_flags;
+			if ((pass & FR_KEEPSTATE) != 0) {
+				fin->fin_flx |= FI_STATE;
+				/*
+				 * Reset the keep state flag here so that we
+				 * don't try and add a new state entry because
+				 * of a match here. That leads to blocking of
+				 * the packet later because the add fails.
+				 */
+				pass &= ~FR_KEEPSTATE;
+			}
 			if ((pass & FR_LOGFIRST) != 0)
 				pass &= ~(FR_LOGFIRST|FR_LOG);
 			*passp = pass;
 		}
+		RWLOCK_EXIT(&softc->ipf_frag);
 	}
-	RWLOCK_EXIT(&ipf_frag);
 	return fr;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_forget                                                   */
+/* Function:    ipf_frag_natforget                                          */
 /* Returns:     Nil                                                         */
-/* Parameters:  ptr(I) - pointer to data structure                          */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              ptr(I) - pointer to data structure                          */
 /*                                                                          */
-/* Search through all of the fragment cache entries and wherever a pointer  */
-/* is found to match ptr, reset it to NULL.                                 */
-/* ------------------------------------------------------------------------ */
-void fr_forget(ptr)
-void *ptr;
-{
-	ipfr_t	*fr;
-
-	WRITE_ENTER(&ipf_frag);
-	for (fr = ipfr_list; fr; fr = fr->ipfr_next)
-		if (fr->ipfr_data == ptr)
-			fr->ipfr_data = NULL;
-	RWLOCK_EXIT(&ipf_frag);
-}
-
-
-/* ------------------------------------------------------------------------ */
-/* Function:    fr_forgetnat                                                */
-/* Returns:     Nil                                                         */
-/* Parameters:  ptr(I) - pointer to data structure                          */
-/*                                                                          */
 /* Search through all of the fragment cache entries for NAT and wherever a  */
 /* pointer  is found to match ptr, reset it to NULL.                        */
 /* ------------------------------------------------------------------------ */
-void fr_forgetnat(ptr)
-void *ptr;
+void
+ipf_frag_natforget(softc, ptr)
+	ipf_main_softc_t *softc;
+	void *ptr;
 {
+	ipf_frag_softc_t *softf = softc->ipf_frag_soft;
 	ipfr_t	*fr;
 
-	WRITE_ENTER(&ipf_natfrag);
-	for (fr = ipfr_natlist; fr; fr = fr->ipfr_next)
+	WRITE_ENTER(&softf->ipfr_natfrag);
+	for (fr = softf->ipfr_natlist; fr; fr = fr->ipfr_next)
 		if (fr->ipfr_data == ptr)
 			fr->ipfr_data = NULL;
-	RWLOCK_EXIT(&ipf_natfrag);
+	RWLOCK_EXIT(&softf->ipfr_natfrag);
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_fragdelete                                               */
+/* Function:    ipf_frag_delete                                             */
 /* Returns:     Nil                                                         */
-/* Parameters:  fra(I)   - pointer to fragment structure to delete          */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              fra(I)   - pointer to fragment structure to delete          */
 /*              tail(IO) - pointer to the pointer to the tail of the frag   */
 /*                         list                                             */
 /*                                                                          */
@@ -688,9 +984,12 @@
 /* the filter rule it is associated with it if it is no longer used as a    */
 /* result of decreasing the reference count.                                */
 /* ------------------------------------------------------------------------ */
-static void fr_fragdelete(fra, tail)
-ipfr_t *fra, ***tail;
+static void
+ipf_frag_delete(softc, fra, tail)
+	ipf_main_softc_t *softc;
+	ipfr_t *fra, ***tail;
 {
+	ipf_frag_softc_t *softf = softc->ipf_frag_soft;
 
 	if (fra->ipfr_next)
 		fra->ipfr_next->ipfr_prev = fra->ipfr_prev;
@@ -703,55 +1002,60 @@
 	*fra->ipfr_hprev = fra->ipfr_hnext;
 
 	if (fra->ipfr_rule != NULL) {
-		(void) fr_derefrule(&fra->ipfr_rule);
+		(void) ipf_derefrule(softc, &fra->ipfr_rule);
 	}
 
 	if (fra->ipfr_ref <= 0)
-		fr_fragfree(fra);
+		ipf_frag_free(softf, fra);
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_fragfree                                                 */
+/* Function:    ipf_frag_free                                               */
 /* Returns:     Nil                                                         */
-/* Parameters:  fra - pointer to frag structure to free                     */
+/* Parameters:  softf(I) - pointer to fragment context information          */
+/*              fra(I)   - pointer to fragment 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  */
+/* Free up a fragment cache entry and bump relevent statistics.             */
 /* ------------------------------------------------------------------------ */
-static void fr_fragfree(fra)
-ipfr_t *fra;
+static void
+ipf_frag_free(softf, fra)
+	ipf_frag_softc_t *softf;
+	ipfr_t *fra;
 {
 	KFREE(fra);
-	ipfr_stats.ifs_expire++;
-	ipfr_inuse--;
+	FBUMP(ifs_expire);
+	softf->ipfr_stats.ifs_inuse--;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_fragclear                                                */
+/* Function:    ipf_frag_clear                                              */
 /* Returns:     Nil                                                         */
-/* Parameters:  Nil                                                         */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
 /*                                                                          */
 /* Free memory in use by fragment state information kept.  Do the normal    */
 /* fragment state stuff first and then the NAT-fragment table.              */
 /* ------------------------------------------------------------------------ */
-void fr_fragclear()
+void
+ipf_frag_clear(softc)
+	ipf_main_softc_t *softc;
 {
+	ipf_frag_softc_t *softf = softc->ipf_frag_soft;
 	ipfr_t	*fra;
 	nat_t	*nat;
 
-	WRITE_ENTER(&ipf_frag);
-	while ((fra = ipfr_list) != NULL) {
+	WRITE_ENTER(&softc->ipf_frag);
+	while ((fra = softf->ipfr_list) != NULL) {
 		fra->ipfr_ref--;
-		fr_fragdelete(fra, &ipfr_tail);
+		ipf_frag_delete(softc, fra, &softf->ipfr_tail);
 	}
-	ipfr_tail = &ipfr_list;
-	RWLOCK_EXIT(&ipf_frag);
+	softf->ipfr_tail = &softf->ipfr_list;
+	RWLOCK_EXIT(&softc->ipf_frag);
 
-	WRITE_ENTER(&ipf_nat);
-	WRITE_ENTER(&ipf_natfrag);
-	while ((fra = ipfr_natlist) != NULL) {
+	WRITE_ENTER(&softc->ipf_nat);
+	WRITE_ENTER(&softf->ipfr_natfrag);
+	while ((fra = softf->ipfr_natlist) != NULL) {
 		nat = fra->ipfr_data;
 		if (nat != NULL) {
 			if (nat->nat_data == fra)
@@ -758,52 +1062,55 @@
 				nat->nat_data = NULL;
 		}
 		fra->ipfr_ref--;
-		fr_fragdelete(fra, &ipfr_nattail);
+		ipf_frag_delete(softc, fra, &softf->ipfr_nattail);
 	}
-	ipfr_nattail = &ipfr_natlist;
-	RWLOCK_EXIT(&ipf_natfrag);
-	RWLOCK_EXIT(&ipf_nat);
+	softf->ipfr_nattail = &softf->ipfr_natlist;
+	RWLOCK_EXIT(&softf->ipfr_natfrag);
+	RWLOCK_EXIT(&softc->ipf_nat);
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_fragexpire                                               */
+/* Function:    ipf_frag_expire                                             */
 /* Returns:     Nil                                                         */
-/* Parameters:  Nil                                                         */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
 /*                                                                          */
 /* Expire entries in the fragment cache table that have been there too long */
 /* ------------------------------------------------------------------------ */
-void fr_fragexpire()
+void
+ipf_frag_expire(softc)
+	ipf_main_softc_t *softc;
 {
+	ipf_frag_softc_t *softf = softc->ipf_frag_soft;
 	ipfr_t	**fp, *fra;
 	nat_t	*nat;
 	SPL_INT(s);
 
-	if (fr_frag_lock)
+	if (softf->ipfr_lock)
 		return;
 
 	SPL_NET(s);
-	WRITE_ENTER(&ipf_frag);
+	WRITE_ENTER(&softc->ipf_frag);
 	/*
 	 * Go through the entire table, looking for entries to expire,
-	 * which is indicated by the ttl being less than or equal to fr_ticks.
+	 * which is indicated by the ttl being less than or equal to ipf_ticks.
 	 */
-	for (fp = &ipfr_list; ((fra = *fp) != NULL); ) {
-		if (fra->ipfr_ttl > fr_ticks)
+	for (fp = &softf->ipfr_list; ((fra = *fp) != NULL); ) {
+		if (fra->ipfr_ttl > softc->ipf_ticks)
 			break;
 		fra->ipfr_ref--;
-		fr_fragdelete(fra, &ipfr_tail);
+		ipf_frag_delete(softc, fra, &softf->ipfr_tail);
 	}
-	RWLOCK_EXIT(&ipf_frag);
+	RWLOCK_EXIT(&softc->ipf_frag);
 
-	WRITE_ENTER(&ipf_ipidfrag);
-	for (fp = &ipfr_ipidlist; ((fra = *fp) != NULL); ) {
-		if (fra->ipfr_ttl > fr_ticks)
+	WRITE_ENTER(&softf->ipfr_ipidfrag);
+	for (fp = &softf->ipfr_ipidlist; ((fra = *fp) != NULL); ) {
+		if (fra->ipfr_ttl > softc->ipf_ticks)
 			break;
 		fra->ipfr_ref--;
-		fr_fragdelete(fra, &ipfr_ipidtail);
+		ipf_frag_delete(softc, fra, &softf->ipfr_ipidtail);
 	}
-	RWLOCK_EXIT(&ipf_ipidfrag);
+	RWLOCK_EXIT(&softf->ipfr_ipidfrag);
 
 	/*
 	 * Same again for the NAT table, except that if the structure also
@@ -815,11 +1122,11 @@
 	 * operations - no need to do that if there are no entries in this
 	 * list, right?
 	 */
-	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)
+	if (softf->ipfr_natlist != NULL) {
+		WRITE_ENTER(&softc->ipf_nat);
+		WRITE_ENTER(&softf->ipfr_natfrag);
+		for (fp = &softf->ipfr_natlist; ((fra = *fp) != NULL); ) {
+			if (fra->ipfr_ttl > softc->ipf_ticks)
 				break;
 			nat = fra->ipfr_data;
 			if (nat != NULL) {
@@ -827,10 +1134,10 @@
 					nat->nat_data = NULL;
 			}
 			fra->ipfr_ref--;
-			fr_fragdelete(fra, &ipfr_nattail);
+			ipf_frag_delete(softc, fra, &softf->ipfr_nattail);
 		}
-		RWLOCK_EXIT(&ipf_natfrag);
-		RWLOCK_EXIT(&ipf_nat);
+		RWLOCK_EXIT(&softf->ipfr_natfrag);
+		RWLOCK_EXIT(&softc->ipf_nat);
 	}
 	SPL_X(s);
 }
@@ -837,66 +1144,65 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_slowtimer                                                */
-/* Returns:     Nil                                                         */
-/* Parameters:  Nil                                                         */
+/* Function:    ipf_frag_pkt_next                                           */
+/* Returns:     int      - 0 == success, else error                         */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              token(I) - pointer to token information for this caller     */
+/*              itp(I)   - pointer to generic iterator from caller          */
 /*                                                                          */
-/* Slowly expire held state for fragments.  Timeouts are set * in           */
-/* expectation of this being called twice per second.                       */
+/* This function is used to step through the fragment cache list used for   */
+/* filter rules. The hard work is done by the more generic ipf_frag_next.   */
 /* ------------------------------------------------------------------------ */
-#if !defined(_KERNEL) || (!SOLARIS && !defined(__hpux) && !defined(__sgi) && \
-			  !defined(__osf__) && !defined(linux))
-# if defined(_KERNEL) && ((BSD >= 199103) || defined(__sgi))
-void fr_slowtimer __P((void *ptr))
-# else
-int fr_slowtimer()
-# endif
+int
+ipf_frag_pkt_next(softc, token, itp)
+	ipf_main_softc_t *softc;
+	ipftoken_t *token;
+	ipfgeniter_t *itp;
 {
-	READ_ENTER(&ipf_global);
+	ipf_frag_softc_t *softf = softc->ipf_frag_soft;
 
-	ipf_expiretokens();
-	fr_fragexpire();
-	fr_timeoutstate();
-	fr_natexpire();
-	fr_authexpire();
-	fr_ticks++;
-	if (fr_running <= 0)
-		goto done;
-# ifdef _KERNEL
-#  if defined(__NetBSD__) && (__NetBSD_Version__ >= 104240000)
-	callout_reset(&fr_slowtimer_ch, hz / 2, fr_slowtimer, NULL);
-#  else
-#   if defined(__OpenBSD__)
-	timeout_add(&fr_slowtimer_ch, hz/2);
-#   else
-#    if (__FreeBSD_version >= 300000)
-	fr_slowtimer_ch = timeout(fr_slowtimer, NULL, hz/2);
-#    else
-#     ifdef linux
-	;
-#     else
-	timeout(fr_slowtimer, NULL, hz/2);
-#     endif
-#    endif /* FreeBSD */
-#   endif /* OpenBSD */
-#  endif /* NetBSD */
-# endif
-done:
-	RWLOCK_EXIT(&ipf_global);
-# if (BSD < 199103) || !defined(_KERNEL)
-	return 0;
-# endif
+#ifdef USE_MUTEXES
+	return ipf_frag_next(softc, token, itp, &softf->ipfr_list,
+			     &softf->ipfr_frag);
+#else
+	return ipf_frag_next(softc, token, itp, &softf->ipfr_list);
+#endif
 }
-#endif /* !SOLARIS && !defined(__hpux) && !defined(__sgi) */
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_nextfrag                                                 */
+/* Function:    ipf_frag_nat_next                                           */
 /* Returns:     int      - 0 == success, else error                         */
-/* Parameters:  token(I) - pointer to token information for this caller     */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              token(I) - pointer to token information for this caller     */
 /*              itp(I)   - pointer to generic iterator from caller          */
+/*                                                                          */
+/* This function is used to step through the fragment cache list used for   */
+/* NAT. The hard work is done by the more generic ipf_frag_next.            */
+/* ------------------------------------------------------------------------ */
+int
+ipf_frag_nat_next(softc, token, itp)
+	ipf_main_softc_t *softc;
+	ipftoken_t *token;
+	ipfgeniter_t *itp;
+{
+	ipf_frag_softc_t *softf = softc->ipf_frag_soft;;
+
+#ifdef USE_MUTEXES
+	return ipf_frag_next(softc, token, itp, &softf->ipfr_natlist, 
+			     &softf->ipfr_natfrag);
+#else
+	return ipf_frag_next(softc, token, itp, &softf->ipfr_natlist);
+#endif
+}
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_frag_next                                               */
+/* Returns:     int      - 0 == success, else error                         */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              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     */
@@ -904,30 +1210,39 @@
 /* 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.     */
+/* fragment cache - hence the reason for passing in top and lock.           */
 /* ------------------------------------------------------------------------ */
-int fr_nextfrag(token, itp, top, tail
+static int
+ipf_frag_next(softc, token, itp, top
 #ifdef USE_MUTEXES
 , lock
 #endif
 )
-ipftoken_t *token;
-ipfgeniter_t *itp;
-ipfr_t **top, ***tail;
+	ipf_main_softc_t *softc;
+	ipftoken_t *token;
+	ipfgeniter_t *itp;
+	ipfr_t **top;
 #ifdef USE_MUTEXES
-ipfrwlock_t *lock;
+	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;
+	if (itp->igi_data == NULL) {
+		IPFERROR(20001);
+		return EFAULT;
 	}
 
+	if (itp->igi_nitems != 1) {
+		IPFERROR(20003);
+		return EFAULT;
+	}
+
+	frag = token->ipt_data;
+
 	READ_ENTER(lock);
+
 	if (frag == NULL)
 		next = *top;
 	else
@@ -941,27 +1256,81 @@
 		next = &zero;
 		token->ipt_data = NULL;
 	}
+	if (next->ipfr_next == NULL)
+		ipf_token_mark_complete(token);
+
 	RWLOCK_EXIT(lock);
 
-	if (frag != NULL) {
+	error = COPYOUT(next, itp->igi_data, sizeof(*next));
+	if (error != 0)
+		IPFERROR(20002);
+
+        if (frag != NULL) {
 #ifdef USE_MUTEXES
-		fr_fragderef(&frag, lock);
+		ipf_frag_deref(softc, &frag, lock);
 #else
-		fr_fragderef(&frag);
+		ipf_frag_deref(softc, &frag);
 #endif
-	}
+        }
+        return error;
+}
 
-	error = COPYOUT(next, itp->igi_data, sizeof(*next));
-	if (error != 0)
-		error = EFAULT;
 
-	return error;
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_frag_pkt_deref                                          */
+/* Returns:     Nil                                                         */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              data(I)  - pointer to frag cache pointer                    */
+/*                                                                          */
+/* This function is the external interface for dropping a reference to a    */
+/* fragment cache entry used by filter rules.                               */
+/* ------------------------------------------------------------------------ */
+void
+ipf_frag_pkt_deref(softc, data)
+	ipf_main_softc_t *softc;
+	void *data;
+{
+	ipfr_t **frp = data;
+
+#ifdef USE_MUTEXES
+	ipf_frag_softc_t *softf = softc->ipf_frag_soft;
+
+	ipf_frag_deref(softc->ipf_frag_soft, frp, &softf->ipfr_frag);
+#else
+	ipf_frag_deref(softc->ipf_frag_soft, frp);
+#endif
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_fragderef                                                */
+/* Function:    ipf_frag_nat_deref                                          */
 /* Returns:     Nil                                                         */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              data(I)  - pointer to frag cache pointer                    */
+/*                                                                          */
+/* This function is the external interface for dropping a reference to a    */
+/* fragment cache entry used by NAT table entries.                          */
+/* ------------------------------------------------------------------------ */
+void
+ipf_frag_nat_deref(softc, data)
+	ipf_main_softc_t *softc;
+	void *data;
+{
+	ipfr_t **frp = data;
+
+#ifdef USE_MUTEXES
+	ipf_frag_softc_t *softf = softc->ipf_frag_soft;
+
+	ipf_frag_deref(softc->ipf_frag_soft, frp, &softf->ipfr_natfrag);
+#else
+	ipf_frag_deref(softc->ipf_frag_soft, frp);
+#endif
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_frag_deref                                              */
+/* Returns:     Nil                                                         */
 /* Parameters:  frp(IO) - pointer to fragment structure to deference        */
 /*              lock(I) - lock associated with the fragment                 */
 /*                                                                          */
@@ -970,16 +1339,19 @@
 /* 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
+static void
+ipf_frag_deref(arg, frp
 #ifdef USE_MUTEXES
 , lock
 #endif
 )
-ipfr_t **frp;
+	void *arg;
+	ipfr_t **frp;
 #ifdef USE_MUTEXES
-ipfrwlock_t *lock;
+	ipfrwlock_t *lock;
 #endif
 {
+	ipf_frag_softc_t *softf = arg;
 	ipfr_t *fra;
 
 	fra = *frp;
@@ -988,6 +1360,6 @@
 	WRITE_ENTER(lock);
 	fra->ipfr_ref--;
 	if (fra->ipfr_ref <= 0)
-		fr_fragfree(fra);
+		ipf_frag_free(softf, fra);
 	RWLOCK_EXIT(lock);
 }

Modified: trunk/sys/contrib/ipfilter/netinet/ip_frag.h
===================================================================
--- trunk/sys/contrib/ipfilter/netinet/ip_frag.h	2018-05-28 18:55:30 UTC (rev 10138)
+++ trunk/sys/contrib/ipfilter/netinet/ip_frag.h	2018-05-28 18:56:30 UTC (rev 10139)
@@ -1,12 +1,13 @@
-/*	$FreeBSD$	*/
+/* $MidnightBSD$ */
+/*	$FreeBSD: stable/10/sys/contrib/ipfilter/netinet/ip_frag.h 302015 2016-06-19 00:39:23Z cy $	*/
 
 /*
- * Copyright (C) 1993-2001 by Darren Reed.
+ * Copyright (C) 2012 by Darren Reed.
  *
  * See the IPFILTER.LICENCE file for details on licencing.
  *
  * @(#)ip_frag.h	1.5 3/24/96
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/contrib/ipfilter/netinet/ip_frag.h 302015 2016-06-19 00:39:23Z cy $
  * Id: ip_frag.h,v 2.23.2.1 2004/03/29 16:21:56 darrenr Exp
  */
 
@@ -21,9 +22,14 @@
 	void	*ipfr_data;
 	frentry_t *ipfr_rule;
 	u_long	ipfr_ttl;
+	u_int	ipfr_pkts;
+	u_int	ipfr_bytes;
+	u_int	ipfr_badorder;
 	int	ipfr_ref;
 	u_short	ipfr_off;
-	u_short	ipfr_seen0;
+	u_short	ipfr_firstend;
+	u_char	ipfr_p;
+	u_char	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
@@ -30,18 +36,20 @@
 	 * therefore important for this set to remain together.
 	 */
 	void	*ipfr_ifp;
-	struct	in_addr	ipfr_src;
-	struct	in_addr	ipfr_dst;
+	i6addr_t	ipfr_source;
+	i6addr_t	ipfr_dest;
 	u_32_t	ipfr_optmsk;
 	u_short	ipfr_secmsk;
 	u_short	ipfr_auth;
-	u_short	ipfr_id;
-	u_char	ipfr_p;
-	u_char	ipfr_tos;
+	u_32_t	ipfr_id;
 	u_32_t	ipfr_pass;
+	int	ipfr_v;
 } ipfr_t;
 
+#define	ipfr_src	ipfr_source.in4
+#define	ipfr_dst	ipfr_dest.in4
 
+
 typedef	struct	ipfrstat {
 	u_long	ifs_exists;	/* add & already exists */
 	u_long	ifs_nomem;
@@ -51,58 +59,68 @@
 	u_long	ifs_inuse;
 	u_long	ifs_retrans0;
 	u_long	ifs_short;
+	u_long	ifs_bad;
+	u_long	ifs_overlap;
+	u_long	ifs_unordered;
+	u_long	ifs_strict;
+	u_long	ifs_miss;
+	u_long	ifs_maximum;
+	u_long	ifs_newbad;
+	u_long	ifs_newrestrictnot0;
 	struct	ipfr	**ifs_table;
 	struct	ipfr	**ifs_nattab;
 } ipfrstat_t;
 
+typedef struct ipf_frag_softc_s  {
+	ipfrwlock_t	ipfr_ipidfrag;
+	ipfrwlock_t	ipfr_frag;
+	ipfrwlock_t	ipfr_natfrag;
+	int		ipfr_size;
+	int		ipfr_ttl;
+	int		ipfr_lock;
+	int		ipfr_inited;
+	ipftuneable_t	*ipf_frag_tune;
+	ipfr_t		*ipfr_list;
+	ipfr_t		**ipfr_tail;
+	ipfr_t		*ipfr_natlist;
+	ipfr_t		**ipfr_nattail;
+	ipfr_t		*ipfr_ipidlist;
+	ipfr_t		**ipfr_ipidtail;
+	ipfr_t		**ipfr_heads;
+	ipfr_t		**ipfr_nattab;
+	ipfr_t		**ipfr_ipidtab;
+	ipfrstat_t	ipfr_stats;
+} ipf_frag_softc_t;
+
 #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;
-extern	int	fr_fraginit __P((void));
-extern	void	fr_fragunload __P((void));
-extern	ipfrstat_t	*fr_fragstats __P((void));
+extern	void	*ipf_frag_soft_create __P((ipf_main_softc_t *));
+extern	int	ipf_frag_soft_init __P((ipf_main_softc_t *, void *));
+extern	int	ipf_frag_soft_fini __P((ipf_main_softc_t *, void *));
+extern	void	ipf_frag_soft_destroy __P((ipf_main_softc_t *, void *));
+extern	int	ipf_frag_main_load __P((void));
+extern	int	ipf_frag_main_unload __P((void));
+extern	int	ipf_frag_load __P((void));
+extern	void	ipf_frag_clear __P((ipf_main_softc_t *));
+extern	void	ipf_frag_expire __P((ipf_main_softc_t *));
+extern	void	ipf_frag_forget __P((void *));
+extern	int	ipf_frag_init __P((void));
+extern	u_32_t	ipf_frag_ipidknown __P((fr_info_t *));
+extern	int	ipf_frag_ipidnew __P((fr_info_t *, u_32_t));
+extern	frentry_t *ipf_frag_known __P((fr_info_t *, u_32_t *));
+extern	void	ipf_frag_natforget __P((ipf_main_softc_t *, void *));
+extern	int	ipf_frag_natnew __P((ipf_main_softc_t *, fr_info_t *, u_32_t, struct nat *));
+extern	nat_t	*ipf_frag_natknown __P((fr_info_t *));
+extern	int	ipf_frag_new __P((ipf_main_softc_t *, fr_info_t *, u_32_t));
+extern	ipfrstat_t	*ipf_frag_stats __P((void *));
+extern	void	ipf_frag_setlock __P((void *, int));
+extern	void	ipf_frag_pkt_deref __P((ipf_main_softc_t *, void *));
+extern	int	ipf_frag_pkt_next __P((ipf_main_softc_t *, ipftoken_t *,
+				       ipfgeniter_t *));
+extern	void	ipf_frag_nat_deref __P((ipf_main_softc_t *, void *));
+extern	int	ipf_frag_nat_next __P((ipf_main_softc_t *, ipftoken_t *,
+				       ipfgeniter_t *));
+extern	void	ipf_slowtimer __P((ipf_main_softc_t *));
 
-extern	int	fr_newfrag __P((fr_info_t *, u_32_t));
-extern	frentry_t *fr_knownfrag __P((fr_info_t *, u_32_t *));
-
-extern	int	fr_nat_newfrag __P((fr_info_t *, u_32_t, struct nat *));
-extern	nat_t	*fr_nat_knownfrag __P((fr_info_t *));
-
-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 *));
-extern	void	fr_fragclear __P((void));
-extern	void	fr_fragexpire __P((void));
-
-#if     defined(_KERNEL) && ((BSD >= 199306) || SOLARIS || defined(__sgi) \
-	        || defined(__osf__) || (defined(__sgi) && (IRIX >= 60500)))
-# if defined(SOLARIS2) && (SOLARIS2 < 7)
-extern	void	fr_slowtimer __P((void));
-# else
-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__ */

Modified: trunk/sys/contrib/ipfilter/netinet/ip_ftp_pxy.c
===================================================================
--- trunk/sys/contrib/ipfilter/netinet/ip_ftp_pxy.c	2018-05-28 18:55:30 UTC (rev 10138)
+++ trunk/sys/contrib/ipfilter/netinet/ip_ftp_pxy.c	2018-05-28 18:56:30 UTC (rev 10139)
@@ -1,7 +1,8 @@
-/*	$FreeBSD$	*/
+/* $MidnightBSD$ */
+/*	$FreeBSD: stable/10/sys/contrib/ipfilter/netinet/ip_ftp_pxy.c 328203 2018-01-20 18:00:42Z cy $	*/
 
 /*
- * Copyright (C) 1997-2003 by Darren Reed
+ * Copyright (C) 2012 by Darren Reed.
  *
  * See the IPFILTER.LICENCE file for details on licencing.
  *
@@ -8,7 +9,7 @@
  * Simple FTP transparent proxy for in-kernel use.  For use with the NAT
  * code.
  *
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/contrib/ipfilter/netinet/ip_ftp_pxy.c 328203 2018-01-20 18:00:42Z cy $
  * Id: ip_ftp_pxy.c,v 2.88.2.19 2006/04/01 10:14:53 darrenr Exp $
  */
 
@@ -15,6 +16,7 @@
 #define	IPF_FTP_PROXY
 
 #define	IPF_MINPORTLEN	18
+#define	IPF_MINEPRTLEN	20
 #define	IPF_MAXPORTLEN	30
 #define	IPF_MIN227LEN	39
 #define	IPF_MAX227LEN	51
@@ -38,94 +40,198 @@
 #define	FTPXY_PASS_2	14
 #define	FTPXY_PAOK_2	15
 
+#define	FTPXY_JUNK_OK	0
+#define	FTPXY_JUNK_BAD	1	/* Ignore all commands for this connection */
+#define	FTPXY_JUNK_EOL	2	/* consume the rest of this line only */
+#define	FTPXY_JUNK_CONT	3	/* Saerching for next numeric */
+
 /*
  * Values for FTP commands.  Numerics cover 0-999
  */
 #define	FTPXY_C_PASV	1000
+#define	FTPXY_C_PORT	1001
+#define	FTPXY_C_EPSV	1002
+#define	FTPXY_C_EPRT	1003
 
-int ippr_ftp_client __P((fr_info_t *, ip_t *, nat_t *, ftpinfo_t *, int));
-int ippr_ftp_complete __P((char *, size_t));
-int ippr_ftp_in __P((fr_info_t *, ap_session_t *, nat_t *));
-int ippr_ftp_init __P((void));
-void ippr_ftp_fini __P((void));
-int ippr_ftp_new __P((fr_info_t *, ap_session_t *, nat_t *));
-int ippr_ftp_out __P((fr_info_t *, ap_session_t *, nat_t *));
-int ippr_ftp_pasv __P((fr_info_t *, ip_t *, nat_t *, ftpinfo_t *, int));
-int ippr_ftp_epsv __P((fr_info_t *, ip_t *, nat_t *, ftpside_t *, int));
-int ippr_ftp_port __P((fr_info_t *, ip_t *, nat_t *, ftpside_t *, int));
-int ippr_ftp_process __P((fr_info_t *, nat_t *, ftpinfo_t *, int));
-int ippr_ftp_server __P((fr_info_t *, ip_t *, nat_t *, ftpinfo_t *, int));
-int ippr_ftp_valid __P((ftpinfo_t *, int, char *, size_t));
-int ippr_ftp_server_valid __P((ftpside_t *, char *, size_t));
-int ippr_ftp_client_valid __P((ftpside_t *, char *, size_t));
-u_short ippr_ftp_atoi __P((char **));
-int ippr_ftp_pasvreply __P((fr_info_t *, ip_t *, nat_t *, ftpside_t *,
-			    u_int, char *, char *, u_int));
 
+typedef struct ipf_ftp_softc_s {
+	int	ipf_p_ftp_pasvonly;
+	/* Do not require logins before transfers */
+	int	ipf_p_ftp_insecure;
+	int	ipf_p_ftp_pasvrdr;
+	/* PASV must be last command prior to 227 */
+	int	ipf_p_ftp_forcepasv;
+	int	ipf_p_ftp_debug;
+	int	ipf_p_ftp_single_xfer;
+	void	*ipf_p_ftp_tune;
+} ipf_ftp_softc_t;
 
-int	ftp_proxy_init = 0;
-int	ippr_ftp_pasvonly = 0;
-int	ippr_ftp_insecure = 0;	/* Do not require logins before transfers */
-int	ippr_ftp_pasvrdr = 0;
-int	ippr_ftp_forcepasv = 0;	/* PASV must be last command prior to 227 */
-#if defined(_KERNEL)
-int	ippr_ftp_debug = 0;
-#else
-int	ippr_ftp_debug = 2;
-#endif
+
+void ipf_p_ftp_main_load __P((void));
+void ipf_p_ftp_main_unload __P((void));
+void *ipf_p_ftp_soft_create __P((ipf_main_softc_t *));
+void ipf_p_ftp_soft_destroy __P((ipf_main_softc_t *, void *));
+
+int ipf_p_ftp_client __P((ipf_ftp_softc_t *, fr_info_t *, ip_t *, nat_t *,
+			  ftpinfo_t *, int));
+int ipf_p_ftp_complete __P((char *, size_t));
+int ipf_p_ftp_in __P((void *, fr_info_t *, ap_session_t *, nat_t *));
+int ipf_p_ftp_new __P((void *, fr_info_t *, ap_session_t *, nat_t *));
+void ipf_p_ftp_del __P((ipf_main_softc_t *, ap_session_t *));
+int ipf_p_ftp_out __P((void *, fr_info_t *, ap_session_t *, nat_t *));
+int ipf_p_ftp_pasv __P((ipf_ftp_softc_t *, fr_info_t *, ip_t *, nat_t *,
+			ftpinfo_t *, int));
+int ipf_p_ftp_epsv __P((ipf_ftp_softc_t *, fr_info_t *, ip_t *, nat_t *,
+			ftpinfo_t *, int));
+int ipf_p_ftp_port __P((ipf_ftp_softc_t *, fr_info_t *, ip_t *, nat_t *,
+			ftpinfo_t *, int));
+int ipf_p_ftp_process __P((ipf_ftp_softc_t *, fr_info_t *, nat_t *,
+			   ftpinfo_t *, int));
+int ipf_p_ftp_server __P((ipf_ftp_softc_t *, fr_info_t *, ip_t *, nat_t *,
+			  ftpinfo_t *, int));
+int ipf_p_ftp_valid __P((ipf_ftp_softc_t *, ftpinfo_t *, int, char *, size_t));
+int ipf_p_ftp_server_valid __P((ipf_ftp_softc_t *, ftpside_t *, char *,
+				size_t));
+int ipf_p_ftp_client_valid __P((ipf_ftp_softc_t *, ftpside_t *, char *,
+				size_t));
+u_short ipf_p_ftp_atoi __P((char **));
+int ipf_p_ftp_pasvreply __P((ipf_ftp_softc_t *, fr_info_t *, ip_t *, nat_t *,
+			     ftpinfo_t *, u_int, char *, char *));
+int ipf_p_ftp_eprt __P((ipf_ftp_softc_t *, fr_info_t *, ip_t *, nat_t *,
+			ftpinfo_t *, int));
+int ipf_p_ftp_eprt4 __P((ipf_ftp_softc_t *, fr_info_t *, ip_t *, nat_t *,
+			 ftpinfo_t *, int));
+int ipf_p_ftp_eprt6 __P((ipf_ftp_softc_t *, fr_info_t *, ip_t *, nat_t *,
+			 ftpinfo_t *, int));
+int ipf_p_ftp_addport __P((ipf_ftp_softc_t *, fr_info_t *, ip_t *, nat_t *,
+			   ftpinfo_t *, int, int, int));
+void ipf_p_ftp_setpending __P((ipf_main_softc_t *, ftpinfo_t *));
+
 /*
- * 1 - security
- * 2 - errors
- * 3 - error debugging
- * 4 - parsing errors
- * 5 - parsing info
- * 6 - parsing debug
+ * Debug levels
  */
+#define	DEBUG_SECURITY		0x01
+#define	DEBUG_ERROR		0x02
+#define	DEBUG_INFO		0x04
+#define	DEBUG_PARSE_ERR		0x08
+#define	DEBUG_PARSE_INFO	0x10
+#define	DEBUG_PARSE		0x20
 
+static	int	ipf_p_ftp_proxy_init = 0;
 static	frentry_t	ftppxyfr;
-static	ipftuneable_t	ftptune = {
-	{ &ippr_ftp_debug },
-	"ippr_ftp_debug",
-	0,
-	10,
-	sizeof(ippr_ftp_debug),
-	0,
-	NULL
+static	ipftuneable_t	ipf_ftp_tuneables[] = {
+	{ { (void *)offsetof(ipf_ftp_softc_t, ipf_p_ftp_debug) },
+		"ftp_debug",	0,	0x7f,
+		stsizeof(ipf_ftp_softc_t, ipf_p_ftp_debug),
+		0, NULL, NULL },
+	{ { (void *)offsetof(ipf_ftp_softc_t, ipf_p_ftp_pasvonly) },
+		"ftp_pasvonly",	0,	1,
+		stsizeof(ipf_ftp_softc_t, ipf_p_ftp_pasvonly),
+		0, NULL, NULL },
+	{ { (void *)offsetof(ipf_ftp_softc_t, ipf_p_ftp_insecure) },
+		"ftp_insecure",	0,	1,
+		stsizeof(ipf_ftp_softc_t, ipf_p_ftp_insecure),
+		0, NULL, NULL },
+	{ { (void *)offsetof(ipf_ftp_softc_t, ipf_p_ftp_pasvrdr) },
+		"ftp_pasvrdr",	0,	1,
+		stsizeof(ipf_ftp_softc_t, ipf_p_ftp_pasvrdr),
+		0, NULL, NULL },
+	{ { (void *)offsetof(ipf_ftp_softc_t, ipf_p_ftp_forcepasv) },
+		"ftp_forcepasv", 0,	1,
+		stsizeof(ipf_ftp_softc_t, ipf_p_ftp_forcepasv),
+		0, NULL, NULL },
+	{ { (void *)offsetof(ipf_ftp_softc_t, ipf_p_ftp_single_xfer) },
+		"ftp_single_xfer", 0,	1,
+		stsizeof(ipf_ftp_softc_t, ipf_p_ftp_single_xfer),
+		0, NULL, NULL },
+	{ { NULL }, NULL, 0, 0, 0, 0, NULL, NULL }
 };
 
 
-/*
- * Initialize local structures.
- */
-int ippr_ftp_init()
+void
+ipf_p_ftp_main_load()
 {
 	bzero((char *)&ftppxyfr, sizeof(ftppxyfr));
 	ftppxyfr.fr_ref = 1;
 	ftppxyfr.fr_flags = FR_INQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE;
+
 	MUTEX_INIT(&ftppxyfr.fr_lock, "FTP Proxy Mutex");
-	ftp_proxy_init = 1;
-	(void) fr_addipftune(&ftptune);
-
-	return 0;
+	ipf_p_ftp_proxy_init = 1;
 }
 
 
-void ippr_ftp_fini()
+void
+ipf_p_ftp_main_unload()
 {
-	(void) fr_delipftune(&ftptune);
 
-	if (ftp_proxy_init == 1) {
+	if (ipf_p_ftp_proxy_init == 1) {
 		MUTEX_DESTROY(&ftppxyfr.fr_lock);
-		ftp_proxy_init = 0;
+		ipf_p_ftp_proxy_init = 0;
 	}
 }
 
 
-int ippr_ftp_new(fin, aps, nat)
-fr_info_t *fin;
-ap_session_t *aps;
-nat_t *nat;
+/*
+ * Initialize local structures.
+ */
+void *
+ipf_p_ftp_soft_create(softc)
+	ipf_main_softc_t *softc;
 {
+	ipf_ftp_softc_t *softf;
+
+	KMALLOC(softf, ipf_ftp_softc_t *);
+	if (softf == NULL)
+		return NULL;
+
+	bzero((char *)softf, sizeof(*softf));
+#if defined(_KERNEL)
+	softf->ipf_p_ftp_debug = 0;
+#else
+	softf->ipf_p_ftp_debug = DEBUG_PARSE_ERR;
+#endif
+	softf->ipf_p_ftp_forcepasv = 1;
+
+	softf->ipf_p_ftp_tune = ipf_tune_array_copy(softf,
+						    sizeof(ipf_ftp_tuneables),
+						    ipf_ftp_tuneables);
+	if (softf->ipf_p_ftp_tune == NULL) {
+		ipf_p_ftp_soft_destroy(softc, softf);
+		return NULL;
+	}
+	if (ipf_tune_array_link(softc, softf->ipf_p_ftp_tune) == -1) {
+		ipf_p_ftp_soft_destroy(softc, softf);
+		return NULL;
+	}
+
+	return softf;
+}
+
+
+void
+ipf_p_ftp_soft_destroy(softc, arg)
+	ipf_main_softc_t *softc;
+	void *arg;
+{
+	ipf_ftp_softc_t *softf = arg;
+
+	if (softf->ipf_p_ftp_tune != NULL) {
+		ipf_tune_array_unlink(softc, softf->ipf_p_ftp_tune);
+		KFREES(softf->ipf_p_ftp_tune, sizeof(ipf_ftp_tuneables));
+		softf->ipf_p_ftp_tune = NULL;
+	}
+
+	KFREE(softf);
+}
+
+
+int
+ipf_p_ftp_new(arg, fin, aps, nat)
+	void *arg;
+	fr_info_t *fin;
+	ap_session_t *aps;
+	nat_t *nat;
+{
 	ftpinfo_t *ftp;
 	ftpside_t *f;
 
@@ -133,11 +239,12 @@
 	if (ftp == NULL)
 		return -1;
 
-	fin = fin;	/* LINT */
 	nat = nat;	/* LINT */
 
 	aps->aps_data = ftp;
 	aps->aps_psiz = sizeof(ftpinfo_t);
+	aps->aps_sport = htons(fin->fin_sport);
+	aps->aps_dport = htons(fin->fin_dport);
 
 	bzero((char *)ftp, sizeof(*ftp));
 	f = &ftp->ftp_side[0];
@@ -152,25 +259,53 @@
 }
 
 
-int ippr_ftp_port(fin, ip, nat, f, dlen)
-fr_info_t *fin;
-ip_t *ip;
-nat_t *nat;
-ftpside_t *f;
-int dlen;
+void
+ipf_p_ftp_setpending(ipf_main_softc_t *softc, ftpinfo_t *ftp)
 {
-	tcphdr_t *tcp, tcph, *tcp2 = &tcph;
+	if (ftp->ftp_pendnat != NULL)
+		ipf_nat_setpending(softc, ftp->ftp_pendnat);
+
+	if (ftp->ftp_pendstate != NULL) {
+		READ_ENTER(&softc->ipf_state);
+		ipf_state_setpending(softc, ftp->ftp_pendstate);
+		RWLOCK_EXIT(&softc->ipf_state);
+	}
+}
+
+
+void
+ipf_p_ftp_del(softc, aps)
+	ipf_main_softc_t *softc;
+	ap_session_t *aps;
+{
+	ftpinfo_t *ftp;
+
+	ftp = aps->aps_data;
+	if (ftp != NULL)
+		ipf_p_ftp_setpending(softc, ftp);
+}
+
+
+int
+ipf_p_ftp_port(softf, fin, ip, nat, ftp, dlen)
+	ipf_ftp_softc_t *softf;
+	fr_info_t *fin;
+	ip_t *ip;
+	nat_t *nat;
+	ftpinfo_t *ftp;
+	int dlen;
+{
 	char newbuf[IPF_FTPBUFSZ], *s;
-	struct in_addr swip, swip2;
 	u_int a1, a2, a3, a4;
-	int inc, off, flags;
 	u_short a5, a6, sp;
 	size_t nlen, olen;
-	fr_info_t fi;
-	nat_t *nat2;
+	tcphdr_t *tcp;
+	int inc, off;
+	ftpside_t *f;
 	mb_t *m;
 
 	m = fin->fin_m;
+	f = &ftp->ftp_side[0];
 	tcp = (tcphdr_t *)fin->fin_dp;
 	off = (char *)tcp - (char *)ip + (TCP_OFF(tcp) << 2) + fin->fin_ipoff;
 
@@ -178,8 +313,10 @@
 	 * Check for client sending out PORT message.
 	 */
 	if (dlen < IPF_MINPORTLEN) {
-		if (ippr_ftp_debug > 1)
-			printf("ippr_ftp_port:dlen(%d) < IPF_MINPORTLEN\n",
+		DT3(ftp_PORT_error_dlen, nat_t *, nat, ftpside_t *, f,
+		    u_int, dlen);
+		if (softf->ipf_p_ftp_debug & DEBUG_PARSE)
+			printf("ipf_p_ftp_port:dlen(%d) < IPF_MINPORTLEN\n",
 			       dlen);
 		return 0;
 	}
@@ -190,16 +327,18 @@
 	/*
 	 * Pick out the address components, two at a time.
 	 */
-	a1 = ippr_ftp_atoi(&s);
+	a1 = ipf_p_ftp_atoi(&s);
 	if (s == NULL) {
-		if (ippr_ftp_debug > 1)
-			printf("ippr_ftp_port:ippr_ftp_atoi(%d) failed\n", 1);
+		DT2(ftp_PORT_error_atoi_1, nat_t *, nat, ftpside_t *, f);
+		if (softf->ipf_p_ftp_debug & DEBUG_PARSE_ERR)
+			printf("ipf_p_ftp_port:ipf_p_ftp_atoi(%d) failed\n", 1);
 		return 0;
 	}
-	a2 = ippr_ftp_atoi(&s);
+	a2 = ipf_p_ftp_atoi(&s);
 	if (s == NULL) {
-		if (ippr_ftp_debug > 1)
-			printf("ippr_ftp_port:ippr_ftp_atoi(%d) failed\n", 2);
+		DT2(ftp_PORT_error_atoi_2, nat_t *, nat, ftpside_t *, f);
+		if (softf->ipf_p_ftp_debug & DEBUG_PARSE_ERR)
+			printf("ipf_p_ftp_port:ipf_p_ftp_atoi(%d) failed\n", 2);
 		return 0;
 	}
 
@@ -210,18 +349,21 @@
 	a1 <<= 16;
 	a1 |= a2;
 	if (((nat->nat_dir == NAT_OUTBOUND) &&
-	     (a1 != ntohl(nat->nat_inip.s_addr))) ||
+	     (a1 != ntohl(nat->nat_osrcaddr))) ||
 	    ((nat->nat_dir == NAT_INBOUND) &&
-	     (a1 != ntohl(nat->nat_oip.s_addr)))) {
-		if (ippr_ftp_debug > 0)
-			printf("ippr_ftp_port:%s != nat->nat_inip\n", "a1");
+	     (a1 != ntohl(nat->nat_nsrcaddr)))) {
+		DT3(ftp_PORT_error_address, nat_t *, nat, ftpside_t *, f,
+		    u_int, a1);
+		if (softf->ipf_p_ftp_debug & DEBUG_ERROR)
+			printf("ipf_p_ftp_port:%s != nat->nat_inip\n", "a1");
 		return APR_ERR(1);
 	}
 
-	a5 = ippr_ftp_atoi(&s);
+	a5 = ipf_p_ftp_atoi(&s);
 	if (s == NULL) {
-		if (ippr_ftp_debug > 1)
-			printf("ippr_ftp_port:ippr_ftp_atoi(%d) failed\n", 3);
+		DT2(ftp_PORT_error_atoi_3, nat_t *, nat, ftpside_t *, f);
+		if (softf->ipf_p_ftp_debug & DEBUG_PARSE_ERR)
+			printf("ipf_p_ftp_port:ipf_p_ftp_atoi(%d) failed\n", 3);
 		return 0;
 	}
 	if (*s == ')')
@@ -232,34 +374,31 @@
 	 */
 	if (*s == '\n')
 		s--;
-	if ((*s == '\r') && (*(s + 1) == '\n')) {
-		s += 2;
-		a6 = a5 & 0xff;
-	} else {
-		if (ippr_ftp_debug > 1)
-			printf("ippr_ftp_port:missing %s\n", "cr-lf");
+	if ((*s != '\r') || (*(s + 1) != '\n')) {
+		DT2(ftp_PORT_error_no_crlf, nat_t *, nat, ftpside_t *, f);
+		if (softf->ipf_p_ftp_debug & DEBUG_PARSE_ERR)
+			printf("ipf_p_ftp_port:missing %s\n", "cr-lf");
 		return 0;
 	}
+	s += 2;
+	a6 = a5 & 0xff;
 
+	/*
+	 * Calculate the source port. Verification of > 1024 is in
+	 * ipf_p_ftp_addport.
+	 */
 	a5 >>= 8;
 	a5 &= 0xff;
 	sp = a5 << 8 | a6;
+
 	/*
-	 * Don't allow the PORT command to specify a port < 1024 due to
-	 * security crap.
-	 */
-	if (sp < 1024) {
-		if (ippr_ftp_debug > 0)
-			printf("ippr_ftp_port:sp(%d) < 1024\n", sp);
-		return 0;
-	}
-	/*
 	 * Calculate new address parts for PORT command
 	 */
 	if (nat->nat_dir == NAT_INBOUND)
-		a1 = ntohl(nat->nat_oip.s_addr);
+		a1 = ntohl(nat->nat_ndstaddr);
 	else
 		a1 = ntohl(ip->ip_src.s_addr);
+	a1 = ntohl(ip->ip_src.s_addr);
 	a2 = (a1 >> 16) & 0xff;
 	a3 = (a1 >> 8) & 0xff;
 	a4 = a1 & 0xff;
@@ -276,20 +415,18 @@
 
 	nlen = strlen(newbuf);
 	inc = nlen - olen;
-	if ((inc + ip->ip_len) > 65535) {
-		if (ippr_ftp_debug > 0)
-			printf("ippr_ftp_port:inc(%d) + ip->ip_len > 65535\n",
+	if ((inc + fin->fin_plen) > 65535) {
+		DT3(ftp_PORT_error_inc, nat_t *, nat, ftpside_t *, f,
+		    int, inc);
+		if (softf->ipf_p_ftp_debug & DEBUG_ERROR)
+			printf("ipf_p_ftp_port:inc(%d) + ip->ip_len > 65535\n",
 			       inc);
 		return 0;
 	}
 
 #if !defined(_KERNEL)
-	bcopy(newbuf, MTOD(m, char *) + off, nlen);
+	M_ADJ(m, inc);
 #else
-# if defined(MENTAT)
-	if (inc < 0)
-		(void)adjmsg(m, inc);
-# else /* defined(MENTAT) */
 	/*
 	 * m_adj takes care of pkthdr.len, if required and treats inc<0 to
 	 * mean remove -len bytes from the end of the packet.
@@ -296,97 +433,195 @@
 	 * The mbuf chain will be extended if necessary by m_copyback().
 	 */
 	if (inc < 0)
-		m_adj(m, inc);
-# endif /* defined(MENTAT) */
+		M_ADJ(m, inc);
 #endif /* !defined(_KERNEL) */
 	COPYBACK(m, off, nlen, newbuf);
+	fin->fin_flx |= FI_DOCKSUM;
 
 	if (inc != 0) {
-		ip->ip_len += inc;
+		fin->fin_plen += inc;
+		ip->ip_len = htons(fin->fin_plen);
 		fin->fin_dlen += inc;
-		fin->fin_plen += inc;
 	}
 
+	f->ftps_cmd = FTPXY_C_PORT;
+	return ipf_p_ftp_addport(softf, fin, ip, nat, ftp, dlen, sp, inc);
+}
+
+
+int
+ipf_p_ftp_addport(softf, fin, ip, nat, ftp, dlen, nport, inc)
+	ipf_ftp_softc_t *softf;
+	fr_info_t *fin;
+	ip_t *ip;
+	nat_t *nat;
+	ftpinfo_t *ftp;
+	int dlen, nport, inc;
+{
+	tcphdr_t tcph, *tcp2 = &tcph;
+	ipf_main_softc_t *softc;
+	ipf_nat_softc_t *softn;
+	int direction;
+	fr_info_t fi;
+	ipnat_t *ipn;
+	nat_t *nat2;
+	u_short sp;
+	int flags;
+
+	softc = fin->fin_main_soft;
+	softn = softc->ipf_nat_soft;
+
+	if ((ftp->ftp_pendnat != NULL)  || (ftp->ftp_pendstate != NULL)) {
+		if (softf->ipf_p_ftp_single_xfer != 0) {
+			DT2(ftp_PORT_error_add_active, nat_t *, nat,
+			    ftpinfo_t *, ftp);
+			if (softf->ipf_p_ftp_debug & DEBUG_ERROR)
+				printf("ipf_p_ftp_addport:xfer active %p/%p\n",
+				       ftp->ftp_pendnat, ftp->ftp_pendstate);
+			return 0;
+		}
+		ipf_p_ftp_setpending(softc, ftp);
+	}
+
 	/*
+	 * Add skeleton NAT entry for connection which will come back the
+	 * other way.
+	 */
+	sp = nport;
+	/*
+	 * Don't allow the PORT command to specify a port < 1024 due to
+	 * security risks.
+	 */
+	if (sp < 1024) {
+		DT3(ftp_PORT_error_port, nat_t *, nat, ftpinfo_t *, ftp,
+		    u_int, sp);
+		if (softf->ipf_p_ftp_debug & DEBUG_SECURITY)
+			printf("ipf_p_ftp_addport:sp(%d) < 1024\n", sp);
+		return 0;
+	}
+	/*
 	 * The server may not make the connection back from port 20, but
 	 * it is the most likely so use it here to check for a conflicting
 	 * mapping.
 	 */
 	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] = fin->fin_data[1] - 1;
+	fi.fin_src6 = nat->nat_ndst6;
+	fi.fin_dst6 = nat->nat_nsrc6;
+
+	if (nat->nat_v[0] == 6) {
+#ifndef USE_INET6
+		return APR_INC(inc);
+#endif
+	}
+
 	/*
 	 * Add skeleton NAT entry for connection which will come back the
 	 * other way.
 	 */
-	if (nat->nat_dir == NAT_OUTBOUND)
-		nat2 = nat_outlookup(&fi, NAT_SEARCH|IPN_TCP, nat->nat_p,
-				     nat->nat_inip, nat->nat_oip);
-	else
-		nat2 = nat_inlookup(&fi, NAT_SEARCH|IPN_TCP, nat->nat_p,
-				    nat->nat_inip, nat->nat_oip);
-	if (nat2 == NULL) {
-		int slen;
-
-		slen = ip->ip_len;
-		ip->ip_len = fin->fin_hlen + sizeof(*tcp2);
-		bzero((char *)tcp2, sizeof(*tcp2));
-		tcp2->th_win = htons(8192);
-		tcp2->th_sport = htons(sp);
-		TCP_OFF_A(tcp2, 5);
-		tcp2->th_flags = TH_SYN;
-		tcp2->th_dport = 0; /* XXX - don't specify remote port */
-		fi.fin_data[1] = 0;
-		fi.fin_dlen = sizeof(*tcp2);
-		fi.fin_plen = fi.fin_hlen + sizeof(*tcp2);
-		fi.fin_dp = (char *)tcp2;
-		fi.fin_fr = &ftppxyfr;
-		fi.fin_out = nat->nat_dir;
-		fi.fin_flx &= FI_LOWTTL|FI_FRAG|FI_TCPUDP|FI_OPTIONS|FI_IGNORE;
-		swip = ip->ip_src;
-		swip2 = ip->ip_dst;
+#ifdef USE_INET6
+	if (nat->nat_v[0] == 6) {
 		if (nat->nat_dir == NAT_OUTBOUND) {
-			fi.fin_fi.fi_saddr = nat->nat_inip.s_addr;
-			ip->ip_src = nat->nat_inip;
-		} else if (nat->nat_dir == NAT_INBOUND) {
-			fi.fin_fi.fi_saddr = nat->nat_oip.s_addr;
-			ip->ip_src = nat->nat_oip;
+			nat2 = ipf_nat6_outlookup(&fi, IPN_TCP|NAT_SEARCH,
+						  nat->nat_pr[1],
+						  &nat->nat_osrc6.in6,
+						  &nat->nat_odst6.in6);
+		} else {
+			nat2 = ipf_nat6_inlookup(&fi, IPN_TCP|NAT_SEARCH,
+						 nat->nat_pr[0],
+						 &nat->nat_odst6.in6,
+						 &nat->nat_osrc6.in6);
 		}
+	} else
+#endif
+	{
+		if (nat->nat_dir == NAT_OUTBOUND) {
+			nat2 = ipf_nat_outlookup(&fi, IPN_TCP|NAT_SEARCH,
+						 nat->nat_pr[1],
+						 nat->nat_osrcip,
+						 nat->nat_odstip);
+		} else {
+			nat2 = ipf_nat_inlookup(&fi, IPN_TCP|NAT_SEARCH,
+						nat->nat_pr[0],
+						nat->nat_odstip,
+						nat->nat_osrcip);
+		}
+	}
+	if (nat2 != NULL)
+		return APR_INC(inc);
 
-		flags = NAT_SLAVE|IPN_TCP|SI_W_DPORT;
-		if (nat->nat_dir == NAT_INBOUND)
-			flags |= NAT_NOTRULEPORT;
-		nat2 = nat_new(&fi, nat->nat_ptr, NULL, flags, nat->nat_dir);
+	ipn = ipf_proxy_rule_rev(nat);
+	if (ipn == NULL)
+		return APR_ERR(1);
+	ipn->in_use = 0;
 
-		if (nat2 != NULL) {
-			(void) nat_proto(&fi, nat2, IPN_TCP);
-			nat_update(&fi, nat2, nat->nat_ptr);
-			fi.fin_ifp = NULL;
-			if (nat->nat_dir == NAT_INBOUND) {
-				fi.fin_fi.fi_daddr = nat->nat_inip.s_addr;
-				ip->ip_dst = nat->nat_inip;
-			}
-			(void) fr_addstate(&fi, NULL, SI_W_DPORT);
-			if (fi.fin_state != NULL)
-				fr_statederef((ipstate_t **)&fi.fin_state);
-		}
-		ip->ip_len = slen;
-		ip->ip_src = swip;
-		ip->ip_dst = swip2;
+	fi.fin_fr = &ftppxyfr;
+	fi.fin_dp = (char *)tcp2;
+	fi.fin_dlen = sizeof(*tcp2);
+	fi.fin_plen = fi.fin_hlen + sizeof(*tcp2);
+	fi.fin_flx &= FI_LOWTTL|FI_FRAG|FI_TCPUDP|FI_OPTIONS|FI_IGNORE;
+	fi.fin_data[1] = sp;
+	fi.fin_data[0] = 0;
+
+	bzero((char *)tcp2, sizeof(*tcp2));
+	tcp2->th_sport = 0;
+	tcp2->th_dport = htons(sp);
+
+	tcp2->th_win = htons(8192);
+	TCP_OFF_A(tcp2, 5);
+	tcp2->th_flags = TH_SYN;
+
+	if (nat->nat_dir == NAT_INBOUND) {
+		fi.fin_out = 1;
+		direction = NAT_OUTBOUND;
+	} else {
+		fi.fin_out = 0;
+		direction = NAT_INBOUND;
 	}
+	flags = SI_W_SPORT|NAT_SLAVE|IPN_TCP;
+
+	MUTEX_ENTER(&softn->ipf_nat_new);
+	if (nat->nat_v[0] == 6) {
+#ifdef USE_INET6
+		nat2 = ipf_nat6_add(&fi, ipn, &ftp->ftp_pendnat, flags,
+				    direction);
+#endif
+	} else {
+		nat2 = ipf_nat_add(&fi, ipn, &ftp->ftp_pendnat, flags,
+				   direction);
+	}
+	MUTEX_EXIT(&softn->ipf_nat_new);
+
+	if (nat2 == NULL) {
+		KFREES(ipn, ipn->in_size);
+		return APR_ERR(1);
+	}
+
+	(void) ipf_nat_proto(&fi, nat2, IPN_TCP);
+	MUTEX_ENTER(&nat2->nat_lock);
+	ipf_nat_update(&fi, nat2);
+	MUTEX_EXIT(&nat2->nat_lock);
+	fi.fin_ifp = NULL;
+	if (nat2->nat_dir == NAT_INBOUND)
+		fi.fin_dst6 = nat->nat_osrc6;
+	if (ipf_state_add(softc, &fi, (ipstate_t **)&ftp->ftp_pendstate,
+			  SI_W_SPORT) != 0)
+		ipf_nat_setpending(softc, nat2);
+
 	return APR_INC(inc);
 }
 
 
-int ippr_ftp_client(fin, ip, nat, ftp, dlen)
-fr_info_t *fin;
-nat_t *nat;
-ftpinfo_t *ftp;
-ip_t *ip;
-int dlen;
+int
+ipf_p_ftp_client(softf, fin, ip, nat, ftp, dlen)
+	ipf_ftp_softc_t *softf;
+	fr_info_t *fin;
+	nat_t *nat;
+	ftpinfo_t *ftp;
+	ip_t *ip;
+	int dlen;
 {
 	char *rptr, *wptr, cmd[6], c;
 	ftpside_t *f;
@@ -408,6 +643,7 @@
 	cmd[i] = '\0';
 
 	ftp->ftp_incok = 0;
+	DT2(ftp_client_command, char [], cmd, int, ftp->ftp_passok);
 	if (!strncmp(cmd, "USER ", 5) || !strncmp(cmd, "XAUT ", 5)) {
 		if (ftp->ftp_passok == FTPXY_ADOK_1 ||
 		    ftp->ftp_passok == FTPXY_AUOK_1) {
@@ -437,14 +673,24 @@
 		 !strncmp(cmd, "ACCT ", 5)) {
 		ftp->ftp_passok = FTPXY_ACCT_1;
 		ftp->ftp_incok = 1;
-	} else if ((ftp->ftp_passok == FTPXY_GO) && !ippr_ftp_pasvonly &&
+	} else if ((ftp->ftp_passok == FTPXY_GO) &&
+		   !softf->ipf_p_ftp_pasvonly &&
 		 !strncmp(cmd, "PORT ", 5)) {
-		inc = ippr_ftp_port(fin, ip, nat, f, dlen);
-	} else if (ippr_ftp_insecure && !ippr_ftp_pasvonly &&
+		inc = ipf_p_ftp_port(softf, fin, ip, nat, ftp, dlen);
+	} else if ((ftp->ftp_passok == FTPXY_GO) &&
+		   !softf->ipf_p_ftp_pasvonly &&
+		 !strncmp(cmd, "EPRT ", 5)) {
+		inc = ipf_p_ftp_eprt(softf, fin, ip, nat, ftp, dlen);
+	} else if (softf->ipf_p_ftp_insecure &&
+		   !softf->ipf_p_ftp_pasvonly &&
 		   !strncmp(cmd, "PORT ", 5)) {
-		inc = ippr_ftp_port(fin, ip, nat, f, dlen);
+		inc = ipf_p_ftp_port(softf, fin, ip, nat, ftp, dlen);
 	}
+	if (softf->ipf_p_ftp_debug & DEBUG_PARSE)
+		printf("ipf_p_ftp_client: cmd[%s] passok %d incok %d inc %d\n",
+		       cmd, ftp->ftp_passok, ftp->ftp_incok, inc);
 
+	DT2(ftp_client_passok, char *, cmd, int, ftp->ftp_passok);
 	while ((*rptr++ != '\n') && (rptr < wptr))
 		;
 	f->ftps_rptr = rptr;
@@ -452,12 +698,14 @@
 }
 
 
-int ippr_ftp_pasv(fin, ip, nat, ftp, dlen)
-fr_info_t *fin;
-ip_t *ip;
-nat_t *nat;
-ftpinfo_t *ftp;
-int dlen;
+int
+ipf_p_ftp_pasv(softf, fin, ip, nat, ftp, dlen)
+	ipf_ftp_softc_t *softf;
+	fr_info_t *fin;
+	ip_t *ip;
+	nat_t *nat;
+	ftpinfo_t *ftp;
+	int dlen;
 {
 	u_int a1, a2, a3, a4, data_ip;
 	char newbuf[IPF_FTPBUFSZ];
@@ -466,11 +714,12 @@
 	ftpside_t *f;
 	char *s;
 
-	if (ippr_ftp_forcepasv != 0 &&
-	    ftp->ftp_side[0].ftps_cmds != FTPXY_C_PASV) {
-		if (ippr_ftp_debug > 0)
-			printf("ippr_ftp_pasv:ftps_cmds(%d) != FTPXY_C_PASV\n",
-			       ftp->ftp_side[0].ftps_cmds);
+	if ((softf->ipf_p_ftp_forcepasv != 0) &&
+	    (ftp->ftp_side[0].ftps_cmd != FTPXY_C_PASV)) {
+		DT2(ftp_PASV_error_state, nat_t *, nat, ftpinfo_t *, ftp);
+		if (softf->ipf_p_ftp_debug & DEBUG_ERROR)
+			printf("ipf_p_ftp_pasv:ftps_cmd(%d) != FTPXY_C_PASV\n",
+			       ftp->ftp_side[0].ftps_cmd);
 		return 0;
 	}
 
@@ -481,14 +730,17 @@
 	 * Check for PASV reply message.
 	 */
 	if (dlen < IPF_MIN227LEN) {
-		if (ippr_ftp_debug > 1)
-			printf("ippr_ftp_pasv:dlen(%d) < IPF_MIN227LEN\n",
+		DT3(ftp_PASV_error_short, nat_t *, nat, ftpinfo_t *, ftp,
+		    int, dlen);
+		if (softf->ipf_p_ftp_debug & DEBUG_ERROR)
+			printf("ipf_p_ftp_pasv:dlen(%d) < IPF_MIN227LEN\n",
 			       dlen);
 		return 0;
 	} else if (strncmp(f->ftps_rptr,
 			   "227 Entering Passive Mod", PASV_REPLEN)) {
-		if (ippr_ftp_debug > 0)
-			printf("ippr_ftp_pasv:%d reply wrong\n", 227);
+		DT2(ftp_PASV_error_string, nat_t *, nat, ftpinfo_t *, ftp);
+		if (softf->ipf_p_ftp_debug & DEBUG_PARSE_ERR)
+			printf("ipf_p_ftp_pasv:%d reply wrong\n", 227);
 		return 0;
 	}
 
@@ -509,16 +761,18 @@
 	/*
 	 * Pick out the address components, two at a time.
 	 */
-	a1 = ippr_ftp_atoi(&s);
+	a1 = ipf_p_ftp_atoi(&s);
 	if (s == NULL) {
-		if (ippr_ftp_debug > 1)
-			printf("ippr_ftp_pasv:ippr_ftp_atoi(%d) failed\n", 1);
+		DT2(ftp_PASV_error_atoi_1, nat_t *, nat, ftpside_t *, f);
+		if (softf->ipf_p_ftp_debug & DEBUG_PARSE_ERR)
+			printf("ipf_p_ftp_pasv:ipf_p_ftp_atoi(%d) failed\n", 1);
 		return 0;
 	}
-	a2 = ippr_ftp_atoi(&s);
+	a2 = ipf_p_ftp_atoi(&s);
 	if (s == NULL) {
-		if (ippr_ftp_debug > 1)
-			printf("ippr_ftp_pasv:ippr_ftp_atoi(%d) failed\n", 2);
+		DT2(ftp_PASV_error_atoi_2, nat_t *, nat, ftpside_t *, f);
+		if (softf->ipf_p_ftp_debug & DEBUG_PARSE_ERR)
+			printf("ipf_p_ftp_pasv:ipf_p_ftp_atoi(%d) failed\n", 2);
 		return 0;
 	}
 
@@ -530,18 +784,21 @@
 	a1 |= a2;
 
 	if (((nat->nat_dir == NAT_INBOUND) &&
-	     (a1 != ntohl(nat->nat_inip.s_addr))) ||
+	     (a1 != ntohl(nat->nat_ndstaddr))) ||
 	    ((nat->nat_dir == NAT_OUTBOUND) &&
-	     (a1 != ntohl(nat->nat_oip.s_addr)))) {
-		if (ippr_ftp_debug > 0)
-			printf("ippr_ftp_pasv:%s != nat->nat_oip\n", "a1");
+	     (a1 != ntohl(nat->nat_odstaddr)))) {
+		DT3(ftp_PASV_error_address, nat_t *, nat, ftpside_t *, f,
+		    u_int, a1);
+		if (softf->ipf_p_ftp_debug & DEBUG_ERROR)
+			printf("ipf_p_ftp_pasv:%s != nat->nat_oip\n", "a1");
 		return 0;
 	}
 
-	a5 = ippr_ftp_atoi(&s);
+	a5 = ipf_p_ftp_atoi(&s);
 	if (s == NULL) {
-		if (ippr_ftp_debug > 1)
-			printf("ippr_ftp_pasv:ippr_ftp_atoi(%d) failed\n", 3);
+		DT2(ftp_PASV_error_atoi_3, nat_t *, nat, ftpside_t *, f);
+		if (softf->ipf_p_ftp_debug & DEBUG_PARSE_ERR)
+			printf("ipf_p_ftp_pasv:ipf_p_ftp_atoi(%d) failed\n", 3);
 		return 0;
 	}
 
@@ -554,13 +811,13 @@
 	/*
 	 * check for CR-LF at the end.
 	 */
-	if ((*s == '\r') && (*(s + 1) == '\n')) {
-		s += 2;
-	} else {
-		if (ippr_ftp_debug > 1)
-			printf("ippr_ftp_pasv:missing %s", "cr-lf\n");
+	if ((*s != '\r') || (*(s + 1) != '\n')) {
+		DT(pasv_missing_crlf);
+		if (softf->ipf_p_ftp_debug & DEBUG_PARSE_ERR)
+			printf("ipf_p_ftp_pasv:missing %s", "cr-lf\n");
 		return 0;
 	}
+	s += 2;
 
 	a6 = a5 & 0xff;
 	a5 >>= 8;
@@ -568,7 +825,7 @@
 	 * Calculate new address parts for 227 reply
 	 */
 	if (nat->nat_dir == NAT_INBOUND) {
-		data_ip = nat->nat_outip.s_addr;
+		data_ip = nat->nat_odstaddr;
 		a1 = ntohl(data_ip);
 	} else
 		data_ip = htonl(a1);
@@ -587,156 +844,165 @@
 		"227 Entering Passive Mode", brackets[0], a1, a2, a3, a4,
 		a5, a6, brackets[1]);
 #endif
-	return ippr_ftp_pasvreply(fin, ip, nat, f, (a5 << 8 | a6),
-				  newbuf, s, data_ip);
+	return ipf_p_ftp_pasvreply(softf, fin, ip, nat, ftp, (a5 << 8 | a6),
+				   newbuf, s);
 }
 
-int ippr_ftp_pasvreply(fin, ip, nat, f, port, newmsg, s, data_ip)
-fr_info_t *fin;
-ip_t *ip;
-nat_t *nat;
-ftpside_t *f;
-u_int port;
-char *newmsg;
-char *s;
-u_int data_ip;
+int
+ipf_p_ftp_pasvreply(softf, fin, ip, nat, ftp, port, newmsg, s)
+	ipf_ftp_softc_t *softf;
+	fr_info_t *fin;
+	ip_t *ip;
+	nat_t *nat;
+	ftpinfo_t *ftp;
+	u_int port;
+	char *newmsg;
+	char *s;
 {
-	int inc, off, nflags, sflags;
+	int inc, off, nflags;
 	tcphdr_t *tcp, tcph, *tcp2;
-	struct in_addr swip, swip2;
-	struct in_addr data_addr;
+	ipf_main_softc_t *softc;
+	ipf_nat_softc_t *softn;
 	size_t nlen, olen;
+#ifdef USE_INET6
+	ip6_t *ip6;
+#endif
+	ipnat_t *ipn;
 	fr_info_t fi;
+	ftpside_t *f;
 	nat_t *nat2;
 	mb_t *m;
 
+	softc = fin->fin_main_soft;
+	softn = softc->ipf_nat_soft;
+
+	if ((ftp->ftp_pendnat != NULL) || (ftp->ftp_pendstate != NULL))
+		ipf_p_ftp_setpending(softc, ftp);
+
 	m = fin->fin_m;
 	tcp = (tcphdr_t *)fin->fin_dp;
 	off = (char *)tcp - (char *)ip + (TCP_OFF(tcp) << 2) + fin->fin_ipoff;
 
-	data_addr.s_addr = data_ip;
 	tcp2 = &tcph;
 	inc = 0;
 
-
+	f = &ftp->ftp_side[1];
 	olen = s - f->ftps_rptr;
 	nlen = strlen(newmsg);
 	inc = nlen - olen;
-	if ((inc + ip->ip_len) > 65535) {
-		if (ippr_ftp_debug > 0)
-			printf("ippr_ftp_pasv:inc(%d) + ip->ip_len > 65535\n",
+	if ((inc + fin->fin_plen) > 65535) {
+		DT3(ftp_PASV_error_inc, nat_t *, nat, ftpside_t *, f,
+		    int, inc);
+		if (softf->ipf_p_ftp_debug & DEBUG_ERROR)
+			printf("ipf_p_ftp_pasv:inc(%d) + ip->ip_len > 65535\n",
 			       inc);
 		return 0;
 	}
 
-#if !defined(_KERNEL)
-	bcopy(newmsg, MTOD(m, char *) + off, nlen);
-#else
-# if defined(MENTAT)
-	if (inc < 0)
-		(void)adjmsg(m, inc);
-# else /* defined(MENTAT) */
-	/*
-	 * m_adj takes care of pkthdr.len, if required and treats inc<0 to
-	 * mean remove -len bytes from the end of the packet.
-	 * The mbuf chain will be extended if necessary by m_copyback().
-	 */
-	if (inc < 0)
-		m_adj(m, inc);
-# endif /* defined(MENTAT) */
-#endif /* !defined(_KERNEL) */
-	COPYBACK(m, off, nlen, newmsg);
+	ipn = ipf_proxy_rule_fwd(nat);
+	if (ipn == NULL)
+		return APR_ERR(1);
+	ipn->in_use = 0;
 
-	if (inc != 0) {
-		ip->ip_len += inc;
-		fin->fin_dlen += inc;
-		fin->fin_plen += inc;
-	}
-
 	/*
 	 * Add skeleton NAT entry for connection which will come back the
 	 * other way.
 	 */
+	bzero((char *)tcp2, sizeof(*tcp2));
 	bcopy((char *)fin, (char *)&fi, sizeof(fi));
-	fi.fin_state = NULL;
-	fi.fin_nat = NULL;
 	fi.fin_flx |= FI_IGNORE;
 	fi.fin_data[0] = 0;
 	fi.fin_data[1] = port;
 	nflags = IPN_TCP|SI_W_SPORT;
-	if (ippr_ftp_pasvrdr && f->ftps_ifp)
-		nflags |= SI_W_DPORT;
-	if (nat->nat_dir == NAT_OUTBOUND)
-		nat2 = nat_outlookup(&fi, nflags|NAT_SEARCH,
-				     nat->nat_p, nat->nat_inip, nat->nat_oip);
+
+	fi.fin_fr = &ftppxyfr;
+	fi.fin_dp = (char *)tcp2;
+	fi.fin_out = 1 - fin->fin_out;
+	fi.fin_dlen = sizeof(*tcp2);
+	fi.fin_src6 = nat->nat_osrc6;
+	fi.fin_dst6 = nat->nat_odst6;
+	fi.fin_plen = fi.fin_hlen + sizeof(*tcp);
+	fi.fin_flx &= FI_LOWTTL|FI_FRAG|FI_TCPUDP|FI_OPTIONS|FI_IGNORE;
+
+	TCP_OFF_A(tcp2, 5);
+	tcp2->th_flags = TH_SYN;
+	tcp2->th_win = htons(8192);
+	tcp2->th_dport = htons(port);
+
+	MUTEX_ENTER(&softn->ipf_nat_new);
+#ifdef USE_INET6
+	if (nat->nat_v[0] == 6)
+		nat2 = ipf_nat6_add(&fi, ipn, &ftp->ftp_pendnat,
+				    nflags, nat->nat_dir);
 	else
-		nat2 = nat_inlookup(&fi, nflags|NAT_SEARCH,
-				    nat->nat_p, nat->nat_inip, nat->nat_oip);
+#endif
+		nat2 = ipf_nat_add(&fi, ipn, &ftp->ftp_pendnat,
+				   nflags, nat->nat_dir);
+	MUTEX_EXIT(&softn->ipf_nat_new);
+
 	if (nat2 == NULL) {
-		int slen;
+		KFREES(ipn, ipn->in_size);
+		return APR_ERR(1);
+	}
 
-		slen = ip->ip_len;
-		ip->ip_len = fin->fin_hlen + sizeof(*tcp2);
-		bzero((char *)tcp2, sizeof(*tcp2));
-		tcp2->th_win = htons(8192);
-		tcp2->th_sport = 0;		/* XXX - fake it for nat_new */
-		TCP_OFF_A(tcp2, 5);
-		tcp2->th_flags = TH_SYN;
-		fi.fin_data[1] = port;
-		fi.fin_dlen = sizeof(*tcp2);
-		tcp2->th_dport = htons(port);
-		fi.fin_data[0] = 0;
-		fi.fin_dp = (char *)tcp2;
-		fi.fin_plen = fi.fin_hlen + sizeof(*tcp);
-		fi.fin_fr = &ftppxyfr;
-		fi.fin_out = nat->nat_dir;
-		fi.fin_flx &= FI_LOWTTL|FI_FRAG|FI_TCPUDP|FI_OPTIONS|FI_IGNORE;
-		swip = ip->ip_src;
-		swip2 = ip->ip_dst;
-		if (nat->nat_dir == NAT_OUTBOUND) {
-			fi.fin_fi.fi_daddr = data_addr.s_addr;
-			fi.fin_fi.fi_saddr = nat->nat_inip.s_addr;
-			ip->ip_dst = data_addr;
-			ip->ip_src = nat->nat_inip;
-		} else if (nat->nat_dir == NAT_INBOUND) {
-			fi.fin_fi.fi_saddr = nat->nat_oip.s_addr;
-			fi.fin_fi.fi_daddr = nat->nat_outip.s_addr;
-			ip->ip_src = nat->nat_oip;
-			ip->ip_dst = nat->nat_outip;
+	(void) ipf_nat_proto(&fi, nat2, IPN_TCP);
+	MUTEX_ENTER(&nat2->nat_lock);
+	ipf_nat_update(&fi, nat2);
+	MUTEX_EXIT(&nat2->nat_lock);
+	fi.fin_ifp = NULL;
+	if (nat->nat_dir == NAT_INBOUND) {
+		if (nat->nat_v[0] == 6) {
+#ifdef USE_INET6
+			fi.fin_dst6 = nat->nat_ndst6;
+#endif
+		} else {
+			fi.fin_daddr = nat->nat_ndstaddr;
 		}
+	}
+	if (ipf_state_add(softc, &fi, (ipstate_t **)&ftp->ftp_pendstate,
+			  SI_W_SPORT) != 0)
+		ipf_nat_setpending(softc, nat2);
 
-		sflags = nflags;
-		nflags |= NAT_SLAVE;
-		if (nat->nat_dir == NAT_INBOUND)
-			nflags |= NAT_NOTRULEPORT;
-		nat2 = nat_new(&fi, nat->nat_ptr, NULL, nflags, nat->nat_dir);
-		if (nat2 != NULL) {
-			(void) nat_proto(&fi, nat2, IPN_TCP);
-			nat_update(&fi, nat2, nat->nat_ptr);
-			fi.fin_ifp = NULL;
-			if (nat->nat_dir == NAT_INBOUND) {
-				fi.fin_fi.fi_daddr = nat->nat_inip.s_addr;
-				ip->ip_dst = nat->nat_inip;
-			}
-			(void) fr_addstate(&fi, NULL, sflags);
-			if (fi.fin_state != NULL)
-				fr_statederef((ipstate_t **)&fi.fin_state);
+#if !defined(_KERNEL)
+	M_ADJ(m, inc);
+#else
+	/*
+	 * m_adj takes care of pkthdr.len, if required and treats inc<0 to
+	 * mean remove -len bytes from the end of the packet.
+	 * The mbuf chain will be extended if necessary by m_copyback().
+	 */
+	if (inc < 0)
+		M_ADJ(m, inc);
+#endif /* !defined(_KERNEL) */
+	COPYBACK(m, off, nlen, newmsg);
+	fin->fin_flx |= FI_DOCKSUM;
+
+	if (inc != 0) {
+		fin->fin_plen += inc;
+		fin->fin_dlen += inc;
+		if (nat->nat_v[0] == 6) {
+#ifdef USE_INET6
+			ip6 = (ip6_t *)fin->fin_ip;
+			u_short len = ntohs(ip6->ip6_plen) + inc;
+			ip6->ip6_plen = htons(len);
+#endif
+		} else {
+			ip->ip_len = htons(fin->fin_plen);
 		}
+	}
 
-		ip->ip_len = slen;
-		ip->ip_src = swip;
-		ip->ip_dst = swip2;
-	}
-	return inc;
+	return APR_INC(inc);
 }
 
 
-int ippr_ftp_server(fin, ip, nat, ftp, dlen)
-fr_info_t *fin;
-ip_t *ip;
-nat_t *nat;
-ftpinfo_t *ftp;
-int dlen;
+int
+ipf_p_ftp_server(softf, fin, ip, nat, ftp, dlen)
+	ipf_ftp_softc_t *softf;
+	fr_info_t *fin;
+	ip_t *ip;
+	nat_t *nat;
+	ftpinfo_t *ftp;
+	int dlen;
 {
 	char *rptr, *wptr;
 	ftpside_t *f;
@@ -747,19 +1013,29 @@
 	rptr = f->ftps_rptr;
 	wptr = f->ftps_wptr;
 
+	DT2(ftp_server_response, char *, rptr, int, ftp->ftp_passok);
 	if (*rptr == ' ')
 		goto server_cmd_ok;
 	if (!ISDIGIT(*rptr) || !ISDIGIT(*(rptr + 1)) || !ISDIGIT(*(rptr + 2)))
 		return 0;
+	if (softf->ipf_p_ftp_debug & DEBUG_PARSE)
+		printf("ipf_p_ftp_server_1: cmd[%4.4s] passok %d\n",
+		       rptr, ftp->ftp_passok);
 	if (ftp->ftp_passok == FTPXY_GO) {
 		if (!strncmp(rptr, "227 ", 4))
-			inc = ippr_ftp_pasv(fin, ip, nat, ftp, dlen);
+			inc = ipf_p_ftp_pasv(softf, fin, ip, nat, ftp, dlen);
 		else if (!strncmp(rptr, "229 ", 4))
-			inc = ippr_ftp_epsv(fin, ip, nat, f, dlen);
-	} else if (ippr_ftp_insecure && !strncmp(rptr, "227 ", 4)) {
-		inc = ippr_ftp_pasv(fin, ip, nat, ftp, dlen);
-	} else if (ippr_ftp_insecure && !strncmp(rptr, "229 ", 4)) {
-		inc = ippr_ftp_epsv(fin, ip, nat, f, dlen);
+			inc = ipf_p_ftp_epsv(softf, fin, ip, nat, ftp, dlen);
+		else if (strncmp(rptr, "200", 3)) {
+			/*
+			 * 200 is returned for a successful command.
+			 */
+			;
+		}
+	} else if (softf->ipf_p_ftp_insecure && !strncmp(rptr, "227 ", 4)) {
+		inc = ipf_p_ftp_pasv(softf, fin, ip, nat, ftp, dlen);
+	} else if (softf->ipf_p_ftp_insecure && !strncmp(rptr, "229 ", 4)) {
+		inc = ipf_p_ftp_epsv(softf, fin, ip, nat, ftp, dlen);
 	} else if (*rptr == '5' || *rptr == '4')
 		ftp->ftp_passok = FTPXY_INIT;
 	else if (ftp->ftp_incok) {
@@ -784,8 +1060,13 @@
 			}
 		}
 	}
+	ftp->ftp_incok = 0;
 server_cmd_ok:
-	ftp->ftp_incok = 0;
+	if (softf->ipf_p_ftp_debug & DEBUG_PARSE)
+		printf("ipf_p_ftp_server_2: cmd[%4.4s] passok %d\n",
+		       rptr, ftp->ftp_passok);
+	DT3(ftp_server_passok, char *,rptr, int, ftp->ftp_incok,
+	    int, ftp->ftp_passok);
 
 	while ((*rptr++ != '\n') && (rptr < wptr))
 		;
@@ -795,13 +1076,20 @@
 
 
 /*
+ * 0 FTPXY_JUNK_OK
+ * 1 FTPXY_JUNK_BAD
+ * 2 FTPXY_JUNK_EOL
+ * 3 FTPXY_JUNK_CONT
+ *
  * Look to see if the buffer starts with something which we recognise as
  * being the correct syntax for the FTP protocol.
  */
-int ippr_ftp_client_valid(ftps, buf, len)
-ftpside_t *ftps;
-char *buf;
-size_t len;
+int
+ipf_p_ftp_client_valid(softf, ftps, buf, len)
+	ipf_ftp_softc_t *softf;
+	ftpside_t *ftps;
+	char *buf;
+	size_t len;
 {
 	register char *s, c, pc;
 	register size_t i = len;
@@ -809,12 +1097,13 @@
 
 	s = buf;
 
-	if (ftps->ftps_junk == 1)
-		return 1;
+	if (ftps->ftps_junk == FTPXY_JUNK_BAD)
+		return FTPXY_JUNK_BAD;
 
 	if (i < 5) {
-		if (ippr_ftp_debug > 3)
-			printf("ippr_ftp_client_valid:i(%d) < 5\n", (int)i);
+		DT1(client_valid, int, i);
+		if (softf->ipf_p_ftp_debug & DEBUG_ERROR)
+			printf("ipf_p_ftp_client_valid:i(%d) < 5\n", (int)i);
 		return 2;
 	}
 
@@ -847,12 +1136,13 @@
 			goto bad_client_command;
 	} else {
 bad_client_command:
-		if (ippr_ftp_debug > 3)
+		DT4(client_junk, int, len, int, i, int, c, char *, buf);
+		if (softf->ipf_p_ftp_debug & DEBUG_PARSE_ERR)
 			printf("%s:bad:junk %d len %d/%d c 0x%x buf [%*.*s]\n",
-			       "ippr_ftp_client_valid",
+			       "ipf_p_ftp_client_valid",
 			       ftps->ftps_junk, (int)len, (int)i, c,
 			       (int)len, (int)len, buf);
-		return 1;
+		return FTPXY_JUNK_BAD;
 	}
 
 	for (; i; i--) {
@@ -860,25 +1150,30 @@
 		c = *s++;
 		if ((pc == '\r') && (c == '\n')) {
 			cmd[4] = '\0';
-			if (!strcmp(cmd, "PASV"))
-				ftps->ftps_cmds = FTPXY_C_PASV;
-			else
-				ftps->ftps_cmds = 0;
+			if (!strcmp(cmd, "PASV")) {
+				ftps->ftps_cmd = FTPXY_C_PASV;
+			} else if (!strcmp(cmd, "EPSV")) {
+				ftps->ftps_cmd = FTPXY_C_EPSV;
+			} else {
+				ftps->ftps_cmd = 0;
+			}
 			return 0;
 		}
 	}
 #if !defined(_KERNEL)
-	printf("ippr_ftp_client_valid:junk after cmd[%*.*s]\n",
+	printf("ipf_p_ftp_client_valid:junk after cmd[%*.*s]\n",
 	       (int)len, (int)len, buf);
 #endif
-	return 2;
+	return FTPXY_JUNK_EOL;
 }
 
 
-int ippr_ftp_server_valid(ftps, buf, len)
-ftpside_t *ftps;
-char *buf;
-size_t len;
+int
+ipf_p_ftp_server_valid(softf, ftps, buf, len)
+	ipf_ftp_softc_t *softf;
+	ftpside_t *ftps;
+	char *buf;
+	size_t len;
 {
 	register char *s, c, pc;
 	register size_t i = len;
@@ -887,19 +1182,22 @@
 	s = buf;
 	cmd = 0;
 
-	if (ftps->ftps_junk == 1)
-		return 1;
+	if (ftps->ftps_junk == FTPXY_JUNK_BAD)
+		return FTPXY_JUNK_BAD;
 
 	if (i < 5) {
-		if (ippr_ftp_debug > 3)
-			printf("ippr_ftp_servert_valid:i(%d) < 5\n", (int)i);
+		DT1(server_valid, int, i);
+		if (softf->ipf_p_ftp_debug & DEBUG_PARSE_ERR)
+			printf("ipf_p_ftp_servert_valid:i(%d) < 5\n", (int)i);
 		return 2;
 	}
 
 	c = *s++;
 	i--;
-	if (c == ' ')
+	if (c == ' ') {
+		cmd = -1;
 		goto search_eol;
+	}
 
 	if (ISDIGIT(c)) {
 		cmd = (c - '0') * 100;
@@ -915,6 +1213,8 @@
 				i--;
 				if ((c != '-') && (c != ' '))
 					goto bad_server_command;
+				if (c == '-')
+					return FTPXY_JUNK_CONT;
 			} else
 				goto bad_server_command;
 		} else
@@ -921,12 +1221,15 @@
 			goto bad_server_command;
 	} else {
 bad_server_command:
-		if (ippr_ftp_debug > 3)
+		DT4(server_junk, int len, buf, int, i, int, c, char *, buf);
+		if (softf->ipf_p_ftp_debug & DEBUG_PARSE_INFO)
 			printf("%s:bad:junk %d len %d/%d c 0x%x buf [%*.*s]\n",
-			       "ippr_ftp_server_valid",
+			       "ipf_p_ftp_server_valid",
 			       ftps->ftps_junk, (int)len, (int)i,
 			       c, (int)len, (int)len, buf);
-		return 1;
+		if (ftps->ftps_junk == FTPXY_JUNK_CONT)
+			return FTPXY_JUNK_CONT;
+		return FTPXY_JUNK_BAD;
 	}
 search_eol:
 	for (; i; i--) {
@@ -933,22 +1236,31 @@
 		pc = c;
 		c = *s++;
 		if ((pc == '\r') && (c == '\n')) {
-			ftps->ftps_cmds = cmd;
-			return 0;
+			if (cmd == -1) {
+				if (ftps->ftps_junk == FTPXY_JUNK_CONT)
+					return FTPXY_JUNK_CONT;
+			} else {
+				ftps->ftps_cmd = cmd;
+			}
+			return FTPXY_JUNK_OK;
 		}
 	}
-	if (ippr_ftp_debug > 3)
-		printf("ippr_ftp_server_valid:junk after cmd[%*.*s]\n",
+
+	DT2(junk_eol, int, len, char *, buf);
+	if (softf->ipf_p_ftp_debug & DEBUG_PARSE_INFO)
+		printf("ipf_p_ftp_server_valid:junk after cmd[%*.*s]\n",
 		       (int)len, (int)len, buf);
-	return 2;
+	return FTPXY_JUNK_EOL;
 }
 
 
-int ippr_ftp_valid(ftp, side, buf, len)
-ftpinfo_t *ftp;
-int side;
-char *buf;
-size_t len;
+int
+ipf_p_ftp_valid(softf, ftp, side, buf, len)
+	ipf_ftp_softc_t *softf;
+	ftpinfo_t *ftp;
+	int side;
+	char *buf;
+	size_t len;
 {
 	ftpside_t *ftps;
 	int ret;
@@ -956,9 +1268,9 @@
 	ftps = &ftp->ftp_side[side];
 
 	if (side == 0)
-		ret = ippr_ftp_client_valid(ftps, buf, len);
+		ret = ipf_p_ftp_client_valid(softf, ftps, buf, len);
 	else
-		ret = ippr_ftp_server_valid(ftps, buf, len);
+		ret = ipf_p_ftp_server_valid(softf, ftps, buf, len);
 	return ret;
 }
 
@@ -971,13 +1283,15 @@
  * rv == 0 for inbound processing,
  * rv == 1 for outbound processing.
  */
-int ippr_ftp_process(fin, nat, ftp, rv)
-fr_info_t *fin;
-nat_t *nat;
-ftpinfo_t *ftp;
-int rv;
+int
+ipf_p_ftp_process(softf, fin, nat, ftp, rv)
+	ipf_ftp_softc_t *softf;
+	fr_info_t *fin;
+	nat_t *nat;
+	ftpinfo_t *ftp;
+	int rv;
 {
-	int mlen, len, off, inc, i, sel, sel2, ok, ackoff, seqoff;
+	int mlen, len, off, inc, i, sel, sel2, ok, ackoff, seqoff, retry;
 	char *rptr, *wptr, *s;
 	u_32_t thseq, thack;
 	ap_session_t *aps;
@@ -995,15 +1309,18 @@
 	t = &ftp->ftp_side[1 - rv];
 	thseq = ntohl(tcp->th_seq);
 	thack = ntohl(tcp->th_ack);
-
 #ifdef __sgi
 	mlen = fin->fin_plen - off;
 #else
 	mlen = MSGDSIZE(m) - off;
 #endif
-	if (ippr_ftp_debug > 4)
-		printf("ippr_ftp_process: mlen %d\n", mlen);
 
+	DT3(process_debug, tcphdr_t *, tcp, int, off, int, mlen);
+	if (softf->ipf_p_ftp_debug & DEBUG_INFO)
+		printf("ipf_p_ftp_process: %d:%d,%d, mlen %d flags %x\n",
+		       fin->fin_out, fin->fin_sport, fin->fin_dport,
+		       mlen, tcp->th_flags);
+
 	if ((mlen == 0) && ((tcp->th_flags & TH_OPENING) == TH_OPENING)) {
 		f->ftps_seq[0] = thseq + 1;
 		t->ftps_seq[0] = thack;
@@ -1016,7 +1333,7 @@
 
 	sel = aps->aps_sel[1 - rv];
 	sel2 = aps->aps_sel[rv];
-	if (rv == 0) {
+	if (rv == 1) {
 		seqoff = aps->aps_seqoff[sel];
 		if (aps->aps_seqmin[sel] > seqoff + thseq)
 			seqoff = aps->aps_seqoff[!sel];
@@ -1025,7 +1342,7 @@
 			ackoff = aps->aps_ackoff[!sel2];
 	} else {
 		seqoff = aps->aps_ackoff[sel];
-		if (ippr_ftp_debug > 2)
+		if (softf->ipf_p_ftp_debug & DEBUG_INFO)
 			printf("seqoff %d thseq %x ackmin %x\n", seqoff, thseq,
 			       aps->aps_ackmin[sel]);
 		if (aps->aps_ackmin[sel] > seqoff + thseq)
@@ -1032,7 +1349,7 @@
 			seqoff = aps->aps_ackoff[!sel];
 
 		ackoff = aps->aps_seqoff[sel2];
-		if (ippr_ftp_debug > 2)
+		if (softf->ipf_p_ftp_debug & DEBUG_INFO)
 			printf("ackoff %d thack %x seqmin %x\n", ackoff, thack,
 			       aps->aps_seqmin[sel2]);
 		if (ackoff > 0) {
@@ -1043,7 +1360,7 @@
 				ackoff = aps->aps_seqoff[!sel2];
 		}
 	}
-	if (ippr_ftp_debug > 2) {
+	if (softf->ipf_p_ftp_debug & DEBUG_INFO) {
 		printf("%s: %x seq %x/%d ack %x/%d len %d/%d off %d\n",
 		       rv ? "IN" : "OUT", tcp->th_flags, thseq, seqoff,
 		       thack, ackoff, mlen, fin->fin_plen, off);
@@ -1060,7 +1377,7 @@
 	 * that it is out of order (and there is no real danger in doing so
 	 * apart from causing packets to go through here ordered).
 	 */
-	if (ippr_ftp_debug > 2) {
+	if (softf->ipf_p_ftp_debug & DEBUG_INFO) {
 		printf("rv %d t:seq[0] %x seq[1] %x %d/%d\n",
 		       rv, t->ftps_seq[0], t->ftps_seq[1], seqoff, ackoff);
 	}
@@ -1078,37 +1395,44 @@
 				ok = 1;
 			}
 		} else {
-			if (t->ftps_seq[0] + ackoff == thack)
+			if (t->ftps_seq[0] + ackoff == thack) {
+				t->ftps_seq[0] = thack;
 				ok = 1;
-			else if (t->ftps_seq[0] == thack + ackoff)
+			} else if (t->ftps_seq[0] == thack + ackoff) {
+				t->ftps_seq[0] = thack + ackoff;
 				ok = 1;
-			else if (t->ftps_seq[1] + ackoff == thack) {
-				t->ftps_seq[0] = thack - ackoff;
+			} else if (t->ftps_seq[1] + ackoff == thack) {
+				t->ftps_seq[0] = thack;
 				ok = 1;
 			} else if (t->ftps_seq[1] == thack + ackoff) {
-				t->ftps_seq[0] = thack - ackoff;
+				t->ftps_seq[0] = thack + ackoff;
 				ok = 1;
 			}
 		}
 	}
 
-	if (ippr_ftp_debug > 2) {
+	if (softf->ipf_p_ftp_debug & DEBUG_INFO) {
 		if (!ok)
 			printf("%s ok\n", "not");
 	}
 
 	if (!mlen) {
-		if (t->ftps_seq[0] + ackoff != thack) {
-			if (ippr_ftp_debug > 1) {
-				printf("%s:seq[0](%x) + (%x) != (%x)\n",
-				       "ippr_ftp_process", t->ftps_seq[0],
+		if (t->ftps_seq[0] + ackoff != thack &&
+		    t->ftps_seq[1] + ackoff != thack) {
+			DT3(thack, ftpside_t *t, t, int, ackoff, u_32_t, thack);
+			if (softf->ipf_p_ftp_debug & DEBUG_ERROR) {
+				printf("%s:seq[0](%u) + (%d) != (%u)\n",
+				       "ipf_p_ftp_process", t->ftps_seq[0],
 				       ackoff, thack);
+				printf("%s:seq[0](%u) + (%d) != (%u)\n",
+				       "ipf_p_ftp_process", t->ftps_seq[1],
+				       ackoff, thack);
 			}
 			return APR_ERR(1);
 		}
 
-		if (ippr_ftp_debug > 2) {
-			printf("ippr_ftp_process:f:seq[0] %x seq[1] %x\n",
+		if (softf->ipf_p_ftp_debug & DEBUG_PARSE) {
+			printf("ipf_p_ftp_process:f:seq[0] %x seq[1] %x\n",
 				f->ftps_seq[0], f->ftps_seq[1]);
 		}
 
@@ -1117,9 +1441,10 @@
 				f->ftps_seq[0] = f->ftps_seq[1] - seqoff;
 				f->ftps_seq[1] = thseq + 1 - seqoff;
 			} else {
-				if (ippr_ftp_debug > 1) {
-					printf("FIN: thseq %x seqoff %d ftps_seq %x %x\n",
-					       thseq, seqoff, f->ftps_seq[0], f->ftps_seq[1]);
+				DT2(thseq, ftpside_t *t, t, u_32_t, thseq);
+				if (softf->ipf_p_ftp_debug & DEBUG_ERROR) {
+					printf("FIN: thseq %x seqoff %d ftps_seq %x\n",
+					       thseq, seqoff, f->ftps_seq[0]);
 				}
 				return APR_ERR(1);
 			}
@@ -1140,8 +1465,9 @@
 	}
 
 	if (ok == 0) {
+		DT3(ok_0, ftpside_t *, f, u_32_t, thseq, int, mlen);
 		inc = thseq - f->ftps_seq[0];
-		if (ippr_ftp_debug > 1) {
+		if (softf->ipf_p_ftp_debug & DEBUG_ERROR) {
 			printf("inc %d sel %d rv %d\n", inc, sel, rv);
 			printf("th_seq %x ftps_seq %x/%x\n",
 			       thseq, f->ftps_seq[0], f->ftps_seq[1]);
@@ -1163,68 +1489,69 @@
 
 	while (mlen > 0) {
 		len = MIN(mlen, sizeof(f->ftps_buf) - (wptr - rptr));
+		if (len == 0)
+			break;
 		COPYDATA(m, off, len, wptr);
 		mlen -= len;
 		off += len;
 		wptr += len;
 
-		if (ippr_ftp_debug > 3)
+whilemore:
+		if (softf->ipf_p_ftp_debug & DEBUG_PARSE)
 			printf("%s:len %d/%d off %d wptr %lx junk %d [%*.*s]\n",
-			       "ippr_ftp_process",
+			       "ipf_p_ftp_process",
 			       len, mlen, off, (u_long)wptr, f->ftps_junk,
 			       len, len, rptr);
 
 		f->ftps_wptr = wptr;
-		if (f->ftps_junk != 0) {
+		if (f->ftps_junk != FTPXY_JUNK_OK) {
 			i = f->ftps_junk;
-			f->ftps_junk = ippr_ftp_valid(ftp, rv, rptr,
+			f->ftps_junk = ipf_p_ftp_valid(softf, ftp, rv, rptr,
 						      wptr - rptr);
+			DT2(junk_transit, int, i, int, f->ftps_junk);
 
-			if (ippr_ftp_debug > 5)
+			if (softf->ipf_p_ftp_debug & DEBUG_PARSE)
 				printf("%s:junk %d -> %d\n",
-				       "ippr_ftp_process", i, f->ftps_junk);
+				       "ipf_p_ftp_process", i, f->ftps_junk);
 
-			if (f->ftps_junk != 0) {
+			if (f->ftps_junk == FTPXY_JUNK_BAD) {
+				DT(buffer_full);
 				if (wptr - rptr == sizeof(f->ftps_buf)) {
-					if (ippr_ftp_debug > 4)
+					if (softf->ipf_p_ftp_debug &
+					    DEBUG_PARSE_INFO)
 						printf("%s:full buffer\n",
-						       "ippr_ftp_process");
+						       "ipf_p_ftp_process");
 					f->ftps_rptr = f->ftps_buf;
 					f->ftps_wptr = f->ftps_buf;
 					rptr = f->ftps_rptr;
 					wptr = f->ftps_wptr;
-					/*
-					 * Because we throw away data here that
-					 * we would otherwise parse, set the
-					 * junk flag to indicate just ignore
-					 * any data upto the next CRLF.
-					 */
-					f->ftps_junk = 1;
 					continue;
 				}
 			}
 		}
 
-		while ((f->ftps_junk == 0) && (wptr > rptr)) {
+		while ((f->ftps_junk == FTPXY_JUNK_OK) && (wptr > rptr)) {
 			len = wptr - rptr;
-			f->ftps_junk = ippr_ftp_valid(ftp, rv, rptr, len);
+			f->ftps_junk = ipf_p_ftp_valid(softf, ftp, rv,
+						       rptr, len);
 
-			if (ippr_ftp_debug > 3) {
+			if (softf->ipf_p_ftp_debug & DEBUG_PARSE) {
 				printf("%s=%d len %d rv %d ptr %lx/%lx ",
-				       "ippr_ftp_valid",
+				       "ipf_p_ftp_valid",
 				       f->ftps_junk, len, rv, (u_long)rptr,
 				       (u_long)wptr);
 				printf("buf [%*.*s]\n", len, len, rptr);
 			}
 
-			if (f->ftps_junk == 0) {
+			if (f->ftps_junk == FTPXY_JUNK_OK) {
+				f->ftps_cmds++;
 				f->ftps_rptr = rptr;
 				if (rv)
-					inc += ippr_ftp_server(fin, ip, nat,
-							       ftp, len);
+					inc += ipf_p_ftp_server(softf, fin, ip,
+								nat, ftp, len);
 				else
-					inc += ippr_ftp_client(fin, ip, nat,
-							       ftp, len);
+					inc += ipf_p_ftp_client(softf, fin, ip,
+								nat, ftp, len);
 				rptr = f->ftps_rptr;
 				wptr = f->ftps_wptr;
 			}
@@ -1234,21 +1561,25 @@
 		 * Off to a bad start so lets just forget about using the
 		 * ftp proxy for this connection.
 		 */
-		if ((f->ftps_cmds == 0) && (f->ftps_junk == 1)) {
+		if ((f->ftps_cmds == 0) && (f->ftps_junk == FTPXY_JUNK_BAD)) {
 			/* f->ftps_seq[1] += inc; */
 
-			if (ippr_ftp_debug > 1)
+			DT(ftp_junk_cmd);
+			if (softf->ipf_p_ftp_debug & DEBUG_ERROR)
 				printf("%s:cmds == 0 junk == 1\n",
-				       "ippr_ftp_process");
+				       "ipf_p_ftp_process");
 			return APR_ERR(2);
 		}
 
-		if ((f->ftps_junk != 0) && (rptr < wptr)) {
+		retry = 0;
+		if ((f->ftps_junk != FTPXY_JUNK_OK) && (rptr < wptr)) {
 			for (s = rptr; s < wptr; s++) {
 				if ((*s == '\r') && (s + 1 < wptr) &&
 				    (*(s + 1) == '\n')) {
 					rptr = s + 2;
-					f->ftps_junk = 0;
+					retry = 1;
+					if (f->ftps_junk != FTPXY_JUNK_CONT)
+						f->ftps_junk = FTPXY_JUNK_OK;
 					break;
 				}
 			}
@@ -1264,7 +1595,7 @@
 			 * current state.
 			 */
 			if (rptr > f->ftps_buf) {
-				bcopy(rptr, f->ftps_buf, len);
+				bcopy(rptr, f->ftps_buf, wptr - rptr);
 				wptr -= rptr - f->ftps_buf;
 				rptr = f->ftps_buf;
 			}
@@ -1271,12 +1602,14 @@
 		}
 		f->ftps_rptr = rptr;
 		f->ftps_wptr = wptr;
+		if (retry)
+			goto whilemore;
 	}
 
 	/* f->ftps_seq[1] += inc; */
 	if (tcp->th_flags & TH_FIN)
 		f->ftps_seq[1]++;
-	if (ippr_ftp_debug > 3) {
+	if (softf->ipf_p_ftp_debug & DEBUG_PARSE_INFO) {
 #ifdef __sgi
 		mlen = fin->fin_plen;
 #else
@@ -1293,11 +1626,14 @@
 }
 
 
-int ippr_ftp_out(fin, aps, nat)
-fr_info_t *fin;
-ap_session_t *aps;
-nat_t *nat;
+int
+ipf_p_ftp_out(arg, fin, aps, nat)
+	void *arg;
+	fr_info_t *fin;
+	ap_session_t *aps;
+	nat_t *nat;
 {
+	ipf_ftp_softc_t *softf = arg;
 	ftpinfo_t *ftp;
 	int rev;
 
@@ -1309,15 +1645,18 @@
 	if (ftp->ftp_side[1 - rev].ftps_ifp == NULL)
 		ftp->ftp_side[1 - rev].ftps_ifp = fin->fin_ifp;
 
-	return ippr_ftp_process(fin, nat, ftp, rev);
+	return ipf_p_ftp_process(softf, fin, nat, ftp, rev);
 }
 
 
-int ippr_ftp_in(fin, aps, nat)
-fr_info_t *fin;
-ap_session_t *aps;
-nat_t *nat;
+int
+ipf_p_ftp_in(arg, fin, aps, nat)
+	void *arg;
+	fr_info_t *fin;
+	ap_session_t *aps;
+	nat_t *nat;
 {
+	ipf_ftp_softc_t *softf = arg;
 	ftpinfo_t *ftp;
 	int rev;
 
@@ -1329,18 +1668,19 @@
 	if (ftp->ftp_side[rev].ftps_ifp == NULL)
 		ftp->ftp_side[rev].ftps_ifp = fin->fin_ifp;
 
-	return ippr_ftp_process(fin, nat, ftp, 1 - rev);
+	return ipf_p_ftp_process(softf, fin, nat, ftp, 1 - rev);
 }
 
 
 /*
- * ippr_ftp_atoi - implement a version of atoi which processes numbers in
+ * ipf_p_ftp_atoi - implement a version of atoi which processes numbers in
  * pairs separated by commas (which are expected to be in the range 0 - 255),
  * returning a 16 bit number combining either side of the , as the MSB and
  * LSB.
  */
-u_short ippr_ftp_atoi(ptr)
-char **ptr;
+u_short
+ipf_p_ftp_atoi(ptr)
+	char **ptr;
 {
 	register char *s = *ptr, c;
 	register u_char i = 0, j = 0;
@@ -1364,26 +1704,237 @@
 }
 
 
-int ippr_ftp_epsv(fin, ip, nat, f, dlen)
-fr_info_t *fin;
-ip_t *ip;
-nat_t *nat;
-ftpside_t *f;
-int dlen;
+int
+ipf_p_ftp_eprt(softf, fin, ip, nat, ftp, dlen)
+	ipf_ftp_softc_t *softf;
+	fr_info_t *fin;
+	ip_t *ip;
+	nat_t *nat;
+	ftpinfo_t *ftp;
+	int dlen;
 {
+	ftpside_t *f;
+
+	/*
+	 * Check for client sending out EPRT message.
+	 */
+	if (dlen < IPF_MINEPRTLEN) {
+		DT1(epert_dlen, int, dlen);
+		if (softf->ipf_p_ftp_debug & DEBUG_PARSE_ERR)
+			printf("ipf_p_ftp_eprt:dlen(%d) < IPF_MINEPRTLEN\n",
+				dlen);
+		return 0;
+	}
+
+	/*
+	 * Parse the EPRT command.  Format is:
+	 * "EPRT |1|1.2.3.4|2000|" for IPv4 and
+	 * "EPRT |2|ef00::1:2|2000|" for IPv6
+	 */
+	f = &ftp->ftp_side[0];
+	if (f->ftps_rptr[5] != '|')
+		return 0;
+	if (f->ftps_rptr[5] == f->ftps_rptr[7]) {
+		if (f->ftps_rptr[6] == '1' && nat->nat_v[0] == 4)
+			return ipf_p_ftp_eprt4(softf, fin, ip, nat, ftp, dlen);
+#ifdef USE_INET6
+		if (f->ftps_rptr[6] == '2' && nat->nat_v[0] == 6)
+			return ipf_p_ftp_eprt6(softf, fin, ip, nat, ftp, dlen);
+#endif
+	}
+	return 0;
+}
+
+
+int
+ipf_p_ftp_eprt4(softf, fin, ip, nat, ftp, dlen)
+	ipf_ftp_softc_t *softf;
+	fr_info_t *fin;
+	ip_t *ip;
+	nat_t *nat;
+	ftpinfo_t *ftp;
+	int dlen;
+{
+	int a1, a2, a3, a4, port, olen, nlen, inc, off;
 	char newbuf[IPF_FTPBUFSZ];
+	char *s, c, delim;
+	u_32_t addr, i;
+	tcphdr_t *tcp;
+	ftpside_t *f;
+	mb_t *m;
+
+	m = fin->fin_m;
+	tcp = (tcphdr_t *)fin->fin_dp;
+	off = (char *)tcp - (char *)ip + (TCP_OFF(tcp) << 2) + fin->fin_ipoff;
+	f = &ftp->ftp_side[0];
+	delim = f->ftps_rptr[5];
+	s = f->ftps_rptr + 8;
+
+	/*
+	 * get the IP address.
+	 */
+	i = 0;
+	while (((c = *s++) != '\0') && ISDIGIT(c)) {
+		i *= 10;
+		i += c - '0';
+	}
+	if (i > 255)
+		return 0;
+	if (c != '.')
+		return 0;
+	addr = (i << 24);
+
+	i = 0;
+	while (((c = *s++) != '\0') && ISDIGIT(c)) {
+		i *= 10;
+		i += c - '0';
+	}
+	if (i > 255)
+		return 0;
+	if (c != '.')
+		return 0;
+	addr |= (addr << 16);
+
+	i = 0;
+	while (((c = *s++) != '\0') && ISDIGIT(c)) {
+		i *= 10;
+		i += c - '0';
+	}
+	if (i > 255)
+		return 0;
+	if (c != '.')
+		return 0;
+	addr |= (addr << 8);
+
+	i = 0;
+	while (((c = *s++) != '\0') && ISDIGIT(c)) {
+		i *= 10;
+		i += c - '0';
+	}
+	if (i > 255)
+		return 0;
+	if (c != delim)
+		return 0;
+	addr |= addr;
+
+	/*
+	 * Get the port number
+	 */
+	i = 0;
+	while (((c = *s++) != '\0') && ISDIGIT(c)) {
+		i *= 10;
+		i += c - '0';
+	}
+	if (i > 65535)
+		return 0;
+	if (c != delim)
+		return 0;
+	port = i;
+
+	/*
+	 * Check for CR-LF at the end of the command string.
+	 */
+	if ((*s != '\r') || (*(s + 1) != '\n')) {
+		DT(eprt4_no_crlf);
+		if (softf->ipf_p_ftp_debug & DEBUG_PARSE_ERR)
+			printf("ipf_p_ftp_eprt4:missing %s\n", "cr-lf");
+		return 0;
+	}
+	s += 2;
+
+	/*
+	 * Calculate new address parts for PORT command
+	 */
+	if (nat->nat_dir == NAT_INBOUND)
+		a1 = ntohl(nat->nat_odstaddr);
+	else
+		a1 = ntohl(ip->ip_src.s_addr);
+	a2 = (a1 >> 16) & 0xff;
+	a3 = (a1 >> 8) & 0xff;
+	a4 = a1 & 0xff;
+	a1 >>= 24;
+	olen = s - f->ftps_rptr;
+	/* DO NOT change this to snprintf! */
+	/*
+	 * While we could force the use of | as a delimiter here, it makes
+	 * sense to preserve whatever character is being used by the systems
+	 * involved in the communication.
+	 */
+#if defined(SNPRINTF) && defined(_KERNEL)
+	SNPRINTF(newbuf, sizeof(newbuf), "%s %c1%c%u.%u.%u.%u%c%u%c\r\n",
+		 "EPRT", delim, delim, a1, a2, a3, a4, delim, port, delim);
+#else
+	(void) sprintf(newbuf, "%s %c1%c%u.%u.%u.%u%c%u%c\r\n",
+		       "EPRT", delim, delim, a1, a2, a3, a4, delim, port,
+			delim);
+#endif
+
+	nlen = strlen(newbuf);
+	inc = nlen - olen;
+	if ((inc + fin->fin_plen) > 65535) {
+		DT2(eprt4_len, int, inc, int, fin->fin_plen);
+		if (softf->ipf_p_ftp_debug & DEBUG_ERROR)
+			printf("ipf_p_ftp_eprt4:inc(%d) + ip->ip_len > 65535\n",
+				inc);
+		return 0;
+	}
+
+	off = (char *)tcp - (char *)ip + (TCP_OFF(tcp) << 2) + fin->fin_ipoff;
+#if !defined(_KERNEL)
+	M_ADJ(m, inc);
+#else
+	if (inc < 0)
+		M_ADJ(m, inc);
+#endif
+	/* the mbuf chain will be extended if necessary by m_copyback() */
+	COPYBACK(m, off, nlen, newbuf);
+	fin->fin_flx |= FI_DOCKSUM;
+
+	if (inc != 0) {
+		fin->fin_plen += inc;
+		ip->ip_len = htons(fin->fin_plen);
+		fin->fin_dlen += inc;
+	}
+
+	f->ftps_cmd = FTPXY_C_EPRT;
+	return ipf_p_ftp_addport(softf, fin, ip, nat, ftp, dlen, port, inc);
+}
+
+
+int
+ipf_p_ftp_epsv(softf, fin, ip, nat, ftp, dlen)
+	ipf_ftp_softc_t *softf;
+	fr_info_t *fin;
+	ip_t *ip;
+	nat_t *nat;
+	ftpinfo_t *ftp;
+	int dlen;
+{
+	char newbuf[IPF_FTPBUFSZ];
+	u_short ap = 0;
+	ftpside_t *f;
 	char *s;
-	u_short ap = 0;
 
+	if ((softf->ipf_p_ftp_forcepasv != 0) &&
+	    (ftp->ftp_side[0].ftps_cmd != FTPXY_C_EPSV)) {
+		DT1(epsv_cmd, int, ftp->ftp_side[0].ftps_cmd);
+		if (softf->ipf_p_ftp_debug & DEBUG_PARSE_ERR)
+			printf("ipf_p_ftp_epsv:ftps_cmd(%d) != FTPXY_C_EPSV\n",
+			       ftp->ftp_side[0].ftps_cmd);
+		return 0;
+	}
+	f = &ftp->ftp_side[1];
+
 #define EPSV_REPLEN	33
 	/*
 	 * Check for EPSV reply message.
 	 */
-	if (dlen < IPF_MIN229LEN)
+	if (dlen < IPF_MIN229LEN) {
 		return (0);
-	else if (strncmp(f->ftps_rptr,
-			 "229 Entering Extended Passive Mode", EPSV_REPLEN))
+	} else if (strncmp(f->ftps_rptr,
+			 "229 Entering Extended Passive Mode", EPSV_REPLEN)) {
 		return (0);
+}
 
 	/*
 	 * Skip the EPSV command + space
@@ -1401,9 +1952,6 @@
 		ap += *s++ - '0';
 	}
 
-	if (!*s)
-		return 0;
-
 	if (*s == '|')
 		s++;
 	if (*s == ')')
@@ -1413,10 +1961,10 @@
 	/*
 	 * check for CR-LF at the end.
 	 */
-	if ((*s == '\r') && (*(s + 1) == '\n')) {
-		s += 2;
-	} else
+	if ((*s != '\r') || (*(s + 1) != '\n')) {
 		return 0;
+	}
+	s += 2;
 
 #if defined(SNPRINTF) && defined(_KERNEL)
 	SNPRINTF(newbuf, sizeof(newbuf), "%s (|||%u|)\r\n",
@@ -1426,6 +1974,218 @@
 		       "229 Entering Extended Passive Mode", ap);
 #endif
 
-	return ippr_ftp_pasvreply(fin, ip, nat, f, (u_int)ap, newbuf, s,
-				  ip->ip_src.s_addr);
+	return ipf_p_ftp_pasvreply(softf, fin, ip, nat, ftp, (u_int)ap,
+				   newbuf, s);
 }
+
+#ifdef USE_INET6
+int
+ipf_p_ftp_eprt6(softf, fin, ip, nat, ftp, dlen)
+	ipf_ftp_softc_t *softf;
+	fr_info_t *fin;
+	ip_t *ip;
+	nat_t *nat;
+	ftpinfo_t *ftp;
+	int dlen;
+{
+	int port, olen, nlen, inc, off, left, i;
+	char newbuf[IPF_FTPBUFSZ];
+	char *s, c;
+	i6addr_t addr, *a6;
+	tcphdr_t *tcp;
+	ip6_t *ip6;
+	char delim;
+	u_short whole;
+	u_short part;
+	ftpside_t *f;
+	u_short *t;
+	int fwd;
+	mb_t *m;
+	u_32_t a;
+
+	m = fin->fin_m;
+	ip6 = (ip6_t *)ip;
+	f = &ftp->ftp_side[0];
+	s = f->ftps_rptr + 8;
+	f = &ftp->ftp_side[0];
+	delim = f->ftps_rptr[5];
+	tcp = (tcphdr_t *)fin->fin_dp;
+	off = (char *)tcp - (char *)ip + (TCP_OFF(tcp) << 2) + fin->fin_ipoff;
+
+	addr.i6[0] = 0;
+	addr.i6[1] = 0;
+	addr.i6[2] = 0;
+	addr.i6[3] = 0;
+	/*
+	 * Parse an IPv6 address.
+	 * Go forward until either :: or | is found. If :: is found,
+	 * reverse direction. Direction change is performed to ease
+	 * parsing an unknown number of 0s in the middle.
+	 */
+	whole = 0;
+	t = (u_short *)&addr;
+	fwd = 1;
+	for (part = 0; (c = *s) != '\0'; ) {
+		if (c == delim) {
+			*t = htons((u_short)whole);
+			break;
+		}
+		if (c == ':') {
+			*t = part;
+			if (fwd) {
+				*t = htons((u_short)whole);
+				t++;
+			} else {
+				*t = htons((u_short)(whole >> 16));
+				t--;
+			}
+			whole = 0;
+			if (fwd == 1 && s[1] == ':') {
+				while (*s && *s != '|')
+					s++;
+				if ((c = *s) != delim)
+					break;
+				t = (u_short *)&addr.i6[3];
+				t++;
+				fwd = 0;
+			} else if (fwd == 0 && s[-1] == ':') {
+				break;
+			}
+		} else {
+			if (c >= '0' && c <= '9') {
+				c -= '0';
+			} else if (c >= 'a' && c <= 'f') {
+				c -= 'a' + 10;
+			} else if (c >= 'A' && c <= 'F') {
+				c -= 'A' + 10;
+			}
+			if (fwd) {
+				whole <<= 8;
+				whole |= c;
+			} else {
+				whole >>= 8;
+				whole |= ((u_32_t)c) << 24;
+			}
+		}
+		if (fwd)
+			s++;
+		else
+			s--;
+	}
+	if (c != ':' && c != delim)
+		return 0;
+
+	while (*s != '|')
+		s++;
+	s++;
+
+	/*
+	 * Get the port number
+	 */
+	i = 0;
+	while (((c = *s++) != '\0') && ISDIGIT(c)) {
+		i *= 10;
+		i += c - '0';
+	}
+	if (i > 65535)
+		return 0;
+	if (c != delim)
+		return 0;
+	port = (u_short)(i & 0xffff);
+
+	/*
+	 * Check for CR-LF at the end of the command string.
+	 */
+	if ((*s != '\r') || (*(s + 1) != '\n')) {
+		DT(eprt6_no_crlf);
+		if (softf->ipf_p_ftp_debug & DEBUG_PARSE_ERR)
+			printf("ipf_p_ftp_eprt6:missing %s\n", "cr-lf");
+		return 0;
+	}
+	s += 2;
+
+	/*
+	 * Calculate new address parts for PORT command
+	 */
+	a6 = (i6addr_t *)&ip6->ip6_src;
+	olen = s - f->ftps_rptr;
+	/* DO NOT change this to snprintf! */
+	/*
+	 * While we could force the use of | as a delimiter here, it makes
+	 * sense to preserve whatever character is being used by the systems
+	 * involved in the communication.
+	 */
+	s = newbuf;
+	left = sizeof(newbuf);
+#if defined(SNPRINTF) && defined(_KERNEL)
+	SNPRINTF(newbuf, left, "EPRT %c2%c", delim, delim);
+	left -= strlen(s) + 1;
+	s += strlen(s);
+	a = ntohl(a6->i6[0]);
+	SNPRINTF(s, left, "%x:%x:", a >> 16, a & 0xffff);
+	left -= strlen(s);
+	s += strlen(s);
+	a = ntohl(a6->i6[1]);
+	SNPRINTF(s, left, "%x:%x:", a >> 16, a & 0xffff);
+	left -= strlen(s);
+	s += strlen(s);
+	a = ntohl(a6->i6[2]);
+	SNPRINTF(s, left, "%x:%x:", a >> 16, a & 0xffff);
+	left -= strlen(s);
+	s += strlen(s);
+	a = ntohl(a6->i6[3]);
+	SNPRINTF(s, left, "%x:%x", a >> 16, a & 0xffff);
+	left -= strlen(s);
+	s += strlen(s);
+	SNPRINTF(s, left, "|%d|\r\n", port);
+#else
+	(void) sprintf(s, "EPRT %c2%c", delim, delim);
+	s += strlen(s);
+	a = ntohl(a6->i6[0]);
+	sprintf(s, "%x:%x:", a >> 16, a & 0xffff);
+	s += strlen(s);
+	a = ntohl(a6->i6[1]);
+	sprintf(s, "%x:%x:", a >> 16, a & 0xffff);
+	left -= strlen(s);
+	s += strlen(s);
+	a = ntohl(a6->i6[2]);
+	sprintf(s, "%x:%x:", a >> 16, a & 0xffff);
+	left -= strlen(s);
+	s += strlen(s);
+	a = ntohl(a6->i6[3]);
+	sprintf(s, "%x:%x", a >> 16, a & 0xffff);
+	left -= strlen(s);
+	s += strlen(s);
+	sprintf(s, "|%d|\r\n", port);
+#endif
+	nlen = strlen(newbuf);
+	inc = nlen - olen;
+	if ((inc + fin->fin_plen) > 65535) {
+		DT2(eprt6_len, int, inc, int, fin->fin_plen);
+		if (softf->ipf_p_ftp_debug & DEBUG_ERROR)
+			printf("ipf_p_ftp_eprt6:inc(%d) + ip->ip_len > 65535\n",
+				inc);
+		return 0;
+	}
+
+	off = (char *)tcp - (char *)ip + (TCP_OFF(tcp) << 2) + fin->fin_ipoff;
+#if !defined(_KERNEL)
+	M_ADJ(m, inc);
+#else
+	if (inc < 0)
+		M_ADJ(m, inc);
+#endif
+	/* the mbuf chain will be extended if necessary by m_copyback() */
+	COPYBACK(m, off, nlen, newbuf);
+	fin->fin_flx |= FI_DOCKSUM;
+
+	if (inc != 0) {
+		fin->fin_plen += inc;
+		ip6->ip6_plen = htons(fin->fin_plen - fin->fin_hlen);
+		fin->fin_dlen += inc;
+	}
+
+	f->ftps_cmd = FTPXY_C_EPRT;
+	return ipf_p_ftp_addport(softf, fin, ip, nat, ftp, dlen, port, inc);
+}
+#endif

Modified: trunk/sys/contrib/ipfilter/netinet/ip_htable.c
===================================================================
--- trunk/sys/contrib/ipfilter/netinet/ip_htable.c	2018-05-28 18:55:30 UTC (rev 10138)
+++ trunk/sys/contrib/ipfilter/netinet/ip_htable.c	2018-05-28 18:56:30 UTC (rev 10139)
@@ -1,7 +1,8 @@
-/*	$FreeBSD$	*/
+/* $MidnightBSD$ */
+/*	$FreeBSD: stable/10/sys/contrib/ipfilter/netinet/ip_htable.c 255332 2013-09-06 23:11:19Z cy $	*/
 
 /*
- * Copyright (C) 1993-2001, 2003 by Darren Reed.
+ * Copyright (C) 2012 by Darren Reed.
  *
  * See the IPFILTER.LICENCE file for details on licencing.
  */
@@ -41,7 +42,7 @@
 #if defined(_KERNEL)
 # include <sys/systm.h>
 #else
-# include <stdio.h>
+# include "ipf.h"
 #endif
 #include <netinet/in.h>
 #include <net/if.h>
@@ -53,63 +54,266 @@
 /* END OF INCLUDES */
 
 #if !defined(lint)
-static const char rcsid[] = "@(#)$Id: ip_htable.c,v 1.4 2013-01-08 01:31:40 laffer1 Exp $";
+static const char rcsid[] = "@(#)$Id$";
 #endif
 
-#ifdef	IPFILTER_LOOKUP
-static iphtent_t *fr_iphmfind __P((iphtable_t *, struct in_addr *));
-static	u_long	ipht_nomem[IPL_LOGSIZE] = { 0, 0, 0, 0, 0, 0, 0, 0 };
-static	u_long	ipf_nhtables[IPL_LOGSIZE] = { 0, 0, 0, 0, 0, 0, 0, 0 };
-static	u_long	ipf_nhtnodes[IPL_LOGSIZE] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+# ifdef USE_INET6
+static iphtent_t *ipf_iphmfind6 __P((iphtable_t *, i6addr_t *));
+# endif
+static iphtent_t *ipf_iphmfind __P((iphtable_t *, struct in_addr *));
+static int ipf_iphmfindip __P((ipf_main_softc_t *, void *, int, void *, u_int));
+static int ipf_htable_clear __P((ipf_main_softc_t *, void *, iphtable_t *));
+static int ipf_htable_create __P((ipf_main_softc_t *, void *, iplookupop_t *));
+static int ipf_htable_deref __P((ipf_main_softc_t *, void *, void *));
+static int ipf_htable_destroy __P((ipf_main_softc_t *, void *, int, char *));
+static void *ipf_htable_exists __P((void *, int, char *));
+static size_t ipf_htable_flush __P((ipf_main_softc_t *, void *,
+				    iplookupflush_t *));
+static void ipf_htable_free __P((void *, iphtable_t *));
+static int ipf_htable_iter_deref __P((ipf_main_softc_t *, void *, int,
+				      int, void *));
+static int ipf_htable_iter_next __P((ipf_main_softc_t *, void *, ipftoken_t *,
+				     ipflookupiter_t *));
+static int ipf_htable_node_add __P((ipf_main_softc_t *, void *,
+				    iplookupop_t *, int));
+static int ipf_htable_node_del __P((ipf_main_softc_t *, void *,
+				    iplookupop_t *, int));
+static int ipf_htable_remove __P((ipf_main_softc_t *, void *, iphtable_t *));
+static void *ipf_htable_soft_create __P((ipf_main_softc_t *));
+static void ipf_htable_soft_destroy __P((ipf_main_softc_t *, void *));
+static int ipf_htable_soft_init __P((ipf_main_softc_t *, void *));
+static void ipf_htable_soft_fini __P((ipf_main_softc_t *, void *));
+static int ipf_htable_stats_get __P((ipf_main_softc_t *, void *,
+				     iplookupop_t *));
+static int ipf_htable_table_add __P((ipf_main_softc_t *, void *,
+				     iplookupop_t *));
+static int ipf_htable_table_del __P((ipf_main_softc_t *, void *,
+				     iplookupop_t *));
+static int ipf_htent_deref __P((void *, iphtent_t *));
+static iphtent_t *ipf_htent_find __P((iphtable_t *, iphtent_t *));
+static int ipf_htent_insert __P((ipf_main_softc_t *, void *, iphtable_t *,
+				 iphtent_t *));
+static int ipf_htent_remove __P((ipf_main_softc_t *, void *, iphtable_t *,
+				 iphtent_t *));
+static void *ipf_htable_select_add_ref __P((void *, int, char *));
+static void ipf_htable_expire __P((ipf_main_softc_t *, void *));
 
-iphtable_t *ipf_htables[IPL_LOGSIZE] = { NULL, NULL, NULL, NULL,
-					 NULL, NULL, NULL, NULL };
 
+typedef struct ipf_htable_softc_s {
+	u_long		ipht_nomem[LOOKUP_POOL_SZ];
+	u_long		ipf_nhtables[LOOKUP_POOL_SZ];
+	u_long		ipf_nhtnodes[LOOKUP_POOL_SZ];
+	iphtable_t	*ipf_htables[LOOKUP_POOL_SZ];
+	iphtent_t	*ipf_node_explist;
+} ipf_htable_softc_t;
 
-void fr_htable_unload()
+ipf_lookup_t ipf_htable_backend = {
+	IPLT_HASH,
+	ipf_htable_soft_create,
+	ipf_htable_soft_destroy,
+	ipf_htable_soft_init,
+	ipf_htable_soft_fini,
+	ipf_iphmfindip,
+	ipf_htable_flush,
+	ipf_htable_iter_deref,
+	ipf_htable_iter_next,
+	ipf_htable_node_add,
+	ipf_htable_node_del,
+	ipf_htable_stats_get,
+	ipf_htable_table_add,
+	ipf_htable_table_del,
+	ipf_htable_deref,
+	ipf_htable_exists,
+	ipf_htable_select_add_ref,
+	NULL,
+	ipf_htable_expire,
+	NULL
+};
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_htable_soft_create                                      */
+/* Returns:     void *   - NULL = failure, else pointer to local context    */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*                                                                          */
+/* Initialise the routing table data structures where required.             */
+/* ------------------------------------------------------------------------ */
+static void *
+ipf_htable_soft_create(softc)
+	ipf_main_softc_t *softc;
 {
+	ipf_htable_softc_t *softh;
+
+	KMALLOC(softh, ipf_htable_softc_t *);
+	if (softh == NULL) {
+		IPFERROR(30026);
+		return NULL;
+	}
+
+	bzero((char *)softh, sizeof(*softh));
+
+	return softh;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_htable_soft_destroy                                     */
+/* Returns:     Nil                                                         */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              arg(I)   - pointer to local context to use                  */
+/*                                                                          */
+/* Clean up the pool by free'ing the radix tree associated with it and free */
+/* up the pool context too.                                                 */
+/* ------------------------------------------------------------------------ */
+static void
+ipf_htable_soft_destroy(softc, arg)
+	ipf_main_softc_t *softc;
+	void *arg;
+{
+	ipf_htable_softc_t *softh = arg;
+
+	KFREE(softh);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_htable_soft_init                                        */
+/* Returns:     int     - 0 = success, else error                           */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              arg(I)   - pointer to local context to use                  */
+/*                                                                          */
+/* Initialise the hash table ready for use.                                 */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_htable_soft_init(softc, arg)
+	ipf_main_softc_t *softc;
+	void *arg;
+{
+	ipf_htable_softc_t *softh = arg;
+
+	bzero((char *)softh, sizeof(*softh));
+
+	return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_htable_soft_fini                                        */
+/* Returns:     Nil                                                         */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              arg(I)   - pointer to local context to use                  */
+/* Locks:       WRITE(ipf_global)                                           */
+/*                                                                          */
+/* Clean up all the pool data structures allocated and call the cleanup     */
+/* function for the radix tree that supports the pools. ipf_pool_destroy is */
+/* used to delete the pools one by one to ensure they're properly freed up. */
+/* ------------------------------------------------------------------------ */
+static void
+ipf_htable_soft_fini(softc, arg)
+	ipf_main_softc_t *softc;
+	void *arg;
+{
 	iplookupflush_t fop;
 
+	fop.iplf_type = IPLT_HASH;
 	fop.iplf_unit = IPL_LOGALL;
-	(void)fr_flushhtable(&fop);
+	fop.iplf_arg = 0;
+	fop.iplf_count = 0;
+	*fop.iplf_name = '\0';
+	ipf_htable_flush(softc, arg, &fop);
 }
 
 
-int fr_gethtablestat(op)
-iplookupop_t *op;
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_htable_stats_get                                        */
+/* Returns:     int - 0 = success, else error                               */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              arg(I)   - pointer to local context to use                  */
+/*              op(I)    - pointer to lookup operation data                 */
+/*                                                                          */
+/* Copy the relevant statistics out of internal structures and into the     */
+/* structure used to export statistics.                                     */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_htable_stats_get(softc, arg, op)
+	ipf_main_softc_t *softc;
+	void *arg;
+	iplookupop_t *op;
 {
+	ipf_htable_softc_t *softh = arg;
 	iphtstat_t stats;
+	int err;
 
-	if (op->iplo_size != sizeof(stats))
+	if (op->iplo_size != sizeof(stats)) {
+		IPFERROR(30001);
 		return EINVAL;
+	}
 
-	stats.iphs_tables = ipf_htables[op->iplo_unit];
-	stats.iphs_numtables = ipf_nhtables[op->iplo_unit];
-	stats.iphs_numnodes = ipf_nhtnodes[op->iplo_unit];
-	stats.iphs_nomem = ipht_nomem[op->iplo_unit];
+	stats.iphs_tables = softh->ipf_htables[op->iplo_unit + 1];
+	stats.iphs_numtables = softh->ipf_nhtables[op->iplo_unit + 1];
+	stats.iphs_numnodes = softh->ipf_nhtnodes[op->iplo_unit + 1];
+	stats.iphs_nomem = softh->ipht_nomem[op->iplo_unit + 1];
 
-	return COPYOUT(&stats, op->iplo_struct, sizeof(stats));
+	err = COPYOUT(&stats, op->iplo_struct, sizeof(stats));
+	if (err != 0) {
+		IPFERROR(30013);
+		return EFAULT;
+	}
+	return 0;
 
 }
 
 
-/*
- * Create a new hash table using the template passed.
- */
-int fr_newhtable(op)
-iplookupop_t *op;
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_htable_create                                           */
+/* Returns:     int - 0 = success, else error                               */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              arg(I)   - pointer to local context to use                  */
+/*              op(I)    - pointer to lookup operation data                 */
+/*                                                                          */
+/* Create a new hash table using the template passed.                       */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_htable_create(softc, arg, op)
+	ipf_main_softc_t *softc;
+	void *arg;
+	iplookupop_t *op;
 {
-	iphtable_t *iph, *oiph;
+	ipf_htable_softc_t *softh = arg;
+	iphtable_t htab, *iph, *oiph;
 	char name[FR_GROUPLEN];
 	int err, i, unit;
 
+	if (op->iplo_size != sizeof(htab)) {
+		IPFERROR(30024);
+		return EINVAL;
+	}
+	err = COPYIN(op->iplo_struct, &htab, sizeof(htab));
+	if (err != 0) {
+		IPFERROR(30003);
+		return EFAULT;
+	}
+
 	unit = op->iplo_unit;
+	if (htab.iph_unit != unit) {
+		IPFERROR(30005);
+		return EINVAL;
+	}
+	if (htab.iph_size < 1) {
+		IPFERROR(30025);
+		return EINVAL;
+	}
+
+
 	if ((op->iplo_arg & IPHASH_ANON) == 0) {
-		iph = fr_existshtable(unit, op->iplo_name);
+		iph = ipf_htable_exists(softh, unit, op->iplo_name);
 		if (iph != NULL) {
-			if ((iph->iph_flags & IPHASH_DELETE) == 0)
+			if ((iph->iph_flags & IPHASH_DELETE) == 0) {
+				IPFERROR(30004);
 				return EEXIST;
+			}
 			iph->iph_flags &= ~IPHASH_DELETE;
+			iph->iph_ref++;
 			return 0;
 		}
 	}
@@ -116,20 +320,12 @@
 
 	KMALLOC(iph, iphtable_t *);
 	if (iph == NULL) {
-		ipht_nomem[op->iplo_unit]++;
+		softh->ipht_nomem[op->iplo_unit + 1]++;
+		IPFERROR(30002);
 		return ENOMEM;
 	}
-	err = COPYIN(op->iplo_struct, iph, sizeof(*iph));
-	if (err != 0) {
-		KFREE(iph);
-		return EFAULT;
-	}
+	*iph = htab;
 
-	if (iph->iph_unit != unit) {
-		KFREE(iph);
-		return EINVAL;
-	}
-
 	if ((op->iplo_arg & IPHASH_ANON) != 0) {
 		i = IPHASH_ANON;
 		do {
@@ -139,7 +335,7 @@
 #else
 			(void)sprintf(name, "%u", i);
 #endif
-			for (oiph = ipf_htables[unit]; oiph != NULL;
+			for (oiph = softh->ipf_htables[unit + 1]; oiph != NULL;
 			     oiph = oiph->iph_next)
 				if (strncmp(oiph->iph_name, name,
 					    sizeof(oiph->iph_name)) == 0)
@@ -149,6 +345,10 @@
 		(void)strncpy(iph->iph_name, name, sizeof(iph->iph_name));
 		(void)strncpy(op->iplo_name, name, sizeof(op->iplo_name));
 		iph->iph_type |= IPHASH_ANON;
+	} else {
+		(void)strncpy(iph->iph_name, op->iplo_name,
+			      sizeof(iph->iph_name));
+		iph->iph_name[sizeof(iph->iph_name) - 1] = '\0';
 	}
 
 	KMALLOCS(iph->iph_table, iphtent_t **,
@@ -155,71 +355,165 @@
 		 iph->iph_size * sizeof(*iph->iph_table));
 	if (iph->iph_table == NULL) {
 		KFREE(iph);
-		ipht_nomem[unit]++;
+		softh->ipht_nomem[unit + 1]++;
+		IPFERROR(30006);
 		return ENOMEM;
 	}
 
 	bzero((char *)iph->iph_table, iph->iph_size * sizeof(*iph->iph_table));
-	iph->iph_masks = 0;
-	iph->iph_list = NULL;
+	iph->iph_maskset[0] = 0;
+	iph->iph_maskset[1] = 0;
+	iph->iph_maskset[2] = 0;
+	iph->iph_maskset[3] = 0;
 
 	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]++;
+	iph->iph_list = NULL;
+	iph->iph_tail = &iph->iph_list;
+	iph->iph_next = softh->ipf_htables[unit + 1];
+	iph->iph_pnext = &softh->ipf_htables[unit + 1];
+	if (softh->ipf_htables[unit + 1] != NULL)
+		softh->ipf_htables[unit + 1]->iph_pnext = &iph->iph_next;
+	softh->ipf_htables[unit + 1] = iph;
 
+	softh->ipf_nhtables[unit + 1]++;
+
 	return 0;
 }
 
 
-/*
- */
-int fr_removehtable(unit, name)
-int unit;
-char *name;
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_htable_table_del                                        */
+/* Returns:     int      - 0 = success, else error                          */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              arg(I)   - pointer to local context to use                  */
+/*              op(I)    - pointer to lookup operation data                 */
+/*                                                                          */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_htable_table_del(softc, arg, op)
+	ipf_main_softc_t *softc;
+	void *arg;
+	iplookupop_t *op;
 {
+	return ipf_htable_destroy(softc, arg, op->iplo_unit, op->iplo_name);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_htable_destroy                                          */
+/* Returns:     int      - 0 = success, else error                          */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              arg(I)   - pointer to local context to use                  */
+/*              op(I)    - pointer to lookup operation data                 */
+/*                                                                          */
+/* Find the hash table that belongs to the relevant part of ipfilter with a */
+/* matching name and attempt to destroy it.  If it is in use, empty it out  */
+/* and mark it for deletion so that when all the references disappear, it   */
+/* can be removed.                                                          */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_htable_destroy(softc, arg, unit, name)
+	ipf_main_softc_t *softc;
+	void *arg;
+	int unit;
+	char *name;
+{
 	iphtable_t *iph;
 
-	iph = fr_findhtable(unit, name);
-	if (iph == NULL)
+	iph = ipf_htable_find(arg, unit, name);
+	if (iph == NULL) {
+		IPFERROR(30007);
 		return ESRCH;
+	}
 
 	if (iph->iph_unit != unit) {
+		IPFERROR(30008);
 		return EINVAL;
 	}
 
 	if (iph->iph_ref != 0) {
-		(void) fr_clearhtable(iph);
+		ipf_htable_clear(softc, arg, iph);
 		iph->iph_flags |= IPHASH_DELETE;
 		return 0;
 	}
 
-	fr_delhtable(iph);
+	ipf_htable_remove(softc, arg, iph);
 
 	return 0;
 }
 
 
-int fr_clearhtable(iph)
-iphtable_t *iph;
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_htable_clear                                            */
+/* Returns:     int      - 0 = success, else error                          */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              arg(I)   - pointer to local context to use                  */
+/*              iph(I)   - pointer to hash table to destroy                 */
+/*                                                                          */
+/* Clean out the hash table by walking the list of entries and removing     */
+/* each one, one by one.                                                    */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_htable_clear(softc, arg, iph)
+	ipf_main_softc_t *softc;
+	void *arg;
+	iphtable_t *iph;
 {
 	iphtent_t *ipe;
 
 	while ((ipe = iph->iph_list) != NULL)
-		if (fr_delhtent(iph, ipe) != 0)
+		if (ipf_htent_remove(softc, arg, iph, ipe) != 0)
 			return 1;
 	return 0;
 }
 
 
-int fr_delhtable(iph)
-iphtable_t *iph;
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_htable_free                                             */
+/* Returns:     Nil                                                         */
+/* Parameters:  arg(I) - pointer to local context to use                    */
+/*              iph(I) - pointer to hash table to destroy                   */
+/*                                                                          */
+/* ------------------------------------------------------------------------ */
+static void
+ipf_htable_free(arg, iph)
+	void *arg;
+	iphtable_t *iph;
 {
+	ipf_htable_softc_t *softh = arg;
 
-	if (fr_clearhtable(iph) != 0)
+	if (iph->iph_next != NULL)
+		iph->iph_next->iph_pnext = iph->iph_pnext;
+	if (iph->iph_pnext != NULL)
+		*iph->iph_pnext = iph->iph_next;
+	iph->iph_pnext = NULL;
+	iph->iph_next = NULL;
+
+	softh->ipf_nhtables[iph->iph_unit + 1]--;
+
+	KFREES(iph->iph_table, iph->iph_size * sizeof(*iph->iph_table));
+	KFREE(iph);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_htable_remove                                           */
+/* Returns:     int      - 0 = success, else error                          */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              arg(I)   - pointer to local context to use                  */
+/*              iph(I)   - pointer to hash table to destroy                 */
+/*                                                                          */
+/* It is necessary to unlink here as well as free (called by deref) so that */
+/* the while loop in ipf_htable_flush() functions properly.                 */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_htable_remove(softc, arg, iph)
+	ipf_main_softc_t *softc;
+	void *arg;
+	iphtable_t *iph;
+{
+
+	if (ipf_htable_clear(softc, arg, iph) != 0)
 		return 1;
 
 	if (iph->iph_pnext != NULL)
@@ -226,36 +520,141 @@
 		*iph->iph_pnext = iph->iph_next;
 	if (iph->iph_next != NULL)
 		iph->iph_next->iph_pnext = iph->iph_pnext;
+	iph->iph_pnext = NULL;
+	iph->iph_next = NULL;
 
-	ipf_nhtables[iph->iph_unit]--;
+	return ipf_htable_deref(softc, arg, iph);
+}
 
-	return fr_derefhtable(iph);
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_htable_node_del                                         */
+/* Returns:     int      - 0 = success, else error                          */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              arg(I)   - pointer to local context to use                  */
+/*              op(I)    - pointer to lookup operation data                 */
+/*              uid(I)   - real uid of process doing operation              */
+/*                                                                          */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_htable_node_del(softc, arg, op, uid)
+	ipf_main_softc_t *softc;
+	void *arg;
+	iplookupop_t *op;
+	int uid;
+{
+        iphtable_t *iph;
+        iphtent_t hte, *ent;
+	int err;
+
+	if (op->iplo_size != sizeof(hte)) {
+		IPFERROR(30014);
+		return EINVAL;
+	}
+
+	err = COPYIN(op->iplo_struct, &hte, sizeof(hte));
+	if (err != 0) {
+		IPFERROR(30015);
+		return EFAULT;
+	}
+
+	iph = ipf_htable_find(arg, op->iplo_unit, op->iplo_name);
+	if (iph == NULL) {
+		IPFERROR(30016);
+		return ESRCH;
+	}
+
+	ent = ipf_htent_find(iph, &hte);
+	if (ent == NULL) {
+		IPFERROR(30022);
+		return ESRCH;
+	}
+
+	if ((uid != 0) && (ent->ipe_uid != uid)) {
+		IPFERROR(30023);
+		return EACCES;
+	}
+
+	err = ipf_htent_remove(softc, arg, iph, ent);
+
+	return err;
 }
 
 
-/*
- * Delete an entry from a hash table.
- */
-int fr_delhtent(iph, ipe)
-iphtable_t *iph;
-iphtent_t *ipe;
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_htable_node_del                                         */
+/* Returns:     int      - 0 = success, else error                          */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              arg(I)   - pointer to local context to use                  */
+/*              op(I)    - pointer to lookup operation data                 */
+/*                                                                          */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_htable_table_add(softc, arg, op)
+	ipf_main_softc_t *softc;
+	void *arg;
+        iplookupop_t *op;
 {
+	int err;
 
+	if (ipf_htable_find(arg, op->iplo_unit, op->iplo_name) != NULL) {
+		IPFERROR(30017);
+		err = EEXIST;
+	} else {
+		err = ipf_htable_create(softc, arg, op);
+	}
+
+	return err;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_htent_remove                                            */
+/* Returns:     int      - 0 = success, else error                          */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              arg(I)   - pointer to local context to use                  */
+/*              iph(I)   - pointer to hash table                            */
+/*              ipe(I)   - pointer to hash table entry to remove            */
+/*                                                                          */
+/* Delete an entry from a hash table.                                       */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_htent_remove(softc, arg, iph, ipe)
+	ipf_main_softc_t *softc;
+	void *arg;
+	iphtable_t *iph;
+	iphtent_t *ipe;
+{
+
+	if (iph->iph_tail == &ipe->ipe_next)
+		iph->iph_tail = ipe->ipe_pnext;
+
+	if (ipe->ipe_hnext != NULL)
+		ipe->ipe_hnext->ipe_phnext = ipe->ipe_phnext;
 	if (ipe->ipe_phnext != NULL)
 		*ipe->ipe_phnext = ipe->ipe_hnext;
-	if (ipe->ipe_hnext != NULL)
-		ipe->ipe_hnext->ipe_phnext = ipe->ipe_phnext;
+	ipe->ipe_phnext = NULL;
+	ipe->ipe_hnext = NULL;
 
+	if (ipe->ipe_dnext != NULL)
+		ipe->ipe_dnext->ipe_pdnext = ipe->ipe_pdnext;
+	if (ipe->ipe_pdnext != NULL)
+		*ipe->ipe_pdnext = ipe->ipe_dnext;
+	ipe->ipe_pdnext = NULL;
+	ipe->ipe_dnext = NULL;
+
+	if (ipe->ipe_next != NULL)
+		ipe->ipe_next->ipe_pnext = ipe->ipe_pnext;
 	if (ipe->ipe_pnext != NULL)
 		*ipe->ipe_pnext = ipe->ipe_next;
-	if (ipe->ipe_next != NULL)
-		ipe->ipe_next->ipe_pnext = ipe->ipe_pnext;
+	ipe->ipe_pnext = NULL;
+	ipe->ipe_next = NULL;
 
 	switch (iph->iph_type & ~IPHASH_ANON)
 	{
 	case IPHASH_GROUPMAP :
 		if (ipe->ipe_group != NULL)
-			fr_delgroup(ipe->ipe_group, IPL_LOGIPF, fr_active);
+			ipf_group_del(softc, ipe->ipe_ptr, NULL);
 		break;
 
 	default :
@@ -264,13 +663,25 @@
 		break;
 	}
 
-	return fr_derefhtent(ipe);
+	return ipf_htent_deref(arg, ipe);
 }
 
 
-int fr_derefhtable(iph)
-iphtable_t *iph;
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_htable_deref                                            */
+/* Returns:     int       - 0 = success, else error                         */
+/* Parameters:  softc(I)  - pointer to soft context main structure          */
+/*              arg(I)    - pointer to local context to use                 */
+/*              object(I) - pointer to hash table                           */
+/*                                                                          */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_htable_deref(softc, arg, object)
+	ipf_main_softc_t *softc;
+	void *arg, *object;
 {
+	ipf_htable_softc_t *softh = arg;
+	iphtable_t *iph = object;
 	int refs;
 
 	iph->iph_ref--;
@@ -277,8 +688,7 @@
 	refs = iph->iph_ref;
 
 	if (iph->iph_ref == 0) {
-		KFREES(iph->iph_table, iph->iph_size * sizeof(*iph->iph_table));
-		KFREE(iph);
+		ipf_htable_free(softh, iph);
 	}
 
 	return refs;
@@ -285,14 +695,22 @@
 }
 
 
-int fr_derefhtent(ipe)
-iphtent_t *ipe;
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_htent_deref                                             */
+/* Parameters:  arg(I) - pointer to local context to use                    */
+/*              ipe(I) -                                                    */
+/*                                                                          */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_htent_deref(arg, ipe)
+	void *arg;
+	iphtent_t *ipe;
 {
+	ipf_htable_softc_t *softh = arg;
 
 	ipe->ipe_ref--;
 	if (ipe->ipe_ref == 0) {
-		ipf_nhtnodes[ipe->ipe_unit]--;
-
+		softh->ipf_nhtnodes[ipe->ipe_unit + 1]--;
 		KFREE(ipe);
 
 		return 0;
@@ -302,26 +720,87 @@
 }
 
 
-iphtable_t *fr_existshtable(unit, name)
-int unit;
-char *name;
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_htable_exists                                           */
+/* Parameters:  arg(I) - pointer to local context to use                    */
+/*                                                                          */
+/* ------------------------------------------------------------------------ */
+static void *
+ipf_htable_exists(arg, unit, name)
+	void *arg;
+	int unit;
+	char *name;
 {
+	ipf_htable_softc_t *softh = arg;
 	iphtable_t *iph;
 
-	for (iph = ipf_htables[unit]; iph != NULL; iph = iph->iph_next)
-		if (strncmp(iph->iph_name, name, sizeof(iph->iph_name)) == 0)
-			break;
+	if (unit == IPL_LOGALL) {
+		int i;
+
+		for (i = 0; i <= LOOKUP_POOL_MAX; i++) {
+			for (iph = softh->ipf_htables[i]; iph != NULL;
+			     iph = iph->iph_next) {
+				if (strncmp(iph->iph_name, name,
+					    sizeof(iph->iph_name)) == 0)
+					break;
+			}
+			if (iph != NULL)
+				break;
+		}
+	} else {
+		for (iph = softh->ipf_htables[unit + 1]; iph != NULL;
+		     iph = iph->iph_next) {
+			if (strncmp(iph->iph_name, name,
+				    sizeof(iph->iph_name)) == 0)
+				break;
+		}
+	}
 	return iph;
 }
 
 
-iphtable_t *fr_findhtable(unit, name)
-int unit;
-char *name;
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_htable_select_add_ref                                   */
+/* Returns:     void *  - NULL = failure, else pointer to the hash table    */
+/* Parameters:  arg(I)  - pointer to local context to use                   */
+/*              unit(I) - ipfilter device to which we are working on        */
+/*              name(I) - name of the hash table                            */
+/*                                                                          */
+/* ------------------------------------------------------------------------ */
+static void *
+ipf_htable_select_add_ref(arg, unit, name)
+	void *arg;
+	int unit;
+	char *name;
 {
 	iphtable_t *iph;
 
-	iph = fr_existshtable(unit, name);
+	iph = ipf_htable_exists(arg, unit, name);
+	if (iph != NULL) {
+		ATOMIC_INC32(iph->iph_ref);
+	}
+	return iph;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_htable_find                                             */
+/* Returns:     void *  - NULL = failure, else pointer to the hash table    */
+/* Parameters:  arg(I)  - pointer to local context to use                   */
+/*              unit(I) - ipfilter device to which we are working on        */
+/*              name(I) - name of the hash table                            */
+/*                                                                          */
+/* This function is exposed becaues it is used in the group-map feature.    */
+/* ------------------------------------------------------------------------ */
+iphtable_t *
+ipf_htable_find(arg, unit, name)
+	void *arg;
+	int unit;
+	char *name;
+{
+	iphtable_t *iph;
+
+	iph = ipf_htable_exists(arg, unit, name);
 	if ((iph != NULL) && (iph->iph_flags & IPHASH_DELETE) == 0)
 		return iph;
 
@@ -329,9 +808,21 @@
 }
 
 
-size_t fr_flushhtable(op)
-iplookupflush_t *op;
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_htable_flush                                            */
+/* Returns:     size_t   - number of entries flushed                        */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              arg(I)   - pointer to local context to use                  */
+/*              op(I)    - pointer to lookup operation data                 */
+/*                                                                          */
+/* ------------------------------------------------------------------------ */
+static size_t
+ipf_htable_flush(softc, arg, op)
+	ipf_main_softc_t *softc;
+	void *arg;
+	iplookupflush_t *op;
 {
+	ipf_htable_softc_t *softh = arg;
 	iphtable_t *iph;
 	size_t freed;
 	int i;
@@ -338,10 +829,10 @@
 
 	freed = 0;
 
-	for (i = 0; i <= IPL_LOGMAX; i++) {
+	for (i = -1; i <= IPL_LOGMAX; i++) {
 		if (op->iplf_unit == i || op->iplf_unit == IPL_LOGALL) {
-			while ((iph = ipf_htables[i]) != NULL) {
-				if (fr_delhtable(iph) == 0) {
+			while ((iph = softh->ipf_htables[i + 1]) != NULL) {
+				if (ipf_htable_remove(softc, arg, iph) == 0) {
 					freed++;
 				} else {
 					iph->iph_flags |= IPHASH_DELETE;
@@ -354,13 +845,73 @@
 }
 
 
-/*
- * Add an entry to a hash table.
- */
-int fr_addhtent(iph, ipeo)
-iphtable_t *iph;
-iphtent_t *ipeo;
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_htable_node_add                                         */
+/* Returns:     int      - 0 = success, else error                          */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              arg(I)   - pointer to local context to use                  */
+/*              op(I)    - pointer to lookup operation data                 */
+/*              uid(I)   - real uid of process doing operation              */
+/*                                                                          */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_htable_node_add(softc, arg, op, uid)
+	ipf_main_softc_t *softc;
+	void *arg;
+	iplookupop_t *op;
+	int uid;
 {
+	iphtable_t *iph;
+	iphtent_t hte;
+	int err;
+
+	if (op->iplo_size != sizeof(hte)) {
+		IPFERROR(30018);
+		return EINVAL;
+	}
+
+	err = COPYIN(op->iplo_struct, &hte, sizeof(hte));
+	if (err != 0) {
+		IPFERROR(30019);
+		return EFAULT;
+	}
+	hte.ipe_uid = uid;
+
+	iph = ipf_htable_find(arg, op->iplo_unit, op->iplo_name);
+	if (iph == NULL) {
+		IPFERROR(30020);
+		return ESRCH;
+	}
+
+	if (ipf_htent_find(iph, &hte) != NULL) {
+		IPFERROR(30021);
+		return EEXIST;
+	}
+
+	err = ipf_htent_insert(softc, arg, iph, &hte);
+
+	return err;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_htent_insert                                            */
+/* Returns:     int      - 0 = success, -1 =  error                         */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              arg(I)   - pointer to local context to use                  */
+/*              op(I)    - pointer to lookup operation data                 */
+/*              ipeo(I)  -                                                  */
+/*                                                                          */
+/* Add an entry to a hash table.                                            */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_htent_insert(softc, arg, iph, ipeo)
+	ipf_main_softc_t *softc;
+	void *arg;
+	iphtable_t *iph;
+	iphtent_t *ipeo;
+{
+	ipf_htable_softc_t *softh = arg;
 	iphtent_t *ipe;
 	u_int hv;
 	int bits;
@@ -370,13 +921,35 @@
 		return -1;
 
 	bcopy((char *)ipeo, (char *)ipe, sizeof(*ipe));
-	ipe->ipe_addr.in4_addr &= ipe->ipe_mask.in4_addr;
-	ipe->ipe_addr.in4_addr = ntohl(ipe->ipe_addr.in4_addr);
-	bits = count4bits(ipe->ipe_mask.in4_addr);
-	ipe->ipe_mask.in4_addr = ntohl(ipe->ipe_mask.in4_addr);
+	ipe->ipe_addr.i6[0] &= ipe->ipe_mask.i6[0];
+	if (ipe->ipe_family == AF_INET) {
+		bits = count4bits(ipe->ipe_mask.in4_addr);
+		ipe->ipe_addr.i6[1] = 0;
+		ipe->ipe_addr.i6[2] = 0;
+		ipe->ipe_addr.i6[3] = 0;
+		ipe->ipe_mask.i6[1] = 0;
+		ipe->ipe_mask.i6[2] = 0;
+		ipe->ipe_mask.i6[3] = 0;
+		hv = IPE_V4_HASH_FN(ipe->ipe_addr.in4_addr,
+				    ipe->ipe_mask.in4_addr, iph->iph_size);
+	} else
+#ifdef USE_INET6
+	if (ipe->ipe_family == AF_INET6) {
+		ipe->ipe_addr.i6[1] &= ipe->ipe_mask.i6[1];
+		ipe->ipe_addr.i6[2] &= ipe->ipe_mask.i6[2];
+		ipe->ipe_addr.i6[3] &= ipe->ipe_mask.i6[3];
 
-	hv = IPE_HASH_FN(ipe->ipe_addr.in4_addr, ipe->ipe_mask.in4_addr,
-			 iph->iph_size);
+		bits = count6bits(ipe->ipe_mask.i6);
+		hv = IPE_V6_HASH_FN(ipe->ipe_addr.i6,
+				    ipe->ipe_mask.i6, iph->iph_size);
+	} else
+#endif
+	{
+		KFREE(ipe);
+		return -1;
+	}
+
+	ipe->ipe_owner = iph;
 	ipe->ipe_ref = 1;
 	ipe->ipe_hnext = iph->iph_table[hv];
 	ipe->ipe_phnext = iph->iph_table + hv;
@@ -385,21 +958,63 @@
 		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;
+	ipe->ipe_pnext = iph->iph_tail;
+	*iph->iph_tail = ipe;
+	iph->iph_tail = &ipe->ipe_next;
+	ipe->ipe_next = NULL;
 
-	if ((bits >= 0) && (bits != 32))
-		iph->iph_masks |= 1 << bits;
+	if (ipe->ipe_die != 0) {
+		/*
+		 * If the new node has a given expiration time, insert it
+		 * into the list of expiring nodes with the ones to be
+		 * removed first added to the front of the list. The
+		 * insertion is O(n) but it is kept sorted for quick scans
+		 * at expiration interval checks.
+		 */
+		iphtent_t *n;
 
+		ipe->ipe_die = softc->ipf_ticks + IPF_TTLVAL(ipe->ipe_die);
+		for (n = softh->ipf_node_explist; n != NULL; n = n->ipe_dnext) {
+			if (ipe->ipe_die < n->ipe_die)
+				break;
+			if (n->ipe_dnext == NULL) {
+				/*
+				 * We've got to the last node and everything
+				 * wanted to be expired before this new node,
+				 * so we have to tack it on the end...
+				 */
+				n->ipe_dnext = ipe;
+				ipe->ipe_pdnext = &n->ipe_dnext;
+				n = NULL;
+				break;
+			}
+		}
+
+		if (softh->ipf_node_explist == NULL) {
+			softh->ipf_node_explist = ipe;
+			ipe->ipe_pdnext = &softh->ipf_node_explist;
+		} else if (n != NULL) {
+			ipe->ipe_dnext = n;
+			ipe->ipe_pdnext = n->ipe_pdnext;
+			n->ipe_pdnext = &ipe->ipe_dnext;
+		}
+	}
+
+	if (ipe->ipe_family == AF_INET) {
+		ipf_inet_mask_add(bits, &iph->iph_v4_masks);
+	}
+#ifdef USE_INET6
+	else if (ipe->ipe_family == AF_INET6) {
+		ipf_inet6_mask_add(bits, &ipe->ipe_mask, &iph->iph_v6_masks);
+	}
+#endif
+
 	switch (iph->iph_type & ~IPHASH_ANON)
 	{
 	case IPHASH_GROUPMAP :
-		ipe->ipe_ptr = fr_addgroup(ipe->ipe_group, NULL,
+		ipe->ipe_ptr = ipf_group_add(softc, ipe->ipe_group, NULL,
 					   iph->iph_flags, IPL_LOGIPF,
-					   fr_active);
+					   softc->ipf_active);
 		break;
 
 	default :
@@ -409,46 +1024,123 @@
 	}
 
 	ipe->ipe_unit = iph->iph_unit;
-	ipf_nhtnodes[ipe->ipe_unit]++;
+	softh->ipf_nhtnodes[ipe->ipe_unit + 1]++;
 
 	return 0;
 }
 
 
-void *fr_iphmfindgroup(tptr, aptr)
-void *tptr, *aptr;
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_htent_find                                              */
+/* Returns:     int     - 0 = success, else error                           */
+/* Parameters:  iph(I)  - pointer to table to search                        */
+/*              ipeo(I) - pointer to entry to find                          */
+/*                                                                          */
+/* While it isn't absolutely necessary to for the address and mask to be    */
+/* passed in through an iphtent_t structure, one is always present when it  */
+/* is time to call this function, so it is just more convenient.            */
+/* ------------------------------------------------------------------------ */
+static iphtent_t *
+ipf_htent_find(iph, ipeo)
+	iphtable_t *iph;
+	iphtent_t *ipeo;
 {
+	iphtent_t ipe, *ent;
+	u_int hv;
+	int bits;
+
+	bcopy((char *)ipeo, (char *)&ipe, sizeof(ipe));
+	ipe.ipe_addr.i6[0] &= ipe.ipe_mask.i6[0];
+	ipe.ipe_addr.i6[1] &= ipe.ipe_mask.i6[1];
+	ipe.ipe_addr.i6[2] &= ipe.ipe_mask.i6[2];
+	ipe.ipe_addr.i6[3] &= ipe.ipe_mask.i6[3];
+	if (ipe.ipe_family == AF_INET) {
+		bits = count4bits(ipe.ipe_mask.in4_addr);
+		ipe.ipe_addr.i6[1] = 0;
+		ipe.ipe_addr.i6[2] = 0;
+		ipe.ipe_addr.i6[3] = 0;
+		ipe.ipe_mask.i6[1] = 0;
+		ipe.ipe_mask.i6[2] = 0;
+		ipe.ipe_mask.i6[3] = 0;
+		hv = IPE_V4_HASH_FN(ipe.ipe_addr.in4_addr,
+				    ipe.ipe_mask.in4_addr, iph->iph_size);
+	} else
+#ifdef USE_INET6
+	if (ipe.ipe_family == AF_INET6) {
+		bits = count6bits(ipe.ipe_mask.i6);
+		hv = IPE_V6_HASH_FN(ipe.ipe_addr.i6,
+				    ipe.ipe_mask.i6, iph->iph_size);
+	} else
+#endif
+		return NULL;
+
+	for (ent = iph->iph_table[hv]; ent != NULL; ent = ent->ipe_hnext) {
+		if (ent->ipe_family != ipe.ipe_family)
+			continue;
+		if (IP6_NEQ(&ipe.ipe_addr, &ent->ipe_addr))
+			continue;
+		if (IP6_NEQ(&ipe.ipe_mask, &ent->ipe_mask))
+			continue;
+		break;
+	}
+
+	return ent;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_iphmfindgroup                                           */
+/* Returns:     int      - 0 = success, else error                          */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              tptr(I)  -                                                  */
+/*              aptr(I)  -                                                  */
+/*                                                                          */
+/* Search a hash table for a matching entry and return the pointer stored   */
+/* in it for use as the next group of rules to search.                      */
+/*                                                                          */
+/* This function is exposed becaues it is used in the group-map feature.    */
+/* ------------------------------------------------------------------------ */
+void *
+ipf_iphmfindgroup(softc, tptr, aptr)
+	ipf_main_softc_t *softc;
+	void *tptr, *aptr;
+{
 	struct in_addr *addr;
 	iphtable_t *iph;
 	iphtent_t *ipe;
 	void *rval;
 
-	READ_ENTER(&ip_poolrw);
+	READ_ENTER(&softc->ipf_poolrw);
 	iph = tptr;
 	addr = aptr;
 
-	ipe = fr_iphmfind(iph, addr);
+	ipe = ipf_iphmfind(iph, addr);
 	if (ipe != NULL)
 		rval = ipe->ipe_ptr;
 	else
 		rval = NULL;
-	RWLOCK_EXIT(&ip_poolrw);
+	RWLOCK_EXIT(&softc->ipf_poolrw);
 	return rval;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_iphmfindip                                               */
+/* Function:    ipf_iphmfindip                                              */
 /* Returns:     int     - 0 == +ve match, -1 == error, 1 == -ve/no match    */
-/* Parameters:  tptr(I)      - pointer to the pool to search                */
+/* Parameters:  softc(I)     - pointer to soft context main structure       */
+/*              tptr(I)      - pointer to the pool to search                */
 /*              ipversion(I) - IP protocol version (4 or 6)                 */
 /*              aptr(I)      - pointer to address information               */
+/*              bytes(I)     - packet length                                */
 /*                                                                          */
 /* Search the hash table for a given address and return a search result.    */
 /* ------------------------------------------------------------------------ */
-int fr_iphmfindip(tptr, ipversion, aptr)
-void *tptr, *aptr;
-int ipversion;
+static int
+ipf_iphmfindip(softc, tptr, ipversion, aptr, bytes)
+	ipf_main_softc_t *softc;
+	void *tptr, *aptr;
+	int ipversion;
+	u_int bytes;
 {
 	struct in_addr *addr;
 	iphtable_t *iph;
@@ -455,9 +1147,6 @@
 	iphtent_t *ipe;
 	int rval;
 
-	if (ipversion != 4)
-		return -1;
-
 	if (tptr == NULL || aptr == NULL)
 		return -1;
 
@@ -464,61 +1153,89 @@
 	iph = tptr;
 	addr = aptr;
 
-	READ_ENTER(&ip_poolrw);
-	ipe = fr_iphmfind(iph, addr);
-	if (ipe != NULL)
+	READ_ENTER(&softc->ipf_poolrw);
+	if (ipversion == 4) {
+		ipe = ipf_iphmfind(iph, addr);
+#ifdef USE_INET6
+	} else if (ipversion == 6) {
+		ipe = ipf_iphmfind6(iph, (i6addr_t *)addr);
+#endif
+	} else {
+		ipe = NULL;
+	}
+
+	if (ipe != NULL) {
 		rval = 0;
-	else
+		ipe->ipe_hits++;
+		ipe->ipe_bytes += bytes;
+	} else {
 		rval = 1;
-	RWLOCK_EXIT(&ip_poolrw);
+	}
+	RWLOCK_EXIT(&softc->ipf_poolrw);
 	return rval;
 }
 
 
-/* Locks:  ip_poolrw */
-static iphtent_t *fr_iphmfind(iph, addr)
-iphtable_t *iph;
-struct in_addr *addr;
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_iphmfindip                                              */
+/* Parameters:  iph(I)  - pointer to hash table                             */
+/*              addr(I) - pointer to IPv4 address                           */
+/* Locks:  ipf_poolrw                                                       */
+/*                                                                          */
+/* ------------------------------------------------------------------------ */
+static iphtent_t *
+ipf_iphmfind(iph, addr)
+	iphtable_t *iph;
+	struct in_addr *addr;
 {
-	u_32_t hmsk, msk, ips;
+	u_32_t msk, ips;
 	iphtent_t *ipe;
 	u_int hv;
+	int i;
 
-	hmsk = iph->iph_masks;
-	msk = 0xffffffff;
+	i = 0;
 maskloop:
-	ips = ntohl(addr->s_addr) & msk;
-	hv = IPE_HASH_FN(ips, msk, iph->iph_size);
+	msk = iph->iph_v4_masks.imt4_active[i];
+	ips = addr->s_addr & msk;
+	hv = IPE_V4_HASH_FN(ips, msk, iph->iph_size);
 	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) {
+		if ((ipe->ipe_family != AF_INET) ||
+		    (ipe->ipe_mask.in4_addr != msk) ||
+		    (ipe->ipe_addr.in4_addr != ips)) {
 			continue;
 		}
 		break;
 	}
 
-	if ((ipe == NULL) && (hmsk != 0)) {
-		while (hmsk != 0) {
-			msk <<= 1;
-			if (hmsk & 0x80000000)
-				break;
-			hmsk <<= 1;
-		}
-		if (hmsk != 0) {
-			hmsk <<= 1;
+	if (ipe == NULL) {
+		i++;
+		if (i < iph->iph_v4_masks.imt4_max)
 			goto maskloop;
-		}
 	}
 	return ipe;
 }
 
 
-int fr_htable_getnext(token, ilp)
-ipftoken_t *token;
-ipflookupiter_t *ilp;
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_htable_iter_next                                        */
+/* Returns:     int      - 0 = success, else error                          */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              arg(I)   - pointer to local context to use                  */
+/*              token(I) -                                                  */
+/*              ilp(I)   -                                                  */
+/*                                                                          */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_htable_iter_next(softc, arg, token, ilp)
+	ipf_main_softc_t *softc;
+	void *arg;
+	ipftoken_t *token;
+	ipflookupiter_t *ilp;
 {
+	ipf_htable_softc_t *softh = arg;
 	iphtent_t *node, zn, *nextnode;
 	iphtable_t *iph, zp, *nextiph;
+	void *hnext;
 	int err;
 
 	err = 0;
@@ -527,7 +1244,7 @@
 	nextiph = NULL;
 	nextnode = NULL;
 
-	READ_ENTER(&ip_poolrw);
+	READ_ENTER(&softc->ipf_poolrw);
 
 	switch (ilp->ili_otype)
 	{
@@ -534,7 +1251,7 @@
 	case IPFLOOKUPITER_LIST :
 		iph = token->ipt_data;
 		if (iph == NULL) {
-			nextiph = ipf_htables[(int)ilp->ili_unit];
+			nextiph = softh->ipf_htables[(int)ilp->ili_unit + 1];
 		} else {
 			nextiph = iph->iph_next;
 		}
@@ -547,15 +1264,18 @@
 			nextiph = &zp;
 			token->ipt_data = NULL;
 		}
+		hnext = nextiph->iph_next;
 		break;
 
 	case IPFLOOKUPITER_NODE :
 		node = token->ipt_data;
 		if (node == NULL) {
-			iph = fr_findhtable(ilp->ili_unit, ilp->ili_name);
-			if (iph == NULL)
+			iph = ipf_htable_find(arg, ilp->ili_unit,
+					      ilp->ili_name);
+			if (iph == NULL) {
+				IPFERROR(30009);
 				err = ESRCH;
-			else {
+			} else {
 				nextnode = iph->iph_list;
 			}
 		} else {
@@ -570,13 +1290,17 @@
 			nextnode = &zn;
 			token->ipt_data = NULL;
 		}
+		hnext = nextnode->ipe_next;
 		break;
+
 	default :
+		IPFERROR(30010);
 		err = EINVAL;
+		hnext = NULL;
 		break;
 	}
 
-	RWLOCK_EXIT(&ip_poolrw);
+	RWLOCK_EXIT(&softc->ipf_poolrw);
 	if (err != 0)
 		return err;
 
@@ -583,60 +1307,162 @@
 	switch (ilp->ili_otype)
 	{
 	case IPFLOOKUPITER_LIST :
+		err = COPYOUT(nextiph, ilp->ili_data, sizeof(*nextiph));
+		if (err != 0) {
+			IPFERROR(30011);
+			err = EFAULT;
+		}
 		if (iph != NULL) {
-			WRITE_ENTER(&ip_poolrw);
-			fr_derefhtable(iph);
-			RWLOCK_EXIT(&ip_poolrw);
+			WRITE_ENTER(&softc->ipf_poolrw);
+			ipf_htable_deref(softc, softh, iph);
+			RWLOCK_EXIT(&softc->ipf_poolrw);
 		}
-		err = COPYOUT(nextiph, ilp->ili_data, sizeof(*nextiph));
-		if (err != 0)
-			err = EFAULT;
 		break;
 
 	case IPFLOOKUPITER_NODE :
+		err = COPYOUT(nextnode, ilp->ili_data, sizeof(*nextnode));
+		if (err != 0) {
+			IPFERROR(30012);
+			err = EFAULT;
+		}
 		if (node != NULL) {
-			WRITE_ENTER(&ip_poolrw);
-			fr_derefhtent(node);
-			RWLOCK_EXIT(&ip_poolrw);
+			WRITE_ENTER(&softc->ipf_poolrw);
+			ipf_htent_deref(softc, node);
+			RWLOCK_EXIT(&softc->ipf_poolrw);
 		}
-		err = COPYOUT(nextnode, ilp->ili_data, sizeof(*nextnode));
-		if (err != 0)
-			err = EFAULT;
 		break;
 	}
 
+	if (hnext == NULL)
+		ipf_token_mark_complete(token);
+
 	return err;
 }
 
 
-void fr_htable_iterderef(otype, unit, data)
-u_int otype;
-int unit;
-void *data;
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_htable_iter_deref                                       */
+/* Returns:     int      - 0 = success, else  error                         */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              arg(I)   - pointer to local context to use                  */
+/*              otype(I) - which data structure type is being walked        */
+/*              unit(I)  - ipfilter device to which we are working on       */
+/*              data(I)  - pointer to old data structure                    */
+/*                                                                          */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_htable_iter_deref(softc, arg, otype, unit, data)
+	ipf_main_softc_t *softc;
+	void *arg;
+	int otype;
+	int unit;
+	void *data;
 {
 
 	if (data == NULL)
-		return;
+		return EFAULT;
 
-	if (unit < 0 || unit > IPL_LOGMAX)
-		return;
+	if (unit < -1 || unit > IPL_LOGMAX)
+		return EINVAL;
 
 	switch (otype)
 	{
 	case IPFLOOKUPITER_LIST :
-		WRITE_ENTER(&ip_poolrw);
-		fr_derefhtable((iphtable_t *)data);
-		RWLOCK_EXIT(&ip_poolrw);
+		ipf_htable_deref(softc, arg, (iphtable_t *)data);
 		break;
 
 	case IPFLOOKUPITER_NODE :
-		WRITE_ENTER(&ip_poolrw);
-		fr_derefhtent((iphtent_t *)data);
-		RWLOCK_EXIT(&ip_poolrw);
+		ipf_htent_deref(arg, (iphtent_t *)data);
 		break;
 	default :
 		break;
 	}
+
+	return 0;
 }
 
-#endif /* IPFILTER_LOOKUP */
+
+#ifdef USE_INET6
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_iphmfind6                                               */
+/* Parameters:  iph(I)  - pointer to hash table                             */
+/*              addr(I) - pointer to IPv6 address                           */
+/* Locks:  ipf_poolrw                                                       */
+/*                                                                          */
+/* ------------------------------------------------------------------------ */
+static iphtent_t *
+ipf_iphmfind6(iph, addr)
+	iphtable_t *iph;
+	i6addr_t *addr;
+{
+	i6addr_t *msk, ips;
+	iphtent_t *ipe;
+	u_int hv;
+	int i;
+
+	i = 0;
+maskloop:
+	msk = iph->iph_v6_masks.imt6_active + i;
+	ips.i6[0] = addr->i6[0] & msk->i6[0];
+	ips.i6[1] = addr->i6[1] & msk->i6[1];
+	ips.i6[2] = addr->i6[2] & msk->i6[2];
+	ips.i6[3] = addr->i6[3] & msk->i6[3];
+	hv = IPE_V6_HASH_FN(ips.i6, msk->i6, iph->iph_size);
+	for (ipe = iph->iph_table[hv]; (ipe != NULL); ipe = ipe->ipe_next) {
+		if ((ipe->ipe_family != AF_INET6) ||
+		    IP6_NEQ(&ipe->ipe_mask, msk) ||
+		    IP6_NEQ(&ipe->ipe_addr, &ips)) {
+			continue;
+		}
+		break;
+	}
+
+	if (ipe == NULL) {
+		i++;
+		if (i < iph->iph_v6_masks.imt6_max)
+			goto maskloop;
+	}
+	return ipe;
+}
+#endif
+
+
+static void
+ipf_htable_expire(softc, arg)
+	ipf_main_softc_t *softc;
+	void *arg;
+{
+	ipf_htable_softc_t *softh = arg;
+	iphtent_t *n;
+
+	while ((n = softh->ipf_node_explist) != NULL) {
+		if (n->ipe_die > softc->ipf_ticks)
+			break;
+
+		ipf_htent_remove(softc, softh, n->ipe_owner, n);
+	}
+}
+
+
+#ifndef _KERNEL
+
+/* ------------------------------------------------------------------------ */
+/*                                                                          */
+/* ------------------------------------------------------------------------ */
+void
+ipf_htable_dump(softc, arg)
+	ipf_main_softc_t *softc;
+	void *arg;
+{
+	ipf_htable_softc_t *softh = arg;
+	iphtable_t *iph;
+	int i;
+
+	printf("List of configured hash tables\n");
+	for (i = 0; i < IPL_LOGSIZE; i++)
+		for (iph = softh->ipf_htables[i]; iph != NULL;
+		     iph = iph->iph_next)
+			printhash(iph, bcopywrap, NULL, opts, NULL);
+
+}
+#endif

Modified: trunk/sys/contrib/ipfilter/netinet/ip_htable.h
===================================================================
--- trunk/sys/contrib/ipfilter/netinet/ip_htable.h	2018-05-28 18:55:30 UTC (rev 10138)
+++ trunk/sys/contrib/ipfilter/netinet/ip_htable.h	2018-05-28 18:56:30 UTC (rev 10139)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 #ifndef __IP_HTABLE_H__
 #define __IP_HTABLE_H__
 
@@ -6,29 +7,45 @@
 typedef	struct	iphtent_s	{
 	struct	iphtent_s	*ipe_next, **ipe_pnext;
 	struct	iphtent_s	*ipe_hnext, **ipe_phnext;
+	struct	iphtent_s	*ipe_dnext, **ipe_pdnext;
+	struct	iphtable_s	*ipe_owner;
 	void		*ipe_ptr;
 	i6addr_t	ipe_addr;
 	i6addr_t	ipe_mask;
+	U_QUAD_T	ipe_hits;
+	U_QUAD_T	ipe_bytes;
+	u_long		ipe_die;
+	int		ipe_uid;
 	int		ipe_ref;
 	int		ipe_unit;
+	char		ipe_family;
+	char		ipe_xxx[3];
 	union	{
 		char	ipeu_char[16];
 		u_long	ipeu_long;
 		u_int	ipeu_int;
-	}ipe_un;
+	} ipe_un;
 } iphtent_t;
 
 #define	ipe_value	ipe_un.ipeu_int
 #define	ipe_group	ipe_un.ipeu_char
 
-#define	IPE_HASH_FN(a, m, s)	(((a) * (m)) % (s))
+#define	IPE_V4_HASH_FN(a, m, s)	((((m) ^ (a)) - 1 - ((a) >> 8)) % (s))
+#define	IPE_V6_HASH_FN(a, m, s)	(((((m)[0] ^ (a)[0]) - ((a)[0] >> 8)) + \
+				  (((m)[1] & (a)[1]) - ((a)[1] >> 8)) + \
+				  (((m)[2] & (a)[2]) - ((a)[2] >> 8)) + \
+				  (((m)[3] & (a)[3]) - ((a)[3] >> 8))) % (s))
 
-
 typedef	struct	iphtable_s	{
 	ipfrwlock_t	iph_rwlock;
 	struct	iphtable_s	*iph_next, **iph_pnext;
 	struct	iphtent_s	**iph_table;
 	struct	iphtent_s	*iph_list;
+	struct	iphtent_s	**iph_tail;
+#ifdef USE_INET6
+	ipf_v6_masktab_t	iph_v6_masks;
+#endif
+	ipf_v4_masktab_t	iph_v4_masks;
 	size_t	iph_size;		/* size of hash table */
 	u_long	iph_seed;		/* hashing seed */
 	u_32_t	iph_flags;
@@ -35,7 +52,7 @@
 	u_int	iph_unit;		/* IPL_LOG* */
 	u_int	iph_ref;
 	u_int	iph_type;		/* lookup or group map  - IPHASH_* */
-	u_int	iph_masks;		/* IPv4 netmasks in use */
+	u_int	iph_maskset[4];		/* netmasks in use */
 	char	iph_name[FR_GROUPLEN];	/* hash table number */
 } iphtable_t;
 
@@ -55,24 +72,11 @@
 } iphtstat_t;
 
 
-extern iphtable_t *ipf_htables[IPL_LOGSIZE];
+extern void *ipf_iphmfindgroup __P((ipf_main_softc_t *, void *, void *));
+extern iphtable_t *ipf_htable_find __P((void *, int, char *));
+extern ipf_lookup_t ipf_htable_backend;
+#ifndef _KERNEL
+extern	void	ipf_htable_dump __P((ipf_main_softc_t *, void *));
+#endif
 
-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((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 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__ */

Modified: trunk/sys/contrib/ipfilter/netinet/ip_ipsec_pxy.c
===================================================================
--- trunk/sys/contrib/ipfilter/netinet/ip_ipsec_pxy.c	2018-05-28 18:55:30 UTC (rev 10138)
+++ trunk/sys/contrib/ipfilter/netinet/ip_ipsec_pxy.c	2018-05-28 18:56:30 UTC (rev 10139)
@@ -1,5 +1,6 @@
+/* $MidnightBSD$ */
 /*
- * Copyright (C) 2001-2003 by Darren Reed
+ * Copyright (C) 2012 by Darren Reed.
  *
  * See the IPFILTER.LICENCE file for details on licencing.
  *
@@ -6,75 +7,123 @@
  * Simple ISAKMP transparent proxy for in-kernel use.  For use with the NAT
  * code.
  *
- * $Id: ip_ipsec_pxy.c,v 1.2 2008-09-19 02:15:13 laffer1 Exp $
+ * $Id$
  *
  */
 #define	IPF_IPSEC_PROXY
 
 
-int ippr_ipsec_init __P((void));
-void ippr_ipsec_fini __P((void));
-int ippr_ipsec_new __P((fr_info_t *, ap_session_t *, nat_t *));
-void ippr_ipsec_del __P((ap_session_t *));
-int ippr_ipsec_inout __P((fr_info_t *, ap_session_t *, nat_t *));
-int ippr_ipsec_match __P((fr_info_t *, ap_session_t *, nat_t *));
+/*
+ * IPSec proxy
+ */
+typedef struct ipf_ipsec_softc_s {
+	frentry_t	ipsec_fr;
+	int		ipsec_proxy_init;
+	int		ipsec_proxy_ttl;
+	ipftq_t		*ipsec_nat_tqe;
+	ipftq_t		*ipsec_state_tqe;
+	char		ipsec_buffer[1500];
+} ipf_ipsec_softc_t;
 
-static	frentry_t	ipsecfr;
-static	ipftq_t		*ipsecnattqe;
-static	ipftq_t		*ipsecstatetqe;
-static	char	ipsec_buffer[1500];
 
-int	ipsec_proxy_init = 0;
-int	ipsec_proxy_ttl = 60;
+void *ipf_p_ipsec_soft_create __P((ipf_main_softc_t *));
+void ipf_p_ipsec_soft_destroy __P((ipf_main_softc_t *, void *));
+int ipf_p_ipsec_soft_init __P((ipf_main_softc_t *, void *));
+void ipf_p_ipsec_soft_fini __P((ipf_main_softc_t *, void *));
+int ipf_p_ipsec_init __P((void));
+void ipf_p_ipsec_fini __P((void));
+int ipf_p_ipsec_new __P((void *, fr_info_t *, ap_session_t *, nat_t *));
+void ipf_p_ipsec_del __P((ipf_main_softc_t *, ap_session_t *));
+int ipf_p_ipsec_inout __P((void *, fr_info_t *, ap_session_t *, nat_t *));
+int ipf_p_ipsec_match __P((fr_info_t *, ap_session_t *, nat_t *));
 
+
 /*
  * IPSec application proxy initialization.
  */
-int ippr_ipsec_init()
+void *
+ipf_p_ipsec_soft_create(softc)
+	ipf_main_softc_t *softc;
 {
-	bzero((char *)&ipsecfr, sizeof(ipsecfr));
-	ipsecfr.fr_ref = 1;
-	ipsecfr.fr_flags = FR_OUTQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE;
-	MUTEX_INIT(&ipsecfr.fr_lock, "IPsec proxy rule lock");
-	ipsec_proxy_init = 1;
+	ipf_ipsec_softc_t *softi;
 
-	ipsecnattqe = fr_addtimeoutqueue(&nat_utqe, ipsec_proxy_ttl);
-	if (ipsecnattqe == NULL)
+	KMALLOC(softi, ipf_ipsec_softc_t *);
+	if (softi == NULL)
+		return NULL;
+
+	bzero((char *)softi, sizeof(*softi));
+	softi->ipsec_fr.fr_ref = 1;
+	softi->ipsec_fr.fr_flags = FR_OUTQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE;
+	MUTEX_INIT(&softi->ipsec_fr.fr_lock, "IPsec proxy rule lock");
+	softi->ipsec_proxy_init = 1;
+	softi->ipsec_proxy_ttl = 60;
+
+	return softi;
+}
+
+
+int
+ipf_p_ipsec_soft_init(softc, arg)
+	ipf_main_softc_t *softc;
+	void *arg;
+{
+	ipf_ipsec_softc_t *softi = arg;
+
+	softi->ipsec_nat_tqe = ipf_state_add_tq(softc, softi->ipsec_proxy_ttl);
+	if (softi->ipsec_nat_tqe == NULL)
 		return -1;
-	ipsecstatetqe = fr_addtimeoutqueue(&ips_utqe, ipsec_proxy_ttl);
-	if (ipsecstatetqe == NULL) {
-		if (fr_deletetimeoutqueue(ipsecnattqe) == 0)
-			fr_freetimeoutqueue(ipsecnattqe);
-		ipsecnattqe = NULL;
+	softi->ipsec_state_tqe = ipf_nat_add_tq(softc, softi->ipsec_proxy_ttl);
+	if (softi->ipsec_state_tqe == NULL) {
+		if (ipf_deletetimeoutqueue(softi->ipsec_nat_tqe) == 0)
+			ipf_freetimeoutqueue(softc, softi->ipsec_nat_tqe);
+		softi->ipsec_nat_tqe = NULL;
 		return -1;
 	}
 
-	ipsecnattqe->ifq_flags |= IFQF_PROXY;
-	ipsecstatetqe->ifq_flags |= IFQF_PROXY;
-
-	ipsecfr.fr_age[0] = ipsec_proxy_ttl;
-	ipsecfr.fr_age[1] = ipsec_proxy_ttl;
+	softi->ipsec_nat_tqe->ifq_flags |= IFQF_PROXY;
+	softi->ipsec_state_tqe->ifq_flags |= IFQF_PROXY;
+	softi->ipsec_fr.fr_age[0] = softi->ipsec_proxy_ttl;
+	softi->ipsec_fr.fr_age[1] = softi->ipsec_proxy_ttl;
 	return 0;
 }
 
 
-void ippr_ipsec_fini()
+void
+ipf_p_ipsec_soft_fini(softc, arg)
+	ipf_main_softc_t *softc;
+	void *arg;
 {
-	if (ipsecnattqe != NULL) {
-		if (fr_deletetimeoutqueue(ipsecnattqe) == 0)
-			fr_freetimeoutqueue(ipsecnattqe);
+	ipf_ipsec_softc_t *softi = arg;
+
+	if (arg == NULL)
+		return;
+
+	if (softi->ipsec_nat_tqe != NULL) {
+		if (ipf_deletetimeoutqueue(softi->ipsec_nat_tqe) == 0)
+			ipf_freetimeoutqueue(softc, softi->ipsec_nat_tqe);
 	}
-	ipsecnattqe = NULL;
-	if (ipsecstatetqe != NULL) {
-		if (fr_deletetimeoutqueue(ipsecstatetqe) == 0)
-			fr_freetimeoutqueue(ipsecstatetqe);
+	softi->ipsec_nat_tqe = NULL;
+	if (softi->ipsec_state_tqe != NULL) {
+		if (ipf_deletetimeoutqueue(softi->ipsec_state_tqe) == 0)
+			ipf_freetimeoutqueue(softc, softi->ipsec_state_tqe);
 	}
-	ipsecstatetqe = NULL;
+	softi->ipsec_state_tqe = NULL;
+}
 
-	if (ipsec_proxy_init == 1) {
-		MUTEX_DESTROY(&ipsecfr.fr_lock);
-		ipsec_proxy_init = 0;
+
+void
+ipf_p_ipsec_soft_destroy(softc, arg)
+	ipf_main_softc_t *softc;
+	void *arg;
+{
+	ipf_ipsec_softc_t *softi = arg;
+
+	if (softi->ipsec_proxy_init == 1) {
+		MUTEX_DESTROY(&softi->ipsec_fr.fr_lock);
+		softi->ipsec_proxy_init = 0;
 	}
+
+	KFREE(softi);
 }
 
 
@@ -81,21 +130,32 @@
 /*
  * Setup for a new IPSEC proxy.
  */
-int ippr_ipsec_new(fin, aps, nat)
-fr_info_t *fin;
-ap_session_t *aps;
-nat_t *nat;
+int
+ipf_p_ipsec_new(arg, fin, aps, nat)
+	void *arg;
+	fr_info_t *fin;
+	ap_session_t *aps;
+	nat_t *nat;
 {
+	ipf_ipsec_softc_t *softi = arg;
+	ipf_main_softc_t *softc = fin->fin_main_soft;
+#ifdef USE_MUTEXES
+	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
+#endif
+	int p, off, dlen, ttl;
 	ipsec_pxy_t *ipsec;
+	ipnat_t *ipn, *np;
 	fr_info_t fi;
-	ipnat_t *ipn;
 	char *ptr;
-	int p, off, dlen, ttl;
+	int size;
+	ip_t *ip;
 	mb_t *m;
-	ip_t *ip;
 
+	if (fin->fin_v != 4)
+		return -1;
+
 	off = fin->fin_plen - fin->fin_dlen + fin->fin_ipoff;
-	bzero(ipsec_buffer, sizeof(ipsec_buffer));
+	bzero(softi->ipsec_buffer, sizeof(softi->ipsec_buffer));
 	ip = fin->fin_ip;
 	m = fin->fin_m;
 
@@ -102,19 +162,30 @@
 	dlen = M_LEN(m) - off;
 	if (dlen < 16)
 		return -1;
-	COPYDATA(m, off, MIN(sizeof(ipsec_buffer), dlen), ipsec_buffer);
+	COPYDATA(m, off, MIN(sizeof(softi->ipsec_buffer), dlen),
+		 softi->ipsec_buffer);
 
-	if (nat_outlookup(fin, 0, IPPROTO_ESP, nat->nat_inip,
+	if (ipf_nat_outlookup(fin, 0, IPPROTO_ESP, nat->nat_nsrcip,
 			  ip->ip_dst) != NULL)
 		return -1;
 
-	aps->aps_psiz = sizeof(*ipsec);
-	KMALLOCS(aps->aps_data, ipsec_pxy_t *, sizeof(*ipsec));
-	if (aps->aps_data == NULL)
+	np = nat->nat_ptr;
+	size = np->in_size;
+	KMALLOC(ipsec, ipsec_pxy_t *);
+	if (ipsec == NULL)
 		return -1;
 
-	ipsec = aps->aps_data;
+	KMALLOCS(ipn, ipnat_t *, size);
+	if (ipn == NULL) {
+		KFREE(ipsec);
+		return -1;
+	}
+
+	aps->aps_data = ipsec;
+	aps->aps_psiz = sizeof(*ipsec);
 	bzero((char *)ipsec, sizeof(*ipsec));
+	bzero((char *)ipn, size);
+	ipsec->ipsc_rule = ipn;
 
 	/*
 	 * Create NAT rule against which the tunnel/transport mapping is
@@ -121,32 +192,38 @@
 	 * created.  This is required because the current NAT rule does not
 	 * describe ESP but UDP instead.
 	 */
-	ipn = &ipsec->ipsc_rule;
-	ttl = IPF_TTLVAL(ipsecnattqe->ifq_ttl);
-	ipn->in_tqehead[0] = fr_addtimeoutqueue(&nat_utqe, ttl);
-	ipn->in_tqehead[1] = fr_addtimeoutqueue(&nat_utqe, ttl);
+	ipn->in_size = size;
+	ttl = IPF_TTLVAL(softi->ipsec_nat_tqe->ifq_ttl);
+	ipn->in_tqehead[0] = ipf_nat_add_tq(softc, ttl);
+	ipn->in_tqehead[1] = ipf_nat_add_tq(softc, ttl);
 	ipn->in_ifps[0] = fin->fin_ifp;
 	ipn->in_apr = NULL;
 	ipn->in_use = 1;
 	ipn->in_hits = 1;
-	ipn->in_nip = ntohl(nat->nat_outip.s_addr);
+	ipn->in_snip = ntohl(nat->nat_nsrcaddr);
 	ipn->in_ippip = 1;
-	ipn->in_inip = nat->nat_inip.s_addr;
-	ipn->in_inmsk = 0xffffffff;
-	ipn->in_outip = fin->fin_saddr;
-	ipn->in_outmsk = nat->nat_outip.s_addr;
-	ipn->in_srcip = fin->fin_saddr;
-	ipn->in_srcmsk = 0xffffffff;
+	ipn->in_osrcip = nat->nat_osrcip;
+	ipn->in_osrcmsk = 0xffffffff;
+	ipn->in_nsrcip = nat->nat_nsrcip;
+	ipn->in_nsrcmsk = 0xffffffff;
+	ipn->in_odstip = nat->nat_odstip;
+	ipn->in_odstmsk = 0xffffffff;
+	ipn->in_ndstip = nat->nat_ndstip;
+	ipn->in_ndstmsk = 0xffffffff;
 	ipn->in_redir = NAT_MAP;
-	bcopy(nat->nat_ptr->in_ifnames[0], ipn->in_ifnames[0],
-	      sizeof(ipn->in_ifnames[0]));
-	ipn->in_p = IPPROTO_ESP;
+	ipn->in_pr[0] = IPPROTO_ESP;
+	ipn->in_pr[1] = IPPROTO_ESP;
+	ipn->in_flags = (np->in_flags | IPN_PROXYRULE);
+	MUTEX_INIT(&ipn->in_lock, "IPSec proxy NAT rule");
 
+	ipn->in_namelen = np->in_namelen;
+	bcopy(np->in_names, ipn->in_ifnames, ipn->in_namelen);
+	ipn->in_ifnames[0] = np->in_ifnames[0];
+	ipn->in_ifnames[1] = np->in_ifnames[1];
+
 	bcopy((char *)fin, (char *)&fi, sizeof(fi));
-	fi.fin_state = NULL;
-	fi.fin_nat = NULL;
 	fi.fin_fi.fi_p = IPPROTO_ESP;
-	fi.fin_fr = &ipsecfr;
+	fi.fin_fr = &softi->ipsec_fr;
 	fi.fin_data[0] = 0;
 	fi.fin_data[1] = 0;
 	p = ip->ip_p;
@@ -154,7 +231,7 @@
 	fi.fin_flx &= ~(FI_TCPUDP|FI_STATE|FI_FRAG);
 	fi.fin_flx |= FI_IGNORE;
 
-	ptr = ipsec_buffer;
+	ptr = softi->ipsec_buffer;
 	bcopy(ptr, (char *)ipsec->ipsc_icookie, sizeof(ipsec_cookie_t));
 	ptr += sizeof(ipsec_cookie_t);
 	bcopy(ptr, (char *)ipsec->ipsc_rcookie, sizeof(ipsec_cookie_t));
@@ -166,18 +243,19 @@
 	if ((ipsec->ipsc_rcookie[0]|ipsec->ipsc_rcookie[1]) != 0)
 		ipsec->ipsc_rckset = 1;
 
-	ipsec->ipsc_nat = nat_new(&fi, ipn, &ipsec->ipsc_nat,
-				  NAT_SLAVE|SI_WILDP, NAT_OUTBOUND);
+	MUTEX_ENTER(&softn->ipf_nat_new);
+	ipsec->ipsc_nat = ipf_nat_add(&fi, ipn, &ipsec->ipsc_nat,
+				      NAT_SLAVE|SI_WILDP, NAT_OUTBOUND);
+	MUTEX_EXIT(&softn->ipf_nat_new);
 	if (ipsec->ipsc_nat != NULL) {
-		(void) nat_proto(&fi, ipsec->ipsc_nat, 0);
-		nat_update(&fi, ipsec->ipsc_nat, ipn);
+		(void) ipf_nat_proto(&fi, ipsec->ipsc_nat, 0);
+		MUTEX_ENTER(&ipsec->ipsc_nat->nat_lock);
+		ipf_nat_update(&fi, ipsec->ipsc_nat);
+		MUTEX_EXIT(&ipsec->ipsc_nat->nat_lock);
 
 		fi.fin_data[0] = 0;
 		fi.fin_data[1] = 0;
-		ipsec->ipsc_state = fr_addstate(&fi, &ipsec->ipsc_state,
-						SI_WILDP);
-		if (fi.fin_state != NULL)
-			fr_statederef((ipstate_t **)&fi.fin_state);
+		(void) ipf_state_add(softc, &fi, &ipsec->ipsc_state, SI_WILDP);
 	}
 	ip->ip_p = p & 0xff;
 	return 0;
@@ -188,11 +266,15 @@
  * For outgoing IKE packets.  refresh timeouts for NAT & state entries, if
  * we can.  If they have disappeared, recreate them.
  */
-int ippr_ipsec_inout(fin, aps, nat)
-fr_info_t *fin;
-ap_session_t *aps;
-nat_t *nat;
+int
+ipf_p_ipsec_inout(arg, fin, aps, nat)
+	void *arg;
+	fr_info_t *fin;
+	ap_session_t *aps;
+	nat_t *nat;
 {
+	ipf_ipsec_softc_t *softi = arg;
+	ipf_main_softc_t *softc = fin->fin_main_soft;
 	ipsec_pxy_t *ipsec;
 	fr_info_t fi;
 	ip_t *ip;
@@ -212,10 +294,8 @@
 
 		if ((ipsec->ipsc_nat == NULL) || (ipsec->ipsc_state == NULL)) {
 			bcopy((char *)fin, (char *)&fi, sizeof(fi));
-			fi.fin_state = NULL;
-			fi.fin_nat = NULL;
 			fi.fin_fi.fi_p = IPPROTO_ESP;
-			fi.fin_fr = &ipsecfr;
+			fi.fin_fr = &softi->ipsec_fr;
 			fi.fin_data[0] = 0;
 			fi.fin_data[1] = 0;
 			ip->ip_p = IPPROTO_ESP;
@@ -227,16 +307,24 @@
 		 * Update NAT timeout/create NAT if missing.
 		 */
 		if (ipsec->ipsc_nat != NULL)
-			fr_queueback(&ipsec->ipsc_nat->nat_tqe);
+			ipf_queueback(softc->ipf_ticks,
+				      &ipsec->ipsc_nat->nat_tqe);
 		else {
-			ipsec->ipsc_nat = nat_new(&fi, &ipsec->ipsc_rule,
-						  &ipsec->ipsc_nat,
-						  NAT_SLAVE|SI_WILDP,
-						  nat->nat_dir);
+#ifdef USE_MUTEXES
+			ipf_nat_softc_t *softn = softc->ipf_nat_soft;
+#endif
+
+			MUTEX_ENTER(&softn->ipf_nat_new);
+			ipsec->ipsc_nat = ipf_nat_add(&fi, ipsec->ipsc_rule,
+						      &ipsec->ipsc_nat,
+						      NAT_SLAVE|SI_WILDP,
+						      nat->nat_dir);
+			MUTEX_EXIT(&softn->ipf_nat_new);
 			if (ipsec->ipsc_nat != NULL) {
-				(void) nat_proto(&fi, ipsec->ipsc_nat, 0);
-				nat_update(&fi, ipsec->ipsc_nat,
-					   &ipsec->ipsc_rule);
+				(void) ipf_nat_proto(&fi, ipsec->ipsc_nat, 0);
+				MUTEX_ENTER(&ipsec->ipsc_nat->nat_lock);
+				ipf_nat_update(&fi, ipsec->ipsc_nat);
+				MUTEX_EXIT(&ipsec->ipsc_nat->nat_lock);
 			}
 		}
 
@@ -243,20 +331,18 @@
 		/*
 		 * Update state timeout/create state if missing.
 		 */
-		READ_ENTER(&ipf_state);
+		READ_ENTER(&softc->ipf_state);
 		if (ipsec->ipsc_state != NULL) {
-			fr_queueback(&ipsec->ipsc_state->is_sti);
+			ipf_queueback(softc->ipf_ticks,
+				      &ipsec->ipsc_state->is_sti);
 			ipsec->ipsc_state->is_die = nat->nat_age;
-			RWLOCK_EXIT(&ipf_state);
+			RWLOCK_EXIT(&softc->ipf_state);
 		} else {
-			RWLOCK_EXIT(&ipf_state);
+			RWLOCK_EXIT(&softc->ipf_state);
 			fi.fin_data[0] = 0;
 			fi.fin_data[1] = 0;
-			ipsec->ipsc_state = fr_addstate(&fi,
-							&ipsec->ipsc_state,
-							SI_WILDP);
-			if (fi.fin_state != NULL)
-				fr_statederef((ipstate_t **)&fi.fin_state);
+			(void) ipf_state_add(softc, &fi, &ipsec->ipsc_state,
+					     SI_WILDP);
 		}
 		ip->ip_p = p;
 	}
@@ -270,10 +356,11 @@
  * in the same order (not reversed depending on packet flow direction as with
  * UDP/TCP port numbers).
  */
-int ippr_ipsec_match(fin, aps, nat)
-fr_info_t *fin;
-ap_session_t *aps;
-nat_t *nat;
+int
+ipf_p_ipsec_match(fin, aps, nat)
+	fr_info_t *fin;
+	ap_session_t *aps;
+	nat_t *nat;
 {
 	ipsec_pxy_t *ipsec;
 	u_32_t cookies[4];
@@ -314,8 +401,10 @@
 /*
  * clean up after ourselves.
  */
-void ippr_ipsec_del(aps)
-ap_session_t *aps;
+void
+ipf_p_ipsec_del(softc, aps)
+	ipf_main_softc_t *softc;
+	ap_session_t *aps;
 {
 	ipsec_pxy_t *ipsec;
 
@@ -327,15 +416,17 @@
 		 * *_del() is on a callback from aps_free(), from nat_delete()
 		 */
 
-		READ_ENTER(&ipf_state);
+		READ_ENTER(&softc->ipf_state);
 		if (ipsec->ipsc_state != NULL) {
-			ipsec->ipsc_state->is_die = fr_ticks + 1;
+			ipsec->ipsc_state->is_die = softc->ipf_ticks + 1;
 			ipsec->ipsc_state->is_me = NULL;
-			fr_queuefront(&ipsec->ipsc_state->is_sti);
+			ipf_queuefront(&ipsec->ipsc_state->is_sti);
 		}
-		RWLOCK_EXIT(&ipf_state);
+		RWLOCK_EXIT(&softc->ipf_state);
 
 		ipsec->ipsc_state = NULL;
 		ipsec->ipsc_nat = NULL;
+		ipsec->ipsc_rule->in_flags |= IPN_DELETE;
+		ipf_nat_rule_deref(softc, &ipsec->ipsc_rule);
 	}
 }

Modified: trunk/sys/contrib/ipfilter/netinet/ip_irc_pxy.c
===================================================================
--- trunk/sys/contrib/ipfilter/netinet/ip_irc_pxy.c	2018-05-28 18:55:30 UTC (rev 10138)
+++ trunk/sys/contrib/ipfilter/netinet/ip_irc_pxy.c	2018-05-28 18:56:30 UTC (rev 10139)
@@ -1,9 +1,10 @@
+/* $MidnightBSD$ */
 /*
- * Copyright (C) 2000-2003 Darren Reed
+ * Copyright (C) 2012 by Darren Reed.
  *
  * See the IPFILTER.LICENCE file for details on licencing.
  *
- * $Id: ip_irc_pxy.c,v 1.2 2008-09-19 02:15:13 laffer1 Exp $
+ * $Id$
  */
 
 #define	IPF_IRC_PROXY
@@ -11,12 +12,12 @@
 #define	IPF_IRCBUFSZ	96	/* This *MUST* be >= 64! */
 
 
-int ippr_irc_init __P((void));
-void ippr_irc_fini __P((void));
-int ippr_irc_new __P((fr_info_t *, ap_session_t *, nat_t *));
-int ippr_irc_out __P((fr_info_t *, ap_session_t *, nat_t *));
-int ippr_irc_send __P((fr_info_t *, nat_t *));
-int ippr_irc_complete __P((ircinfo_t *, char *, size_t));
+void ipf_p_irc_main_load __P((void));
+void ipf_p_irc_main_unload __P((void));
+int ipf_p_irc_new __P((void *, fr_info_t *, ap_session_t *, nat_t *));
+int ipf_p_irc_out __P((void *, fr_info_t *, ap_session_t *, nat_t *));
+int ipf_p_irc_send __P((fr_info_t *, nat_t *));
+int ipf_p_irc_complete __P((ircinfo_t *, char *, size_t));
 u_short ipf_irc_atoi __P((char **));
 
 static	frentry_t	ircnatfr;
@@ -27,7 +28,8 @@
 /*
  * Initialize local structures.
  */
-int ippr_irc_init()
+void
+ipf_p_irc_main_load()
 {
 	bzero((char *)&ircnatfr, sizeof(ircnatfr));
 	ircnatfr.fr_ref = 1;
@@ -34,12 +36,11 @@
 	ircnatfr.fr_flags = FR_INQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE;
 	MUTEX_INIT(&ircnatfr.fr_lock, "IRC proxy rule lock");
 	irc_proxy_init = 1;
-
-	return 0;
 }
 
 
-void ippr_irc_fini()
+void
+ipf_p_irc_main_unload()
 {
 	if (irc_proxy_init == 1) {
 		MUTEX_DESTROY(&ircnatfr.fr_lock);
@@ -48,7 +49,7 @@
 }
 
 
-const char *ippr_irc_dcctypes[] = {
+const char *ipf_p_irc_dcctypes[] = {
 	"CHAT ",	/* CHAT chat ipnumber portnumber */
 	"SEND ",	/* SEND filename ipnumber portnumber */
 	"MOVE ",
@@ -64,10 +65,11 @@
  */
 
 
-int ippr_irc_complete(ircp, buf, len)
-ircinfo_t *ircp;
-char *buf;
-size_t len;
+int
+ipf_p_irc_complete(ircp, buf, len)
+	ircinfo_t *ircp;
+	char *buf;
+	size_t len;
 {
 	register char *s, c;
 	register size_t i;
@@ -145,12 +147,12 @@
 	/*
 	 * Check for a recognised DCC command
 	 */
-	for (j = 0, k = 0; ippr_irc_dcctypes[j]; j++) {
-		k = MIN(strlen(ippr_irc_dcctypes[j]), i);
-		if (!strncmp(ippr_irc_dcctypes[j], s, k))
+	for (j = 0, k = 0; ipf_p_irc_dcctypes[j]; j++) {
+		k = MIN(strlen(ipf_p_irc_dcctypes[j]), i);
+		if (!strncmp(ipf_p_irc_dcctypes[j], s, k))
 			break;
 	}
-	if (!ippr_irc_dcctypes[j])
+	if (!ipf_p_irc_dcctypes[j])
 		return 0;
 
 	ircp->irc_type = s;
@@ -222,18 +224,22 @@
 }
 
 
-int ippr_irc_new(fin, aps, nat)
-fr_info_t *fin;
-ap_session_t *aps;
-nat_t *nat;
+int
+ipf_p_irc_new(arg, fin, aps, nat)
+	void *arg;
+	fr_info_t *fin;
+	ap_session_t *aps;
+	nat_t *nat;
 {
 	ircinfo_t *irc;
 
+	if (fin->fin_v != 4)
+		return -1;
+
 	KMALLOC(irc, ircinfo_t *);
 	if (irc == NULL)
 		return -1;
 
-	fin = fin;	/* LINT */
 	nat = nat;	/* LINT */
 
 	aps->aps_data = irc;
@@ -244,13 +250,15 @@
 }
 
 
-int ippr_irc_send(fin, nat)
-fr_info_t *fin;
-nat_t *nat;
+int
+ipf_p_irc_send(fin, nat)
+	fr_info_t *fin;
+	nat_t *nat;
 {
 	char ctcpbuf[IPF_IRCBUFSZ], newbuf[IPF_IRCBUFSZ];
 	tcphdr_t *tcp, tcph, *tcp2 = &tcph;
 	int off, inc = 0, i, dlen;
+	ipf_main_softc_t *softc;
 	size_t nlen = 0, olen;
 	struct in_addr swip;
 	u_short a5, sp;
@@ -263,6 +271,7 @@
 #ifdef	MENTAT
 	mb_t *m1;
 #endif
+	softc = fin->fin_main_soft;
 
 	m = fin->fin_m;
 	ip = fin->fin_ip;
@@ -285,14 +294,14 @@
 	*newbuf = '\0';
 
 	irc = nat->nat_aps->aps_data;
-	if (ippr_irc_complete(irc, ctcpbuf, dlen) == 0)
+	if (ipf_p_irc_complete(irc, ctcpbuf, dlen) == 0)
 		return 0;
 
 	/*
-	 * check that IP address in the PORT/PASV reply is the same as the
-	 * sender of the command - prevents using PORT for port scanning.
+	 * check that IP address in the DCC reply is the same as the
+	 * sender of the command - prevents use for port scanning.
 	 */
-	if (irc->irc_ipnum != ntohl(nat->nat_inip.s_addr))
+	if (irc->irc_ipnum != ntohl(nat->nat_osrcaddr))
 		return 0;
 
 	a5 = irc->irc_port;
@@ -315,7 +324,7 @@
 	nlen = strlen(newbuf);
 	inc = nlen - olen;
 
-	if ((inc + ip->ip_len) > 65535)
+	if ((inc + fin->fin_plen) > 65535)
 		return 0;
 
 #ifdef	MENTAT
@@ -326,7 +335,7 @@
 
 		/* alloc enough to keep same trailer space for lower driver */
 		nm = allocb(nlen, BPRI_MED);
-		PANIC((!nm),("ippr_irc_out: allocb failed"));
+		PANIC((!nm),("ipf_p_irc_out: allocb failed"));
 
 		nm->b_band = m1->b_band;
 		nm->b_wptr += nlen;
@@ -333,7 +342,7 @@
 
 		m1->b_wptr -= olen;
 		PANIC((m1->b_wptr < m1->b_rptr),
-		      ("ippr_irc_out: cannot handle fragmented data block"));
+		      ("ipf_p_irc_out: cannot handle fragmented data block"));
 
 		linkb(m1, nm);
 	} else {
@@ -350,13 +359,14 @@
 	/* the mbuf chain will be extended if necessary by m_copyback() */
 #endif
 	COPYBACK(m, off, nlen, newbuf);
+	fin->fin_flx |= FI_DOCKSUM;
 
 	if (inc != 0) {
 #if defined(MENTAT) || defined(__sgi)
 		register u_32_t	sum1, sum2;
 
-		sum1 = ip->ip_len;
-		sum2 = ip->ip_len + inc;
+		sum1 = fin->fin_plen;
+		sum2 = fin->fin_plen + inc;
 
 		/* Because ~1 == -2, We really need ~1 == -1 */
 		if (sum1 > sum2)
@@ -364,9 +374,11 @@
 		sum2 -= sum1;
 		sum2 = (sum2 & 0xffff) + (sum2 >> 16);
 
-		fix_outcksum(fin, &ip->ip_sum, sum2);
+		ipf_fix_outcksum(0, &ip->ip_sum, sum2, 0);
 #endif
-		ip->ip_len += inc;
+		fin->fin_plen += inc;
+		ip->ip_len = htons(fin->fin_plen);
+		fin->fin_dlen += inc;
 	}
 
 	/*
@@ -389,16 +401,18 @@
 	bcopy((caddr_t)fin, (caddr_t)&fi, sizeof(fi));
 	fi.fin_data[0] = sp;
 	fi.fin_data[1] = fin->fin_data[1];
-	nat2 = nat_outlookup(fin, IPN_TCP, nat->nat_p, nat->nat_inip,
+	nat2 = ipf_nat_outlookup(fin, IPN_TCP, nat->nat_pr[1], nat->nat_nsrcip,
 			     ip->ip_dst);
 	if (nat2 == NULL) {
+#ifdef USE_MUTEXES
+		ipf_nat_softc_t *softn = softc->ipf_nat_soft;
+#endif
+
 		bcopy((caddr_t)fin, (caddr_t)&fi, sizeof(fi));
 		bzero((char *)tcp2, sizeof(*tcp2));
 		tcp2->th_win = htons(8192);
 		tcp2->th_sport = sp;
 		tcp2->th_dport = 0; /* XXX - don't specify remote port */
-		fi.fin_state = NULL;
-		fi.fin_nat = NULL;
 		fi.fin_data[0] = ntohs(sp);
 		fi.fin_data[1] = 0;
 		fi.fin_dp = (char *)tcp2;
@@ -406,16 +420,18 @@
 		fi.fin_dlen = sizeof(*tcp2);
 		fi.fin_plen = fi.fin_hlen + sizeof(*tcp2);
 		swip = ip->ip_src;
-		ip->ip_src = nat->nat_inip;
-		nat2 = nat_new(&fi, nat->nat_ptr, NULL,
+		ip->ip_src = nat->nat_nsrcip;
+		MUTEX_ENTER(&softn->ipf_nat_new);
+		nat2 = ipf_nat_add(&fi, nat->nat_ptr, NULL,
 			       NAT_SLAVE|IPN_TCP|SI_W_DPORT, NAT_OUTBOUND);
+		MUTEX_EXIT(&softn->ipf_nat_new);
 		if (nat2 != NULL) {
-			(void) nat_proto(&fi, nat2, 0);
-			nat_update(&fi, nat2, nat2->nat_ptr);
+			(void) ipf_nat_proto(&fi, nat2, 0);
+			MUTEX_ENTER(&nat2->nat_lock);
+			ipf_nat_update(&fi, nat2);
+			MUTEX_EXIT(&nat2->nat_lock);
 
-			(void) fr_addstate(&fi, NULL, SI_W_DPORT);
-			if (fi.fin_state != NULL)
-				fr_statederef((ipstate_t **)&fi.fin_state);
+			(void) ipf_state_add(softc, &fi, NULL, SI_W_DPORT);
 		}
 		ip->ip_src = swip;
 	}
@@ -423,11 +439,13 @@
 }
 
 
-int ippr_irc_out(fin, aps, nat)
-fr_info_t *fin;
-ap_session_t *aps;
-nat_t *nat;
+int
+ipf_p_irc_out(arg, fin, aps, nat)
+	void *arg;
+	fr_info_t *fin;
+	ap_session_t *aps;
+	nat_t *nat;
 {
 	aps = aps;	/* LINT */
-	return ippr_irc_send(fin, nat);
+	return ipf_p_irc_send(fin, nat);
 }

Modified: trunk/sys/contrib/ipfilter/netinet/ip_log.c
===================================================================
--- trunk/sys/contrib/ipfilter/netinet/ip_log.c	2018-05-28 18:55:30 UTC (rev 10138)
+++ trunk/sys/contrib/ipfilter/netinet/ip_log.c	2018-05-28 18:56:30 UTC (rev 10139)
@@ -1,11 +1,12 @@
-/*	$FreeBSD$	*/
+/* $MidnightBSD$ */
+/*	$FreeBSD: stable/10/sys/contrib/ipfilter/netinet/ip_log.c 305138 2016-08-31 18:00:41Z dim $	*/
 
 /*
- * Copyright (C) 1997-2003 by Darren Reed.
+ * Copyright (C) 2012 by Darren Reed.
  *
  * See the IPFILTER.LICENCE file for details on licencing.
  *
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/contrib/ipfilter/netinet/ip_log.c 305138 2016-08-31 18:00:41Z dim $
  * Id: ip_log.c,v 2.75.2.19 2007/09/09 11:32:06 darrenr Exp $
  */
 #include <sys/param.h>
@@ -15,26 +16,16 @@
 # define        KERNEL	1
 # define        _KERNEL	1
 #endif
-#if defined(__NetBSD__) && (NetBSD >= 199905) && !defined(IPFILTER_LKM) && \
-    defined(_KERNEL)
-# if (__NetBSD_Version__ < 399001400)
-#  include "opt_ipfilter_log.h"
-# else
-#  include "opt_ipfilter.h"
-# endif
+#if defined(__FreeBSD__) && !defined(_KERNEL)
+# include <osreldate.h>
 #endif
-#if defined(__FreeBSD__) && !defined(IPFILTER_LKM)
-# if defined(_KERNEL)
-#  if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000)
-#   include "opt_ipfilter.h"
-#  endif
+#ifndef SOLARIS
+# if defined(sun) && (defined(__svr4__) || defined(__SVR4))
+#  define	SOLARIS		1
 # else
-#  include <osreldate.h>
+#  define	SOLARIS		0
 # endif
 #endif
-#ifndef SOLARIS
-# define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4)))
-#endif
 #include <sys/errno.h>
 #include <sys/types.h>
 #include <sys/file.h>
@@ -104,7 +95,6 @@
 #if __FreeBSD_version >= 300000
 # include <net/if_var.h>
 #endif
-#include <net/route.h>
 #include <netinet/in.h>
 #ifdef __sgi
 # include <sys/ddi.h>
@@ -148,66 +138,149 @@
 #  include	<machine/sys/user.h>
 #  include	<sys/kthread_iface.h>
 #  define	READ_COLLISION	0x001
-
-iplog_select_t	iplog_ss[IPL_LOGMAX+1];
-
 extern int selwait;
 # endif /* IPL_SELECT */
 
+typedef struct ipf_log_softc_s {
+	ipfmutex_t	ipl_mutex[IPL_LOGSIZE];
+# if SOLARIS && defined(_KERNEL)
+	kcondvar_t	ipl_wait[IPL_LOGSIZE];
+# endif
 # if defined(linux) && defined(_KERNEL)
-wait_queue_head_t	iplh_linux[IPL_LOGSIZE];
+	wait_queue_head_t	iplh_linux[IPL_LOGSIZE];
 # endif
-# if SOLARIS && defined(_KERNEL)
-extern	kcondvar_t	iplwait;
-extern	struct pollhead	iplpollhead[IPL_LOGSIZE];
+# if defined(__hpux) && defined(_KERNEL)
+	iplog_select_t	ipl_ss[IPL_LOGSIZE];
 # endif
+	iplog_t		**iplh[IPL_LOGSIZE];
+	iplog_t		*iplt[IPL_LOGSIZE];
+	iplog_t		*ipll[IPL_LOGSIZE];
+	u_long		ipl_logfail[IPL_LOGSIZE];
+	u_long		ipl_logok[IPL_LOGSIZE];
+	fr_info_t	ipl_crc[IPL_LOGSIZE];
+	u_32_t		ipl_counter[IPL_LOGSIZE];
+	int		ipl_suppress;
+	int		ipl_logall;
+	int		ipl_log_init;
+	int		ipl_logsize;
+	int		ipl_used[IPL_LOGSIZE];
+	int		ipl_magic[IPL_LOGSIZE];
+	ipftuneable_t	*ipf_log_tune;
+	int		ipl_readers[IPL_LOGSIZE];
+} ipf_log_softc_t;
 
-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_logmax = IPL_LOGMAX;
-int	ipl_logall = 0;
-int	ipl_log_init = 0;
-int	ipl_logsize = IPFILTER_LOGSIZE;
-int	ipl_magic[IPL_LOGSIZE] = { IPL_MAGIC, IPL_MAGIC_NAT, IPL_MAGIC_STATE,
-				   IPL_MAGIC, IPL_MAGIC, IPL_MAGIC,
-				   IPL_MAGIC, IPL_MAGIC };
+static int magic[IPL_LOGSIZE] = { IPL_MAGIC, IPL_MAGIC_NAT, IPL_MAGIC_STATE,
+				  IPL_MAGIC, IPL_MAGIC, IPL_MAGIC,
+				  IPL_MAGIC, IPL_MAGIC };
 
+static ipftuneable_t ipf_log_tuneables[] = {
+	/* log */
+	{ { (void *)offsetof(ipf_log_softc_t, ipl_suppress) },
+		"log_suppress",		0,	1,
+		stsizeof(ipf_log_softc_t, ipl_suppress),
+		0,			NULL,	NULL },
+	{ { (void *)offsetof(ipf_log_softc_t, ipl_logall) },
+		"log_all",		0,	1,
+		stsizeof(ipf_log_softc_t, ipl_logall),
+		0,			NULL,	NULL },
+	{ { (void *)offsetof(ipf_log_softc_t, ipl_logsize) },
+		"log_size",		0,	0x80000,
+		stsizeof(ipf_log_softc_t, ipl_logsize),
+		0,			NULL,	NULL },
+	{ { NULL },		NULL,			0,	0,
+		0,
+		0,			NULL,	NULL }
+};
 
+
+int
+ipf_log_main_load()
+{
+	return 0;
+}
+
+
+int
+ipf_log_main_unload()
+{
+	return 0;
+}
+
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_loginit                                                  */
+/* Function:    ipf_log_soft_create                                         */
+/* Returns:     void * - NULL = failure, else pointer to log context data   */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*                                                                          */
+/* Initialise log buffers & pointers.  Also iniialised the CRC to a local   */
+/* secret for use in calculating the "last log checksum".                   */
+/* ------------------------------------------------------------------------ */
+void *
+ipf_log_soft_create(softc)
+	ipf_main_softc_t *softc;
+{
+	ipf_log_softc_t *softl;
+	int i;
+
+	KMALLOC(softl, ipf_log_softc_t *);
+	if (softl == NULL)
+		return NULL;
+
+	bzero((char *)softl, sizeof(*softl));
+	bcopy((char *)magic, (char *)softl->ipl_magic, sizeof(magic));
+
+	softl->ipf_log_tune = ipf_tune_array_copy(softl,
+						  sizeof(ipf_log_tuneables),
+						  ipf_log_tuneables);
+	if (softl->ipf_log_tune == NULL) {
+		ipf_log_soft_destroy(softc, softl);
+		return NULL;
+	}
+	if (ipf_tune_array_link(softc, softl->ipf_log_tune) == -1) {
+		ipf_log_soft_destroy(softc, softl);
+		return NULL;
+	}
+
+	for (i = IPL_LOGMAX; i >= 0; i--) {
+		MUTEX_INIT(&softl->ipl_mutex[i], "ipf log mutex");
+	}
+
+	softl->ipl_suppress = 1;
+	softl->ipl_logall = 0;
+	softl->ipl_log_init = 0;
+	softl->ipl_logsize = IPFILTER_LOGSIZE;
+
+	return softl;
+}
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_log_soft_init                                           */
 /* Returns:     int - 0 == success (always returned)                        */
-/* Parameters:  Nil                                                         */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
 /*                                                                          */
 /* Initialise log buffers & pointers.  Also iniialised the CRC to a local   */
 /* secret for use in calculating the "last log checksum".                   */
 /* ------------------------------------------------------------------------ */
-int fr_loginit()
+int
+ipf_log_soft_init(softc, arg)
+	ipf_main_softc_t *softc;
+	void *arg;
 {
-	int	i;
+	ipf_log_softc_t *softl = arg;
+	int i;
 
 	for (i = IPL_LOGMAX; i >= 0; i--) {
-		iplt[i] = NULL;
-		ipll[i] = NULL;
-		iplh[i] = &iplt[i];
-		iplused[i] = 0;
-		bzero((char *)&iplcrc[i], sizeof(iplcrc[i]));
+		softl->iplt[i] = NULL;
+		softl->ipll[i] = NULL;
+		softl->iplh[i] = &softl->iplt[i];
+		bzero((char *)&softl->ipl_crc[i], sizeof(softl->ipl_crc[i]));
 # ifdef	IPL_SELECT
-		iplog_ss[i].read_waiter = 0;
-		iplog_ss[i].state = 0;
+		softl->iplog_ss[i].read_waiter = 0;
+		softl->iplog_ss[i].state = 0;
 # endif
-# if defined(linux) && defined(_KERNEL)
-		init_waitqueue_head(iplh_linux + i);
-# endif
 	}
 
-# if SOLARIS && defined(_KERNEL)
-	cv_init(&iplwait, "ipl condvar", CV_DRIVER, NULL);
-# endif
-	MUTEX_INIT(&ipl_mutex, "ipf log mutex");
 
-	ipl_log_init = 1;
+	softl->ipl_log_init = 1;
 
 	return 0;
 }
@@ -214,34 +287,89 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_logunload                                                */
-/* Returns:     Nil                                                         */
-/* Parameters:  Nil                                                         */
+/* Function:    ipf_log_soft_fini                                           */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              arg(I)   - pointer to log context structure                 */
 /*                                                                          */
 /* Clean up any log data that has accumulated without being read.           */
 /* ------------------------------------------------------------------------ */
-void fr_logunload()
+int
+ipf_log_soft_fini(softc, arg)
+	ipf_main_softc_t *softc;
+	void *arg;
 {
+	ipf_log_softc_t *softl = arg;
 	int i;
 
-	if (ipl_log_init == 0)
-		return;
+	if (softl->ipl_log_init == 0)
+		return 0;
 
-	for (i = IPL_LOGMAX; i >= 0; i--)
-		(void) ipflog_clear(i);
+	softl->ipl_log_init = 0;
 
+	for (i = IPL_LOGMAX; i >= 0; i--) {
+		(void) ipf_log_clear(softc, i);
+
+		/*
+		 * This is a busy-wait loop so as to avoid yet another lock
+		 * to wait on.
+		 */
+		MUTEX_ENTER(&softl->ipl_mutex[i]);
+		while (softl->ipl_readers[i] > 0) {
 # if SOLARIS && defined(_KERNEL)
-	cv_destroy(&iplwait);
+			cv_broadcast(&softl->ipl_wait[i]);
+			MUTEX_EXIT(&softl->ipl_mutex[i]);
+			delay(100);
+			pollwakeup(&softc->ipf_poll_head[i], POLLRDNORM);
+# else
+			MUTEX_EXIT(&softl->ipl_mutex[i]);
+			WAKEUP(softl->iplh, i);
+			POLLWAKEUP(i);
 # endif
-	MUTEX_DESTROY(&ipl_mutex);
+			MUTEX_ENTER(&softl->ipl_mutex[i]);
+		}
+		MUTEX_EXIT(&softl->ipl_mutex[i]);
+	}
 
-	ipl_log_init = 0;
+	return 0;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    ipflog                                                      */
-/* Returns:     int - 0 == success, -1 == failure                           */
+/* Function:    ipf_log_soft_destroy                                        */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              arg(I)   - pointer to log context structure                 */
+/*                                                                          */
+/* When this function is called, it is expected that there are no longer    */
+/* any threads active in the reading code path or the logging code path.    */
+/* ------------------------------------------------------------------------ */
+void
+ipf_log_soft_destroy(softc, arg)
+	ipf_main_softc_t *softc;
+	void *arg;
+{
+	ipf_log_softc_t *softl = arg;
+	int i;
+
+	for (i = IPL_LOGMAX; i >= 0; i--) {
+# if SOLARIS && defined(_KERNEL)
+		cv_destroy(&softl->ipl_wait[i]);
+# endif
+		MUTEX_DESTROY(&softl->ipl_mutex[i]);
+	}
+
+	if (softl->ipf_log_tune != NULL) {
+		ipf_tune_array_unlink(softc, softl->ipf_log_tune);
+		KFREES(softl->ipf_log_tune, sizeof(ipf_log_tuneables));
+		softl->ipf_log_tune = NULL;
+	}
+
+	KFREE(softl);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_log_pkt                                                 */
+/* Returns:     int      - 0 == success, -1 == failure                      */
 /* Parameters:  fin(I)   - pointer to packet information                    */
 /*              flags(I) - flags from filter rules                          */
 /*                                                                          */
@@ -251,10 +379,13 @@
 /* how much data to copy into the log, including part of the data body if   */
 /* requested.                                                               */
 /* ------------------------------------------------------------------------ */
-int ipflog(fin, flags)
-fr_info_t *fin;
-u_int flags;
+int
+ipf_log_pkt(fin, flags)
+	fr_info_t *fin;
+	u_int flags;
 {
+	ipf_main_softc_t *softc = fin->fin_main_soft;
+	ipf_log_softc_t *softl = softc->ipf_log_soft;
 	register size_t hlen;
 	int types[2], mlen;
 	size_t sizes[2];
@@ -262,8 +393,7 @@
 	ipflog_t ipfl;
 	u_char p;
 	mb_t *m;
-# if (SOLARIS || defined(__hpux)) && defined(_KERNEL) && \
-  !defined(_INET_IP_STACK_H)
+# if (SOLARIS || defined(__hpux)) && defined(_KERNEL) && !defined(FW_HOOKS)
 	qif_t *ifp;
 # else
 	struct ifnet *ifp;
@@ -275,10 +405,8 @@
 
 	ipfl.fl_nattag.ipt_num[0] = 0;
 	ifp = fin->fin_ifp;
-	if (fin->fin_exthdr != NULL)
-		hlen = (char *)fin->fin_dp - (char *)fin->fin_ip;
-	else
-		hlen = fin->fin_hlen;
+	hlen = (char *)fin->fin_dp - (char *)fin->fin_ip;
+
 	/*
 	 * calculate header size.
 	 */
@@ -292,7 +420,7 @@
 			struct icmp *icmp;
 
 			icmp = (struct icmp *)fin->fin_dp;
-	
+
 			/*
 			 * For ICMP, if the packet is an error packet, also
 			 * include the information about the packet which
@@ -339,15 +467,14 @@
 	 * Get the interface number and name to which this packet is
 	 * currently associated.
 	 */
-# if (SOLARIS || defined(__hpux)) && defined(_KERNEL) && \
-     !defined(_INET_IP_STACK_H)
+# if (SOLARIS || defined(__hpux)) && defined(_KERNEL)
+#  if !defined(FW_HOOKS)
 	ipfl.fl_unit = (u_int)ifp->qf_ppa;
+#  endif
 	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)) || \
-      (SOLARIS && defined(_INET_IP_STACK_H))
+#  if (defined(NetBSD) && (NetBSD  <= 1991011) && (NetBSD >= 199603)) || \
+      OPENBSD_GE_REV(199603) || defined(linux) || FREEBSD_GE_REV(501113)
 	COPYIFNAME(fin->fin_v, ifp, ipfl.fl_ifname);
 #  else
 	ipfl.fl_unit = (u_int)ifp->if_unit;
@@ -357,13 +484,13 @@
 			if ((ipfl.fl_ifname[2] = ifp->if_name[2]))
 				ipfl.fl_ifname[3] = ifp->if_name[3];
 #   else
-	COPYIFNAME(fin->fin_v, ifp, ipfl.fl_ifname);
+	(void) strncpy(ipfl.fl_ifname, IFNAME(ifp), sizeof(ipfl.fl_ifname));
 	ipfl.fl_ifname[sizeof(ipfl.fl_ifname) - 1] = '\0';
 #   endif
 #  endif
 # endif /* __hpux || SOLARIS */
 	mlen = fin->fin_plen - hlen;
-	if (!ipl_logall) {
+	if (!softl->ipl_logall) {
 		mlen = (flags & FR_LOGBODY) ? MIN(mlen, 128) : 0;
 	} else if ((flags & FR_LOGBODY) == 0) {
 		mlen = 0;
@@ -385,8 +512,10 @@
 		bcopy(fin->fin_nattag, (void *)&ipfl.fl_nattag,
 		      sizeof(ipfl.fl_nattag));
 	ipfl.fl_flags = flags;
+	ipfl.fl_breason = (fin->fin_reason & 0xff);
 	ipfl.fl_dir = fin->fin_out;
 	ipfl.fl_lflags = fin->fin_flx;
+	ipfl.fl_family = fin->fin_family;
 	ptrs[0] = (void *)&ipfl;
 	sizes[0] = sizeof(ipfl);
 	types[0] = 0;
@@ -408,14 +537,15 @@
 	sizes[1] = hlen + mlen;
 	types[1] = 1;
 # endif /* MENTAT */
-	return ipllog(IPL_LOGIPF, fin, ptrs, sizes, types, 2);
+	return ipf_log_items(softc, IPL_LOGIPF, fin, ptrs, sizes, types, 2);
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    ipllog                                                      */
-/* Returns:     int - 0 == success, -1 == failure                           */
-/* Parameters:  dev(I)    - device that owns this log record                */
+/* Function:    ipf_log_items                                               */
+/* Returns:     int       - 0 == success, -1 == failure                     */
+/* Parameters:  softc(I)  - pointer to main soft context                    */
+/*              unit(I)   - device we are reading from                      */
 /*              fin(I)    - pointer to packet information                   */
 /*              items(I)  - array of pointers to log data                   */
 /*              itemsz(I) - array of size of valid memory pointed to        */
@@ -426,14 +556,17 @@
 /* miscellaneous packet information, as well as packet data, for reading    */
 /* from the log device.                                                     */
 /* ------------------------------------------------------------------------ */
-int ipllog(dev, fin, items, itemsz, types, cnt)
-int dev;
-fr_info_t *fin;
-void **items;
-size_t *itemsz;
-int *types, cnt;
+int
+ipf_log_items(softc, unit, fin, items, itemsz, types, cnt)
+	ipf_main_softc_t *softc;
+	int unit;
+	fr_info_t *fin;
+	void **items;
+	size_t *itemsz;
+	int *types, cnt;
 {
-	u_char *buf, *ptr;
+	ipf_log_softc_t *softl = softc->ipf_log_soft;
+	caddr_t buf, ptr;
 	iplog_t *ipl;
 	size_t len;
 	int i;
@@ -440,58 +573,34 @@
 	SPL_INT(s);
 
 	/*
-	 * Check to see if this log record has a CRC which matches the last
-	 * record logged.  If it does, just up the count on the previous one
-	 * rather than create a new one.
-	 */
-	if (ipl_suppress) {
-		MUTEX_ENTER(&ipl_mutex);
-		if ((fin != NULL) && (fin->fin_off == 0)) {
-			if ((ipll[dev] != NULL) &&
-			    bcmp((char *)fin, (char *)&iplcrc[dev],
-				 FI_LCSIZE) == 0) {
-				ipll[dev]->ipl_count++;
-				MUTEX_EXIT(&ipl_mutex);
-				return 0;
-			}
-			bcopy((char *)fin, (char *)&iplcrc[dev], FI_LCSIZE);
-		} else
-			bzero((char *)&iplcrc[dev], FI_CSIZE);
-		MUTEX_EXIT(&ipl_mutex);
-	}
-
-	/*
 	 * Get the total amount of data to be logged.
 	 */
 	for (i = 0, len = sizeof(iplog_t); i < cnt; i++)
 		len += itemsz[i];
 
+	SPL_NET(s);
+	MUTEX_ENTER(&softl->ipl_mutex[unit]);
+	softl->ipl_counter[unit]++;
 	/*
 	 * check that we have space to record this information and can
 	 * allocate that much.
 	 */
-	KMALLOCS(buf, u_char *, len);
-	if (buf == NULL)
+	if ((softl->ipl_used[unit] + len) > softl->ipl_logsize) {
+		softl->ipl_logfail[unit]++;
+		MUTEX_EXIT(&softl->ipl_mutex[unit]);
 		return -1;
-	SPL_NET(s);
-	MUTEX_ENTER(&ipl_mutex);
-	if ((iplused[dev] + len) > ipl_logsize) {
-		MUTEX_EXIT(&ipl_mutex);
-		SPL_X(s);
-		KFREES(buf, len);
+	}
+
+	KMALLOCS(buf, caddr_t, len);
+	if (buf == NULL) {
+		softl->ipl_logfail[unit]++;
+		MUTEX_EXIT(&softl->ipl_mutex[unit]);
 		return -1;
 	}
-	iplused[dev] += len;
-	MUTEX_EXIT(&ipl_mutex);
-	SPL_X(s);
-
-	/*
-	 * advance the log pointer to the next empty record and deduct the
-	 * amount of space we're going to use.
-	 */
 	ipl = (iplog_t *)buf;
-	ipl->ipl_magic = ipl_magic[dev];
+	ipl->ipl_magic = softl->ipl_magic[unit];
 	ipl->ipl_count = 1;
+	ipl->ipl_seqnum = softl->ipl_counter[unit];
 	ipl->ipl_next = NULL;
 	ipl->ipl_dsize = len;
 #ifdef _KERNEL
@@ -509,32 +618,60 @@
 		if (types[i] == 0) {
 			bcopy(items[i], ptr, itemsz[i]);
 		} else if (types[i] == 1) {
-			COPYDATA(items[i], 0, itemsz[i], (char *)ptr);
+			COPYDATA(items[i], 0, itemsz[i], ptr);
 		}
 		ptr += itemsz[i];
 	}
-	SPL_NET(s);
-	MUTEX_ENTER(&ipl_mutex);
-	ipll[dev] = ipl;
-	*iplh[dev] = ipl;
-	iplh[dev] = &ipl->ipl_next;
+	/*
+	 * Check to see if this log record has a CRC which matches the last
+	 * record logged.  If it does, just up the count on the previous one
+	 * rather than create a new one.
+	 */
+	if (softl->ipl_suppress) {
+		if ((fin != NULL) && (fin->fin_off == 0)) {
+			if ((softl->ipll[unit] != NULL) &&
+			    (fin->fin_crc == softl->ipl_crc[unit].fin_crc) &&
+			    bcmp((char *)fin, (char *)&softl->ipl_crc[unit],
+				 FI_LCSIZE) == 0) {
+				softl->ipll[unit]->ipl_count++;
+				MUTEX_EXIT(&softl->ipl_mutex[unit]);
+				SPL_X(s);
+				KFREES(buf, len);
+				return 0;
+			}
+			bcopy((char *)fin, (char *)&softl->ipl_crc[unit],
+			      FI_LCSIZE);
+			softl->ipl_crc[unit].fin_crc = fin->fin_crc;
+		} else
+			bzero((char *)&softl->ipl_crc[unit], FI_CSIZE);
+	}
 
 	/*
+	 * advance the log pointer to the next empty record and deduct the
+	 * amount of space we're going to use.
+	 */
+	softl->ipl_logok[unit]++;
+	softl->ipll[unit] = ipl;
+	*softl->iplh[unit] = ipl;
+	softl->iplh[unit] = &ipl->ipl_next;
+	softl->ipl_used[unit] += len;
+
+	/*
 	 * Now that the log record has been completed and added to the queue,
 	 * wake up any listeners who may want to read it.
 	 */
 # if SOLARIS && defined(_KERNEL)
-	cv_signal(&iplwait);
-	MUTEX_EXIT(&ipl_mutex);
-	pollwakeup(&iplpollhead[dev], POLLRDNORM);
+	cv_signal(&softl->ipl_wait[unit]);
+	MUTEX_EXIT(&softl->ipl_mutex[unit]);
+	pollwakeup(&softc->ipf_poll_head[unit], POLLRDNORM);
 # else
-	MUTEX_EXIT(&ipl_mutex);
-	WAKEUP(iplh, dev);
-	POLLWAKEUP(dev);
+	MUTEX_EXIT(&softl->ipl_mutex[unit]);
+	WAKEUP(softl->iplh, unit);
+	POLLWAKEUP(unit);
 # endif
 	SPL_X(s);
 # ifdef	IPL_SELECT
-	iplog_input_ready(dev);
+	iplog_input_ready(unit);
 # endif
 	return 0;
 }
@@ -541,10 +678,11 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    ipflog_read                                                 */
-/* Returns:     int    - 0 == success, else error value.                    */
-/* Parameters:  unit(I) - device we are reading from                        */
-/*              uio(O)  - pointer to information about where to store data  */
+/* Function:    ipf_log_read                                                */
+/* Returns:     int      - 0 == success, else error value.                  */
+/* Parameters:  softc(I) - pointer to main soft context                     */
+/*              unit(I)  - device we are reading from                       */
+/*              uio(O)   - pointer to information about where to store data */
 /*                                                                          */
 /* Called to handle a read on an IPFilter device.  Returns only complete    */
 /* log messages - will not partially copy a log record out to userland.     */
@@ -552,26 +690,42 @@
 /* NOTE: This function will block and wait for a signal to return data if   */
 /* there is none present.  Asynchronous I/O is not implemented.             */
 /* ------------------------------------------------------------------------ */
-int ipflog_read(unit, uio)
-minor_t unit;
-struct uio *uio;
+int
+ipf_log_read(softc, unit, uio)
+	ipf_main_softc_t *softc;
+	minor_t unit;
+	struct uio *uio;
 {
+	ipf_log_softc_t *softl = softc->ipf_log_soft;
 	size_t dlen, copied;
 	int error = 0;
 	iplog_t *ipl;
 	SPL_INT(s);
 
+	if (softl->ipl_log_init == 0) {
+		IPFERROR(40007);
+		return 0;
+	}
+
 	/*
 	 * Sanity checks.  Make sure the minor # is valid and we're copying
 	 * a valid chunk of data.
 	 */
-	if (IPL_LOGMAX < unit)
+	if (IPL_LOGMAX < unit) {
+		IPFERROR(40001);
 		return ENXIO;
+	}
 	if (uio->uio_resid == 0)
 		return 0;
-	if ((uio->uio_resid < sizeof(iplog_t)) ||
-	    (uio->uio_resid > ipl_logsize))
+
+	if (uio->uio_resid < sizeof(iplog_t)) {
+		IPFERROR(40002);
 		return EINVAL;
+	}
+	if (uio->uio_resid > softl->ipl_logsize) {
+		IPFERROR(40005);
+		return EINVAL;
+	}
 
 	/*
 	 * Lock the log so we can snapshot the variables.  Wait for a signal
@@ -578,12 +732,16 @@
 	 * if the log is empty.
 	 */
 	SPL_NET(s);
-	MUTEX_ENTER(&ipl_mutex);
+	MUTEX_ENTER(&softl->ipl_mutex[unit]);
+	softl->ipl_readers[unit]++;
 
-	while (iplt[unit] == NULL) {
+	while (softl->ipl_log_init == 1 && softl->iplt[unit] == NULL) {
 # if SOLARIS && defined(_KERNEL)
-		if (!cv_wait_sig(&iplwait, &ipl_mutex.ipf_lk)) {
-			MUTEX_EXIT(&ipl_mutex);
+		if (!cv_wait_sig(&softl->ipl_wait[unit],
+				 &softl->ipl_mutex[unit].ipf_lk)) {
+			softl->ipl_readers[unit]--;
+			MUTEX_EXIT(&softl->ipl_mutex[unit]);
+			IPFERROR(40003);
 			return EINTR;
 		}
 # else
@@ -593,37 +751,49 @@
 #   ifdef IPL_SELECT
 		if (uio->uio_fpflags & (FNBLOCK|FNDELAY)) {
 			/* this is no blocking system call */
-			MUTEX_EXIT(&ipl_mutex);
+			softl->ipl_readers[unit]--;
+			MUTEX_EXIT(&softl->ipl_mutex[unit]);
 			return 0;
 		}
 #   endif
 
-		MUTEX_EXIT(&ipl_mutex);
-		l = get_sleep_lock(&iplh[unit]);
-		error = sleep(&iplh[unit], PZERO+1);
+		MUTEX_EXIT(&softl->ipl_mutex[unit]);
+		l = get_sleep_lock(&softl->iplh[unit]);
+		error = sleep(&softl->iplh[unit], PZERO+1);
 		spinunlock(l);
 #  else
 #   if defined(__osf__) && defined(_KERNEL)
-		error = mpsleep(&iplh[unit], PSUSP|PCATCH,  "iplread", 0,
-				&ipl_mutex, MS_LOCK_SIMPLE);
+		error = mpsleep(&softl->iplh[unit], PSUSP|PCATCH,  "ipfread", 0,
+				&softl->ipl_mutex, MS_LOCK_SIMPLE);
 #   else
-		MUTEX_EXIT(&ipl_mutex);
+		MUTEX_EXIT(&softl->ipl_mutex[unit]);
 		SPL_X(s);
-		error = SLEEP(unit + iplh, "ipl sleep");
+		error = SLEEP(unit + softl->iplh, "ipl sleep");
 #   endif /* __osf__ */
 #  endif /* __hpux */
-		if (error)
+		SPL_NET(s);
+		MUTEX_ENTER(&softl->ipl_mutex[unit]);
+		if (error) {
+			softl->ipl_readers[unit]--;
+			MUTEX_EXIT(&softl->ipl_mutex[unit]);
+			IPFERROR(40004);
 			return error;
-		SPL_NET(s);
-		MUTEX_ENTER(&ipl_mutex);
+		}
 # endif /* SOLARIS */
 	}
+	if (softl->ipl_log_init != 1) {
+		softl->ipl_readers[unit]--;
+		MUTEX_EXIT(&softl->ipl_mutex[unit]);
+		IPFERROR(40008);
+		return EIO;
+	}
 
-# if (BSD >= 199101) || defined(__FreeBSD__) || defined(__osf__)
+# if (defined(BSD) && (BSD >= 199101)) || defined(__FreeBSD__) || \
+     defined(__osf__)
 	uio->uio_rw = UIO_READ;
 # endif
 
-	for (copied = 0; (ipl = iplt[unit]) != NULL; copied += dlen) {
+	for (copied = 0; (ipl = softl->iplt[unit]) != NULL; copied += dlen) {
 		dlen = ipl->ipl_dsize;
 		if (dlen > uio->uio_resid)
 			break;
@@ -630,30 +800,32 @@
 		/*
 		 * Don't hold the mutex over the uiomove call.
 		 */
-		iplt[unit] = ipl->ipl_next;
-		iplused[unit] -= dlen;
-		MUTEX_EXIT(&ipl_mutex);
+		softl->iplt[unit] = ipl->ipl_next;
+		softl->ipl_used[unit] -= dlen;
+		MUTEX_EXIT(&softl->ipl_mutex[unit]);
 		SPL_X(s);
 		error = UIOMOVE(ipl, dlen, UIO_READ, uio);
 		if (error) {
 			SPL_NET(s);
-			MUTEX_ENTER(&ipl_mutex);
-			ipl->ipl_next = iplt[unit];
-			iplt[unit] = ipl;
-			iplused[unit] += dlen;
+			MUTEX_ENTER(&softl->ipl_mutex[unit]);
+			IPFERROR(40006);
+			ipl->ipl_next = softl->iplt[unit];
+			softl->iplt[unit] = ipl;
+			softl->ipl_used[unit] += dlen;
 			break;
 		}
-		MUTEX_ENTER(&ipl_mutex);
-		KFREES(ipl, dlen);
+		MUTEX_ENTER(&softl->ipl_mutex[unit]);
+		KFREES((caddr_t)ipl, dlen);
 		SPL_NET(s);
 	}
-	if (!iplt[unit]) {
-		iplused[unit] = 0;
-		iplh[unit] = &iplt[unit];
-		ipll[unit] = NULL;
+	if (!softl->iplt[unit]) {
+		softl->ipl_used[unit] = 0;
+		softl->iplh[unit] = &softl->iplt[unit];
+		softl->ipll[unit] = NULL;
 	}
 
-	MUTEX_EXIT(&ipl_mutex);
+	softl->ipl_readers[unit]--;
+	MUTEX_EXIT(&softl->ipl_mutex[unit]);
 	SPL_X(s);
 	return error;
 }
@@ -660,31 +832,35 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    ipflog_clear                                                */
-/* Returns:     int    - number of log bytes cleared.                       */
-/* Parameters:  unit(I) - device we are reading from                        */
+/* Function:    ipf_log_clear                                               */
+/* Returns:     int      - number of log bytes cleared.                     */
+/* Parameters:  softc(I) - pointer to main soft context                     */
+/*              unit(I)  - device we are reading from                       */
 /*                                                                          */
 /* Deletes all queued up log records for a given output device.             */
 /* ------------------------------------------------------------------------ */
-int ipflog_clear(unit)
-minor_t unit;
+int
+ipf_log_clear(softc, unit)
+	ipf_main_softc_t *softc;
+	minor_t unit;
 {
+	ipf_log_softc_t *softl = softc->ipf_log_soft;
 	iplog_t *ipl;
 	int used;
 	SPL_INT(s);
 
 	SPL_NET(s);
-	MUTEX_ENTER(&ipl_mutex);
-	while ((ipl = iplt[unit]) != NULL) {
-		iplt[unit] = ipl->ipl_next;
-		KFREES(ipl, ipl->ipl_dsize);
+	MUTEX_ENTER(&softl->ipl_mutex[unit]);
+	while ((ipl = softl->iplt[unit]) != NULL) {
+		softl->iplt[unit] = ipl->ipl_next;
+		KFREES((caddr_t)ipl, ipl->ipl_dsize);
 	}
-	iplh[unit] = &iplt[unit];
-	ipll[unit] = NULL;
-	used = iplused[unit];
-	iplused[unit] = 0;
-	bzero((char *)&iplcrc[unit], FI_CSIZE);
-	MUTEX_EXIT(&ipl_mutex);
+	softl->iplh[unit] = &softl->iplt[unit];
+	softl->ipll[unit] = NULL;
+	used = softl->ipl_used[unit];
+	softl->ipl_used[unit] = 0;
+	bzero((char *)&softl->ipl_crc[unit], FI_CSIZE);
+	MUTEX_EXIT(&softl->ipl_mutex[unit]);
 	SPL_X(s);
 	return used;
 }
@@ -691,16 +867,90 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    ipflog_canread                                              */
-/* Returns:     int    - 0 == no data to read, 1 = data present             */
-/* Parameters:  unit(I) - device we are reading from                        */
+/* Function:    ipf_log_canread                                             */
+/* Returns:     int      - 0 == no data to read, 1 = data present           */
+/* Parameters:  softc(I) - pointer to main soft context                     */
+/*              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;
+int
+ipf_log_canread(softc, unit)
+	ipf_main_softc_t *softc;
+	int unit;
 {
-	return iplt[unit] != NULL;
+	ipf_log_softc_t *softl = softc->ipf_log_soft;
+
+	return softl->iplt[unit] != NULL;
 }
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_log_canread                                             */
+/* Returns:     int      - 0 == no data to read, 1 = data present           */
+/* Parameters:  softc(I) - pointer to main soft context                     */
+/*              unit(I)  - device we are reading from                       */
+/*                                                                          */
+/* Returns how many bytes are currently held in log buffers for the         */
+/* selected ipf device.                                                     */
+/* ------------------------------------------------------------------------ */
+int
+ipf_log_bytesused(softc, unit)
+	ipf_main_softc_t *softc;
+	int unit;
+{
+	ipf_log_softc_t *softl = softc->ipf_log_soft;
+
+	if (softl == NULL)
+		return 0;
+
+	return softl->ipl_used[unit];
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_log_failures                                            */
+/* Returns:     U_QUAD_T - number of log failures                           */
+/* Parameters:  softc(I) - pointer to main soft context                     */
+/*              unit(I)  - device we are reading from                       */
+/*                                                                          */
+/* Returns how many times we've tried to log a packet but failed to do so   */
+/* for the selected ipf device.                                             */
+/* ------------------------------------------------------------------------ */
+u_long
+ipf_log_failures(softc, unit)
+	ipf_main_softc_t *softc;
+	int unit;
+{
+	ipf_log_softc_t *softl = softc->ipf_log_soft;
+
+	if (softl == NULL)
+		return 0;
+
+	return softl->ipl_logfail[unit];
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_log_logok                                               */
+/* Returns:     U_QUAD_T - number of packets logged                         */
+/* Parameters:  softc(I) - pointer to main soft context                     */
+/*              unit(I)  - device we are reading from                       */
+/*                                                                          */
+/* Returns how many times we've successfully logged a packet for the        */
+/* selected ipf device.                                                     */
+/* ------------------------------------------------------------------------ */
+u_long
+ipf_log_logok(softc, unit)
+	ipf_main_softc_t *softc;
+	int unit;
+{
+	ipf_log_softc_t *softl = softc->ipf_log_soft;
+
+	if (softl == NULL)
+		return 0;
+
+	return softl->ipl_logok[unit];
+}
 #endif /* IPFILTER_LOG */

Modified: trunk/sys/contrib/ipfilter/netinet/ip_lookup.c
===================================================================
--- trunk/sys/contrib/ipfilter/netinet/ip_lookup.c	2018-05-28 18:55:30 UTC (rev 10138)
+++ trunk/sys/contrib/ipfilter/netinet/ip_lookup.c	2018-05-28 18:56:30 UTC (rev 10139)
@@ -1,5 +1,7 @@
+/* $MidnightBSD$ */
+/* $FreeBSD: stable/10/sys/contrib/ipfilter/netinet/ip_lookup.c 255332 2013-09-06 23:11:19Z cy $ */
 /*
- * Copyright (C) 2002-2003 by Darren Reed.
+ * Copyright (C) 2012 by Darren Reed.
  *
  * See the IPFILTER.LICENCE file for details on licencing.
  */
@@ -24,7 +26,9 @@
 # include <sys/ioctl.h>
 #endif
 #if !defined(_KERNEL)
+# include <stdio.h>
 # include <string.h>
+# include <stdlib.h>
 # define _KERNEL
 # ifdef __OpenBSD__
 struct file;
@@ -33,14 +37,10 @@
 # undef _KERNEL
 #endif
 #include <sys/socket.h>
-#if (defined(__osf__) || defined(AIX) || defined(__hpux) || defined(__sgi)) && defined(_KERNEL)
-# include "radix_ipf_local.h"
-# define _RADIX_H_
-#endif
 #include <net/if.h>
 #if defined(__FreeBSD__)
-#  include <sys/cdefs.h>
-#  include <sys/proc.h>
+# include <sys/cdefs.h>
+# include <sys/proc.h>
 #endif
 #if defined(_KERNEL)
 # include <sys/systm.h>
@@ -47,92 +47,213 @@
 # if !defined(__SVR4) && !defined(__svr4__)
 #  include <sys/mbuf.h>
 # endif
+#else
+# include "ipf.h"
 #endif
 #include <netinet/in.h>
 
 #include "netinet/ip_compat.h"
 #include "netinet/ip_fil.h"
+#include "netinet/ip_lookup.h"
 #include "netinet/ip_pool.h"
 #include "netinet/ip_htable.h"
-#include "netinet/ip_lookup.h"
+#include "netinet/ip_dstlist.h"
 /* END OF INCLUDES */
 
 #if !defined(lint)
-static const char rcsid[] = "@(#)$Id: ip_lookup.c,v 1.4 2013-01-08 01:31:40 laffer1 Exp $";
+static const char rcsid[] = "@(#)$Id$";
 #endif
 
-#ifdef	IPFILTER_LOOKUP
-int	ip_lookup_inited = 0;
+/*
+ * In this file, ip_pool.c, ip_htable.c and ip_dstlist.c, you will find the
+ * range for unit is [-1,IPL_LOGMAX]. The -1 is considered to be a valid number
+ * and represents a "wildcard" or "all" units (IPL_LOGALL). The reason for not
+ * starting the numbering at 0 is because the numbers [0,IPL_LOGMAX] correspond
+ * to the minor device number for their respective device. Thus where there is
+ * array indexing on the unit, +1 is used to map [-1.IPL_LOGMAX] to
+ * [0.POOL_LOOKUP_MAX].
+ */
+static int ipf_lookup_addnode __P((ipf_main_softc_t *, caddr_t, int));
+static int ipf_lookup_delnode __P((ipf_main_softc_t *, caddr_t, int));
+static int ipf_lookup_addtable __P((ipf_main_softc_t *, caddr_t));
+static int ipf_lookup_deltable __P((ipf_main_softc_t *, caddr_t));
+static int ipf_lookup_stats __P((ipf_main_softc_t *, caddr_t));
+static int ipf_lookup_flush __P((ipf_main_softc_t *, caddr_t));
+static int ipf_lookup_iterate __P((ipf_main_softc_t *, void *, int, void *));
+static int ipf_lookup_deltok __P((ipf_main_softc_t *, void *, int, void *));
 
-static int iplookup_addnode __P((caddr_t));
-static int iplookup_delnode __P((caddr_t data));
-static int iplookup_addtable __P((caddr_t));
-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 *));
+#define	MAX_BACKENDS	3
+static ipf_lookup_t *backends[MAX_BACKENDS] = {
+	&ipf_pool_backend,
+	&ipf_htable_backend,
+	&ipf_dstlist_backend
+};
 
 
+typedef struct ipf_lookup_softc_s {
+	void		*ipf_back[MAX_BACKENDS];
+} ipf_lookup_softc_t;
+
+
 /* ------------------------------------------------------------------------ */
-/* Function:    iplookup_init                                               */
-/* Returns:     int     - 0 = success, else error                           */
-/* Parameters:  Nil                                                         */
+/* Function:    ipf_lookup_init                                             */
+/* Returns:     int      - 0 = success, else error                          */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
 /*                                                                          */
 /* Initialise all of the subcomponents of the lookup infrstructure.         */
 /* ------------------------------------------------------------------------ */
-int ip_lookup_init()
+void *
+ipf_lookup_soft_create(softc)
+	ipf_main_softc_t *softc;
 {
+	ipf_lookup_softc_t *softl;
+	ipf_lookup_t **l;
+	int i;
 
-	if (ip_pool_init() == -1)
-		return -1;
+	KMALLOC(softl, ipf_lookup_softc_t *);
+	if (softl == NULL)
+		return NULL;
 
-	RWLOCK_INIT(&ip_poolrw, "ip pool rwlock");
+	bzero((char *)softl, sizeof(*softl));
 
-	ip_lookup_inited = 1;
+	for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) {
+		softl->ipf_back[i] = (*(*l)->ipfl_create)(softc);
+		if (softl->ipf_back[i] == NULL) {
+			ipf_lookup_soft_destroy(softc, softl);
+			return NULL;
+		}
+	}
 
+	return softl;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_lookup_soft_init                                        */
+/* Returns:     int      - 0 = success, else error                          */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              arg(I)   - pointer to local context to use                  */
+/*                                                                          */
+/* Initialise all of the subcomponents of the lookup infrstructure.         */
+/* ------------------------------------------------------------------------ */
+int
+ipf_lookup_soft_init(softc, arg)
+	ipf_main_softc_t *softc;
+	void *arg;
+{
+	ipf_lookup_softc_t *softl = (ipf_lookup_softc_t *)arg;
+	int err = 0;
+	int i;
+
+	for (i = 0; i < MAX_BACKENDS; i++) {
+		err = (*backends[i]->ipfl_init)(softc, softl->ipf_back[i]);
+		if (err != 0)
+			break;
+	}
+
+	return err;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_lookup_soft_fini                                        */
+/* Returns:     int      - 0 = success, else error                          */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              arg(I)   - pointer to local context to use                  */
+/*                                                                          */
+/* Call the fini function in each backend to cleanup all allocated data.    */
+/* ------------------------------------------------------------------------ */
+int
+ipf_lookup_soft_fini(softc, arg)
+	ipf_main_softc_t *softc;
+	void *arg;
+{
+	ipf_lookup_softc_t *softl = (ipf_lookup_softc_t *)arg;
+	int i;
+
+	for (i = 0; i < MAX_BACKENDS; i++) {
+		if (softl->ipf_back[i] != NULL)
+			(*backends[i]->ipfl_fini)(softc,
+						  softl->ipf_back[i]);
+	}
+
 	return 0;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    iplookup_unload                                             */
+/* Function:    ipf_lookup_expire                                           */
+/* Returns:     Nil                                                         */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*                                                                          */
+/* Step through each of the backends and call their expire functions,       */
+/* allowing them to delete any lifetime limited data.                       */
+/* ------------------------------------------------------------------------ */
+void
+ipf_lookup_expire(softc)
+	ipf_main_softc_t *softc;
+{
+	ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
+	int i;
+
+	WRITE_ENTER(&softc->ipf_poolrw);
+	for (i = 0; i < MAX_BACKENDS; i++)
+		(*backends[i]->ipfl_expire)(softc, softl->ipf_back[i]);
+	RWLOCK_EXIT(&softc->ipf_poolrw);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_lookup_softc_destroy                                    */
 /* Returns:     int     - 0 = success, else error                           */
-/* Parameters:  Nil                                                         */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              arg(I)   - pointer to local context to use                  */
 /*                                                                          */
 /* Free up all pool related memory that has been allocated whilst IPFilter  */
 /* has been running.  Also, do any other deinitialisation required such     */
-/* ip_lookup_init() can be called again, safely.                            */
+/* ipf_lookup_init() can be called again, safely.                           */
 /* ------------------------------------------------------------------------ */
-void ip_lookup_unload()
+void
+ipf_lookup_soft_destroy(softc, arg)
+	ipf_main_softc_t *softc;
+	void *arg;
 {
-	ip_pool_fini();
-	fr_htable_unload();
+	ipf_lookup_softc_t *softl = (ipf_lookup_softc_t *)arg;
+	int i;
 
-	if (ip_lookup_inited == 1) {
-		RW_DESTROY(&ip_poolrw);
-		ip_lookup_inited = 0;
+	for (i = 0; i < MAX_BACKENDS; i++) {
+		if (softl->ipf_back[i] != NULL)
+			(*backends[i]->ipfl_destroy)(softc,
+						     softl->ipf_back[i]);
 	}
+
+	KFREE(softl);
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    iplookup_ioctl                                              */
+/* Function:    ipf_lookup_ioctl                                            */
 /* Returns:     int      - 0 = success, else error                          */
-/* Parameters:  data(IO) - pointer to ioctl data to be copied to/from user  */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              arg(I)   - pointer to local context to use                  */
+/*              data(IO) - pointer to ioctl data to be copied to/from user  */
 /*                         space.                                           */
 /*              cmd(I)   - ioctl command number                             */
 /*              mode(I)  - file mode bits used with open                    */
+/*              uid(I)   - uid of process doing ioctl                       */
+/*              ctx(I)   - pointer that represents context for uid          */
 /*                                                                          */
 /* Handle ioctl commands sent to the ioctl device.  For the most part, this */
 /* involves just calling another function to handle the specifics of each   */
 /* command.                                                                 */
 /* ------------------------------------------------------------------------ */
-int ip_lookup_ioctl(data, cmd, mode, uid, ctx)
-caddr_t data;
-ioctlcmd_t cmd;
-int mode, uid;
-void *ctx;
+int
+ipf_lookup_ioctl(softc, data, cmd, mode, uid, ctx)
+	ipf_main_softc_t *softc;
+	caddr_t data;
+	ioctlcmd_t cmd;
+	int mode, uid;
+	void *ctx;
 {
 	int err;
 	SPL_INT(s);
@@ -145,52 +266,53 @@
 	{
 	case SIOCLOOKUPADDNODE :
 	case SIOCLOOKUPADDNODEW :
-		WRITE_ENTER(&ip_poolrw);
-		err = iplookup_addnode(data);
-		RWLOCK_EXIT(&ip_poolrw);
+		WRITE_ENTER(&softc->ipf_poolrw);
+		err = ipf_lookup_addnode(softc, data, uid);
+		RWLOCK_EXIT(&softc->ipf_poolrw);
 		break;
 
 	case SIOCLOOKUPDELNODE :
 	case SIOCLOOKUPDELNODEW :
-		WRITE_ENTER(&ip_poolrw);
-		err = iplookup_delnode(data);
-		RWLOCK_EXIT(&ip_poolrw);
+		WRITE_ENTER(&softc->ipf_poolrw);
+		err = ipf_lookup_delnode(softc, data, uid);
+		RWLOCK_EXIT(&softc->ipf_poolrw);
 		break;
 
 	case SIOCLOOKUPADDTABLE :
-		WRITE_ENTER(&ip_poolrw);
-		err = iplookup_addtable(data);
-		RWLOCK_EXIT(&ip_poolrw);
+		WRITE_ENTER(&softc->ipf_poolrw);
+		err = ipf_lookup_addtable(softc, data);
+		RWLOCK_EXIT(&softc->ipf_poolrw);
 		break;
 
 	case SIOCLOOKUPDELTABLE :
-		WRITE_ENTER(&ip_poolrw);
-		err = iplookup_deltable(data);
-		RWLOCK_EXIT(&ip_poolrw);
+		WRITE_ENTER(&softc->ipf_poolrw);
+		err = ipf_lookup_deltable(softc, data);
+		RWLOCK_EXIT(&softc->ipf_poolrw);
 		break;
 
 	case SIOCLOOKUPSTAT :
 	case SIOCLOOKUPSTATW :
-		WRITE_ENTER(&ip_poolrw);
-		err = iplookup_stats(data);
-		RWLOCK_EXIT(&ip_poolrw);
+		WRITE_ENTER(&softc->ipf_poolrw);
+		err = ipf_lookup_stats(softc, data);
+		RWLOCK_EXIT(&softc->ipf_poolrw);
 		break;
 
 	case SIOCLOOKUPFLUSH :
-		WRITE_ENTER(&ip_poolrw);
-		err = iplookup_flush(data);
-		RWLOCK_EXIT(&ip_poolrw);
+		WRITE_ENTER(&softc->ipf_poolrw);
+		err = ipf_lookup_flush(softc, data);
+		RWLOCK_EXIT(&softc->ipf_poolrw);
 		break;
 
 	case SIOCLOOKUPITER :
-		err = iplookup_iterate(data, uid, ctx);
+		err = ipf_lookup_iterate(softc, data, uid, ctx);
 		break;
 
 	case SIOCIPFDELTOK :
-		err = iplookup_deltok(data, uid, ctx);
+		err = ipf_lookup_deltok(softc, data, uid, ctx);
 		break;
 
 	default :
+		IPFERROR(50001);
 		err = EINVAL;
 		break;
 	}
@@ -200,145 +322,105 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    iplookup_addnode                                            */
+/* Function:    ipf_lookup_addnode                                          */
 /* Returns:     int     - 0 = success, else error                           */
-/* Parameters:  data(I) - pointer to data from ioctl call                   */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              data(I) - pointer to data from ioctl call                   */
 /*                                                                          */
 /* Add a new data node to a lookup structure.  First, check to see if the   */
 /* parent structure refered to by name exists and if it does, then go on to */
 /* add a node to it.                                                        */
 /* ------------------------------------------------------------------------ */
-static int iplookup_addnode(data)
-caddr_t data;
+static int
+ipf_lookup_addnode(softc, data, uid)
+	ipf_main_softc_t *softc;
+	caddr_t data;
+	int uid;
 {
-	ip_pool_node_t node, *m;
+	ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
 	iplookupop_t op;
-	iphtable_t *iph;
-	iphtent_t hte;
-	ip_pool_t *p;
+	ipf_lookup_t **l;
 	int err;
+	int i;
 
 	err = BCOPYIN(data, &op, sizeof(op));
-	if (err != 0)
+	if (err != 0) {
+		IPFERROR(50002);
 		return EFAULT;
+	}
 
-	if (op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX)
+	if ((op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) &&
+	    (op.iplo_unit != IPLT_ALL)) {
+		IPFERROR(50003);
 		return EINVAL;
+	}
 
 	op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
 
-	switch (op.iplo_type)
-	{
-	case IPLT_POOL :
-		if (op.iplo_size != sizeof(node))
-			return EINVAL;
+	for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) {
+		if (op.iplo_type == (*l)->ipfl_type) {
+			err = (*(*l)->ipfl_node_add)(softc,
+						     softl->ipf_back[i],
+						     &op, uid);
+			break;
+		}
+	}
 
-		err = COPYIN(op.iplo_struct, &node, sizeof(node));
-		if (err != 0)
-			return EFAULT;
-
-		p = ip_pool_find(op.iplo_unit, op.iplo_name);
-		if (p == NULL)
-			return ESRCH;
-
-		/*
-		 * add an entry to a pool - return an error if it already
-		 * exists remove an entry from a pool - if it exists
-		 * - in both cases, the pool *must* exist!
-		 */
-		m = ip_pool_findeq(p, &node.ipn_addr, &node.ipn_mask);
-		if (m)
-			return EEXIST;
-		err = ip_pool_insert(p, &node.ipn_addr.adf_addr,
-				     &node.ipn_mask.adf_addr, node.ipn_info);
-		break;
-
-	case IPLT_HASH :
-		if (op.iplo_size != sizeof(hte))
-			return EINVAL;
-
-		err = COPYIN(op.iplo_struct, &hte, sizeof(hte));
-		if (err != 0)
-			return EFAULT;
-
-		iph = fr_findhtable(op.iplo_unit, op.iplo_name);
-		if (iph == NULL)
-			return ESRCH;
-		err = fr_addhtent(iph, &hte);
-		break;
-
-	default :
+	if (i == MAX_BACKENDS) {
+		IPFERROR(50012);
 		err = EINVAL;
-		break;
 	}
+
 	return err;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    iplookup_delnode                                            */
+/* Function:    ipf_lookup_delnode                                          */
 /* Returns:     int     - 0 = success, else error                           */
-/* Parameters:  data(I) - pointer to data from ioctl call                   */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              data(I) - pointer to data from ioctl call                   */
 /*                                                                          */
 /* Delete a node from a lookup table by first looking for the table it is   */
 /* in and then deleting the entry that gets found.                          */
 /* ------------------------------------------------------------------------ */
-static int iplookup_delnode(data)
-caddr_t data;
+static int
+ipf_lookup_delnode(softc, data, uid)
+	ipf_main_softc_t *softc;
+	caddr_t data;
+	int uid;
 {
-	ip_pool_node_t node, *m;
+	ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
 	iplookupop_t op;
-	iphtable_t *iph;
-	iphtent_t hte;
-	ip_pool_t *p;
+	ipf_lookup_t **l;
 	int err;
+	int i;
 
 	err = BCOPYIN(data, &op, sizeof(op));
-	if (err != 0)
+	if (err != 0) {
+		IPFERROR(50042);
 		return EFAULT;
+	}
 
-	if (op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX)
+	if ((op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) &&
+	    (op.iplo_unit != IPLT_ALL)) {
+		IPFERROR(50013);
 		return EINVAL;
+	}
 
 	op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
 
-	switch (op.iplo_type)
-	{
-	case IPLT_POOL :
-		if (op.iplo_size != sizeof(node))
-			return EINVAL;
+	for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) {
+		if (op.iplo_type == (*l)->ipfl_type) {
+			err = (*(*l)->ipfl_node_del)(softc, softl->ipf_back[i],
+						     &op, uid);
+			break;
+		}
+	}
 
-		err = COPYIN(op.iplo_struct, &node, sizeof(node));
-		if (err != 0)
-			return EFAULT;
-
-		p = ip_pool_find(op.iplo_unit, op.iplo_name);
-		if (!p)
-			return ESRCH;
-
-		m = ip_pool_findeq(p, &node.ipn_addr, &node.ipn_mask);
-		if (m == NULL)
-			return ENOENT;
-		err = ip_pool_remove(p, m);
-		break;
-
-	case IPLT_HASH :
-		if (op.iplo_size != sizeof(hte))
-			return EINVAL;
-
-		err = COPYIN(op.iplo_struct, &hte, sizeof(hte));
-		if (err != 0)
-			return EFAULT;
-
-		iph = fr_findhtable(op.iplo_unit, op.iplo_name);
-		if (iph == NULL)
-			return ESRCH;
-		err = fr_delhtent(iph, &hte);
-		break;
-
-	default :
+	if (i == MAX_BACKENDS) {
+		IPFERROR(50021);
 		err = EINVAL;
-		break;
 	}
 	return err;
 }
@@ -345,47 +427,50 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    iplookup_addtable                                           */
+/* Function:    ipf_lookup_addtable                                         */
 /* Returns:     int     - 0 = success, else error                           */
-/* Parameters:  data(I) - pointer to data from ioctl call                   */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              data(I) - pointer to data from ioctl call                   */
 /*                                                                          */
 /* Create a new lookup table, if one doesn't already exist using the name   */
 /* for this one.                                                            */
 /* ------------------------------------------------------------------------ */
-static int iplookup_addtable(data)
-caddr_t data;
+static int
+ipf_lookup_addtable(softc, data)
+	ipf_main_softc_t *softc;
+	caddr_t data;
 {
+	ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
 	iplookupop_t op;
-	int err;
+	ipf_lookup_t **l;
+	int err, i;
 
 	err = BCOPYIN(data, &op, sizeof(op));
-	if (err != 0)
+	if (err != 0) {
+		IPFERROR(50022);
 		return EFAULT;
+	}
 
-	if (op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX)
+	if ((op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) &&
+	    (op.iplo_unit != IPLT_ALL)) {
+		IPFERROR(50023);
 		return EINVAL;
+	}
 
 	op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
 
-	switch (op.iplo_type)
-	{
-	case IPLT_POOL :
-		if (ip_pool_find(op.iplo_unit, op.iplo_name) != NULL)
-			err = EEXIST;
-		else
-			err = ip_pool_create(&op);
-		break;
+	for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) {
+		if (op.iplo_type == (*l)->ipfl_type) {
+			err = (*(*l)->ipfl_table_add)(softc,
+						      softl->ipf_back[i],
+						      &op);
+			break;
+		}
+	}
 
-	case IPLT_HASH :
-		if (fr_findhtable(op.iplo_unit, op.iplo_name) != NULL)
-			err = EEXIST;
-		else
-			err = fr_newhtable(&op);
-		break;
-
-	default :
+	if (i == MAX_BACKENDS) {
+		IPFERROR(50026);
 		err = EINVAL;
-		break;
 	}
 
 	/*
@@ -394,8 +479,10 @@
 	 */
 	if ((err == 0) && ((op.iplo_arg & LOOKUP_ANON) != 0)) {
 		err = BCOPYOUT(&op, data, sizeof(op));
-		if (err != 0)
+		if (err != 0) {
+			IPFERROR(50027);
 			err = EFAULT;
+		}
 	}
 
 	return err;
@@ -403,45 +490,50 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    iplookup_deltable                                           */
+/* Function:    ipf_lookup_deltable                                         */
 /* Returns:     int     - 0 = success, else error                           */
-/* Parameters:  data(I) - pointer to data from ioctl call                   */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              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.                           */
 /* ------------------------------------------------------------------------ */
-static int iplookup_deltable(data)
-caddr_t data;
+static int
+ipf_lookup_deltable(softc, data)
+	ipf_main_softc_t *softc;
+	caddr_t data;
 {
+	ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
 	iplookupop_t op;
-	int err;
+	ipf_lookup_t **l;
+	int err, i;
 
 	err = BCOPYIN(data, &op, sizeof(op));
-	if (err != 0)
+	if (err != 0) {
+		IPFERROR(50028);
 		return EFAULT;
+	}
 
-	if (op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX)
+	if ((op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) &&
+	    (op.iplo_unit != IPLT_ALL)) {
+		IPFERROR(50029);
 		return EINVAL;
+	}
 
 	op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
 
-	/*
-	 * create a new pool - fail if one already exists with
-	 * the same #
-	 */
-	switch (op.iplo_type)
-	{
-	case IPLT_POOL :
-		err = ip_pool_destroy(op.iplo_unit, op.iplo_name);
-		break;
+	for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) {
+		if (op.iplo_type == (*l)->ipfl_type) {
+			err = (*(*l)->ipfl_table_del)(softc,
+						      softl->ipf_back[i],
+						      &op);
+			break;
+		}
+	}
 
-	case IPLT_HASH :
-		err = fr_removehtable(op.iplo_unit, op.iplo_name);
-		break;
-
-	default :
+	if (i == MAX_BACKENDS) {
+		IPFERROR(50030);
 		err = EINVAL;
-		break;
 	}
 	return err;
 }
@@ -448,86 +540,108 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    iplookup_stats                                              */
+/* Function:    ipf_lookup_stats                                            */
 /* Returns:     int     - 0 = success, else error                           */
-/* Parameters:  data(I) - pointer to data from ioctl call                   */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              data(I) - pointer to data from ioctl call                   */
 /*                                                                          */
 /* Copy statistical information from inside the kernel back to user space.  */
 /* ------------------------------------------------------------------------ */
-static int iplookup_stats(data)
-caddr_t data;
+static int
+ipf_lookup_stats(softc, data)
+	ipf_main_softc_t *softc;
+	caddr_t data;
 {
+	ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
 	iplookupop_t op;
+	ipf_lookup_t **l;
 	int err;
+	int i;
 
 	err = BCOPYIN(data, &op, sizeof(op));
-	if (err != 0)
+	if (err != 0) {
+		IPFERROR(50031);
 		return EFAULT;
+	}
 
-	if (op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX)
+	if ((op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) &&
+	    (op.iplo_unit != IPLT_ALL)) {
+		IPFERROR(50032);
 		return EINVAL;
+	}
 
-	switch (op.iplo_type)
-	{
-	case IPLT_POOL :
-		err = ip_pool_statistics(&op);
-		break;
+	for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) {
+		if (op.iplo_type == (*l)->ipfl_type) {
+			err = (*(*l)->ipfl_stats_get)(softc,
+						      softl->ipf_back[i],
+						      &op);
+			break;
+		}
+	}
 
-	case IPLT_HASH :
-		err = fr_gethtablestat(&op);
-		break;
-
-	default :
+	if (i == MAX_BACKENDS) {
+		IPFERROR(50033);
 		err = EINVAL;
-		break;
 	}
+
 	return err;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    iplookup_flush                                              */
+/* Function:    ipf_lookup_flush                                            */
 /* Returns:     int     - 0 = success, else error                           */
-/* Parameters:  data(I) - pointer to data from ioctl call                   */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              data(I) - pointer to data from ioctl call                   */
 /*                                                                          */
 /* A flush is called when we want to flush all the nodes from a particular  */
 /* entry in the hash table/pool or want to remove all groups from those.    */
 /* ------------------------------------------------------------------------ */
-static int iplookup_flush(data)
-caddr_t data;
+static int
+ipf_lookup_flush(softc, data)
+	ipf_main_softc_t *softc;
+	caddr_t data;
 {
-	int err, unit, num, type;
+	ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
+	int err, unit, num, type, i;
 	iplookupflush_t flush;
+	ipf_lookup_t **l;
 
 	err = BCOPYIN(data, &flush, sizeof(flush));
-	if (err != 0)
+	if (err != 0) {
+		IPFERROR(50034);
 		return EFAULT;
+	}
 
 	unit = flush.iplf_unit;
-	if ((unit < 0 || unit > IPL_LOGMAX) && (unit != IPLT_ALL))
+	if ((unit < 0 || unit > IPL_LOGMAX) && (unit != IPLT_ALL)) {
+		IPFERROR(50035);
 		return EINVAL;
+	}
 
 	flush.iplf_name[sizeof(flush.iplf_name) - 1] = '\0';
 
 	type = flush.iplf_type;
+	IPFERROR(50036);
 	err = EINVAL;
 	num = 0;
 
-	if (type == IPLT_POOL || type == IPLT_ALL) {
-		err = 0;
-		num = ip_pool_flush(&flush);
+	for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) {
+		if (type == (*l)->ipfl_type || type == IPLT_ALL) {
+			err = 0;
+			num += (*(*l)->ipfl_flush)(softc,
+						   softl->ipf_back[i],
+						   &flush);
+		}
 	}
 
-	if (type == IPLT_HASH  || type == IPLT_ALL) {
-		err = 0;
-		num += fr_flushhtable(&flush);
-	}
-
 	if (err == 0) {
 		flush.iplf_count = num;
 		err = BCOPYOUT(&flush, data, sizeof(flush));
-		if (err != 0)
+		if (err != 0) {
+			IPFERROR(50037);
 			err = EFAULT;
+		}
 	}
 	return err;
 }
@@ -534,129 +648,159 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    ip_lookup_delref                                            */
+/* Function:    ipf_lookup_delref                                           */
 /* Returns:     void                                                        */
-/* Parameters:  type(I) - table type to operate on                          */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              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;
+void
+ipf_lookup_deref(softc, type, ptr)
+	ipf_main_softc_t *softc;
+	int type;
+	void *ptr;
 {
+	ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
+	int i;
+
 	if (ptr == NULL)
 		return;
 
-	WRITE_ENTER(&ip_poolrw);
-	switch (type)
-	{
-	case IPLT_POOL :
-		ip_pool_deref(ptr);
-		break;
-
-	case IPLT_HASH :
-		fr_derefhtable(ptr);
-		break;
+	for (i = 0; i < MAX_BACKENDS; i++) {
+		if (type == backends[i]->ipfl_type) {
+			WRITE_ENTER(&softc->ipf_poolrw);
+			(*backends[i]->ipfl_table_deref)(softc,
+							 softl->ipf_back[i],
+							 ptr);
+			RWLOCK_EXIT(&softc->ipf_poolrw);
+			break;
+		}
 	}
-	RWLOCK_EXIT(&ip_poolrw);
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    iplookup_iterate                                            */
+/* Function:    ipf_lookup_iterate                                          */
 /* Returns:     int     - 0 = success, else error                           */
-/* Parameters:  data(I) - pointer to data from ioctl call                   */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              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;
+static int
+ipf_lookup_iterate(softc, data, uid, ctx)
+	ipf_main_softc_t *softc;
+	void *data;
+	int uid;
+	void *ctx;
 {
+	ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
 	ipflookupiter_t iter;
 	ipftoken_t *token;
-	int err;
+	int err, i;
 	SPL_INT(s);
 
-	err = fr_inobj(data, &iter, IPFOBJ_LOOKUPITER);
+	err = ipf_inobj(softc, data, NULL, &iter, IPFOBJ_LOOKUPITER);
 	if (err != 0)
 		return err;
 
-	if (iter.ili_unit > IPL_LOGMAX)
+	if (iter.ili_unit < IPL_LOGALL && iter.ili_unit > IPL_LOGMAX) {
+		IPFERROR(50038);
 		return EINVAL;
+	}
 
-	if (iter.ili_ival != IPFGENITER_LOOKUP)
+	if (iter.ili_ival != IPFGENITER_LOOKUP) {
+		IPFERROR(50039);
 		return EINVAL;
+	}
 
 	SPL_SCHED(s);
-	token = ipf_findtoken(iter.ili_key, uid, ctx);
+	token = ipf_token_find(softc, iter.ili_key, uid, ctx);
 	if (token == NULL) {
-		RWLOCK_EXIT(&ipf_tokens);
 		SPL_X(s);
+		IPFERROR(50040);
 		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;
+	for (i = 0; i < MAX_BACKENDS; i++) {
+		if (iter.ili_type == backends[i]->ipfl_type) {
+			err = (*backends[i]->ipfl_iter_next)(softc,
+							     softl->ipf_back[i],
+							     token, &iter);
+			break;
+		}
 	}
-	RWLOCK_EXIT(&ipf_tokens);
 	SPL_X(s);
 
+	if (i == MAX_BACKENDS) {
+		IPFERROR(50041);
+		err = EINVAL;
+	}
+
+	WRITE_ENTER(&softc->ipf_tokens);
+	ipf_token_deref(softc, token);
+	RWLOCK_EXIT(&softc->ipf_tokens);
+
 	return err;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    iplookup_iterderef                                          */
-/* Returns:     int     - 0 = success, else error                           */
-/* Parameters:  data(I) - pointer to data from ioctl call                   */
+/* Function:    ipf_lookup_iterderef                                        */
+/* Returns:     void                                                        */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              type(I)  - backend type to iterate through                  */
+/*              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.                           */
+/* Because each of the backend types has a different data structure,        */
+/* iteration is limited to one type at a time (i.e. it is not permitted to  */
+/* go on from pool types to hash types as part of the "get next".)          */
 /* ------------------------------------------------------------------------ */
-void ip_lookup_iterderef(type, data)
-u_32_t type;
-void *data;
+void
+ipf_lookup_iterderef(softc, type, data)
+	ipf_main_softc_t *softc;
+	u_32_t type;
+	void *data;
 {
-	iplookupiterkey_t	key;
+	ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
+	struct iplookupiterkey *lkey;
+	iplookupiterkey_t key;
+	int i;
 
 	key.ilik_key = type;
+	lkey = &key.ilik_unstr;
 
-	if (key.ilik_unstr.ilik_ival != IPFGENITER_LOOKUP)
+	if (lkey->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;
+	WRITE_ENTER(&softc->ipf_poolrw);
+
+	for (i = 0; i < MAX_BACKENDS; i++) {
+		if (lkey->ilik_type == backends[i]->ipfl_type) {
+			(*backends[i]->ipfl_iter_deref)(softc,
+							softl->ipf_back[i],
+							lkey->ilik_otype,
+							lkey->ilik_unit,
+							data);
+			break;
+		}
 	}
+	RWLOCK_EXIT(&softc->ipf_poolrw);
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    iplookup_deltok                                             */
+/* Function:    ipf_lookup_deltok                                           */
 /* Returns:     int     - 0 = success, else error                           */
-/* Parameters:  data(I) - pointer to data from ioctl call                   */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              data(I) - pointer to data from ioctl call                   */
 /*              uid(I)  - uid of caller                                     */
 /*              ctx(I)  - pointer to give the uid context                   */
 /*                                                                          */
@@ -664,32 +808,198 @@
 /* "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
+ipf_lookup_deltok(softc, data, uid, ctx)
+	ipf_main_softc_t *softc;
+	void *data;
+	int uid;
+	void *ctx;
 {
 	int error, key;
 	SPL_INT(s);
 
 	SPL_SCHED(s);
-	error = BCOPYIN(data, &key, sizeof(key)); 
+	error = BCOPYIN(data, &key, sizeof(key));
 	if (error == 0)
-		error = ipf_deltoken(key, uid, ctx);
+		error = ipf_token_del(softc, key, uid, ctx);
 	SPL_X(s);
 	return error;
 }
 
 
-#else /* IPFILTER_LOOKUP */
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_lookup_res_num                                          */
+/* Returns:     void * - NULL = failure, else success.                      */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              unit(I)     - device for which this is for                  */
+/*              type(I)     - type of lookup these parameters are for.      */
+/*              number(I)   - table number to use when searching            */
+/*              funcptr(IO) - pointer to pointer for storing IP address     */
+/*                            searching function.                           */
+/*                                                                          */
+/* Search for the "table" number passed in amongst those configured for     */
+/* that particular type.  If the type is recognised then the function to    */
+/* call to do the IP address search will be change, regardless of whether   */
+/* or not the "table" number exists.                                        */
+/* ------------------------------------------------------------------------ */
+void *
+ipf_lookup_res_num(softc, unit, type, number, funcptr)
+	ipf_main_softc_t *softc;
+	int unit;
+	u_int type;
+	u_int number;
+	lookupfunc_t *funcptr;
+{
+	char name[FR_GROUPLEN];
 
+#if defined(SNPRINTF) && defined(_KERNEL)
+	SNPRINTF(name, sizeof(name), "%u", number);
+#else
+	(void) sprintf(name, "%u", number);
+#endif
+
+	return ipf_lookup_res_name(softc, unit, type, name, funcptr);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_lookup_res_name                                         */
+/* Returns:     void * - NULL = failure, else success.                      */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              unit(I)     - device for which this is for                  */
+/*              type(I)     - type of lookup these parameters are for.      */
+/*              name(I)     - table name to use when searching              */
+/*              funcptr(IO) - pointer to pointer for storing IP address     */
+/*                            searching function.                           */
+/*                                                                          */
+/* Search for the "table" number passed in amongst those configured for     */
+/* that particular type.  If the type is recognised then the function to    */
+/* call to do the IP address search will be changed, regardless of whether  */
+/* or not the "table" number exists.                                        */
+/* ------------------------------------------------------------------------ */
+void *
+ipf_lookup_res_name(softc, unit, type, name, funcptr)
+	ipf_main_softc_t *softc;
+	int unit;
+	u_int type;
+	char *name;
+	lookupfunc_t *funcptr;
+{
+	ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
+	ipf_lookup_t **l;
+	void *ptr = NULL;
+	int i;
+
+	READ_ENTER(&softc->ipf_poolrw);
+
+	for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) {
+		if (type == (*l)->ipfl_type) {
+			ptr = (*(*l)->ipfl_select_add_ref)(softl->ipf_back[i],
+							   unit, name);
+			if (ptr != NULL && funcptr != NULL) {
+				*funcptr = (*l)->ipfl_addr_find;
+			}
+			break;
+		}
+	}
+
+	if (i == MAX_BACKENDS) {
+		ptr = NULL;
+		if (funcptr != NULL)
+			*funcptr = NULL;
+	}
+
+	RWLOCK_EXIT(&softc->ipf_poolrw);
+
+	return ptr;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_lookup_find_htable                                      */
+/* Returns:     void * - NULL = failure, else success.                      */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              unit(I)     - device for which this is for                  */
+/*              name(I)     - table name to use when searching              */
+/*                                                                          */
+/* To support the group-map feature, where a hash table maps address        */
+/* networks to rule group numbers, we need to expose a function that uses   */
+/* only the hash table backend.                                             */
+/* ------------------------------------------------------------------------ */
+void *
+ipf_lookup_find_htable(softc, unit, name)
+	ipf_main_softc_t *softc;
+	int unit;
+	char *name;
+{
+	ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
+	ipf_lookup_t **l;
+	void *tab = NULL;
+	int i;
+
+	READ_ENTER(&softc->ipf_poolrw);
+
+	for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++)
+		if (IPLT_HASH == (*l)->ipfl_type) {
+			tab = ipf_htable_find(softl->ipf_back[i], unit, name);
+			break;
+		}
+
+	RWLOCK_EXIT(&softc->ipf_poolrw);
+
+	return tab;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_lookup_sync                                             */
+/* Returns:     void                                                        */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*                                                                          */
+/* This function is the interface that the machine dependent sync functions */
+/* call when a network interface name change occurs. It then calls the sync */
+/* functions of the lookup implementations - if they have one.              */
+/* ------------------------------------------------------------------------ */
 /*ARGSUSED*/
-int ip_lookup_ioctl(data, cmd, mode, uid, ctx)
-caddr_t data;
-ioctlcmd_t cmd;
-int mode, uid;
-void *ctx;
+void
+ipf_lookup_sync(softc, ifp)
+	ipf_main_softc_t *softc;
+	void *ifp;
 {
-	return EIO;
+	ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
+	ipf_lookup_t **l;
+	int i;
+
+	READ_ENTER(&softc->ipf_poolrw);
+
+	for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++)
+		if ((*l)->ipfl_sync != NULL)
+			(*(*l)->ipfl_sync)(softc, softl->ipf_back[i]);
+
+	RWLOCK_EXIT(&softc->ipf_poolrw);
 }
-#endif /* IPFILTER_LOOKUP */
+
+
+#ifndef _KERNEL
+void
+ipf_lookup_dump(softc, arg)
+	ipf_main_softc_t *softc;
+	void *arg;
+{
+	ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
+	ipf_lookup_t **l;
+	int i;
+
+	for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++)
+		if (IPLT_POOL == (*l)->ipfl_type) {
+			ipf_pool_dump(softc, softl->ipf_back[i]);
+			break;
+		}
+
+	for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++)
+		if (IPLT_HASH == (*l)->ipfl_type) {
+			ipf_htable_dump(softc, softl->ipf_back[i]);
+			break;
+		}
+}
+#endif

Modified: trunk/sys/contrib/ipfilter/netinet/ip_lookup.h
===================================================================
--- trunk/sys/contrib/ipfilter/netinet/ip_lookup.h	2018-05-28 18:55:30 UTC (rev 10138)
+++ trunk/sys/contrib/ipfilter/netinet/ip_lookup.h	2018-05-28 18:56:30 UTC (rev 10139)
@@ -1,4 +1,11 @@
-
+/* $MidnightBSD$ */
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
 #ifndef __IP_LOOKUP_H__
 #define __IP_LOOKUP_H__
 
@@ -24,6 +31,9 @@
 # define	SIOCLOOKUPDELNODEW	_IOW(r, 68, struct iplookupop)
 #endif
 
+#define	LOOKUP_POOL_MAX	(IPL_LOGSIZE)
+#define	LOOKUP_POOL_SZ	(IPL_LOGSIZE + 1)
+
 typedef	struct	iplookupop	{
 	int	iplo_type;	/* IPLT_* */
 	int	iplo_unit;	/* IPL_LOG* */
@@ -40,7 +50,7 @@
 	int	iplf_type;	/* IPLT_* */
 	int	iplf_unit;	/* IPL_LOG* */
 	u_int	iplf_arg;
-	size_t	iplf_count;
+	u_int	iplf_count;
 	char	iplf_name[FR_GROUPLEN];
 } iplookupflush_t;
 
@@ -55,16 +65,18 @@
 #define	IPLT_NONE	0
 #define	IPLT_POOL	1
 #define	IPLT_HASH	2
+#define	IPLT_DSTLIST	3
 
+
 #define	IPLT_ANON	0x80000000
 
 
 typedef	union	{
 	struct	iplookupiterkey {
-		char	ilik_ival;
+		u_char	ilik_ival;
 		u_char	ilik_type;	/* IPLT_* */
 		u_char	ilik_otype;
-		u_char	ilik_unit;	/* IPL_LOG* */
+		signed char	ilik_unit;	/* IPL_LOG* */
 	} ilik_unstr;
 	u_32_t	ilik_key;
 } iplookupiterkey_t;
@@ -86,10 +98,56 @@
 #define	IPFLOOKUPITER_NODE	1
 
 
-extern int ip_lookup_init __P((void));
-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 *));
+typedef struct ipf_lookup {
+	int	ipfl_type;
+	void	*(*ipfl_create) __P((ipf_main_softc_t *));
+	void	(*ipfl_destroy) __P((ipf_main_softc_t *, void *));
+	int	(*ipfl_init) __P((ipf_main_softc_t *, void *));
+	void	(*ipfl_fini) __P((ipf_main_softc_t *, void *));
+	int	(*ipfl_addr_find) __P((ipf_main_softc_t *, void *,
+				       int, void *, u_int));
+	size_t	(*ipfl_flush) __P((ipf_main_softc_t *, void *,
+				   iplookupflush_t *));
+	int	(*ipfl_iter_deref) __P((ipf_main_softc_t *, void *,
+					int, int, void *));
+	int	(*ipfl_iter_next) __P((ipf_main_softc_t *, void *,
+				       ipftoken_t *, ipflookupiter_t *));
+	int	(*ipfl_node_add) __P((ipf_main_softc_t *, void *,
+				      iplookupop_t *, int));
+	int	(*ipfl_node_del) __P((ipf_main_softc_t *, void *,
+				      iplookupop_t *, int));
+	int	(*ipfl_stats_get) __P((ipf_main_softc_t *, void *,
+				       iplookupop_t *));
+	int	(*ipfl_table_add) __P((ipf_main_softc_t *, void *,
+				       iplookupop_t *));
+	int	(*ipfl_table_del) __P((ipf_main_softc_t *, void *,
+				       iplookupop_t *));
+	int	(*ipfl_table_deref) __P((ipf_main_softc_t *, void *, void *));
+	void	*(*ipfl_table_find) __P((void *, int, char *));
+	void	*(*ipfl_select_add_ref) __P((void *, int, char *));
+	int	(*ipfl_select_node) __P((fr_info_t *, void *, u_32_t *,
+					 frdest_t *));
+	void	(*ipfl_expire) __P((ipf_main_softc_t *, void *));
+	void	(*ipfl_sync) __P((ipf_main_softc_t *, void *));
+} ipf_lookup_t;
 
+extern int ipf_lookup_init __P((void));
+extern int ipf_lookup_ioctl __P((ipf_main_softc_t *, caddr_t, ioctlcmd_t, int, int, void *));
+extern void ipf_lookup_main_unload __P((void));
+extern void ipf_lookup_deref __P((ipf_main_softc_t *, int, void *));
+extern void ipf_lookup_iterderef __P((ipf_main_softc_t *, u_32_t, void *));
+extern void *ipf_lookup_res_name __P((ipf_main_softc_t *, int, u_int, char *,
+				      lookupfunc_t *));
+extern void *ipf_lookup_res_num __P((ipf_main_softc_t *, int, u_int, u_int,
+				     lookupfunc_t *));
+extern void ipf_lookup_soft_destroy __P((ipf_main_softc_t *, void *));
+extern void *ipf_lookup_soft_create __P((ipf_main_softc_t *));
+extern int ipf_lookup_soft_init __P((ipf_main_softc_t *, void *));
+extern int ipf_lookup_soft_fini __P((ipf_main_softc_t *, void *));
+extern void *ipf_lookup_find_htable __P((ipf_main_softc_t *, int, char *));
+extern void ipf_lookup_expire __P((ipf_main_softc_t *));
+extern void ipf_lookup_sync __P((ipf_main_softc_t *, void *));
+#ifndef _KERNEL
+extern	void	ipf_lookup_dump __P((ipf_main_softc_t *, void *));
+#endif
 #endif /* __IP_LOOKUP_H__ */

Modified: trunk/sys/contrib/ipfilter/netinet/ip_nat.c
===================================================================
--- trunk/sys/contrib/ipfilter/netinet/ip_nat.c	2018-05-28 18:55:30 UTC (rev 10138)
+++ trunk/sys/contrib/ipfilter/netinet/ip_nat.c	2018-05-28 18:56:30 UTC (rev 10139)
@@ -1,7 +1,8 @@
-/*	$FreeBSD$	*/
+/* $MidnightBSD$ */
+/*	$FreeBSD: stable/10/sys/contrib/ipfilter/netinet/ip_nat.c 324513 2017-10-11 05:02:36Z cy $	*/
 
 /*
- * Copyright (C) 1995-2003 by Darren Reed.
+ * Copyright (C) 2012 by Darren Reed.
  *
  * See the IPFILTER.LICENCE file for details on licencing.
  */
@@ -16,30 +17,23 @@
 #include <sys/param.h>
 #include <sys/time.h>
 #include <sys/file.h>
-#if defined(_KERNEL) && defined(__NetBSD_Version__) && \
-    (__NetBSD_Version__ >= 399002000)
+#if defined(_KERNEL) && \
+    (defined(__NetBSD_Version) && (__NetBSD_Version >= 399002000))
 # include <sys/kauth.h>
 #endif
-#if defined(__NetBSD__) && (NetBSD >= 199905) && !defined(IPFILTER_LKM) && \
-    defined(_KERNEL)
-#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>
 # include <string.h>
 # include <stdlib.h>
-# define _KERNEL
-# ifdef __OpenBSD__
+# define KERNEL
+# ifdef _OpenBSD__
 struct file;
 # endif
 # include <sys/uio.h>
-# undef _KERNEL
+# undef KERNEL
 #endif
-#if defined(_KERNEL) && (__FreeBSD_version >= 220000)
+#if defined(_KERNEL) && \
+    defined(__FreeBSD_version) && (__FreeBSD_version >= 220000)
 # include <sys/filio.h>
 # include <sys/fcntl.h>
 #else
@@ -61,7 +55,7 @@
 #if defined(__SVR4) || defined(__svr4__)
 # include <sys/filio.h>
 # include <sys/byteorder.h>
-# ifdef _KERNEL
+# ifdef KERNEL
 #  include <sys/dditypes.h>
 # endif
 # include <sys/stream.h>
@@ -73,14 +67,10 @@
 #include <net/if.h>
 #if __FreeBSD_version >= 300000
 # include <net/if_var.h>
-# if defined(_KERNEL) && !defined(IPFILTER_LKM)
-#  include "opt_ipfilter.h"
-# endif
 #endif
 #ifdef sun
 # include <net/af.h>
 #endif
-#include <net/route.h>
 #include <netinet/in.h>
 #include <netinet/in_systm.h>
 #include <netinet/ip.h>
@@ -99,17 +89,23 @@
 #include <netinet/ip_icmp.h>
 #include "netinet/ip_compat.h"
 #include <netinet/tcpip.h>
+#include "netinet/ipl.h"
 #include "netinet/ip_fil.h"
 #include "netinet/ip_nat.h"
 #include "netinet/ip_frag.h"
 #include "netinet/ip_state.h"
 #include "netinet/ip_proxy.h"
-#ifdef	IPFILTER_SYNC
+#include "netinet/ip_lookup.h"
+#include "netinet/ip_dstlist.h"
 #include "netinet/ip_sync.h"
-#endif
-#if (__FreeBSD_version >= 300000)
+#if FREEBSD_GE_REV(300000)
 # include <sys/malloc.h>
 #endif
+#ifdef HAS_SYS_MD5_H
+# include <sys/md5.h>
+#else
+# include "md5.h"
+#endif
 /* END OF INCLUDES */
 
 #undef	SOCKADDR_IN
@@ -117,27 +113,97 @@
 
 #if !defined(lint)
 static const char sccsid[] = "@(#)ip_nat.c	1.11 6/5/96 (C) 1995 Darren Reed";
-static const char rcsid[] = "@(#)$FreeBSD$";
-/* static const char rcsid[] = "@(#)$Id: ip_nat.c,v 1.5 2013-01-08 01:31:40 laffer1 Exp $"; */
+static const char rcsid[] = "@(#)$FreeBSD: stable/10/sys/contrib/ipfilter/netinet/ip_nat.c 324513 2017-10-11 05:02:36Z cy $";
+/* static const char rcsid[] = "@(#)$Id: ip_nat.c,v 2.195.2.102 2007/10/16 10:08:10 darrenr Exp $"; */
 #endif
 
 
+#define	NATFSUM(n,v,f)	((v) == 4 ? (n)->f.in4.s_addr : (n)->f.i6[0] + \
+			 (n)->f.i6[1] + (n)->f.i6[2] + (n)->f.i6[3])
+#define	NBUMP(x)	softn->(x)++
+#define	NBUMPD(x, y)	do { \
+				softn->x.y++; \
+				DT(y); \
+			} while (0)
+#define	NBUMPSIDE(y,x)	softn->ipf_nat_stats.ns_side[y].x++
+#define	NBUMPSIDED(y,x)	do { softn->ipf_nat_stats.ns_side[y].x++; \
+			     DT(x); } while (0)
+#define	NBUMPSIDEX(y,x,z) \
+			do { softn->ipf_nat_stats.ns_side[y].x++; \
+			     DT(z); } while (0)
+#define	NBUMPSIDEDF(y,x)do { softn->ipf_nat_stats.ns_side[y].x++; \
+			     DT1(x, fr_info_t *, fin); } while (0)
+
+frentry_t	ipfnatblock;
+
+static ipftuneable_t ipf_nat_tuneables[] = {
+	/* nat */
+	{ { (void *)offsetof(ipf_nat_softc_t, ipf_nat_lock) },
+		"nat_lock",	0,	1,
+		stsizeof(ipf_nat_softc_t, ipf_nat_lock),
+		IPFT_RDONLY,		NULL,	NULL },
+	{ { (void *)offsetof(ipf_nat_softc_t, ipf_nat_table_sz) },
+		"nat_table_size", 1,	0x7fffffff,
+		stsizeof(ipf_nat_softc_t, ipf_nat_table_sz),
+		0,			NULL,	ipf_nat_rehash },
+	{ { (void *)offsetof(ipf_nat_softc_t, ipf_nat_table_max) },
+		"nat_table_max", 1,	0x7fffffff,
+		stsizeof(ipf_nat_softc_t, ipf_nat_table_max),
+		0,			NULL,	NULL },
+	{ { (void *)offsetof(ipf_nat_softc_t, ipf_nat_maprules_sz) },
+		"nat_rules_size", 1,	0x7fffffff,
+		stsizeof(ipf_nat_softc_t, ipf_nat_maprules_sz),
+		0,			NULL,	ipf_nat_rehash_rules },
+	{ { (void *)offsetof(ipf_nat_softc_t, ipf_nat_rdrrules_sz) },
+		"rdr_rules_size", 1,	0x7fffffff,
+		stsizeof(ipf_nat_softc_t, ipf_nat_rdrrules_sz),
+		0,			NULL,	ipf_nat_rehash_rules },
+	{ { (void *)offsetof(ipf_nat_softc_t, ipf_nat_hostmap_sz) },
+		"hostmap_size",	1,	0x7fffffff,
+		stsizeof(ipf_nat_softc_t, ipf_nat_hostmap_sz),
+		0,			NULL,	ipf_nat_hostmap_rehash },
+	{ { (void *)offsetof(ipf_nat_softc_t, ipf_nat_maxbucket) },
+		"nat_maxbucket",1,	0x7fffffff,
+		stsizeof(ipf_nat_softc_t, ipf_nat_maxbucket),
+		0,			NULL,	NULL },
+	{ { (void *)offsetof(ipf_nat_softc_t, ipf_nat_logging) },
+		"nat_logging",	0,	1,
+		stsizeof(ipf_nat_softc_t, ipf_nat_logging),
+		0,			NULL,	NULL },
+	{ { (void *)offsetof(ipf_nat_softc_t, ipf_nat_doflush) },
+		"nat_doflush",	0,	1,
+		stsizeof(ipf_nat_softc_t, ipf_nat_doflush),
+		0,			NULL,	NULL },
+	{ { (void *)offsetof(ipf_nat_softc_t, ipf_nat_table_wm_low) },
+		"nat_table_wm_low",	1,	99,
+		stsizeof(ipf_nat_softc_t, ipf_nat_table_wm_low),
+		0,			NULL,	NULL },
+	{ { (void *)offsetof(ipf_nat_softc_t, ipf_nat_table_wm_high) },
+		"nat_table_wm_high",	2,	100,
+		stsizeof(ipf_nat_softc_t, ipf_nat_table_wm_high),
+		0,			NULL,	NULL },
+	{ { 0 },
+		NULL,			0,	0,
+		0,
+		0,			NULL,	NULL }
+};
+
 /* ======================================================================== */
 /* How the NAT is organised and works.                                      */
 /*                                                                          */
 /* Inside (interface y) NAT       Outside (interface x)                     */
 /* -------------------- -+- -------------------------------------           */
-/* Packet going          |   out, processsed by fr_checknatout() for x      */
+/* Packet going          |   out, processsed by ipf_nat_checkout() for x    */
 /* ------------>         |   ------------>                                  */
 /* src=10.1.1.1          |   src=192.1.1.1                                  */
 /*                       |                                                  */
-/*                       |   in, processed by fr_checknatin() for x         */
+/*                       |   in, processed by ipf_nat_checkin() for x       */
 /* <------------         |   <------------                                  */
 /* dst=10.1.1.1          |   dst=192.1.1.1                                  */
 /* -------------------- -+- -------------------------------------           */
-/* fr_checknatout() - changes ip_src and if required, sport                 */
+/* ipf_nat_checkout() - changes ip_src and if required, sport               */
 /*             - creates a new mapping, if required.                        */
-/* fr_checknatin()  - changes ip_dst and if required, dport                 */
+/* ipf_nat_checkin()  - changes ip_dst and if required, dport               */
 /*                                                                          */
 /* In the NAT table, internal source is recorded as "in" and externally     */
 /* seen as "out".                                                           */
@@ -144,173 +210,304 @@
 /* ======================================================================== */
 
 
-nat_t	**nat_table[2] = { NULL, NULL },
-	*nat_instances = NULL;
-ipnat_t	*nat_list = NULL;
-u_int	ipf_nattable_max = NAT_TABLE_MAX;
-u_int	ipf_nattable_sz = NAT_TABLE_SZ;
-u_int	ipf_natrules_sz = NAT_SIZE;
-u_int	ipf_rdrrules_sz = RDR_SIZE;
-u_int	ipf_hostmap_sz = HOSTMAP_SIZE;
-u_int	fr_nat_maxbucket = 0,
-	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	**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;
+#if SOLARIS && !defined(INSTANCES)
+extern	int		pfil_delayed_copy;
+#endif
+
+static	int	ipf_nat_flush_entry __P((ipf_main_softc_t *, void *));
+static	int	ipf_nat_getent __P((ipf_main_softc_t *, caddr_t, int));
+static	int	ipf_nat_getsz __P((ipf_main_softc_t *, caddr_t, int));
+static	int	ipf_nat_putent __P((ipf_main_softc_t *, caddr_t, int));
+static	void	ipf_nat_addmap __P((ipf_nat_softc_t *, ipnat_t *));
+static	void	ipf_nat_addrdr __P((ipf_nat_softc_t *, ipnat_t *));
+static	int	ipf_nat_builddivertmp __P((ipf_nat_softc_t *, ipnat_t *));
+static	int	ipf_nat_clearlist __P((ipf_main_softc_t *, ipf_nat_softc_t *));
+static	int	ipf_nat_cmp_rules __P((ipnat_t *, ipnat_t *));
+static	int	ipf_nat_decap __P((fr_info_t *, nat_t *));
+static	void	ipf_nat_delrule __P((ipf_main_softc_t *, ipf_nat_softc_t *,
+				     ipnat_t *, int));
+static	int	ipf_nat_extraflush __P((ipf_main_softc_t *, ipf_nat_softc_t *, int));
+static	int	ipf_nat_finalise __P((fr_info_t *, nat_t *));
+static	int	ipf_nat_flushtable __P((ipf_main_softc_t *, ipf_nat_softc_t *));
+static	int	ipf_nat_getnext __P((ipf_main_softc_t *, ipftoken_t *,
+				     ipfgeniter_t *, ipfobj_t *));
+static	int	ipf_nat_gettable __P((ipf_main_softc_t *, ipf_nat_softc_t *,
+				      char *));
+static	hostmap_t *ipf_nat_hostmap __P((ipf_nat_softc_t *, ipnat_t *,
+					struct in_addr, struct in_addr,
+					struct in_addr, u_32_t));
+static	int	ipf_nat_icmpquerytype __P((int));
+static	int	ipf_nat_iterator __P((ipf_main_softc_t *, ipftoken_t *,
+				      ipfgeniter_t *, ipfobj_t *));
+static	int	ipf_nat_match __P((fr_info_t *, ipnat_t *));
+static	int	ipf_nat_matcharray __P((nat_t *, int *, u_long));
+static	int	ipf_nat_matchflush __P((ipf_main_softc_t *, ipf_nat_softc_t *,
+					caddr_t));
+static	void	ipf_nat_mssclamp __P((tcphdr_t *, u_32_t, fr_info_t *,
+				      u_short *));
+static	int	ipf_nat_newmap __P((fr_info_t *, nat_t *, natinfo_t *));
+static	int	ipf_nat_newdivert __P((fr_info_t *, nat_t *, natinfo_t *));
+static	int	ipf_nat_newrdr __P((fr_info_t *, nat_t *, natinfo_t *));
+static	int	ipf_nat_newrewrite __P((fr_info_t *, nat_t *, natinfo_t *));
+static	int	ipf_nat_nextaddr __P((fr_info_t *, nat_addr_t *, u_32_t *,
+				      u_32_t *));
+static	int	ipf_nat_nextaddrinit __P((ipf_main_softc_t *, char *,
+					  nat_addr_t *, int, void *));
+static	int	ipf_nat_resolverule __P((ipf_main_softc_t *, ipnat_t *));
+static	int	ipf_nat_ruleaddrinit __P((ipf_main_softc_t *,
+					  ipf_nat_softc_t *, ipnat_t *));
+static	void	ipf_nat_rule_fini __P((ipf_main_softc_t *, ipnat_t *));
+static	int	ipf_nat_rule_init __P((ipf_main_softc_t *, ipf_nat_softc_t *,
+				       ipnat_t *));
+static	int	ipf_nat_siocaddnat __P((ipf_main_softc_t *, ipf_nat_softc_t *,
+					ipnat_t *, int));
+static	void	ipf_nat_siocdelnat __P((ipf_main_softc_t *, ipf_nat_softc_t *,
+					ipnat_t *, int));
+static	void	ipf_nat_tabmove __P((ipf_nat_softc_t *, nat_t *));
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_nat_main_load                                           */
+/* Returns:     int - 0 == success, -1 == failure                           */
+/* Parameters:  Nil                                                         */
+/*                                                                          */
+/* The only global NAT structure that needs to be initialised is the filter */
+/* rule that is used with blocking packets.                                 */
+/* ------------------------------------------------------------------------ */
+int
+ipf_nat_main_load()
+{
+	bzero((char *)&ipfnatblock, sizeof(ipfnatblock));
+	ipfnatblock.fr_flags = FR_BLOCK|FR_QUICK;
+	ipfnatblock.fr_ref = 1;
+
+	return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_nat_main_unload                                         */
+/* Returns:     int - 0 == success, -1 == failure                           */
+/* Parameters:  Nil                                                         */
+/*                                                                          */
+/* A null-op function that exists as a placeholder so that the flow in      */
+/* other functions is obvious.                                              */
+/* ------------------------------------------------------------------------ */
+int
+ipf_nat_main_unload()
+{
+	return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_nat_soft_create                                         */
+/* Returns:     void * - NULL = failure, else pointer to NAT context        */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*                                                                          */
+/* Allocate the initial soft context structure for NAT and populate it with */
+/* some default values. Creating the tables is left until we call _init so  */
+/* that sizes can be changed before we get under way.                       */
+/* ------------------------------------------------------------------------ */
+void *
+ipf_nat_soft_create(softc)
+	ipf_main_softc_t *softc;
+{
+	ipf_nat_softc_t *softn;
+
+	KMALLOC(softn, ipf_nat_softc_t *);
+	if (softn == NULL)
+		return NULL;
+
+	bzero((char *)softn, sizeof(*softn));
+
+	softn->ipf_nat_tune = ipf_tune_array_copy(softn,
+						  sizeof(ipf_nat_tuneables),
+						  ipf_nat_tuneables);
+	if (softn->ipf_nat_tune == NULL) {
+		ipf_nat_soft_destroy(softc, softn);
+		return NULL;
+	}
+	if (ipf_tune_array_link(softc, softn->ipf_nat_tune) == -1) {
+		ipf_nat_soft_destroy(softc, softn);
+		return NULL;
+	}
+
+	softn->ipf_nat_list_tail = &softn->ipf_nat_list;
+
+	softn->ipf_nat_table_max = NAT_TABLE_MAX;
+	softn->ipf_nat_table_sz = NAT_TABLE_SZ;
+	softn->ipf_nat_maprules_sz = NAT_SIZE;
+	softn->ipf_nat_rdrrules_sz = RDR_SIZE;
+	softn->ipf_nat_hostmap_sz = HOSTMAP_SIZE;
+	softn->ipf_nat_doflush = 0;
 #ifdef  IPFILTER_LOG
-int	nat_logging = 1;
+	softn->ipf_nat_logging = 1;
 #else
-int	nat_logging = 0;
+	softn->ipf_nat_logging = 0;
 #endif
 
-u_long	fr_defnatage = DEF_NAT_AGE,
-	fr_defnatipage = 120,		/* 60 seconds */
-	fr_defnaticmpage = 6;		/* 3 seconds */
-natstat_t nat_stats;
-int	fr_nat_lock = 0;
-int	fr_nat_init = 0;
-#if SOLARIS && !defined(_INET_IP_STACK_H)
-extern	int		pfil_delayed_copy;
-#endif
+	softn->ipf_nat_defage = DEF_NAT_AGE;
+	softn->ipf_nat_defipage = IPF_TTLVAL(60);
+	softn->ipf_nat_deficmpage = IPF_TTLVAL(3);
+	softn->ipf_nat_table_wm_high = 99;
+	softn->ipf_nat_table_wm_low = 90;
 
-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_delrdr __P((struct ipnat *));
-static	void	nat_delnat __P((struct ipnat *));
-static	int	fr_natgetent __P((caddr_t, int));
-static	int	fr_natgetsz __P((caddr_t, int));
-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	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	int	nat_finalise __P((fr_info_t *, nat_t *, natinfo_t *,
-				      tcphdr_t *, nat_t **, int));
-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	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 *));
+	return softn;
+}
 
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_nat_soft_destroy                                        */
+/* Returns:     Nil                                                         */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*                                                                          */
+/* ------------------------------------------------------------------------ */
+void
+ipf_nat_soft_destroy(softc, arg)
+	ipf_main_softc_t *softc;
+	void *arg;
+{
+	ipf_nat_softc_t *softn = arg;
 
+	if (softn->ipf_nat_tune != NULL) {
+		ipf_tune_array_unlink(softc, softn->ipf_nat_tune);
+		KFREES(softn->ipf_nat_tune, sizeof(ipf_nat_tuneables));
+		softn->ipf_nat_tune = NULL;
+	}
+
+	KFREE(softn);
+}
+
+
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_natinit                                                  */
+/* Function:    ipf_nat_init                                                */
 /* Returns:     int - 0 == success, -1 == failure                           */
-/* Parameters:  Nil                                                         */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
 /*                                                                          */
 /* Initialise all of the NAT locks, tables and other structures.            */
 /* ------------------------------------------------------------------------ */
-int fr_natinit()
+int
+ipf_nat_soft_init(softc, arg)
+	ipf_main_softc_t *softc;
+	void *arg;
 {
+	ipf_nat_softc_t *softn = arg;
+	ipftq_t *tq;
 	int i;
 
-	KMALLOCS(nat_table[0], nat_t **, sizeof(nat_t *) * ipf_nattable_sz);
-	if (nat_table[0] != NULL)
-		bzero((char *)nat_table[0], ipf_nattable_sz * sizeof(nat_t *));
-	else
+	KMALLOCS(softn->ipf_nat_table[0], nat_t **, \
+		 sizeof(nat_t *) * softn->ipf_nat_table_sz);
+
+	if (softn->ipf_nat_table[0] != NULL) {
+		bzero((char *)softn->ipf_nat_table[0],
+		      softn->ipf_nat_table_sz * sizeof(nat_t *));
+	} else {
 		return -1;
+	}
 
-	KMALLOCS(nat_table[1], nat_t **, sizeof(nat_t *) * ipf_nattable_sz);
-	if (nat_table[1] != NULL)
-		bzero((char *)nat_table[1], ipf_nattable_sz * sizeof(nat_t *));
-	else
+	KMALLOCS(softn->ipf_nat_table[1], nat_t **, \
+		 sizeof(nat_t *) * softn->ipf_nat_table_sz);
+
+	if (softn->ipf_nat_table[1] != NULL) {
+		bzero((char *)softn->ipf_nat_table[1],
+		      softn->ipf_nat_table_sz * sizeof(nat_t *));
+	} else {
 		return -2;
+	}
 
-	KMALLOCS(nat_rules, ipnat_t **, sizeof(ipnat_t *) * ipf_natrules_sz);
-	if (nat_rules != NULL)
-		bzero((char *)nat_rules, ipf_natrules_sz * sizeof(ipnat_t *));
-	else
+	KMALLOCS(softn->ipf_nat_map_rules, ipnat_t **, \
+		 sizeof(ipnat_t *) * softn->ipf_nat_maprules_sz);
+
+	if (softn->ipf_nat_map_rules != NULL) {
+		bzero((char *)softn->ipf_nat_map_rules,
+		      softn->ipf_nat_maprules_sz * sizeof(ipnat_t *));
+	} else {
 		return -3;
+	}
 
-	KMALLOCS(rdr_rules, ipnat_t **, sizeof(ipnat_t *) * ipf_rdrrules_sz);
-	if (rdr_rules != NULL)
-		bzero((char *)rdr_rules, ipf_rdrrules_sz * sizeof(ipnat_t *));
-	else
+	KMALLOCS(softn->ipf_nat_rdr_rules, ipnat_t **, \
+		 sizeof(ipnat_t *) * softn->ipf_nat_rdrrules_sz);
+
+	if (softn->ipf_nat_rdr_rules != NULL) {
+		bzero((char *)softn->ipf_nat_rdr_rules,
+		      softn->ipf_nat_rdrrules_sz * sizeof(ipnat_t *));
+	} else {
 		return -4;
+	}
 
-	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
+	KMALLOCS(softn->ipf_hm_maptable, hostmap_t **, \
+		 sizeof(hostmap_t *) * softn->ipf_nat_hostmap_sz);
+
+	if (softn->ipf_hm_maptable != NULL) {
+		bzero((char *)softn->ipf_hm_maptable,
+		      sizeof(hostmap_t *) * softn->ipf_nat_hostmap_sz);
+	} else {
 		return -5;
-	ipf_hm_maplist = NULL;
+	}
+	softn->ipf_hm_maplist = NULL;
 
-	KMALLOCS(nat_stats.ns_bucketlen[0], u_long *,
-		 ipf_nattable_sz * sizeof(u_long));
-	if (nat_stats.ns_bucketlen[0] == NULL)
+	KMALLOCS(softn->ipf_nat_stats.ns_side[0].ns_bucketlen, u_int *,
+		 softn->ipf_nat_table_sz * sizeof(u_int));
+
+	if (softn->ipf_nat_stats.ns_side[0].ns_bucketlen == NULL) {
 		return -6;
-	bzero((char *)nat_stats.ns_bucketlen[0],
-	      ipf_nattable_sz * sizeof(u_long));
+	}
+	bzero((char *)softn->ipf_nat_stats.ns_side[0].ns_bucketlen,
+	      softn->ipf_nat_table_sz * sizeof(u_int));
 
-	KMALLOCS(nat_stats.ns_bucketlen[1], u_long *,
-		 ipf_nattable_sz * sizeof(u_long));
-	if (nat_stats.ns_bucketlen[1] == NULL)
+	KMALLOCS(softn->ipf_nat_stats.ns_side[1].ns_bucketlen, u_int *,
+		 softn->ipf_nat_table_sz * sizeof(u_int));
+
+	if (softn->ipf_nat_stats.ns_side[1].ns_bucketlen == NULL) {
 		return -7;
+	}
 
-	bzero((char *)nat_stats.ns_bucketlen[1],
-	      ipf_nattable_sz * sizeof(u_long));
+	bzero((char *)softn->ipf_nat_stats.ns_side[1].ns_bucketlen,
+	      softn->ipf_nat_table_sz * sizeof(u_int));
 
-	if (fr_nat_maxbucket == 0) {
-		for (i = ipf_nattable_sz; i > 0; i >>= 1)
-			fr_nat_maxbucket++;
-		fr_nat_maxbucket *= 2;
+	if (softn->ipf_nat_maxbucket == 0) {
+		for (i = softn->ipf_nat_table_sz; i > 0; i >>= 1)
+			softn->ipf_nat_maxbucket++;
+		softn->ipf_nat_maxbucket *= 2;
 	}
 
-	fr_sttab_init(nat_tqb);
+	ipf_sttab_init(softc, softn->ipf_nat_tcptq);
 	/*
 	 * Increase this because we may have "keep state" following this too
 	 * and packet storms can occur if this is removed too quickly.
 	 */
-	nat_tqb[IPF_TCPS_CLOSED].ifq_ttl = fr_tcplastack;
-	nat_tqb[IPF_TCP_NSTATES - 1].ifq_next = &nat_udptq;
-	nat_udptq.ifq_ttl = fr_defnatage;
-	nat_udptq.ifq_ref = 1;
-	nat_udptq.ifq_head = NULL;
-	nat_udptq.ifq_tail = &nat_udptq.ifq_head;
-	MUTEX_INIT(&nat_udptq.ifq_lock, "nat ipftq udp tab");
-	nat_udptq.ifq_next = &nat_icmptq;
-	nat_icmptq.ifq_ttl = fr_defnaticmpage;
-	nat_icmptq.ifq_ref = 1;
-	nat_icmptq.ifq_head = NULL;
-	nat_icmptq.ifq_tail = &nat_icmptq.ifq_head;
-	MUTEX_INIT(&nat_icmptq.ifq_lock, "nat icmp ipftq tab");
-	nat_icmptq.ifq_next = &nat_iptq;
-	nat_iptq.ifq_ttl = fr_defnatipage;
-	nat_iptq.ifq_ref = 1;
-	nat_iptq.ifq_head = NULL;
-	nat_iptq.ifq_tail = &nat_iptq.ifq_head;
-	MUTEX_INIT(&nat_iptq.ifq_lock, "nat ip ipftq tab");
-	nat_iptq.ifq_next = NULL;
+	softn->ipf_nat_tcptq[IPF_TCPS_CLOSED].ifq_ttl = softc->ipf_tcplastack;
+	softn->ipf_nat_tcptq[IPF_TCP_NSTATES - 1].ifq_next =
+							&softn->ipf_nat_udptq;
 
-	for (i = 0; i < IPF_TCP_NSTATES; i++) {
-		if (nat_tqb[i].ifq_ttl < fr_defnaticmpage)
-			nat_tqb[i].ifq_ttl = fr_defnaticmpage;
+	IPFTQ_INIT(&softn->ipf_nat_udptq, softn->ipf_nat_defage,
+		   "nat ipftq udp tab");
+	softn->ipf_nat_udptq.ifq_next = &softn->ipf_nat_udpacktq;
+
+	IPFTQ_INIT(&softn->ipf_nat_udpacktq, softn->ipf_nat_defage,
+		   "nat ipftq udpack tab");
+	softn->ipf_nat_udpacktq.ifq_next = &softn->ipf_nat_icmptq;
+
+	IPFTQ_INIT(&softn->ipf_nat_icmptq, softn->ipf_nat_deficmpage,
+		   "nat icmp ipftq tab");
+	softn->ipf_nat_icmptq.ifq_next = &softn->ipf_nat_icmpacktq;
+
+	IPFTQ_INIT(&softn->ipf_nat_icmpacktq, softn->ipf_nat_defage,
+		   "nat icmpack ipftq tab");
+	softn->ipf_nat_icmpacktq.ifq_next = &softn->ipf_nat_iptq;
+
+	IPFTQ_INIT(&softn->ipf_nat_iptq, softn->ipf_nat_defipage,
+		   "nat ip ipftq tab");
+	softn->ipf_nat_iptq.ifq_next = &softn->ipf_nat_pending;
+
+	IPFTQ_INIT(&softn->ipf_nat_pending, 1, "nat pending ipftq tab");
+	softn->ipf_nat_pending.ifq_next = NULL;
+
+	for (i = 0, tq = softn->ipf_nat_tcptq; i < IPF_TCP_NSTATES; i++, tq++) {
+		if (tq->ifq_ttl < softn->ipf_nat_deficmpage)
+			tq->ifq_ttl = softn->ipf_nat_deficmpage;
 #ifdef LARGE_NAT
-		else if (nat_tqb[i].ifq_ttl > fr_defnatage)
-			nat_tqb[i].ifq_ttl = fr_defnatage;
+		else if (tq->ifq_ttl > softn->ipf_nat_defage)
+			tq->ifq_ttl = softn->ipf_nat_defage;
 #endif
 	}
 
@@ -319,14 +516,12 @@
 	 * this too and packet storms can occur if this is removed
 	 * too quickly.
 	 */
-	nat_tqb[IPF_TCPS_CLOSED].ifq_ttl = nat_tqb[IPF_TCPS_LAST_ACK].ifq_ttl;
+	softn->ipf_nat_tcptq[IPF_TCPS_CLOSED].ifq_ttl = softc->ipf_tcplastack;
 
-	RWLOCK_INIT(&ipf_nat, "ipf IP NAT rwlock");
-	RWLOCK_INIT(&ipf_natfrag, "ipf IP NAT-Frag rwlock");
-	MUTEX_INIT(&ipf_nat_new, "ipf nat new mutex");
-	MUTEX_INIT(&ipf_natio, "ipf nat io mutex");
+	MUTEX_INIT(&softn->ipf_nat_new, "ipf nat new mutex");
+	MUTEX_INIT(&softn->ipf_nat_io, "ipf nat io mutex");
 
-	fr_nat_init = 1;
+	softn->ipf_nat_inited = 1;
 
 	return 0;
 }
@@ -333,8 +528,113 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    nat_addrdr                                                  */
+/* Function:    ipf_nat_soft_fini                                           */
 /* Returns:     Nil                                                         */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*                                                                          */
+/* Free all memory used by NAT structures allocated at runtime.             */
+/* ------------------------------------------------------------------------ */
+int
+ipf_nat_soft_fini(softc, arg)
+	ipf_main_softc_t *softc;
+	void *arg;
+{
+	ipf_nat_softc_t *softn = arg;
+	ipftq_t *ifq, *ifqnext;
+
+	(void) ipf_nat_clearlist(softc, softn);
+	(void) ipf_nat_flushtable(softc, softn);
+
+	/*
+	 * Proxy timeout queues are not cleaned here because although they
+	 * exist on the NAT list, ipf_proxy_unload is called after unload
+	 * and the proxies actually are responsible for them being created.
+	 * Should the proxy timeouts have their own list?  There's no real
+	 * justification as this is the only complication.
+	 */
+	for (ifq = softn->ipf_nat_utqe; ifq != NULL; ifq = ifqnext) {
+		ifqnext = ifq->ifq_next;
+		if (ipf_deletetimeoutqueue(ifq) == 0)
+			ipf_freetimeoutqueue(softc, ifq);
+	}
+
+	if (softn->ipf_nat_table[0] != NULL) {
+		KFREES(softn->ipf_nat_table[0],
+		       sizeof(nat_t *) * softn->ipf_nat_table_sz);
+		softn->ipf_nat_table[0] = NULL;
+	}
+	if (softn->ipf_nat_table[1] != NULL) {
+		KFREES(softn->ipf_nat_table[1],
+		       sizeof(nat_t *) * softn->ipf_nat_table_sz);
+		softn->ipf_nat_table[1] = NULL;
+	}
+	if (softn->ipf_nat_map_rules != NULL) {
+		KFREES(softn->ipf_nat_map_rules,
+		       sizeof(ipnat_t *) * softn->ipf_nat_maprules_sz);
+		softn->ipf_nat_map_rules = NULL;
+	}
+	if (softn->ipf_nat_rdr_rules != NULL) {
+		KFREES(softn->ipf_nat_rdr_rules,
+		       sizeof(ipnat_t *) * softn->ipf_nat_rdrrules_sz);
+		softn->ipf_nat_rdr_rules = NULL;
+	}
+	if (softn->ipf_hm_maptable != NULL) {
+		KFREES(softn->ipf_hm_maptable,
+		       sizeof(hostmap_t *) * softn->ipf_nat_hostmap_sz);
+		softn->ipf_hm_maptable = NULL;
+	}
+	if (softn->ipf_nat_stats.ns_side[0].ns_bucketlen != NULL) {
+		KFREES(softn->ipf_nat_stats.ns_side[0].ns_bucketlen,
+		       sizeof(u_int) * softn->ipf_nat_table_sz);
+		softn->ipf_nat_stats.ns_side[0].ns_bucketlen = NULL;
+	}
+	if (softn->ipf_nat_stats.ns_side[1].ns_bucketlen != NULL) {
+		KFREES(softn->ipf_nat_stats.ns_side[1].ns_bucketlen,
+		       sizeof(u_int) * softn->ipf_nat_table_sz);
+		softn->ipf_nat_stats.ns_side[1].ns_bucketlen = NULL;
+	}
+
+	if (softn->ipf_nat_inited == 1) {
+		softn->ipf_nat_inited = 0;
+		ipf_sttab_destroy(softn->ipf_nat_tcptq);
+
+		MUTEX_DESTROY(&softn->ipf_nat_new);
+		MUTEX_DESTROY(&softn->ipf_nat_io);
+
+		MUTEX_DESTROY(&softn->ipf_nat_udptq.ifq_lock);
+		MUTEX_DESTROY(&softn->ipf_nat_udpacktq.ifq_lock);
+		MUTEX_DESTROY(&softn->ipf_nat_icmptq.ifq_lock);
+		MUTEX_DESTROY(&softn->ipf_nat_icmpacktq.ifq_lock);
+		MUTEX_DESTROY(&softn->ipf_nat_iptq.ifq_lock);
+		MUTEX_DESTROY(&softn->ipf_nat_pending.ifq_lock);
+	}
+
+	return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_nat_setlock                                             */
+/* Returns:     Nil                                                         */
+/* Parameters:  arg(I) - pointer to soft state information                  */
+/*              tmp(I) - new lock value                                     */
+/*                                                                          */
+/* Set the "lock status" of NAT to the value in tmp.                        */
+/* ------------------------------------------------------------------------ */
+void
+ipf_nat_setlock(arg, tmp)
+	void *arg;
+	int tmp;
+{
+	ipf_nat_softc_t *softn = arg;
+
+	softn->ipf_nat_lock = tmp;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_nat_addrdr                                              */
+/* Returns:     Nil                                                         */
 /* Parameters:  n(I) - pointer to NAT rule to add                           */
 /*                                                                          */
 /* Adds a redirect rule to the hash table of redirect rules and the list of */
@@ -341,31 +641,41 @@
 /* loaded NAT rules.  Updates the bitmask indicating which netmasks are in  */
 /* use by redirect rules.                                                   */
 /* ------------------------------------------------------------------------ */
-static void nat_addrdr(n)
-ipnat_t *n;
+static void
+ipf_nat_addrdr(softn, n)
+	ipf_nat_softc_t *softn;
+	ipnat_t *n;
 {
 	ipnat_t **np;
 	u_32_t j;
 	u_int hv;
+	u_int rhv;
 	int k;
 
-	k = count4bits(n->in_outmsk);
-	if ((k >= 0) && (k != 32))
-		rdr_masks |= 1 << k;
-	j = (n->in_outip & n->in_outmsk);
-	hv = NAT_HASH_FN(j, 0, ipf_rdrrules_sz);
-	np = rdr_rules + hv;
+	if (n->in_odstatype == FRI_NORMAL) {
+		k = count4bits(n->in_odstmsk);
+		ipf_inet_mask_add(k, &softn->ipf_nat_rdr_mask);
+		j = (n->in_odstaddr & n->in_odstmsk);
+		rhv = NAT_HASH_FN(j, 0, 0xffffffff);
+	} else {
+		ipf_inet_mask_add(0, &softn->ipf_nat_rdr_mask);
+		j = 0;
+		rhv = 0;
+	}
+	hv = rhv % softn->ipf_nat_rdrrules_sz;
+	np = softn->ipf_nat_rdr_rules + hv;
 	while (*np != NULL)
 		np = &(*np)->in_rnext;
 	n->in_rnext = NULL;
 	n->in_prnext = np;
-	n->in_hv = hv;
+	n->in_hv[0] = hv;
+	n->in_use++;
 	*np = n;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    nat_addnat                                                  */
+/* Function:    ipf_nat_addmap                                              */
 /* Returns:     Nil                                                         */
 /* Parameters:  n(I) - pointer to NAT rule to add                           */
 /*                                                                          */
@@ -373,63 +683,91 @@
 /* NAT rules.  Updates the bitmask indicating which netmasks are in use by  */
 /* redirect rules.                                                          */
 /* ------------------------------------------------------------------------ */
-static void nat_addnat(n)
-ipnat_t *n;
+static void
+ipf_nat_addmap(softn, n)
+	ipf_nat_softc_t *softn;
+	ipnat_t *n;
 {
 	ipnat_t **np;
 	u_32_t j;
 	u_int hv;
+	u_int rhv;
 	int k;
 
-	k = count4bits(n->in_inmsk);
-	if ((k >= 0) && (k != 32))
-		nat_masks |= 1 << k;
-	j = (n->in_inip & n->in_inmsk);
-	hv = NAT_HASH_FN(j, 0, ipf_natrules_sz);
-	np = nat_rules + hv;
+	if (n->in_osrcatype == FRI_NORMAL) {
+		k = count4bits(n->in_osrcmsk);
+		ipf_inet_mask_add(k, &softn->ipf_nat_map_mask);
+		j = (n->in_osrcaddr & n->in_osrcmsk);
+		rhv = NAT_HASH_FN(j, 0, 0xffffffff);
+	} else {
+		ipf_inet_mask_add(0, &softn->ipf_nat_map_mask);
+		j = 0;
+		rhv = 0;
+	}
+	hv = rhv % softn->ipf_nat_maprules_sz;
+	np = softn->ipf_nat_map_rules + hv;
 	while (*np != NULL)
 		np = &(*np)->in_mnext;
 	n->in_mnext = NULL;
 	n->in_pmnext = np;
-	n->in_hv = hv;
+	n->in_hv[1] = rhv;
+	n->in_use++;
 	*np = n;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    nat_delrdr                                                  */
+/* Function:    ipf_nat_delrdr                                              */
 /* Returns:     Nil                                                         */
 /* Parameters:  n(I) - pointer to NAT rule to delete                        */
 /*                                                                          */
 /* Removes a redirect rule from the hash table of redirect rules.           */
 /* ------------------------------------------------------------------------ */
-static void nat_delrdr(n)
-ipnat_t *n;
+void
+ipf_nat_delrdr(softn, n)
+	ipf_nat_softc_t *softn;
+	ipnat_t *n;
 {
+	if (n->in_odstatype == FRI_NORMAL) {
+		int k = count4bits(n->in_odstmsk);
+		ipf_inet_mask_del(k, &softn->ipf_nat_rdr_mask);
+	} else {
+		ipf_inet_mask_del(0, &softn->ipf_nat_rdr_mask);
+	}
 	if (n->in_rnext)
 		n->in_rnext->in_prnext = n->in_prnext;
 	*n->in_prnext = n->in_rnext;
+	n->in_use--;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    nat_delnat                                                  */
+/* Function:    ipf_nat_delmap                                              */
 /* Returns:     Nil                                                         */
 /* Parameters:  n(I) - pointer to NAT rule to delete                        */
 /*                                                                          */
 /* Removes a NAT map rule from the hash table of NAT map rules.             */
 /* ------------------------------------------------------------------------ */
-static void nat_delnat(n)
-ipnat_t *n;
+void
+ipf_nat_delmap(softn, n)
+	ipf_nat_softc_t *softn;
+	ipnat_t *n;
 {
+	if (n->in_osrcatype == FRI_NORMAL) {
+		int k = count4bits(n->in_osrcmsk);
+		ipf_inet_mask_del(k, &softn->ipf_nat_map_mask);
+	} else {
+		ipf_inet_mask_del(0, &softn->ipf_nat_map_mask);
+	}
 	if (n->in_mnext != NULL)
 		n->in_mnext->in_pmnext = n->in_pmnext;
 	*n->in_pmnext = n->in_mnext;
+	n->in_use--;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    nat_hostmap                                                 */
+/* Function:    ipf_nat_hostmap                                             */
 /* Returns:     struct hostmap* - NULL if no hostmap could be created,      */
 /*                                else a pointer to the hostmapping to use  */
 /* Parameters:  np(I)   - pointer to NAT rule                               */
@@ -442,50 +780,63 @@
 /* that is not doing port based translation.  If is not yet allocated, then */
 /* create a new entry if a non-NULL NAT rule pointer has been supplied.     */
 /* ------------------------------------------------------------------------ */
-static struct hostmap *nat_hostmap(np, src, dst, map, port)
-ipnat_t *np;
-struct in_addr src;
-struct in_addr dst;
-struct in_addr map;
-u_32_t port;
+static struct hostmap *
+ipf_nat_hostmap(softn, np, src, dst, map, port)
+	ipf_nat_softc_t *softn;
+	ipnat_t *np;
+	struct in_addr src;
+	struct in_addr dst;
+	struct in_addr map;
+	u_32_t port;
 {
 	hostmap_t *hm;
-	u_int hv;
+	u_int hv, rhv;
 
 	hv = (src.s_addr ^ dst.s_addr);
 	hv += src.s_addr;
 	hv += dst.s_addr;
-	hv %= HOSTMAP_SIZE;
-	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) &&
+	rhv = hv;
+	hv %= softn->ipf_nat_hostmap_sz;
+	for (hm = softn->ipf_hm_maptable[hv]; hm; hm = hm->hm_hnext)
+		if ((hm->hm_osrcip.s_addr == src.s_addr) &&
+		    (hm->hm_odstip.s_addr == dst.s_addr) &&
 		    ((np == NULL) || (np == hm->hm_ipnat)) &&
 		    ((port == 0) || (port == hm->hm_port))) {
+			softn->ipf_nat_stats.ns_hm_addref++;
 			hm->hm_ref++;
 			return hm;
 		}
 
-	if (np == NULL)
+	if (np == NULL) {
+		softn->ipf_nat_stats.ns_hm_nullnp++;
 		return NULL;
+	}
 
 	KMALLOC(hm, hostmap_t *);
 	if (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_next = softn->ipf_hm_maplist;
+		hm->hm_pnext = &softn->ipf_hm_maplist;
+		if (softn->ipf_hm_maplist != NULL)
+			softn->ipf_hm_maplist->hm_pnext = &hm->hm_next;
+		softn->ipf_hm_maplist = hm;
+		hm->hm_hnext = softn->ipf_hm_maptable[hv];
+		hm->hm_phnext = softn->ipf_hm_maptable + hv;
+		if (softn->ipf_hm_maptable[hv] != NULL)
+			softn->ipf_hm_maptable[hv]->hm_phnext = &hm->hm_hnext;
+		softn->ipf_hm_maptable[hv] = hm;
 		hm->hm_ipnat = np;
-		hm->hm_srcip = src;
-		hm->hm_dstip = dst;
-		hm->hm_mapip = map;
+		np->in_use++;
+		hm->hm_osrcip = src;
+		hm->hm_odstip = dst;
+		hm->hm_nsrcip = map;
+		hm->hm_ndstip.s_addr = 0;
 		hm->hm_ref = 1;
 		hm->hm_port = port;
+		hm->hm_hv = rhv;
+		hm->hm_v = 4;
+		softn->ipf_nat_stats.ns_hm_new++;
+	} else {
+		softn->ipf_nat_stats.ns_hm_newfail++;
 	}
 	return hm;
 }
@@ -492,7 +843,7 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_hostmapdel                                               */
+/* Function:    ipf_nat_hostmapdel                                          */
 /* Returns:     Nil                                                         */
 /* Parameters:  hmp(I) - pointer to hostmap structure pointer               */
 /* Write Locks: ipf_nat                                                     */
@@ -500,8 +851,10 @@
 /* Decrement the references to this hostmap structure by one.  If this      */
 /* reaches zero then remove it and free it.                                 */
 /* ------------------------------------------------------------------------ */
-void fr_hostmapdel(hmp)
-struct hostmap **hmp;
+void
+ipf_nat_hostmapdel(softc, hmp)
+	ipf_main_softc_t *softc;
+	struct hostmap **hmp;
 {
 	struct hostmap *hm;
 
@@ -510,6 +863,7 @@
 
 	hm->hm_ref--;
 	if (hm->hm_ref == 0) {
+		ipf_nat_rule_deref(softc, &hm->hm_ipnat);
 		if (hm->hm_hnext)
 			hm->hm_hnext->hm_phnext = hm->hm_phnext;
 		*hm->hm_phnext = hm->hm_hnext;
@@ -522,7 +876,7 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fix_outcksum                                                */
+/* Function:    ipf_fix_outcksum                                            */
 /* Returns:     Nil                                                         */
 /* Parameters:  fin(I) - pointer to packet information                      */
 /*              sp(I)  - location of 16bit checksum to update               */
@@ -530,10 +884,11 @@
 /*                                                                          */
 /* Adjusts the 16bit checksum by "n" for packets going out.                 */
 /* ------------------------------------------------------------------------ */
-void fix_outcksum(fin, sp, n)
-fr_info_t *fin;
-u_short *sp;
-u_32_t n;
+void
+ipf_fix_outcksum(cksum, sp, n, partial)
+	int cksum;
+	u_short *sp;
+	u_32_t n, partial;
 {
 	u_short sumshort;
 	u_32_t sum1;
@@ -541,13 +896,16 @@
 	if (n == 0)
 		return;
 
-	if (n & NAT_HW_CKSUM) {
-		n &= 0xffff;
-		n += fin->fin_dlen;
-		n = (n & 0xffff) + (n >> 16);
-		*sp = n & 0xffff;
+	if (cksum == 4) {
+		*sp = 0;
 		return;
 	}
+	if (cksum == 2) {
+		sum1 = partial;
+		sum1 = (sum1 & 0xffff) + (sum1 >> 16);
+		*sp = htons(sum1);
+		return;
+	}
 	sum1 = (~ntohs(*sp)) & 0xffff;
 	sum1 += (n);
 	sum1 = (sum1 >> 16) + (sum1 & 0xffff);
@@ -559,7 +917,7 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fix_incksum                                                 */
+/* Function:    ipf_fix_incksum                                             */
 /* Returns:     Nil                                                         */
 /* Parameters:  fin(I) - pointer to packet information                      */
 /*              sp(I)  - location of 16bit checksum to update               */
@@ -567,10 +925,11 @@
 /*                                                                          */
 /* Adjusts the 16bit checksum by "n" for packets going in.                  */
 /* ------------------------------------------------------------------------ */
-void fix_incksum(fin, sp, n)
-fr_info_t *fin;
-u_short *sp;
-u_32_t n;
+void
+ipf_fix_incksum(cksum, sp, n, partial)
+	int cksum;
+	u_short *sp;
+	u_32_t n, partial;
 {
 	u_short sumshort;
 	u_32_t sum1;
@@ -578,13 +937,17 @@
 	if (n == 0)
 		return;
 
-	if (n & NAT_HW_CKSUM) {
-		n &= 0xffff;
-		n += fin->fin_dlen;
-		n = (n & 0xffff) + (n >> 16);
-		*sp = n & 0xffff;
+	if (cksum == 4) {
+		*sp = 0;
 		return;
 	}
+	if (cksum == 2) {
+		sum1 = partial;
+		sum1 = (sum1 & 0xffff) + (sum1 >> 16);
+		*sp = htons(sum1);
+		return;
+	}
+
 	sum1 = (~ntohs(*sp)) & 0xffff;
 	sum1 += ~(n) & 0xffff;
 	sum1 = (sum1 >> 16) + (sum1 & 0xffff);
@@ -596,7 +959,7 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fix_datacksum                                               */
+/* Function:    ipf_fix_datacksum                                           */
 /* Returns:     Nil                                                         */
 /* Parameters:  sp(I)  - location of 16bit checksum to update               */
 /*              n((I)  - amount to adjust checksum by                       */
@@ -613,9 +976,10 @@
 /* processing like hardware cksum or ntohs processing have been done by the */
 /* kernel on the data section.                                              */
 /* ------------------------------------------------------------------------ */
-void fix_datacksum(sp, n)
-u_short *sp;
-u_32_t n;
+void
+ipf_fix_datacksum(sp, n)
+	u_short *sp;
+	u_32_t n;
 {
 	u_short sumshort;
 	u_32_t sum1;
@@ -634,42 +998,48 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_nat_ioctl                                                */
+/* Function:    ipf_nat_ioctl                                               */
 /* Returns:     int - 0 == success, != 0 == failure                         */
-/* Parameters:  data(I) - pointer to ioctl data                             */
-/*              cmd(I)  - ioctl command integer                             */
-/*              mode(I) - file mode bits used with open                     */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              data(I)  - pointer to ioctl data                            */
+/*              cmd(I)   - ioctl command integer                            */
+/*              mode(I)  - file mode bits used with open                    */
+/*              uid(I)   - uid of calling process                           */
+/*              ctx(I)   - pointer used as key for finding context          */
 /*                                                                          */
 /* Processes an ioctl call made to operate on the IP Filter NAT device.     */
 /* ------------------------------------------------------------------------ */
-int fr_nat_ioctl(data, cmd, mode, uid, ctx)
-ioctlcmd_t cmd;
-caddr_t data;
-int mode, uid;
-void *ctx;
+int
+ipf_nat_ioctl(softc, data, cmd, mode, uid, ctx)
+	ipf_main_softc_t *softc;
+	ioctlcmd_t cmd;
+	caddr_t data;
+	int mode, uid;
+	void *ctx;
 {
-	ipnat_t *nat, *nt, *n = NULL, **np = NULL;
+	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
 	int error = 0, ret, arg, getlock;
+	ipnat_t *nat, *nt, *n;
 	ipnat_t natd;
 	SPL_INT(s);
 
-#if (BSD >= 199306) && defined(_KERNEL)
-# if defined(__NetBSD_Version__) && (__NetBSD_Version__ >= 399002000)
+#if BSD_GE_YEAR(199306) && defined(_KERNEL)
+# if NETBSD_GE_REV(399002000)
 	if ((mode & FWRITE) &&
 	     kauth_authorize_network(curlwp->l_cred, KAUTH_NETWORK_FIREWALL,
 				     KAUTH_REQ_NETWORK_FIREWALL_FW,
-				     NULL, NULL, NULL)) {
-		return EPERM;
-	}
+				     NULL, NULL, NULL))
 # else
 #  if defined(__FreeBSD_version) && (__FreeBSD_version >= 500034)
-	if (securelevel_ge(curthread->td_ucred, 3) && (mode & FWRITE)) {
+	if (securelevel_ge(curthread->td_ucred, 3) && (mode & FWRITE))
 #  else
-	if ((securelevel >= 3) && (mode & FWRITE)) {
+	if ((securelevel >= 3) && (mode & FWRITE))
 #  endif
+# endif
+	{
+		IPFERROR(60001);
 		return EPERM;
 	}
-# endif
 #endif
 
 #if defined(__osf__) && defined(_KERNEL)
@@ -678,48 +1048,69 @@
 	getlock = (mode & NAT_LOCKHELD) ? 0 : 1;
 #endif
 
-	nat = NULL;     /* XXX gcc -Wuninitialized */
-	if (cmd == (ioctlcmd_t)SIOCADNAT) {
-		KMALLOC(nt, ipnat_t *);
-	} else {
-		nt = NULL;
-	}
+	n = NULL;
+	nt = NULL;
+	nat = NULL;
 
-	if ((cmd == (ioctlcmd_t)SIOCADNAT) || (cmd == (ioctlcmd_t)SIOCRMNAT)) {
+	if ((cmd == (ioctlcmd_t)SIOCADNAT) || (cmd == (ioctlcmd_t)SIOCRMNAT) ||
+	    (cmd == (ioctlcmd_t)SIOCPURGENAT)) {
 		if (mode & NAT_SYSSPACE) {
 			bcopy(data, (char *)&natd, sizeof(natd));
+			nat = &natd;
 			error = 0;
 		} else {
-			error = fr_inobj(data, &natd, IPFOBJ_IPNAT);
+			bzero(&natd, sizeof(natd));
+			error = ipf_inobj(softc, data, NULL, &natd,
+					  IPFOBJ_IPNAT);
+			if (error != 0)
+				goto done;
+
+			if (natd.in_size < sizeof(ipnat_t)) {
+				error = EINVAL;
+				goto done;
+			}
+			KMALLOCS(nt, ipnat_t *, natd.in_size);
+			if (nt == NULL) {
+				IPFERROR(60070);
+				error = ENOMEM;
+				goto done;
+			}
+			bzero(nt, natd.in_size);
+			error = ipf_inobjsz(softc, data, nt, IPFOBJ_IPNAT,
+					    natd.in_size);
+			if (error)
+				goto done;
+			nat = nt;
 		}
-	}
 
-	if (error != 0)
-		goto done;
-
-	/*
-	 * For add/delete, look to see if the NAT entry is already present
-	 */
-	if ((cmd == (ioctlcmd_t)SIOCADNAT) || (cmd == (ioctlcmd_t)SIOCRMNAT)) {
-		nat = &natd;
-		if (nat->in_v == 0)	/* For backward compat. */
-			nat->in_v = 4;
+		/*
+		 * For add/delete, look to see if the NAT entry is
+		 * already present
+		 */
 		nat->in_flags &= IPN_USERFLAGS;
 		if ((nat->in_redir & NAT_MAPBLK) == 0) {
-			if ((nat->in_flags & IPN_SPLIT) == 0)
-				nat->in_inip &= nat->in_inmsk;
-			if ((nat->in_flags & IPN_IPRANGE) == 0)
-				nat->in_outip &= nat->in_outmsk;
+			if (nat->in_osrcatype == FRI_NORMAL ||
+			    nat->in_osrcatype == FRI_NONE)
+				nat->in_osrcaddr &= nat->in_osrcmsk;
+			if (nat->in_odstatype == FRI_NORMAL ||
+			    nat->in_odstatype == FRI_NONE)
+				nat->in_odstaddr &= nat->in_odstmsk;
+			if ((nat->in_flags & (IPN_SPLIT|IPN_SIPRANGE)) == 0) {
+				if (nat->in_nsrcatype == FRI_NORMAL)
+					nat->in_nsrcaddr &= nat->in_nsrcmsk;
+				if (nat->in_ndstatype == FRI_NORMAL)
+					nat->in_ndstaddr &= nat->in_ndstmsk;
+			}
 		}
-		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) == 0) {
-				if (nat->in_redir == NAT_REDIRECT &&
-				    nat->in_pnext != n->in_pnext)
-					continue;
+
+		error = ipf_nat_rule_init(softc, softn, nat);
+		if (error != 0)
+			goto done;
+
+		MUTEX_ENTER(&softn->ipf_nat_io);
+		for (n = softn->ipf_nat_list; n != NULL; n = n->in_next)
+			if (ipf_nat_cmp_rules(nat, n) == 0)
 				break;
-			}
 	}
 
 	switch (cmd)
@@ -729,24 +1120,27 @@
 	{
 		int tmp;
 
-		if (!(mode & FWRITE))
+		if (!(mode & FWRITE)) {
+			IPFERROR(60002);
 			error = EPERM;
-		else {
-			tmp = ipflog_clear(IPL_LOGNAT);
-			error = BCOPYOUT((char *)&tmp, (char *)data,
-					 sizeof(tmp));
-			if (error != 0)
+		} else {
+			tmp = ipf_log_clear(softc, IPL_LOGNAT);
+			error = BCOPYOUT(&tmp, data, sizeof(tmp));
+			if (error != 0) {
+				IPFERROR(60057);
 				error = EFAULT;
+			}
 		}
 		break;
 	}
 
 	case SIOCSETLG :
-		if (!(mode & FWRITE))
+		if (!(mode & FWRITE)) {
+			IPFERROR(60003);
 			error = EPERM;
-		else {
-			error = BCOPYIN((char *)data, (char *)&nat_logging,
-					sizeof(nat_logging));
+		} else {
+			error = BCOPYIN(data, &softn->ipf_nat_logging,
+					sizeof(softn->ipf_nat_logging));
 			if (error != 0)
 				error = EFAULT;
 		}
@@ -753,91 +1147,142 @@
 		break;
 
 	case SIOCGETLG :
-		error = BCOPYOUT((char *)&nat_logging, (char *)data,
-				 sizeof(nat_logging));
-		if (error != 0)
+		error = BCOPYOUT(&softn->ipf_nat_logging, data,
+				 sizeof(softn->ipf_nat_logging));
+		if (error != 0) {
+			IPFERROR(60004);
 			error = EFAULT;
+		}
 		break;
 
 	case FIONREAD :
-		arg = iplused[IPL_LOGNAT];
+		arg = ipf_log_bytesused(softc, IPL_LOGNAT);
 		error = BCOPYOUT(&arg, data, sizeof(arg));
-		if (error != 0)
+		if (error != 0) {
+			IPFERROR(60005);
 			error = EFAULT;
+		}
 		break;
 #endif
 	case SIOCADNAT :
 		if (!(mode & FWRITE)) {
+			IPFERROR(60006);
 			error = EPERM;
 		} else if (n != NULL) {
+			natd.in_flineno = n->in_flineno;
+			(void) ipf_outobj(softc, data, &natd, IPFOBJ_IPNAT);
+			IPFERROR(60007);
 			error = EEXIST;
 		} else if (nt == NULL) {
+			IPFERROR(60008);
 			error = ENOMEM;
 		}
 		if (error != 0) {
-			MUTEX_EXIT(&ipf_natio);
+			MUTEX_EXIT(&softn->ipf_nat_io);
 			break;
 		}
-		bcopy((char *)nat, (char *)nt, sizeof(*n));
-		error = nat_siocaddnat(nt, np, getlock);
-		MUTEX_EXIT(&ipf_natio);
-		if (error == 0)
+		if (nat != nt)
+			bcopy((char *)nat, (char *)nt, sizeof(*n));
+		error = ipf_nat_siocaddnat(softc, softn, nt, getlock);
+		MUTEX_EXIT(&softn->ipf_nat_io);
+		if (error == 0) {
+			nat = NULL;
 			nt = NULL;
+		}
 		break;
 
 	case SIOCRMNAT :
+	case SIOCPURGENAT :
 		if (!(mode & FWRITE)) {
+			IPFERROR(60009);
 			error = EPERM;
 			n = NULL;
 		} else if (n == NULL) {
+			IPFERROR(60010);
 			error = ESRCH;
 		}
 
 		if (error != 0) {
-			MUTEX_EXIT(&ipf_natio);
+			MUTEX_EXIT(&softn->ipf_nat_io);
 			break;
 		}
-		nat_siocdelnat(n, np, getlock);
+		if (cmd == (ioctlcmd_t)SIOCPURGENAT) {
+			error = ipf_outobjsz(softc, data, n, IPFOBJ_IPNAT,
+					     n->in_size);
+			if (error) {
+				MUTEX_EXIT(&softn->ipf_nat_io);
+				goto done;
+			}
+			n->in_flags |= IPN_PURGE;
+		}
+		ipf_nat_siocdelnat(softc, softn, n, getlock);
 
-		MUTEX_EXIT(&ipf_natio);
+		MUTEX_EXIT(&softn->ipf_nat_io);
 		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 = 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;
-		nat_stats.ns_rdrtab_sz = ipf_rdrrules_sz;
-		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);
+	    {
+		natstat_t *nsp = &softn->ipf_nat_stats;
+
+		nsp->ns_side[0].ns_table = softn->ipf_nat_table[0];
+		nsp->ns_side[1].ns_table = softn->ipf_nat_table[1];
+		nsp->ns_list = softn->ipf_nat_list;
+		nsp->ns_maptable = softn->ipf_hm_maptable;
+		nsp->ns_maplist = softn->ipf_hm_maplist;
+		nsp->ns_nattab_sz = softn->ipf_nat_table_sz;
+		nsp->ns_nattab_max = softn->ipf_nat_table_max;
+		nsp->ns_rultab_sz = softn->ipf_nat_maprules_sz;
+		nsp->ns_rdrtab_sz = softn->ipf_nat_rdrrules_sz;
+		nsp->ns_hostmap_sz = softn->ipf_nat_hostmap_sz;
+		nsp->ns_instances = softn->ipf_nat_instances;
+		nsp->ns_ticks = softc->ipf_ticks;
+#ifdef IPFILTER_LOGGING
+		nsp->ns_log_ok = ipf_log_logok(softc, IPF_LOGNAT);
+		nsp->ns_log_fail = ipf_log_failures(softc, IPF_LOGNAT);
+#else
+		nsp->ns_log_ok = 0;
+		nsp->ns_log_fail = 0;
+#endif
+		error = ipf_outobj(softc, data, nsp, IPFOBJ_NATSTAT);
 		break;
+	    }
 
 	case SIOCGNATL :
 	    {
 		natlookup_t nl;
 
-		error = fr_inobj(data, &nl, IPFOBJ_NATLOOKUP);
+		error = ipf_inobj(softc, data, NULL, &nl, IPFOBJ_NATLOOKUP);
 		if (error == 0) {
 			void *ptr;
 
 			if (getlock) {
-				READ_ENTER(&ipf_nat);
+				READ_ENTER(&softc->ipf_nat);
 			}
-			ptr = nat_lookupredir(&nl);
+
+			switch (nl.nl_v)
+			{
+			case 4 :
+				ptr = ipf_nat_lookupredir(&nl);
+				break;
+#ifdef USE_INET6
+			case 6 :
+				ptr = ipf_nat6_lookupredir(&nl);
+				break;
+#endif
+			default:
+				ptr = NULL;
+				break;
+			}
+
 			if (getlock) {
-				RWLOCK_EXIT(&ipf_nat);
+				RWLOCK_EXIT(&softc->ipf_nat);
 			}
 			if (ptr != NULL) {
-				error = fr_outobj(data, &nl, IPFOBJ_NATLOOKUP);
+				error = ipf_outobj(softc, data, &nl,
+						   IPFOBJ_NATLOOKUP);
 			} else {
+				IPFERROR(60011);
 				error = ESRCH;
 			}
 		}
@@ -846,27 +1291,30 @@
 
 	case SIOCIPFFL :	/* old SIOCFLNAT & SIOCCNATL */
 		if (!(mode & FWRITE)) {
+			IPFERROR(60012);
 			error = EPERM;
 			break;
 		}
 		if (getlock) {
-			WRITE_ENTER(&ipf_nat);
+			WRITE_ENTER(&softc->ipf_nat);
 		}
 
 		error = BCOPYIN(data, &arg, sizeof(arg));
-		if (error != 0)
+		if (error != 0) {
+			IPFERROR(60013);
 			error = EFAULT;
-		else {
+		} else {
 			if (arg == 0)
-				ret = nat_flushtable();
+				ret = ipf_nat_flushtable(softc, softn);
 			else if (arg == 1)
-				ret = nat_clearlist();
+				ret = ipf_nat_clearlist(softc, softn);
 			else
-				ret = nat_extraflush(arg);
+				ret = ipf_nat_extraflush(softc, softn, arg);
+			ipf_proxy_flush(softc->ipf_proxy_soft, arg);
 		}
 
 		if (getlock) {
-			RWLOCK_EXIT(&ipf_nat);
+			RWLOCK_EXIT(&softc->ipf_nat);
 		}
 		if (error == 0) {
 			error = BCOPYOUT(&ret, data, sizeof(ret));
@@ -873,38 +1321,61 @@
 		}
 		break;
 
+	case SIOCMATCHFLUSH :
+		if (!(mode & FWRITE)) {
+			IPFERROR(60014);
+			error = EPERM;
+			break;
+		}
+		if (getlock) {
+			WRITE_ENTER(&softc->ipf_nat);
+		}
+
+		error = ipf_nat_matchflush(softc, softn, data);
+
+		if (getlock) {
+			RWLOCK_EXIT(&softc->ipf_nat);
+		}
+		break;
+
 	case SIOCPROXY :
-		error = appr_ioctl(data, cmd, mode, ctx);
+		error = ipf_proxy_ioctl(softc, data, cmd, mode, ctx);
 		break;
 
 	case SIOCSTLCK :
 		if (!(mode & FWRITE)) {
+			IPFERROR(60015);
 			error = EPERM;
 		} else {
-			error = fr_lock(data, &fr_nat_lock);
+			error = ipf_lock(data, &softn->ipf_nat_lock);
 		}
 		break;
 
 	case SIOCSTPUT :
 		if ((mode & FWRITE) != 0) {
-			error = fr_natputent(data, getlock);
+			error = ipf_nat_putent(softc, data, getlock);
 		} else {
+			IPFERROR(60016);
 			error = EACCES;
 		}
 		break;
 
 	case SIOCSTGSZ :
-		if (fr_nat_lock) {
-			error = fr_natgetsz(data, getlock);
-		} else
+		if (softn->ipf_nat_lock) {
+			error = ipf_nat_getsz(softc, data, getlock);
+		} else {
+			IPFERROR(60017);
 			error = EACCES;
+		}
 		break;
 
 	case SIOCSTGET :
-		if (fr_nat_lock) {
-			error = fr_natgetent(data, getlock);
-		} else
+		if (softn->ipf_nat_lock) {
+			error = ipf_nat_getent(softc, data, getlock);
+		} else {
+			IPFERROR(60018);
 			error = EACCES;
+		}
 		break;
 
 	case SIOCGENITER :
@@ -911,15 +1382,19 @@
 	    {
 		ipfgeniter_t iter;
 		ipftoken_t *token;
+		ipfobj_t obj;
 
+		error = ipf_inobj(softc, data, &obj, &iter, IPFOBJ_GENITER);
+		if (error != 0)
+			break;
+
 		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);
+		token = ipf_token_find(softc, iter.igi_type, uid, ctx);
+		if (token != NULL) {
+			error  = ipf_nat_iterator(softc, token, &iter, &obj);
+			WRITE_ENTER(&softc->ipf_tokens);
+			ipf_token_deref(softc, token);
+			RWLOCK_EXIT(&softc->ipf_tokens);
 		}
 		SPL_X(s);
 		break;
@@ -926,166 +1401,147 @@
 	    }
 
 	case SIOCIPFDELTOK :
-		error = BCOPYIN((caddr_t)data, (caddr_t)&arg, sizeof(arg));
+		error = BCOPYIN(data, &arg, sizeof(arg));
 		if (error == 0) {
 			SPL_SCHED(s);
-			error = ipf_deltoken(arg, uid, ctx);
+			error = ipf_token_del(softc, arg, uid, ctx);
 			SPL_X(s);
 		} else {
+			IPFERROR(60019);
 			error = EFAULT;
 		}
 		break;
 
 	case SIOCGTQTAB :
-		error = fr_outobj(data, nat_tqb, IPFOBJ_STATETQTAB);
+		error = ipf_outobj(softc, data, softn->ipf_nat_tcptq,
+				   IPFOBJ_STATETQTAB);
 		break;
 
 	case SIOCGTABL :
-		error = nat_gettable(data);
+		error = ipf_nat_gettable(softc, softn, data);
 		break;
 
 	default :
+		IPFERROR(60020);
 		error = EINVAL;
 		break;
 	}
 done:
+	if (nat != NULL)
+		ipf_nat_rule_fini(softc, nat);
 	if (nt != NULL)
-		KFREE(nt);
+		KFREES(nt, nt->in_size);
 	return error;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    nat_siocaddnat                                              */
+/* Function:    ipf_nat_siocaddnat                                          */
 /* Returns:     int - 0 == success, != 0 == failure                         */
-/* Parameters:  n(I)       - pointer to new NAT rule                        */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              softn(I) - pointer to NAT context structure                 */
+/*              n(I)       - pointer to new NAT rule                        */
 /*              np(I)      - pointer to where to insert new NAT rule        */
-/*              getlock(I) - flag indicating if lock on ipf_nat is held     */
-/* Mutex Locks: ipf_natio                                                   */
+/*              getlock(I) - flag indicating if lock on  is held            */
+/* Mutex Locks: ipf_nat_io                                                   */
 /*                                                                          */
 /* Handle SIOCADNAT.  Resolve and calculate details inside the NAT rule     */
 /* from information passed to the kernel, then add it  to the appropriate   */
 /* NAT rule table(s).                                                       */
 /* ------------------------------------------------------------------------ */
-static int nat_siocaddnat(n, np, getlock)
-ipnat_t *n, **np;
-int getlock;
+static int
+ipf_nat_siocaddnat(softc, softn, n, getlock)
+	ipf_main_softc_t *softc;
+	ipf_nat_softc_t *softn;
+	ipnat_t *n;
+	int getlock;
 {
-	int error = 0, i, j;
+	int error = 0;
 
-	if (nat_resolverule(n) != 0)
+	if (ipf_nat_resolverule(softc, n) != 0) {
+		IPFERROR(60022);
 		return ENOENT;
+	}
 
-	if ((n->in_age[0] == 0) && (n->in_age[1] != 0))
+	if ((n->in_age[0] == 0) && (n->in_age[1] != 0)) {
+		IPFERROR(60023);
 		return EINVAL;
+	}
 
-	n->in_use = 0;
-	if (n->in_redir & NAT_MAPBLK)
-		n->in_space = USABLE_PORTS * ~ntohl(n->in_outmsk);
-	else if (n->in_flags & IPN_AUTOPORTMAP)
-		n->in_space = USABLE_PORTS * ~ntohl(n->in_inmsk);
-	else if (n->in_flags & IPN_IPRANGE)
-		n->in_space = ntohl(n->in_outmsk) - ntohl(n->in_outip);
-	else if (n->in_flags & IPN_SPLIT)
-		n->in_space = 2;
-	else if (n->in_outmsk != 0)
-		n->in_space = ~ntohl(n->in_outmsk);
-	else
-		n->in_space = 1;
-
-	/*
-	 * Calculate the number of valid IP addresses in the output
-	 * mapping range.  In all cases, the range is inclusive of
-	 * the start and ending IP addresses.
-	 * If to a CIDR address, lose 2: broadcast + network address
-	 *                               (so subtract 1)
-	 * If to a range, add one.
-	 * If to a single IP address, set to 1.
-	 */
-	if (n->in_space) {
-		if ((n->in_flags & IPN_IPRANGE) != 0)
-			n->in_space += 1;
-		else
-			n->in_space -= 1;
-	} else
-		n->in_space = 1;
-
-	if ((n->in_outmsk != 0xffffffff) && (n->in_outmsk != 0) &&
-	    ((n->in_flags & (IPN_IPRANGE|IPN_SPLIT)) == 0))
-		n->in_nip = ntohl(n->in_outip) + 1;
-	else if ((n->in_flags & IPN_SPLIT) &&
-		 (n->in_redir & NAT_REDIRECT))
-		n->in_nip = ntohl(n->in_inip);
-	else
-		n->in_nip = ntohl(n->in_outip);
-	if (n->in_redir & NAT_MAP) {
-		n->in_pnext = ntohs(n->in_pmin);
+	if (n->in_redir == (NAT_DIVERTUDP|NAT_MAP)) {
 		/*
-		 * Multiply by the number of ports made available.
+		 * Prerecord whether or not the destination of the divert
+		 * is local or not to the interface the packet is going
+		 * to be sent out.
 		 */
-		if (ntohs(n->in_pmax) >= ntohs(n->in_pmin)) {
-			n->in_space *= (ntohs(n->in_pmax) -
-					ntohs(n->in_pmin) + 1);
-			/*
-			 * Because two different sources can map to
-			 * different destinations but use the same
-			 * local IP#/port #.
-			 * If the result is smaller than in_space, then
-			 * we may have wrapped around 32bits.
-			 */
-			i = n->in_inmsk;
-			if ((i != 0) && (i != 0xffffffff)) {
-				j = n->in_space * (~ntohl(i) + 1);
-				if (j >= n->in_space)
-					n->in_space = j;
-				else
-					n->in_space = 0xffffffff;
-			}
-		}
-		/*
-		 * If no protocol is specified, multiple by 256 to allow for
-		 * at least one IP:IP mapping per protocol.
-		 */
-		if ((n->in_flags & IPN_TCPUDPICMP) == 0) {
-				j = n->in_space * 256;
-				if (j >= n->in_space)
-					n->in_space = j;
-				else
-					n->in_space = 0xffffffff;
-		}
+		n->in_dlocal = ipf_deliverlocal(softc, n->in_v[1],
+						n->in_ifps[1], &n->in_ndstip6);
 	}
 
-	/* Otherwise, these fields are preset */
-
 	if (getlock) {
-		WRITE_ENTER(&ipf_nat);
+		WRITE_ENTER(&softc->ipf_nat);
 	}
 	n->in_next = NULL;
-	*np = n;
+	n->in_pnext = softn->ipf_nat_list_tail;
+	*n->in_pnext = n;
+	softn->ipf_nat_list_tail = &n->in_next;
+	n->in_use++;
 
-	if (n->in_age[0] != 0)
-		n->in_tqehead[0] = fr_addtimeoutqueue(&nat_utqe, n->in_age[0]);
-
-	if (n->in_age[1] != 0)
-		n->in_tqehead[1] = fr_addtimeoutqueue(&nat_utqe, n->in_age[1]);
-
 	if (n->in_redir & NAT_REDIRECT) {
 		n->in_flags &= ~IPN_NOTDST;
-		nat_addrdr(n);
+		switch (n->in_v[0])
+		{
+		case 4 :
+			ipf_nat_addrdr(softn, n);
+			break;
+#ifdef USE_INET6
+		case 6 :
+			ipf_nat6_addrdr(softn, n);
+			break;
+#endif
+		default :
+			break;
+		}
+		ATOMIC_INC32(softn->ipf_nat_stats.ns_rules_rdr);
 	}
+
 	if (n->in_redir & (NAT_MAP|NAT_MAPBLK)) {
 		n->in_flags &= ~IPN_NOTSRC;
-		nat_addnat(n);
+		switch (n->in_v[0])
+		{
+		case 4 :
+			ipf_nat_addmap(softn, n);
+			break;
+#ifdef USE_INET6
+		case 6 :
+			ipf_nat6_addmap(softn, n);
+			break;
+#endif
+		default :
+			break;
+		}
+		ATOMIC_INC32(softn->ipf_nat_stats.ns_rules_map);
 	}
+
+	if (n->in_age[0] != 0)
+		n->in_tqehead[0] = ipf_addtimeoutqueue(softc,
+						       &softn->ipf_nat_utqe,
+						       n->in_age[0]);
+
+	if (n->in_age[1] != 0)
+		n->in_tqehead[1] = ipf_addtimeoutqueue(softc,
+						       &softn->ipf_nat_utqe,
+						       n->in_age[1]);
+
 	MUTEX_INIT(&n->in_lock, "ipnat rule lock");
 
 	n = NULL;
-	nat_stats.ns_rules++;
-#if SOLARIS && !defined(_INET_IP_STACK_H)
+	ATOMIC_INC32(softn->ipf_nat_stats.ns_rules);
+#if SOLARIS && !defined(INSTANCES)
 	pfil_delayed_copy = 0;
 #endif
 	if (getlock) {
-		RWLOCK_EXIT(&ipf_nat);			/* WRITE */
+		RWLOCK_EXIT(&softc->ipf_nat);			/* WRITE */
 	}
 
 	return error;
@@ -1093,30 +1549,113 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    nat_resolvrule                                              */
+/* Function:    ipf_nat_ruleaddrinit                                        */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              softn(I) - pointer to NAT context structure                 */
+/*              n(I)     - pointer to NAT rule                              */
+/*                                                                          */
+/* Initialise all of the NAT address structures in a NAT rule.              */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_nat_ruleaddrinit(softc, softn, n)
+	ipf_main_softc_t *softc;
+	ipf_nat_softc_t *softn;
+	ipnat_t *n;
+{
+	int idx, error;
+
+	if ((n->in_ndst.na_atype == FRI_LOOKUP) &&
+	    (n->in_ndst.na_type != IPLT_DSTLIST)) {
+		IPFERROR(60071);
+		return EINVAL;
+	}
+	if ((n->in_nsrc.na_atype == FRI_LOOKUP) &&
+	    (n->in_nsrc.na_type != IPLT_DSTLIST)) {
+		IPFERROR(60069);
+		return EINVAL;
+	}
+
+	if (n->in_redir == NAT_BIMAP) {
+		n->in_ndstaddr = n->in_osrcaddr;
+		n->in_ndstmsk = n->in_osrcmsk;
+		n->in_odstaddr = n->in_nsrcaddr;
+		n->in_odstmsk = n->in_nsrcmsk;
+
+	}
+
+	if (n->in_redir & NAT_REDIRECT)
+		idx = 1;
+	else
+		idx = 0;
+	/*
+	 * Initialise all of the address fields.
+	 */
+	error = ipf_nat_nextaddrinit(softc, n->in_names, &n->in_osrc, 1,
+				     n->in_ifps[idx]);
+	if (error != 0)
+		return error;
+
+	error = ipf_nat_nextaddrinit(softc, n->in_names, &n->in_odst, 1,
+				     n->in_ifps[idx]);
+	if (error != 0)
+		return error;
+
+	error = ipf_nat_nextaddrinit(softc, n->in_names, &n->in_nsrc, 1,
+				     n->in_ifps[idx]);
+	if (error != 0)
+		return error;
+
+	error = ipf_nat_nextaddrinit(softc, n->in_names, &n->in_ndst, 1,
+				     n->in_ifps[idx]);
+	if (error != 0)
+		return error;
+
+	if (n->in_redir & NAT_DIVERTUDP)
+		ipf_nat_builddivertmp(softn, n);
+
+	return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_nat_resolvrule                                          */
 /* Returns:     Nil                                                         */
-/* Parameters:  n(I)  - pointer to NAT rule                                 */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              n(I)     - pointer to NAT rule                              */
 /*                                                                          */
 /* Handle SIOCADNAT.  Resolve and calculate details inside the NAT rule     */
 /* from information passed to the kernel, then add it  to the appropriate   */
 /* NAT rule table(s).                                                       */
 /* ------------------------------------------------------------------------ */
-static int nat_resolverule(n)
-ipnat_t *n;
+static int
+ipf_nat_resolverule(softc, n)
+	ipf_main_softc_t *softc;
+	ipnat_t *n;
 {
-	n->in_ifnames[0][LIFNAMSIZ - 1] = '\0';
-	n->in_ifps[0] = fr_resolvenic(n->in_ifnames[0], 4);
+	char *base;
 
-	n->in_ifnames[1][LIFNAMSIZ - 1] = '\0';
-	if (n->in_ifnames[1][0] == '\0') {
-		(void) strncpy(n->in_ifnames[1], n->in_ifnames[0], LIFNAMSIZ);
+	base = n->in_names;
+
+	n->in_ifps[0] = ipf_resolvenic(softc, base + n->in_ifnames[0],
+				       n->in_v[0]);
+
+	if (n->in_ifnames[1] == -1) {
+		n->in_ifnames[1] = n->in_ifnames[0];
 		n->in_ifps[1] = n->in_ifps[0];
 	} else {
-		n->in_ifps[1] = fr_resolvenic(n->in_ifnames[1], 4);
+		n->in_ifps[1] = ipf_resolvenic(softc, base + n->in_ifnames[1],
+					       n->in_v[1]);
 	}
 
-	if (n->in_plabel[0] != '\0') {
-		n->in_apr = appr_lookup(n->in_p, n->in_plabel);
+	if (n->in_plabel != -1) {
+		if (n->in_redir & NAT_REDIRECT)
+			n->in_apr = ipf_proxy_lookup(softc->ipf_proxy_soft,
+						     n->in_pr[0],
+						     base + n->in_plabel);
+		else
+			n->in_apr = ipf_proxy_lookup(softc->ipf_proxy_soft,
+						     n->in_pr[1],
+						     base + n->in_plabel);
 		if (n->in_apr == NULL)
 			return -1;
 	}
@@ -1125,72 +1664,45 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    nat_siocdelnat                                              */
+/* Function:    ipf_nat_siocdelnat                                          */
 /* Returns:     int - 0 == success, != 0 == failure                         */
-/* Parameters:  n(I)       - pointer to new NAT rule                        */
-/*              np(I)      - pointer to where to insert new NAT rule        */
-/*              getlock(I) - flag indicating if lock on ipf_nat is held     */
-/* Mutex Locks: ipf_natio                                                   */
+/* Parameters:  softc(I)   - pointer to soft context main structure         */
+/*              softn(I)   - pointer to NAT context structure               */
+/*              n(I)       - pointer to new NAT rule                        */
+/*              getlock(I) - flag indicating if lock on  is held            */
+/* Mutex Locks: ipf_nat_io                                                  */
 /*                                                                          */
 /* Handle SIOCADNAT.  Resolve and calculate details inside the NAT rule     */
 /* from information passed to the kernel, then add it  to the appropriate   */
 /* NAT rule table(s).                                                       */
 /* ------------------------------------------------------------------------ */
-static void nat_siocdelnat(n, np, getlock)
-ipnat_t *n, **np;
-int getlock;
+static void
+ipf_nat_siocdelnat(softc, softn, n, getlock)
+	ipf_main_softc_t *softc;
+	ipf_nat_softc_t *softn;
+	ipnat_t *n;
+	int getlock;
 {
 	if (getlock) {
-		WRITE_ENTER(&ipf_nat);
+		WRITE_ENTER(&softc->ipf_nat);
 	}
-	if (n->in_redir & NAT_REDIRECT)
-		nat_delrdr(n);
-	if (n->in_redir & (NAT_MAPBLK|NAT_MAP))
-		nat_delnat(n);
-	if (nat_list == NULL) {
-		nat_masks = 0;
-		rdr_masks = 0;
-	}
 
-	if (n->in_tqehead[0] != NULL) {
-		if (fr_deletetimeoutqueue(n->in_tqehead[0]) == 0) {
-			fr_freetimeoutqueue(n->in_tqehead[1]);
-		}
-	}
+	ipf_nat_delrule(softc, softn, n, 1);
 
-	if (n->in_tqehead[1] != NULL) {
-		if (fr_deletetimeoutqueue(n->in_tqehead[1]) == 0) {
-			fr_freetimeoutqueue(n->in_tqehead[1]);
-		}
-	}
-
-	*np = n->in_next;
-
-	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 && !defined(_INET_IP_STACK_H)
-		if (nat_stats.ns_rules == 0)
-			pfil_delayed_copy = 1;
-#endif
-	} else {
-		n->in_flags |= IPN_DELETE;
-		n->in_next = NULL;
-	}
 	if (getlock) {
-		RWLOCK_EXIT(&ipf_nat);			/* READ/WRITE */
+		RWLOCK_EXIT(&softc->ipf_nat);			/* READ/WRITE */
 	}
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_natgetsz                                                 */
+/* Function:    ipf_nat_getsz                                               */
 /* Returns:     int - 0 == success, != 0 is the error value.                */
-/* Parameters:  data(I) - pointer to natget structure with kernel pointer   */
-/*                        get the size of.                                  */
+/* Parameters:  softc(I)   - pointer to soft context main structure         */
+/*              data(I)    - pointer to natget structure with kernel        */
+/*                           pointer get the size of.                       */
+/*              getlock(I) - flag indicating whether or not the caller      */
+/*                           holds a lock on ipf_nat                        */
 /*                                                                          */
 /* Handle SIOCSTGSZ.                                                        */
 /* Return the size of the nat list entry to be copied back to user space.   */
@@ -1197,24 +1709,31 @@
 /* The size of the entry is stored in the ng_sz field and the enture natget */
 /* structure is copied back to the user.                                    */
 /* ------------------------------------------------------------------------ */
-static int fr_natgetsz(data, getlock)
-caddr_t data;
-int getlock;
+static int
+ipf_nat_getsz(softc, data, getlock)
+	ipf_main_softc_t *softc;
+	caddr_t data;
+	int getlock;
 {
+	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
 	ap_session_t *aps;
 	nat_t *nat, *n;
 	natget_t ng;
+	int error;
 
-	if (BCOPYIN(data, &ng, sizeof(ng)) != 0)
+	error = BCOPYIN(data, &ng, sizeof(ng));
+	if (error != 0) {
+		IPFERROR(60024);
 		return EFAULT;
+	}
 
 	if (getlock) {
-		READ_ENTER(&ipf_nat);
+		READ_ENTER(&softc->ipf_nat);
 	}
 
 	nat = ng.ng_ptr;
 	if (!nat) {
-		nat = nat_instances;
+		nat = softn->ipf_nat_instances;
 		ng.ng_sz = 0;
 		/*
 		 * Empty list so the size returned is 0.  Simple.
@@ -1221,10 +1740,13 @@
 		 */
 		if (nat == NULL) {
 			if (getlock) {
-				RWLOCK_EXIT(&ipf_nat);
+				RWLOCK_EXIT(&softc->ipf_nat);
 			}
-			if (BCOPYOUT(&ng, data, sizeof(ng)) != 0)
+			error = BCOPYOUT(&ng, data, sizeof(ng));
+			if (error != 0) {
+				IPFERROR(60025);
 				return EFAULT;
+			}
 			return 0;
 		}
 	} else {
@@ -1233,13 +1755,14 @@
 		 * current list of entries.  Security precaution to prevent
 		 * copying of random kernel data.
 		 */
-		for (n = nat_instances; n; n = n->nat_next)
+		for (n = softn->ipf_nat_instances; n; n = n->nat_next)
 			if (n == nat)
 				break;
 		if (n == NULL) {
 			if (getlock) {
-				RWLOCK_EXIT(&ipf_nat);
+				RWLOCK_EXIT(&softc->ipf_nat);
 			}
+			IPFERROR(60026);
 			return ESRCH;
 		}
 	}
@@ -1255,56 +1778,71 @@
 			ng.ng_sz += aps->aps_psiz;
 	}
 	if (getlock) {
-		RWLOCK_EXIT(&ipf_nat);
+		RWLOCK_EXIT(&softc->ipf_nat);
 	}
 
-	if (BCOPYOUT(&ng, data, sizeof(ng)) != 0)
+	error = BCOPYOUT(&ng, data, sizeof(ng));
+	if (error != 0) {
+		IPFERROR(60027);
 		return EFAULT;
+	}
 	return 0;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_natgetent                                                */
+/* Function:    ipf_nat_getent                                              */
 /* Returns:     int - 0 == success, != 0 is the error value.                */
-/* Parameters:  data(I) - pointer to natget structure with kernel pointer   */
-/*                        to NAT structure to copy out.                     */
+/* Parameters:  softc(I)   - pointer to soft context main structure         */
+/*              data(I)    - pointer to natget structure with kernel pointer*/
+/*                           to NAT structure to copy out.                  */
+/*              getlock(I) - flag indicating whether or not the caller      */
+/*                           holds a lock on ipf_nat                        */
 /*                                                                          */
 /* Handle SIOCSTGET.                                                        */
 /* Copies out NAT entry to user space.  Any additional data held for a      */
 /* proxy is also copied, as to is the NAT rule which was responsible for it */
 /* ------------------------------------------------------------------------ */
-static int fr_natgetent(data, getlock)
-caddr_t data;
-int getlock;
+static int
+ipf_nat_getent(softc, data, getlock)
+	ipf_main_softc_t *softc;
+	caddr_t data;
+	int getlock;
 {
+	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
 	int error, outsize;
 	ap_session_t *aps;
 	nat_save_t *ipn, ipns;
 	nat_t *n, *nat;
 
-	error = fr_inobj(data, &ipns, IPFOBJ_NATSAVE);
+	error = ipf_inobj(softc, data, NULL, &ipns, IPFOBJ_NATSAVE);
 	if (error != 0)
 		return error;
 
-	if ((ipns.ipn_dsize < sizeof(ipns)) || (ipns.ipn_dsize > 81920))
+	if ((ipns.ipn_dsize < sizeof(ipns)) || (ipns.ipn_dsize > 81920)) {
+		IPFERROR(60028);
 		return EINVAL;
+	}
 
 	KMALLOCS(ipn, nat_save_t *, ipns.ipn_dsize);
-	if (ipn == NULL)
+	if (ipn == NULL) {
+		IPFERROR(60029);
 		return ENOMEM;
+	}
 
 	if (getlock) {
-		READ_ENTER(&ipf_nat);
+		READ_ENTER(&softc->ipf_nat);
 	}
 
 	ipn->ipn_dsize = ipns.ipn_dsize;
 	nat = ipns.ipn_next;
 	if (nat == NULL) {
-		nat = nat_instances;
+		nat = softn->ipf_nat_instances;
 		if (nat == NULL) {
-			if (nat_instances == NULL)
+			if (softn->ipf_nat_instances == NULL) {
+				IPFERROR(60030);
 				error = ENOENT;
+			}
 			goto finished;
 		}
 	} else {
@@ -1313,10 +1851,11 @@
 		 * current list of entries.  Security precaution to prevent
 		 * copying of random kernel data.
 		 */
-		for (n = nat_instances; n; n = n->nat_next)
+		for (n = softn->ipf_nat_instances; n; n = n->nat_next)
 			if (n == nat)
 				break;
 		if (n == NULL) {
+			IPFERROR(60031);
 			error = ESRCH;
 			goto finished;
 		}
@@ -1333,7 +1872,7 @@
 	 */
 	if (nat->nat_ptr != NULL)
 		bcopy((char *)nat->nat_ptr, (char *)&ipn->ipn_ipnat,
-		      sizeof(ipn->ipn_ipnat));
+		      ipn->ipn_ipnat.in_size);
 
 	/*
 	 * If we also know the NAT entry has an associated filter rule,
@@ -1354,6 +1893,7 @@
 		char *s;
 
 		if (outsize < sizeof(*aps)) {
+			IPFERROR(60032);
 			error = ENOBUFS;
 			goto finished;
 		}
@@ -1364,20 +1904,23 @@
 		outsize -= sizeof(*aps);
 		if ((aps->aps_data != NULL) && (outsize >= aps->aps_psiz))
 			bcopy(aps->aps_data, s, aps->aps_psiz);
-		else
+		else {
+			IPFERROR(60033);
 			error = ENOBUFS;
+		}
 	}
 	if (error == 0) {
 		if (getlock) {
-			RWLOCK_EXIT(&ipf_nat);
+			READ_ENTER(&softc->ipf_nat);
 			getlock = 0;
 		}
-		error = fr_outobjsz(data, ipn, IPFOBJ_NATSAVE, ipns.ipn_dsize);
+		error = ipf_outobjsz(softc, data, ipn, IPFOBJ_NATSAVE,
+				     ipns.ipn_dsize);
 	}
 
 finished:
 	if (getlock) {
-		RWLOCK_EXIT(&ipf_nat);
+		READ_ENTER(&softc->ipf_nat);
 	}
 	if (ipn != NULL) {
 		KFREES(ipn, ipns.ipn_dsize);
@@ -1387,21 +1930,25 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_natputent                                                */
+/* Function:    ipf_nat_putent                                              */
 /* Returns:     int - 0 == success, != 0 is the error value.                */
-/* Parameters:  data(I) -     pointer to natget structure with NAT          */
-/*                            structure information to load into the kernel */
+/* Parameters:  softc(I)   - pointer to soft context main structure         */
+/*              data(I)    - pointer to natget structure with NAT           */
+/*                           structure information to load into the kernel  */
 /*              getlock(I) - flag indicating whether or not a write lock    */
-/*                           on ipf_nat is already held.                    */
+/*                           on is already held.                            */
 /*                                                                          */
 /* Handle SIOCSTPUT.                                                        */
 /* Loads a NAT table entry from user space, including a NAT rule, proxy and */
 /* firewall rule data structures, if pointers to them indicate so.          */
 /* ------------------------------------------------------------------------ */
-static int fr_natputent(data, getlock)
-caddr_t data;
-int getlock;
+static int
+ipf_nat_putent(softc, data, getlock)
+	ipf_main_softc_t *softc;
+	caddr_t data;
+	int getlock;
 {
+	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
 	nat_save_t ipn, *ipnn;
 	ap_session_t *aps;
 	nat_t *n, *nat;
@@ -1410,7 +1957,7 @@
 	ipnat_t *in;
 	int error;
 
-	error = fr_inobj(data, &ipn, IPFOBJ_NATSAVE);
+	error = ipf_inobj(softc, data, NULL, &ipn, IPFOBJ_NATSAVE);
 	if (error != 0)
 		return error;
 
@@ -1417,6 +1964,7 @@
 	/*
 	 * Initialise early because of code at junkput label.
 	 */
+	n = NULL;
 	in = NULL;
 	aps = NULL;
 	nat = NULL;
@@ -1429,17 +1977,21 @@
 	 */
 	if (ipn.ipn_dsize > sizeof(ipn)) {
 		if (ipn.ipn_dsize > 81920) {
+			IPFERROR(60034);
 			error = ENOMEM;
 			goto junkput;
 		}
 
 		KMALLOCS(ipnn, nat_save_t *, ipn.ipn_dsize);
-		if (ipnn == NULL)
+		if (ipnn == NULL) {
+			IPFERROR(60035);
 			return ENOMEM;
+		}
 
-		error = fr_inobjsz(data, ipnn, IPFOBJ_NATSAVE, ipn.ipn_dsize);
+		bzero(ipnn, ipn.ipn_dsize);
+		error = ipf_inobjsz(softc, data, ipnn, IPFOBJ_NATSAVE,
+				    ipn.ipn_dsize);
 		if (error != 0) {
-			error = EFAULT;
 			goto junkput;
 		}
 	} else
@@ -1447,13 +1999,29 @@
 
 	KMALLOC(nat, nat_t *);
 	if (nat == NULL) {
+		IPFERROR(60037);
 		error = ENOMEM;
 		goto junkput;
 	}
 
 	bcopy((char *)&ipnn->ipn_nat, (char *)nat, sizeof(*nat));
+
+	switch (nat->nat_v[0])
+	{
+	case 4:
+#ifdef USE_INET6
+	case 6 :
+#endif
+		break;
+	default :
+		IPFERROR(60061);
+		error = EPROTONOSUPPORT;
+		goto junkput;
+		/*NOTREACHED*/
+	}
+
 	/*
-	 * Initialize all these so that nat_delete() doesn't cause a crash.
+	 * Initialize all these so that ipf_nat_delete() doesn't cause a crash.
 	 */
 	bzero((char *)nat, offsetof(struct nat, nat_tqe));
 	nat->nat_tqe.tqe_pnext = NULL;
@@ -1466,20 +2034,22 @@
 	 */
 	in = ipnn->ipn_nat.nat_ptr;
 	if (in != NULL) {
-		KMALLOC(in, ipnat_t *);
+		KMALLOCS(in, ipnat_t *, ipnn->ipn_ipnat.in_size);
 		nat->nat_ptr = in;
 		if (in == NULL) {
+			IPFERROR(60038);
 			error = ENOMEM;
 			goto junkput;
 		}
-		bzero((char *)in, offsetof(struct ipnat, in_next6));
-		bcopy((char *)&ipnn->ipn_ipnat, (char *)in, sizeof(*in));
+		bcopy((char *)&ipnn->ipn_ipnat, (char *)in,
+		      ipnn->ipn_ipnat.in_size);
 		in->in_use = 1;
 		in->in_flags |= IPN_DELETE;
 
-		ATOMIC_INC(nat_stats.ns_rules);
+		ATOMIC_INC32(softn->ipf_nat_stats.ns_rules);
 
-		if (nat_resolverule(in) != 0) {
+		if (ipf_nat_resolverule(softc, in) != 0) {
+			IPFERROR(60039);
 			error = ESRCH;
 			goto junkput;
 		}
@@ -1491,43 +2061,76 @@
 	 * 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_v = nat->nat_v[0];
+	fin.fin_p = nat->nat_pr[0];
+	fin.fin_rev = nat->nat_rev;
+	fin.fin_ifp = nat->nat_ifps[0];
+	fin.fin_data[0] = ntohs(nat->nat_ndport);
+	fin.fin_data[1] = ntohs(nat->nat_nsport);
+
+	switch (nat->nat_dir)
+	{
+	case NAT_OUTBOUND :
+	case NAT_DIVERTOUT :
 		if (getlock) {
-			READ_ENTER(&ipf_nat);
+			READ_ENTER(&softc->ipf_nat);
 		}
-		n = nat_inlookup(&fin, nat->nat_flags, fin.fin_p,
-				 nat->nat_oip, nat->nat_inip);
+
+		fin.fin_v = nat->nat_v[1];
+		if (nat->nat_v[1] == 4) {
+			n = ipf_nat_inlookup(&fin, nat->nat_flags, fin.fin_p,
+					     nat->nat_ndstip, nat->nat_nsrcip);
+#ifdef USE_INET6
+		} else if (nat->nat_v[1] == 6) {
+			n = ipf_nat6_inlookup(&fin, nat->nat_flags, fin.fin_p,
+					      &nat->nat_ndst6.in6,
+					      &nat->nat_nsrc6.in6);
+#endif
+		}
+
 		if (getlock) {
-			RWLOCK_EXIT(&ipf_nat);
+			RWLOCK_EXIT(&softc->ipf_nat);
 		}
 		if (n != NULL) {
+			IPFERROR(60040);
 			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);
+		break;
+
+	case NAT_INBOUND :
+	case NAT_DIVERTIN :
 		if (getlock) {
-			READ_ENTER(&ipf_nat);
+			READ_ENTER(&softc->ipf_nat);
 		}
-		n = nat_outlookup(&fin, nat->nat_flags, fin.fin_p,
-				  nat->nat_outip, nat->nat_oip);
+
+		if (fin.fin_v == 4) {
+			n = ipf_nat_outlookup(&fin, nat->nat_flags, fin.fin_p,
+					      nat->nat_ndstip,
+					      nat->nat_nsrcip);
+#ifdef USE_INET6
+		} else if (fin.fin_v == 6) {
+			n = ipf_nat6_outlookup(&fin, nat->nat_flags, fin.fin_p,
+					       &nat->nat_ndst6.in6,
+					       &nat->nat_nsrc6.in6);
+#endif
+		}
+
 		if (getlock) {
-			RWLOCK_EXIT(&ipf_nat);
+			RWLOCK_EXIT(&softc->ipf_nat);
 		}
 		if (n != NULL) {
+			IPFERROR(60041);
 			error = EEXIST;
 			goto junkput;
 		}
-	} else {
+		break;
+
+	default :
+		IPFERROR(60042);
 		error = EINVAL;
 		goto junkput;
 	}
@@ -1541,6 +2144,7 @@
 		KMALLOC(aps, ap_session_t *);
 		nat->nat_aps = aps;
 		if (aps == NULL) {
+			IPFERROR(60043);
 			error = ENOMEM;
 			goto junkput;
 		}
@@ -1551,11 +2155,13 @@
 			aps->aps_apr = NULL;
 		if (aps->aps_psiz != 0) {
 			if (aps->aps_psiz > 81920) {
+				IPFERROR(60044);
 				error = ENOMEM;
 				goto junkput;
 			}
 			KMALLOCS(aps->aps_data, void *, aps->aps_psiz);
 			if (aps->aps_data == NULL) {
+				IPFERROR(60045);
 				error = ENOMEM;
 				goto junkput;
 			}
@@ -1577,12 +2183,13 @@
 			KMALLOC(fr, frentry_t *);
 			nat->nat_fr = fr;
 			if (fr == NULL) {
+				IPFERROR(60046);
 				error = ENOMEM;
 				goto junkput;
 			}
 			ipnn->ipn_nat.nat_fr = fr;
 			fr->fr_ref = 1;
-			(void) fr_outobj(data, ipnn, IPFOBJ_NATSAVE);
+			(void) ipf_outobj(softc, data, ipnn, IPFOBJ_NATSAVE);
 			bcopy((char *)&ipnn->ipn_fr, (char *)fr, sizeof(*fr));
 
 			fr->fr_ref = 1;
@@ -1594,9 +2201,9 @@
 			MUTEX_INIT(&fr->fr_lock, "nat-filter rule lock");
 		} else {
 			if (getlock) {
-				READ_ENTER(&ipf_nat);
+				READ_ENTER(&softc->ipf_nat);
 			}
-			for (n = nat_instances; n; n = n->nat_next)
+			for (n = softn->ipf_nat_instances; n; n = n->nat_next)
 				if (n->nat_fr == fr)
 					break;
 
@@ -1606,10 +2213,11 @@
 				MUTEX_EXIT(&fr->fr_lock);
 			}
 			if (getlock) {
-				RWLOCK_EXIT(&ipf_nat);
+				RWLOCK_EXIT(&softc->ipf_nat);
 			}
 
-			if (!n) {
+			if (n == NULL) {
+				IPFERROR(60047);
 				error = ESRCH;
 				goto junkput;
 			}
@@ -1622,25 +2230,30 @@
 	}
 
 	if (getlock) {
-		WRITE_ENTER(&ipf_nat);
+		WRITE_ENTER(&softc->ipf_nat);
 	}
-	error = nat_insert(nat, nat->nat_rev);
-	if ((error == 0) && (aps != NULL)) {
-		aps->aps_next = ap_sess_list;
-		ap_sess_list = aps;
-	}
+
+	if (fin.fin_v == 4)
+		error = ipf_nat_finalise(&fin, nat);
+#ifdef USE_INET6
+	else
+		error = ipf_nat6_finalise(&fin, nat);
+#endif
+
 	if (getlock) {
-		RWLOCK_EXIT(&ipf_nat);
+		RWLOCK_EXIT(&softc->ipf_nat);
 	}
 
 	if (error == 0)
 		return 0;
 
+	IPFERROR(60048);
 	error = ENOMEM;
 
 junkput:
-	if (fr != NULL)
-		(void) fr_derefrule(&fr);
+	if (fr != NULL) {
+		(void) ipf_derefrule(softc, &fr);
+	}
 
 	if ((ipnn != NULL) && (ipnn != &ipn)) {
 		KFREES(ipnn, ipn.ipn_dsize);
@@ -1654,8 +2267,8 @@
 		}
 		if (in != NULL) {
 			if (in->in_apr)
-				appr_free(in->in_apr);
-			KFREE(in);
+				ipf_proxy_deref(in->in_apr);
+			KFREES(in, in->in_size);
 		}
 		KFREE(nat);
 	}
@@ -1664,9 +2277,10 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    nat_delete                                                  */
+/* Function:    ipf_nat_delete                                              */
 /* Returns:     Nil                                                         */
-/* Parameters:  natd(I)    - pointer to NAT structure to delete             */
+/* Parameters:  softc(I)   - pointer to soft context main structure         */
+/*              nat(I)     - pointer to NAT structure to delete             */
 /*              logtype(I) - type of LOG record to create before deleting   */
 /* Write Lock:  ipf_nat                                                     */
 /*                                                                          */
@@ -1673,18 +2287,19 @@
 /* Delete a nat entry from the various lists and table.  If NAT logging is  */
 /* enabled then generate a NAT log record for this event.                   */
 /* ------------------------------------------------------------------------ */
-void nat_delete(nat, logtype)
-struct nat *nat;
-int logtype;
+void
+ipf_nat_delete(softc, nat, logtype)
+	ipf_main_softc_t *softc;
+	struct nat *nat;
+	int logtype;
 {
+	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
+	int madeorphan = 0, bkt, removed = 0;
+	nat_stat_side_t *nss;
 	struct ipnat *ipn;
-	int removed = 0;
 
-	if (logtype != 0 && nat_logging != 0)
-		nat_log(nat, logtype);
-#if defined(NEED_LOCAL_RAND) && defined(_KERNEL)
-	ipf_rand_push(nat, sizeof(*nat));
-#endif
+	if (logtype != 0 && softn->ipf_nat_logging != 0)
+		ipf_nat_log(softc, softn, nat, logtype);
 
 	/*
 	 * Take it as a general indication that all the pointers are set if
@@ -1693,9 +2308,20 @@
 	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]]--;
+		bkt = nat->nat_hv[0] % softn->ipf_nat_table_sz;
+		nss = &softn->ipf_nat_stats.ns_side[0];
+		nss->ns_bucketlen[bkt]--;
+		if (nss->ns_bucketlen[bkt] == 0) {
+			nss->ns_inuse--;
+		}
 
+		bkt = nat->nat_hv[1] % softn->ipf_nat_table_sz;
+		nss = &softn->ipf_nat_stats.ns_side[1];
+		nss->ns_bucketlen[bkt]--;
+		if (nss->ns_bucketlen[bkt] == 0) {
+			nss->ns_inuse--;
+		}
+
 		*nat->nat_pnext = nat->nat_next;
 		if (nat->nat_next != NULL) {
 			nat->nat_next->nat_pnext = nat->nat_pnext;
@@ -1717,20 +2343,34 @@
 		}
 		nat->nat_phnext[1] = NULL;
 
-		if ((nat->nat_flags & SI_WILDP) != 0)
-			nat_stats.ns_wilds--;
+		if ((nat->nat_flags & SI_WILDP) != 0) {
+			ATOMIC_DEC32(softn->ipf_nat_stats.ns_wilds);
+		}
+		madeorphan = 1;
 	}
 
 	if (nat->nat_me != NULL) {
 		*nat->nat_me = NULL;
 		nat->nat_me = NULL;
+		nat->nat_ref--;
+		ASSERT(nat->nat_ref >= 0);
 	}
 
-	if (nat->nat_tqe.tqe_ifq != NULL)
-		fr_deletequeueentry(&nat->nat_tqe);
+	if (nat->nat_tqe.tqe_ifq != NULL) {
+		/*
+		 * No call to ipf_freetimeoutqueue() is made here, they are
+		 * garbage collected in ipf_nat_expire().
+		 */
+		(void) ipf_deletequeueentry(&nat->nat_tqe);
+	}
 
+	if (nat->nat_sync) {
+		ipf_sync_del_nat(softc->ipf_sync_soft, nat->nat_sync);
+		nat->nat_sync = NULL;
+	}
+
 	if (logtype == NL_EXPIRE)
-		nat_stats.ns_expire++;
+		softn->ipf_nat_stats.ns_expire++;
 
 	MUTEX_ENTER(&nat->nat_lock);
 	/*
@@ -1743,36 +2383,37 @@
 			nat->nat_ref -= 2;
 			MUTEX_EXIT(&nat->nat_lock);
 			if (removed)
-				nat_stats.ns_orphans++;
+				softn->ipf_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++;
+		if (madeorphan == 1)
+			softn->ipf_nat_stats.ns_orphans++;
 		return;
 	}
+	ASSERT(nat->nat_ref >= 0);
 	MUTEX_EXIT(&nat->nat_lock);
 
+	nat->nat_ref = 0;
+
+	if (madeorphan == 0)
+		softn->ipf_nat_stats.ns_orphans--;
+
 	/*
-	 * At this point, nat_ref is 1, doing "--" would make it 0..
+	 * At this point, nat_ref can be either 0 or -1
 	 */
-	nat->nat_ref = 0;
-	if (!removed)
-		nat_stats.ns_orphans--;
+	softn->ipf_nat_stats.ns_proto[nat->nat_pr[0]]--;
 
-#ifdef	IPFILTER_SYNC
-	if (nat->nat_sync)
-		ipfsync_del(nat->nat_sync);
-#endif
+	if (nat->nat_fr != NULL) {
+		(void) ipf_derefrule(softc, &nat->nat_fr);
+	}
 
-	if (nat->nat_fr != NULL)
-		(void) fr_derefrule(&nat->nat_fr);
+	if (nat->nat_hm != NULL) {
+		ipf_nat_hostmapdel(softc, &nat->nat_hm);
+	}
 
-	if (nat->nat_hm != NULL)
-		fr_hostmapdel(&nat->nat_hm);
-
 	/*
 	 * If there is an active reference from the nat entry to its parent
 	 * rule, decrement the rule's reference count and free it too if no
@@ -1779,14 +2420,21 @@
 	 * longer being used.
 	 */
 	ipn = nat->nat_ptr;
+	nat->nat_ptr = NULL;
+
 	if (ipn != NULL) {
-		fr_ipnatderef(&ipn);
+		ipn->in_space++;
+		ipf_nat_rule_deref(softc, &ipn);
 	}
 
+	if (nat->nat_aps != NULL) {
+		ipf_proxy_free(softc, nat->nat_aps);
+		nat->nat_aps = NULL;
+	}
+
 	MUTEX_DESTROY(&nat->nat_lock);
 
-	aps_free(nat->nat_aps);
-	nat_stats.ns_inuse--;
+	softn->ipf_nat_stats.ns_active--;
 
 	/*
 	 * If there's a fragment table entry too for this nat entry, then
@@ -1793,7 +2441,7 @@
 	 * dereference that as well.  This is after nat_lock is released
 	 * because of Tru64.
 	 */
-	fr_forgetnat((void *)nat);
+	ipf_frag_natforget(softc, (void *)nat);
 
 	KFREE(nat);
 }
@@ -1800,17 +2448,23 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    nat_flushtable                                              */
+/* Function:    ipf_nat_flushtable                                          */
 /* Returns:     int - number of NAT rules deleted                           */
-/* Parameters:  Nil                                                         */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              softn(I) - pointer to NAT context structure                 */
+/* Write Lock:  ipf_nat                                                     */
 /*                                                                          */
 /* Deletes all currently active NAT sessions.  In deleting each NAT entry a */
-/* log record should be emitted in nat_delete() if NAT logging is enabled.  */
+/* log record should be emitted in ipf_nat_delete() if NAT logging is       */
+/* enabled.                                                                 */
 /* ------------------------------------------------------------------------ */
 /*
  * nat_flushtable - clear the NAT table of all mapping entries.
  */
-static int nat_flushtable()
+static int
+ipf_nat_flushtable(softc, softn)
+	ipf_main_softc_t *softc;
+	ipf_nat_softc_t *softn;
 {
 	nat_t *nat;
 	int j = 0;
@@ -1819,67 +2473,141 @@
 	 * ALL NAT mappings deleted, so lets just make the deletions
 	 * quicker.
 	 */
-	if (nat_table[0] != NULL)
-		bzero((char *)nat_table[0],
-		      sizeof(nat_table[0]) * ipf_nattable_sz);
-	if (nat_table[1] != NULL)
-		bzero((char *)nat_table[1],
-		      sizeof(nat_table[1]) * ipf_nattable_sz);
+	if (softn->ipf_nat_table[0] != NULL)
+		bzero((char *)softn->ipf_nat_table[0],
+		      sizeof(softn->ipf_nat_table[0]) *
+		      softn->ipf_nat_table_sz);
+	if (softn->ipf_nat_table[1] != NULL)
+		bzero((char *)softn->ipf_nat_table[1],
+		      sizeof(softn->ipf_nat_table[1]) *
+		      softn->ipf_nat_table_sz);
 
-	while ((nat = nat_instances) != NULL) {
-		nat_delete(nat, NL_FLUSH);
+	while ((nat = softn->ipf_nat_instances) != NULL) {
+		ipf_nat_delete(softc, nat, NL_FLUSH);
 		j++;
 	}
 
-	nat_stats.ns_inuse = 0;
 	return j;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    nat_clearlist                                               */
+/* Function:    ipf_nat_clearlist                                           */
 /* Returns:     int - number of NAT/RDR rules deleted                       */
-/* Parameters:  Nil                                                         */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              softn(I) - pointer to NAT context structure                 */
 /*                                                                          */
 /* Delete all rules in the current list of rules.  There is nothing elegant */
 /* about this cleanup: simply free all entries on the list of rules and     */
 /* clear out the tables used for hashed NAT rule lookups.                   */
 /* ------------------------------------------------------------------------ */
-static int nat_clearlist()
+static int
+ipf_nat_clearlist(softc, softn)
+	ipf_main_softc_t *softc;
+	ipf_nat_softc_t *softn;
 {
-	ipnat_t *n, **np = &nat_list;
+	ipnat_t *n;
 	int i = 0;
 
-	if (nat_rules != NULL)
-		bzero((char *)nat_rules, sizeof(*nat_rules) * ipf_natrules_sz);
-	if (rdr_rules != NULL)
-		bzero((char *)rdr_rules, sizeof(*rdr_rules) * ipf_rdrrules_sz);
+	if (softn->ipf_nat_map_rules != NULL) {
+		bzero((char *)softn->ipf_nat_map_rules,
+		      sizeof(*softn->ipf_nat_map_rules) *
+		      softn->ipf_nat_maprules_sz);
+	}
+	if (softn->ipf_nat_rdr_rules != NULL) {
+		bzero((char *)softn->ipf_nat_rdr_rules,
+		      sizeof(*softn->ipf_nat_rdr_rules) *
+		      softn->ipf_nat_rdrrules_sz);
+	}
 
-	while ((n = *np) != NULL) {
-		*np = n->in_next;
-		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 {
-			n->in_flags |= IPN_DELETE;
-			n->in_next = NULL;
-		}
+	while ((n = softn->ipf_nat_list) != NULL) {
+		ipf_nat_delrule(softc, softn, n, 0);
 		i++;
 	}
-#if SOLARIS && !defined(_INET_IP_STACK_H)
+#if SOLARIS && !defined(INSTANCES)
 	pfil_delayed_copy = 1;
 #endif
-	nat_masks = 0;
-	rdr_masks = 0;
 	return i;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    nat_newmap                                                  */
+/* Function:    ipf_nat_delrule                                             */
+/* Returns:     Nil                                                         */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              softn(I) - pointer to NAT context structure                 */
+/*              np(I)    - pointer to NAT rule to delete                    */
+/*              purge(I) - 1 == allow purge, 0 == prevent purge             */
+/* Locks:       WRITE(ipf_nat)                                              */
+/*                                                                          */
+/* Preventing "purge" from occuring is allowed because when all of the NAT  */
+/* rules are being removed, allowing the "purge" to walk through the list   */
+/* of NAT sessions, possibly multiple times, would be a large performance   */
+/* hit, on the order of O(N^2).                                             */
+/* ------------------------------------------------------------------------ */
+static void
+ipf_nat_delrule(softc, softn, np, purge)
+	ipf_main_softc_t *softc;
+	ipf_nat_softc_t *softn;
+	ipnat_t *np;
+	int purge;
+{
+
+	if (np->in_pnext != NULL) {
+		*np->in_pnext = np->in_next;
+		if (np->in_next != NULL)
+			np->in_next->in_pnext = np->in_pnext;
+		if (softn->ipf_nat_list_tail == &np->in_next)
+			softn->ipf_nat_list_tail = np->in_pnext;
+	}
+
+	if ((purge == 1) && ((np->in_flags & IPN_PURGE) != 0)) {
+		nat_t *next;
+		nat_t *nat;
+
+		for (next = softn->ipf_nat_instances; (nat = next) != NULL;) {
+			next = nat->nat_next;
+			if (nat->nat_ptr == np)
+				ipf_nat_delete(softc, nat, NL_PURGE);
+		}
+	}
+
+	if ((np->in_flags & IPN_DELETE) == 0) {
+		if (np->in_redir & NAT_REDIRECT) {
+			switch (np->in_v[0])
+			{
+			case 4 :
+				ipf_nat_delrdr(softn, np);
+				break;
+#ifdef USE_INET6
+			case 6 :
+				ipf_nat6_delrdr(softn, np);
+				break;
+#endif
+			}
+		}
+		if (np->in_redir & (NAT_MAPBLK|NAT_MAP)) {
+			switch (np->in_v[0])
+			{
+			case 4 :
+				ipf_nat_delmap(softn, np);
+				break;
+#ifdef USE_INET6
+			case 6 :
+				ipf_nat6_delmap(softn, np);
+				break;
+#endif
+			}
+		}
+	}
+
+	np->in_flags |= IPN_DELETE;
+	ipf_nat_rule_deref(softc, &np);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_nat_newmap                                              */
 /* Returns:     int - -1 == error, 0 == success                             */
 /* Parameters:  fin(I) - pointer to packet information                      */
 /*              nat(I) - pointer to NAT entry                               */
@@ -1891,11 +2619,14 @@
 /* ni.nai_ip is passed in uninitialised and must be set, in host byte order,*/
 /* to the new IP address for the translation.                               */
 /* ------------------------------------------------------------------------ */
-static INLINE int nat_newmap(fin, nat, ni)
-fr_info_t *fin;
-nat_t *nat;
-natinfo_t *ni;
+static int
+ipf_nat_newmap(fin, nat, ni)
+	fr_info_t *fin;
+	nat_t *nat;
+	natinfo_t *ni;
 {
+	ipf_main_softc_t *softc = fin->fin_main_soft;
+	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
 	u_short st_port, dport, sport, port, sp, dp;
 	struct in_addr in, inb;
 	hostmap_t *hm;
@@ -1912,12 +2643,18 @@
 	l = 0;
 	hm = NULL;
 	np = ni->nai_np;
-	st_ip = np->in_nip;
-	st_port = np->in_pnext;
-	flags = ni->nai_flags;
-	sport = ni->nai_sport;
-	dport = ni->nai_dport;
+	st_ip = np->in_snip;
+	st_port = np->in_spnext;
+	flags = nat->nat_flags;
 
+	if (flags & IPN_ICMPQUERY) {
+		sport = fin->fin_data[1];
+		dport = 0;
+	} else {
+		sport = htons(fin->fin_data[0]);
+		dport = htons(fin->fin_data[1]);
+	}
+
 	/*
 	 * Do a loop until we either run out of entries to try or we find
 	 * a NAT mapping that isn't currently being used.  This is done
@@ -1925,50 +2662,54 @@
 	 */
 	do {
 		port = 0;
-		in.s_addr = htonl(np->in_nip);
+		in.s_addr = htonl(np->in_snip);
 		if (l == 0) {
 			/*
 			 * Check to see if there is an existing NAT
 			 * setup for this IP address pair.
 			 */
-			hm = nat_hostmap(np, fin->fin_src, fin->fin_dst,
-					 in, 0);
+			hm = ipf_nat_hostmap(softn, np, fin->fin_src,
+					     fin->fin_dst, in, 0);
 			if (hm != NULL)
-				in.s_addr = hm->hm_mapip.s_addr;
+				in.s_addr = hm->hm_nsrcip.s_addr;
 		} else if ((l == 1) && (hm != NULL)) {
-			fr_hostmapdel(&hm);
+			ipf_nat_hostmapdel(softc, &hm);
 		}
 		in.s_addr = ntohl(in.s_addr);
 
 		nat->nat_hm = hm;
 
-		if ((np->in_outmsk == 0xffffffff) && (np->in_pnext == 0)) {
-			if (l > 0)
+		if ((np->in_nsrcmsk == 0xffffffff) && (np->in_spnext == 0)) {
+			if (l > 0) {
+				NBUMPSIDEX(1, ns_exhausted, ns_exhausted_1);
 				return -1;
+			}
 		}
 
 		if (np->in_redir == NAT_BIMAP &&
-		    np->in_inmsk == np->in_outmsk) {
+		    np->in_osrcmsk == np->in_nsrcmsk) {
 			/*
 			 * map the address block in a 1:1 fashion
 			 */
-			in.s_addr = np->in_outip;
-			in.s_addr |= fin->fin_saddr & ~np->in_inmsk;
+			in.s_addr = np->in_nsrcaddr;
+			in.s_addr |= fin->fin_saddr & ~np->in_osrcmsk;
 			in.s_addr = ntohl(in.s_addr);
 
 		} else if (np->in_redir & NAT_MAPBLK) {
 			if ((l >= np->in_ppip) || ((l > 0) &&
-			     !(flags & IPN_TCPUDP)))
+			     !(flags & IPN_TCPUDP))) {
+				NBUMPSIDEX(1, ns_exhausted, ns_exhausted_2);
 				return -1;
+			}
 			/*
 			 * map-block - Calculate destination address.
 			 */
 			in.s_addr = ntohl(fin->fin_saddr);
-			in.s_addr &= ntohl(~np->in_inmsk);
+			in.s_addr &= ntohl(~np->in_osrcmsk);
 			inb.s_addr = in.s_addr;
 			in.s_addr /= np->in_ippip;
-			in.s_addr &= ntohl(~np->in_outmsk);
-			in.s_addr += ntohl(np->in_outip);
+			in.s_addr &= ntohl(~np->in_nsrcmsk);
+			in.s_addr += ntohl(np->in_nsrcaddr);
 			/*
 			 * Calculate destination port.
 			 */
@@ -1982,28 +2723,34 @@
 				port = htons(port);
 			}
 
-		} else if ((np->in_outip == 0) &&
-			   (np->in_outmsk == 0xffffffff)) {
+		} else if ((np->in_nsrcaddr == 0) &&
+			   (np->in_nsrcmsk == 0xffffffff)) {
+			i6addr_t in6;
+
 			/*
 			 * 0/32 - use the interface's IP address.
 			 */
 			if ((l > 0) ||
-			    fr_ifpaddr(4, FRI_NORMAL, fin->fin_ifp,
-				       &in, NULL) == -1)
+			    ipf_ifpaddr(softc, 4, FRI_NORMAL, fin->fin_ifp,
+				       &in6, NULL) == -1) {
+				NBUMPSIDEX(1, ns_new_ifpaddr, ns_new_ifpaddr_1);
 				return -1;
-			in.s_addr = ntohl(in.s_addr);
+			}
+			in.s_addr = ntohl(in6.in4.s_addr);
 
-		} else if ((np->in_outip == 0) && (np->in_outmsk == 0)) {
+		} else if ((np->in_nsrcaddr == 0) && (np->in_nsrcmsk == 0)) {
 			/*
 			 * 0/0 - use the original source address/port.
 			 */
-			if (l > 0)
+			if (l > 0) {
+				NBUMPSIDEX(1, ns_exhausted, ns_exhausted_3);
 				return -1;
+			}
 			in.s_addr = ntohl(fin->fin_saddr);
 
-		} else if ((np->in_outmsk != 0xffffffff) &&
-			   (np->in_pnext == 0) && ((l > 0) || (hm == NULL)))
-			np->in_nip++;
+		} else if ((np->in_nsrcmsk != 0xffffffff) &&
+			   (np->in_spnext == 0) && ((l > 0) || (hm == NULL)))
+			np->in_snip++;
 
 		natl = NULL;
 
@@ -2014,11 +2761,9 @@
 			 * "ports auto" (without map-block)
 			 */
 			if ((l > 0) && (l % np->in_ppip == 0)) {
-				if (l > np->in_space) {
-					return -1;
-				} else if ((l > np->in_ppip) &&
-					   np->in_outmsk != 0xffffffff)
-					np->in_nip++;
+				if ((l > np->in_ppip) &&
+				    np->in_nsrcmsk != 0xffffffff)
+					np->in_snip++;
 			}
 			if (np->in_ppip != 0) {
 				port = ntohs(sport);
@@ -2032,35 +2777,35 @@
 			}
 
 		} else if (((np->in_redir & NAT_MAPBLK) == 0) &&
-			   (flags & IPN_TCPUDPICMP) && (np->in_pnext != 0)) {
+			   (flags & IPN_TCPUDPICMP) && (np->in_spnext != 0)) {
 			/*
 			 * Standard port translation.  Select next port.
 			 */
 			if (np->in_flags & IPN_SEQUENTIAL) {
-				port = np->in_pnext;
+				port = np->in_spnext;
 			} else {
-				port = ipf_random() % (ntohs(np->in_pmax) -
-						       ntohs(np->in_pmin));
-				port += ntohs(np->in_pmin);
+				port = ipf_random() % (np->in_spmax -
+						       np->in_spmin + 1);
+				port += np->in_spmin;
 			}
 			port = htons(port);
-			np->in_pnext++;
+			np->in_spnext++;
 
-			if (np->in_pnext > ntohs(np->in_pmax)) {
-				np->in_pnext = ntohs(np->in_pmin);
-				if (np->in_outmsk != 0xffffffff)
-					np->in_nip++;
+			if (np->in_spnext > np->in_spmax) {
+				np->in_spnext = np->in_spmin;
+				if (np->in_nsrcmsk != 0xffffffff)
+					np->in_snip++;
 			}
 		}
 
-		if (np->in_flags & IPN_IPRANGE) {
-			if (np->in_nip > ntohl(np->in_outmsk))
-				np->in_nip = ntohl(np->in_outip);
+		if (np->in_flags & IPN_SIPRANGE) {
+			if (np->in_snip > ntohl(np->in_nsrcmsk))
+				np->in_snip = ntohl(np->in_nsrcaddr);
 		} else {
-			if ((np->in_outmsk != 0xffffffff) &&
-			    ((np->in_nip + 1) & ntohl(np->in_outmsk)) >
-			    ntohl(np->in_outip))
-				np->in_nip = ntohl(np->in_outip) + 1;
+			if ((np->in_nsrcmsk != 0xffffffff) &&
+			    ((np->in_snip + 1) & ntohl(np->in_nsrcmsk)) >
+			    ntohl(np->in_nsrcaddr))
+				np->in_snip = ntohl(np->in_nsrcaddr) + 1;
 		}
 
 		if ((port == 0) && (flags & (IPN_TCPUDPICMP|IPN_ICMPQUERY)))
@@ -2080,9 +2825,9 @@
 		sp = fin->fin_data[0];
 		dp = fin->fin_data[1];
 		fin->fin_data[0] = fin->fin_data[1];
-		fin->fin_data[1] = htons(port);
-		natl = nat_inlookup(fin, flags & ~(SI_WILDP|NAT_SEARCH),
-				    (u_int)fin->fin_p, fin->fin_dst, inb);
+		fin->fin_data[1] = ntohs(port);
+		natl = ipf_nat_inlookup(fin, flags & ~(SI_WILDP|NAT_SEARCH),
+					(u_int)fin->fin_p, fin->fin_dst, inb);
 		fin->fin_data[0] = sp;
 		fin->fin_data[1] = dp;
 
@@ -2091,64 +2836,41 @@
 		 * start ?
 		 */
 		if ((natl != NULL) &&
-		    (np->in_pnext != 0) && (st_port == np->in_pnext) &&
-		    (np->in_nip != 0) && (st_ip == np->in_nip))
+		    (np->in_spnext != 0) && (st_port == np->in_spnext) &&
+		    (np->in_snip != 0) && (st_ip == np->in_snip)) {
+			NBUMPSIDED(1, ns_wrap);
 			return -1;
+		}
 		l++;
 	} while (natl != NULL);
 
-	if (np->in_space > 0)
-		np->in_space--;
-
 	/* Setup the NAT table */
-	nat->nat_inip = fin->fin_src;
-	nat->nat_outip.s_addr = htonl(in.s_addr);
-	nat->nat_oip = fin->fin_dst;
+	nat->nat_osrcip = fin->fin_src;
+	nat->nat_nsrcaddr = htonl(in.s_addr);
+	nat->nat_odstip = fin->fin_dst;
+	nat->nat_ndstip = fin->fin_dst;
 	if (nat->nat_hm == NULL)
-		nat->nat_hm = nat_hostmap(np, fin->fin_src, fin->fin_dst,
-					  nat->nat_outip, 0);
+		nat->nat_hm = ipf_nat_hostmap(softn, np, fin->fin_src,
+					      fin->fin_dst, nat->nat_nsrcip,
+					      0);
 
-	/*
-	 * The ICMP checksum does not have a pseudo header containing
-	 * the IP addresses
-	 */
-	ni->nai_sum1 = LONG_SUM(ntohl(fin->fin_saddr));
-	ni->nai_sum2 = LONG_SUM(in.s_addr);
-	if ((flags & IPN_TCPUDP)) {
-		ni->nai_sum1 += ntohs(sport);
-		ni->nai_sum2 += ntohs(port);
-	}
-
 	if (flags & IPN_TCPUDP) {
-		nat->nat_inport = sport;
-		nat->nat_outport = port;	/* sport */
-		nat->nat_oport = dport;
+		nat->nat_osport = sport;
+		nat->nat_nsport = port;	/* sport */
+		nat->nat_odport = dport;
+		nat->nat_ndport = dport;
 		((tcphdr_t *)fin->fin_dp)->th_sport = port;
 	} else if (flags & IPN_ICMPQUERY) {
+		nat->nat_oicmpid = fin->fin_data[1];
 		((icmphdr_t *)fin->fin_dp)->icmp_id = port;
-		nat->nat_inport = port;
-		nat->nat_outport = port;
-	} else if (fin->fin_p == IPPROTO_GRE) {
-#if 0
-		nat->nat_gre.gs_flags = ((grehdr_t *)fin->fin_dp)->gr_flags;
-		if (GRE_REV(nat->nat_gre.gs_flags) == 1) {
-			nat->nat_oport = 0;/*fin->fin_data[1];*/
-			nat->nat_inport = 0;/*fin->fin_data[0];*/
-			nat->nat_outport = 0;/*fin->fin_data[0];*/
-			nat->nat_call[0] = fin->fin_data[0];
-			nat->nat_call[1] = fin->fin_data[0];
-		}
-#endif
+		nat->nat_nicmpid = port;
 	}
-	ni->nai_ip.s_addr = in.s_addr;
-	ni->nai_port = port;
-	ni->nai_nport = dport;
 	return 0;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    nat_newrdr                                                  */
+/* Function:    ipf_nat_newrdr                                              */
 /* Returns:     int - -1 == error, 0 == success (no move), 1 == success and */
 /*                    allow rule to be moved if IPN_ROUNDR is set.          */
 /* Parameters:  fin(I) - pointer to packet information                      */
@@ -2159,11 +2881,14 @@
 /* ni.nai_ip is passed in uninitialised and must be set, in host byte order,*/
 /* to the new IP address for the translation.                               */
 /* ------------------------------------------------------------------------ */
-static INLINE int nat_newrdr(fin, nat, ni)
-fr_info_t *fin;
-nat_t *nat;
-natinfo_t *ni;
+static int
+ipf_nat_newrdr(fin, nat, ni)
+	fr_info_t *fin;
+	nat_t *nat;
+	natinfo_t *ni;
 {
+	ipf_main_softc_t *softc = fin->fin_main_soft;
+	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
 	u_short nport, dport, sport;
 	struct in_addr in, inb;
 	u_short sp, dp;
@@ -2177,10 +2902,19 @@
 	hm = NULL;
 	in.s_addr = 0;
 	np = ni->nai_np;
-	flags = ni->nai_flags;
-	sport = ni->nai_sport;
-	dport = ni->nai_dport;
+	flags = nat->nat_flags;
 
+	if (flags & IPN_ICMPQUERY) {
+		dport = fin->fin_data[1];
+		sport = 0;
+	} else {
+		sport = htons(fin->fin_data[0]);
+		dport = htons(fin->fin_data[1]);
+	}
+
+	/* TRACE sport, dport */
+
+
 	/*
 	 * If the matching rule has IPN_STICKY set, then we want to have the
 	 * same rule kick in as before.  Why would this happen?  If you have
@@ -2190,13 +2924,14 @@
 	 */
 	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);
+		hm = ipf_nat_hostmap(softn, NULL, fin->fin_src, fin->fin_dst,
+				     in, (u_32_t)dport);
 		if (hm != NULL) {
-			in.s_addr = ntohl(hm->hm_mapip.s_addr);
+			in.s_addr = ntohl(hm->hm_ndstip.s_addr);
 			np = hm->hm_ipnat;
 			ni->nai_np = np;
 			move = 0;
+			ipf_nat_hostmapdel(softc, &hm);
 		}
 	}
 
@@ -2207,35 +2942,43 @@
 	 * internal port.
 	 */
 	if (np->in_flags & IPN_SPLIT) {
-		in.s_addr = np->in_nip;
+		in.s_addr = np->in_dnip;
+		inb.s_addr = htonl(in.s_addr);
 
 		if ((np->in_flags & (IPN_ROUNDR|IPN_STICKY)) == IPN_STICKY) {
-			hm = nat_hostmap(NULL, fin->fin_src, fin->fin_dst,
-					 in, (u_32_t)dport);
+			hm = ipf_nat_hostmap(softn, NULL, fin->fin_src,
+					     fin->fin_dst, inb, (u_32_t)dport);
 			if (hm != NULL) {
-				in.s_addr = hm->hm_mapip.s_addr;
+				in.s_addr = hm->hm_ndstip.s_addr;
 				move = 0;
 			}
 		}
 
 		if (hm == NULL || hm->hm_ref == 1) {
-			if (np->in_inip == htonl(in.s_addr)) {
-				np->in_nip = ntohl(np->in_inmsk);
+			if (np->in_ndstaddr == htonl(in.s_addr)) {
+				np->in_dnip = ntohl(np->in_ndstmsk);
 				move = 0;
 			} else {
-				np->in_nip = ntohl(np->in_inip);
+				np->in_dnip = ntohl(np->in_ndstaddr);
 			}
 		}
+		if (hm != NULL)
+			ipf_nat_hostmapdel(softc, &hm);
 
-	} else if ((np->in_inip == 0) && (np->in_inmsk == 0xffffffff)) {
+	} else if ((np->in_ndstaddr == 0) && (np->in_ndstmsk == 0xffffffff)) {
+		i6addr_t in6;
+
 		/*
 		 * 0/32 - use the interface's IP address.
 		 */
-		if (fr_ifpaddr(4, FRI_NORMAL, fin->fin_ifp, &in, NULL) == -1)
+		if (ipf_ifpaddr(softc, 4, FRI_NORMAL, fin->fin_ifp,
+			       &in6, NULL) == -1) {
+			NBUMPSIDEX(0, ns_new_ifpaddr, ns_new_ifpaddr_2);
 			return -1;
-		in.s_addr = ntohl(in.s_addr);
+		}
+		in.s_addr = ntohl(in6.in4.s_addr);
 
-	} else if ((np->in_inip == 0) && (np->in_inmsk== 0)) {
+	} else if ((np->in_ndstaddr == 0) && (np->in_ndstmsk== 0)) {
 		/*
 		 * 0/0 - use the original destination address/port.
 		 */
@@ -2242,18 +2985,18 @@
 		in.s_addr = ntohl(fin->fin_daddr);
 
 	} else if (np->in_redir == NAT_BIMAP &&
-		   np->in_inmsk == np->in_outmsk) {
+		   np->in_ndstmsk == np->in_odstmsk) {
 		/*
 		 * map the address block in a 1:1 fashion
 		 */
-		in.s_addr = np->in_inip;
-		in.s_addr |= fin->fin_daddr & ~np->in_inmsk;
+		in.s_addr = np->in_ndstaddr;
+		in.s_addr |= fin->fin_daddr & ~np->in_ndstmsk;
 		in.s_addr = ntohl(in.s_addr);
 	} else {
-		in.s_addr = ntohl(np->in_inip);
+		in.s_addr = ntohl(np->in_ndstaddr);
 	}
 
-	if ((np->in_pnext == 0) || ((flags & NAT_NOTRULEPORT) != 0))
+	if ((np->in_dpnext == 0) || ((flags & NAT_NOTRULEPORT) != 0))
 		nport = dport;
 	else {
 		/*
@@ -2261,12 +3004,15 @@
 		 * pmin == pmax, the gain is not significant.
 		 */
 		if (((np->in_flags & IPN_FIXEDDPORT) == 0) &&
-		    (np->in_pmin != np->in_pmax)) {
-			nport = ntohs(dport) - ntohs(np->in_pmin) +
-				ntohs(np->in_pnext);
+		    (np->in_odport != np->in_dtop)) {
+			nport = ntohs(dport) - np->in_odport + np->in_dpmax;
 			nport = htons(nport);
-		} else
-			nport = np->in_pnext;
+		} else {
+			nport = htons(np->in_dpnext);
+			np->in_dpnext++;
+			if (np->in_dpnext > np->in_dpmax)
+				np->in_dpnext = np->in_dpmin;
+		}
 	}
 
 	/*
@@ -2275,8 +3021,10 @@
 	 * setup any translation for this either.
 	 */
 	if (in.s_addr == 0) {
-		if (nport == dport)
+		if (nport == dport) {
+			NBUMPSIDED(0, ns_xlate_null);
 			return -1;
+		}
 		in.s_addr = ntohl(fin->fin_daddr);
 	}
 
@@ -2290,47 +3038,35 @@
 	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),
+	natl = ipf_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)
+	if (natl != NULL) {
+		DT2(ns_new_xlate_exists, fr_info_t *, fin, nat_t *, natl);
+		NBUMPSIDE(0, ns_xlate_exists);
 		return -1;
+	}
 
-	nat->nat_inip.s_addr = htonl(in.s_addr);
-	nat->nat_outip = fin->fin_dst;
-	nat->nat_oip = fin->fin_src;
+	inb.s_addr = htonl(in.s_addr);
+	nat->nat_ndstaddr = htonl(in.s_addr);
+	nat->nat_odstip = fin->fin_dst;
+	nat->nat_nsrcip = fin->fin_src;
+	nat->nat_osrcip = 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);
+		nat->nat_hm = ipf_nat_hostmap(softn, np, fin->fin_src,
+					      fin->fin_dst, inb, (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);
-
-	ni->nai_ip.s_addr = in.s_addr;
-	ni->nai_nport = nport;
-	ni->nai_port = sport;
-
 	if (flags & IPN_TCPUDP) {
-		nat->nat_inport = nport;
-		nat->nat_outport = dport;
-		nat->nat_oport = sport;
+		nat->nat_odport = dport;
+		nat->nat_ndport = nport;
+		nat->nat_osport = sport;
+		nat->nat_nsport = sport;
 		((tcphdr_t *)fin->fin_dp)->th_dport = nport;
 	} else if (flags & IPN_ICMPQUERY) {
+		nat->nat_oicmpid = fin->fin_data[1];
 		((icmphdr_t *)fin->fin_dp)->icmp_id = nport;
-		nat->nat_inport = nport;
-		nat->nat_outport = nport;
-	} else if (fin->fin_p == IPPROTO_GRE) {
-#if 0
-		nat->nat_gre.gs_flags = ((grehdr_t *)fin->fin_dp)->gr_flags;
-		if (GRE_REV(nat->nat_gre.gs_flags) == 1) {
-			nat->nat_call[0] = fin->fin_data[0];
-			nat->nat_call[1] = fin->fin_data[1];
-			nat->nat_oport = 0; /*fin->fin_data[0];*/
-			nat->nat_inport = 0; /*fin->fin_data[1];*/
-			nat->nat_outport = 0; /*fin->fin_data[1];*/
-		}
-#endif
+		nat->nat_nicmpid = nport;
 	}
 
 	return move;
@@ -2337,7 +3073,7 @@
 }
 
 /* ------------------------------------------------------------------------ */
-/* Function:    nat_new                                                     */
+/* Function:    ipf_nat_add                                                 */
 /* Returns:     nat_t* - NULL == failure to create new NAT structure,       */
 /*                       else pointer to new NAT structure                  */
 /* Parameters:  fin(I)       - pointer to packet information                */
@@ -2358,29 +3094,32 @@
 /* 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;
-ipnat_t *np;
-nat_t **natsave;
-u_int flags;
-int direction;
+nat_t *
+ipf_nat_add(fin, np, natsave, flags, direction)
+	fr_info_t *fin;
+	ipnat_t *np;
+	nat_t **natsave;
+	u_int flags;
+	int direction;
 {
-	u_short port = 0, sport = 0, dport = 0, nport = 0;
-	tcphdr_t *tcp = NULL;
+	ipf_main_softc_t *softc = fin->fin_main_soft;
+	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
 	hostmap_t *hm = NULL;
-	struct in_addr in;
 	nat_t *nat, *natl;
+	natstat_t *nsp;
 	u_int nflags;
 	natinfo_t ni;
-	u_32_t sumd;
 	int move;
-#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) && defined(ICK_M_CTL_MAGIC)
-	qpktinfo_t *qpi = fin->fin_qpi;
-#endif
 
-	if (nat_stats.ns_inuse >= ipf_nattable_max) {
-		nat_stats.ns_memfail++;
-		fr_nat_doflush = 1;
+	nsp = &softn->ipf_nat_stats;
+
+	if ((nsp->ns_active * 100 / softn->ipf_nat_table_max) >
+	    softn->ipf_nat_table_wm_high) {
+		softn->ipf_nat_doflush = 1;
+	}
+
+	if (nsp->ns_active >= softn->ipf_nat_table_max) {
+		NBUMPSIDED(fin->fin_out, ns_table_max);
 		return NULL;
 	}
 
@@ -2389,8 +3128,6 @@
 	nflags &= NAT_FROMRULE;
 
 	ni.nai_np = np;
-	ni.nai_nflags = nflags;
-	ni.nai_flags = flags;
 	ni.nai_dport = 0;
 	ni.nai_sport = 0;
 
@@ -2397,7 +3134,7 @@
 	/* Give me a new nat */
 	KMALLOC(nat, nat_t *);
 	if (nat == NULL) {
-		nat_stats.ns_memfail++;
+		NBUMPSIDED(fin->fin_out, ns_memfail);
 		/*
 		 * Try to automatically tune the max # of entries in the
 		 * table allowed to be less than what will cause kmem_alloc()
@@ -2404,19 +3141,16 @@
 		 * to fail and try to eliminate panics due to out of memory
 		 * conditions arising.
 		 */
-		if (ipf_nattable_max > ipf_nattable_sz) {
-			ipf_nattable_max = nat_stats.ns_inuse - 100;
-			printf("ipf_nattable_max reduced to %d\n",
-				ipf_nattable_max);
+		if ((softn->ipf_nat_table_max > softn->ipf_nat_table_sz) &&
+		    (nsp->ns_active > 100)) {
+			softn->ipf_nat_table_max = nsp->ns_active - 100;
+			printf("table_max reduced to %d\n",
+				softn->ipf_nat_table_max);
 		}
 		return NULL;
 	}
 
-	if (flags & IPN_TCPUDP) {
-		tcp = fin->fin_dp;
-		ni.nai_sport = htons(fin->fin_sport);
-		ni.nai_dport = htons(fin->fin_dport);
-	} else if (flags & IPN_ICMPQUERY) {
+	if (flags & IPN_ICMPQUERY) {
 		/*
 		 * In the ICMP query NAT code, we translate the ICMP id fields
 		 * to make them unique. This is indepedent of the ICMP type
@@ -2430,28 +3164,34 @@
 		 * the concept of source port. We overlay sport, so we can
 		 * maximally reuse the existing code.
 		 */
-		ni.nai_sport = ((icmphdr_t *)fin->fin_dp)->icmp_id;
-		ni.nai_dport = ni.nai_sport;
+		ni.nai_sport = fin->fin_data[1];
+		ni.nai_dport = 0;
 	}
 
 	bzero((char *)nat, sizeof(*nat));
 	nat->nat_flags = flags;
 	nat->nat_redir = np->in_redir;
+	nat->nat_dir = direction;
+	nat->nat_pr[0] = fin->fin_p;
+	nat->nat_pr[1] = fin->fin_p;
 
-	if ((flags & NAT_SLAVE) == 0) {
-		MUTEX_ENTER(&ipf_nat_new);
-	}
-
 	/*
-	 * Search the current table for a match.
+	 * Search the current table for a match and create a new mapping
+	 * if there is none found.
 	 */
-	if (direction == NAT_OUTBOUND) {
+	if (np->in_redir & NAT_DIVERTUDP) {
+		move = ipf_nat_newdivert(fin, nat, &ni);
+
+	} else if (np->in_redir & NAT_REWRITE) {
+		move = ipf_nat_newrewrite(fin, nat, &ni);
+
+	} else if (direction == NAT_OUTBOUND) {
 		/*
 		 * We can now arrange to call this for the same connection
 		 * because ipf_nat_new doesn't protect the code path into
 		 * this function.
 		 */
-		natl = nat_outlookup(fin, nflags, (u_int)fin->fin_p,
+		natl = ipf_nat_outlookup(fin, nflags, (u_int)fin->fin_p,
 				     fin->fin_src, fin->fin_dst);
 		if (natl != NULL) {
 			KFREE(nat);
@@ -2459,18 +3199,13 @@
 			goto done;
 		}
 
-		move = nat_newmap(fin, nat, &ni);
-		if (move == -1)
-			goto badnat;
-
-		np = ni.nai_np;
-		in = ni.nai_ip;
+		move = ipf_nat_newmap(fin, nat, &ni);
 	} else {
 		/*
-		 * NAT_INBOUND is used only for redirects rules
+		 * NAT_INBOUND is used for redirects rules
 		 */
-		natl = nat_inlookup(fin, nflags, (u_int)fin->fin_p,
-				    fin->fin_src, fin->fin_dst);
+		natl = ipf_nat_inlookup(fin, nflags, (u_int)fin->fin_p,
+					fin->fin_src, fin->fin_dst);
 		if (natl != NULL) {
 			KFREE(nat);
 			nat = natl;
@@ -2477,98 +3212,79 @@
 			goto done;
 		}
 
-		move = nat_newrdr(fin, nat, &ni);
-		if (move == -1)
-			goto badnat;
-
-		np = ni.nai_np;
-		in = ni.nai_ip;
+		move = ipf_nat_newrdr(fin, nat, &ni);
 	}
-	port = ni.nai_port;
-	nport = ni.nai_nport;
+	if (move == -1)
+		goto badnat;
 
-	if ((move == 1) && (np->in_flags & IPN_ROUNDR)) {
-		if (np->in_redir == NAT_REDIRECT) {
-			nat_delrdr(np);
-			nat_addrdr(np);
-		} else if (np->in_redir == NAT_MAP) {
-			nat_delnat(np);
-			nat_addnat(np);
+	np = ni.nai_np;
+
+	nat->nat_mssclamp = np->in_mssclamp;
+	nat->nat_me = natsave;
+	nat->nat_fr = fin->fin_fr;
+	nat->nat_rev = fin->fin_rev;
+	nat->nat_ptr = np;
+	nat->nat_dlocal = np->in_dlocal;
+
+	if ((np->in_apr != NULL) && ((nat->nat_flags & NAT_SLAVE) == 0)) {
+		if (ipf_proxy_new(fin, nat) == -1) {
+			NBUMPSIDED(fin->fin_out, ns_appr_fail);
+			goto badnat;
 		}
 	}
 
-	if (flags & IPN_TCPUDP) {
-		sport = ni.nai_sport;
-		dport = ni.nai_dport;
-	} else if (flags & IPN_ICMPQUERY) {
-		sport = ni.nai_sport;
-		dport = 0;
+	nat->nat_ifps[0] = np->in_ifps[0];
+	if (np->in_ifps[0] != NULL) {
+		COPYIFNAME(np->in_v[0], np->in_ifps[0], nat->nat_ifnames[0]);
 	}
 
-	CALC_SUMD(ni.nai_sum1, ni.nai_sum2, sumd);
-	nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16);
-#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) && defined(ICK_M_CTL_MAGIC)
-	if ((flags & IPN_TCP) && dohwcksum &&
-	    (((ill_t *)qpi->qpi_ill)->ill_ick.ick_magic == ICK_M_CTL_MAGIC)) {
-		if (direction == NAT_OUTBOUND)
-			ni.nai_sum1 = LONG_SUM(in.s_addr);
-		else
-			ni.nai_sum1 = LONG_SUM(ntohl(fin->fin_saddr));
-		ni.nai_sum1 += LONG_SUM(ntohl(fin->fin_daddr));
-		ni.nai_sum1 += 30;
-		ni.nai_sum1 = (ni.nai_sum1 & 0xffff) + (ni.nai_sum1 >> 16);
-		nat->nat_sumd[1] = NAT_HW_CKSUM|(ni.nai_sum1 & 0xffff);
-	} else
-#endif
-		nat->nat_sumd[1] = nat->nat_sumd[0];
+	nat->nat_ifps[1] = np->in_ifps[1];
+	if (np->in_ifps[1] != NULL) {
+		COPYIFNAME(np->in_v[1], np->in_ifps[1], nat->nat_ifnames[1]);
+	}
 
-	if ((flags & IPN_TCPUDPICMP) && ((sport != port) || (dport != nport))) {
-		if (direction == NAT_OUTBOUND)
-			ni.nai_sum1 = LONG_SUM(ntohl(fin->fin_saddr));
-		else
-			ni.nai_sum1 = LONG_SUM(ntohl(fin->fin_daddr));
+	if (ipf_nat_finalise(fin, nat) == -1) {
+		goto badnat;
+	}
 
-		ni.nai_sum2 = LONG_SUM(in.s_addr);
+	np->in_use++;
 
-		CALC_SUMD(ni.nai_sum1, ni.nai_sum2, sumd);
-		nat->nat_ipsumd = (sumd & 0xffff) + (sumd >> 16);
-	} else {
-		nat->nat_ipsumd = nat->nat_sumd[0];
-		if (!(flags & IPN_TCPUDPICMP)) {
-			nat->nat_sumd[0] = 0;
-			nat->nat_sumd[1] = 0;
+	if ((move == 1) && (np->in_flags & IPN_ROUNDR)) {
+		if ((np->in_redir & (NAT_REDIRECT|NAT_MAP)) == NAT_REDIRECT) {
+			ipf_nat_delrdr(softn, np);
+			ipf_nat_addrdr(softn, np);
+		} else if ((np->in_redir & (NAT_REDIRECT|NAT_MAP)) == NAT_MAP) {
+			ipf_nat_delmap(softn, np);
+			ipf_nat_addmap(softn, np);
 		}
 	}
 
-	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;
+		nsp->ns_wilds++;
+	nsp->ns_proto[nat->nat_pr[0]]++;
+
 	goto done;
 badnat:
-	nat_stats.ns_badnat++;
+	DT2(ns_badnatnew, fr_info_t *, fin, nat_t *, nat);
+	NBUMPSIDE(fin->fin_out, ns_badnatnew);
 	if ((hm = nat->nat_hm) != NULL)
-		fr_hostmapdel(&hm);
+		ipf_nat_hostmapdel(softc, &hm);
 	KFREE(nat);
 	nat = NULL;
 done:
-	if ((flags & NAT_SLAVE) == 0) {
-		MUTEX_EXIT(&ipf_nat_new);
-	}
+	if (nat != NULL && np != NULL)
+		np->in_hits++;
+	if (natsave != NULL)
+		*natsave = nat;
 	return nat;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    nat_finalise                                                */
+/* Function:    ipf_nat_finalise                                            */
 /* Returns:     int - 0 == sucess, -1 == failure                            */
 /* Parameters:  fin(I) - pointer to packet information                      */
 /*              nat(I) - pointer to NAT entry                               */
-/*              ni(I)  - pointer to structure with misc. information needed */
-/*                       to create new NAT entry.                           */
 /* Write Lock:  ipf_nat                                                     */
 /*                                                                          */
 /* This is the tail end of constructing a new NAT entry and is the same     */
@@ -2575,50 +3291,92 @@
 /* for both IPv4 and IPv6.                                                  */
 /* ------------------------------------------------------------------------ */
 /*ARGSUSED*/
-static int nat_finalise(fin, nat, ni, tcp, natsave, direction)
-fr_info_t *fin;
-nat_t *nat;
-natinfo_t *ni;
-tcphdr_t *tcp;
-nat_t **natsave;
-int direction;
+static int
+ipf_nat_finalise(fin, nat)
+	fr_info_t *fin;
+	nat_t *nat;
 {
+	ipf_main_softc_t *softc = fin->fin_main_soft;
+	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
+	u_32_t sum1, sum2, sumd;
 	frentry_t *fr;
-	ipnat_t *np;
+	u_32_t flags;
+#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) && defined(ICK_M_CTL_MAGIC)
+	qpktinfo_t *qpi = fin->fin_qpi;
+#endif
 
-	np = ni->nai_np;
+	flags = nat->nat_flags;
 
-	if (np->in_ifps[0] != NULL) {
-		COPYIFNAME(4, np->in_ifps[0], nat->nat_ifnames[0]);
+	switch (nat->nat_pr[0])
+	{
+	case IPPROTO_ICMP :
+		sum1 = LONG_SUM(ntohs(nat->nat_oicmpid));
+		sum2 = LONG_SUM(ntohs(nat->nat_nicmpid));
+		CALC_SUMD(sum1, sum2, sumd);
+		nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16);
+
+		break;
+
+	default :
+		sum1 = LONG_SUM(ntohl(nat->nat_osrcaddr) + \
+				ntohs(nat->nat_osport));
+		sum2 = LONG_SUM(ntohl(nat->nat_nsrcaddr) + \
+				ntohs(nat->nat_nsport));
+		CALC_SUMD(sum1, sum2, sumd);
+		nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16);
+
+		sum1 = LONG_SUM(ntohl(nat->nat_odstaddr) + \
+				ntohs(nat->nat_odport));
+		sum2 = LONG_SUM(ntohl(nat->nat_ndstaddr) + \
+				ntohs(nat->nat_ndport));
+		CALC_SUMD(sum1, sum2, sumd);
+		nat->nat_sumd[0] += (sumd & 0xffff) + (sumd >> 16);
+		break;
 	}
-	if (np->in_ifps[1] != NULL) {
-		COPYIFNAME(4, np->in_ifps[1], nat->nat_ifnames[1]);
+
+	/*
+	 * Compute the partial checksum, just in case.
+	 * This is only ever placed into outbound packets so care needs
+	 * to be taken over which pair of addresses are used.
+	 */
+	if (nat->nat_dir == NAT_OUTBOUND) {
+		sum1 = LONG_SUM(ntohl(nat->nat_nsrcaddr));
+		sum1 += LONG_SUM(ntohl(nat->nat_ndstaddr));
+	} else {
+		sum1 = LONG_SUM(ntohl(nat->nat_osrcaddr));
+		sum1 += LONG_SUM(ntohl(nat->nat_odstaddr));
 	}
-#ifdef	IPFILTER_SYNC
-	if ((nat->nat_flags & SI_CLONE) == 0)
-		nat->nat_sync = ipfsync_new(SMC_NAT, fin, nat);
-#endif
+	sum1 += nat->nat_pr[1];
+	nat->nat_sumd[1] = (sum1 & 0xffff) + (sum1 >> 16);
 
-	nat->nat_me = natsave;
-	nat->nat_dir = direction;
-	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;
-	if (nat->nat_p == IPPROTO_TCP)
-		nat->nat_seqnext[0] = ntohl(tcp->th_seq);
+	sum1 = LONG_SUM(ntohl(nat->nat_osrcaddr));
+	sum2 = LONG_SUM(ntohl(nat->nat_nsrcaddr));
+	CALC_SUMD(sum1, sum2, sumd);
+	nat->nat_ipsumd = (sumd & 0xffff) + (sumd >> 16);
 
-	if ((np->in_apr != NULL) && ((ni->nai_flags & NAT_SLAVE) == 0))
-		if (appr_new(fin, nat) == -1)
-			return -1;
+	sum1 = LONG_SUM(ntohl(nat->nat_odstaddr));
+	sum2 = LONG_SUM(ntohl(nat->nat_ndstaddr));
+	CALC_SUMD(sum1, sum2, sumd);
+	nat->nat_ipsumd += (sumd & 0xffff) + (sumd >> 16);
 
-	if (nat_insert(nat, fin->fin_rev) == 0) {
-		if (nat_logging)
-			nat_log(nat, (u_int)np->in_redir);
-		np->in_use++;
-		fr = fin->fin_fr;
-		nat->nat_fr = fr;
+	nat->nat_v[0] = 4;
+	nat->nat_v[1] = 4;
+
+	if ((nat->nat_ifps[0] != NULL) && (nat->nat_ifps[0] != (void *)-1)) {
+		nat->nat_mtu[0] = GETIFMTU_4(nat->nat_ifps[0]);
+	}
+
+	if ((nat->nat_ifps[1] != NULL) && (nat->nat_ifps[1] != (void *)-1)) {
+		nat->nat_mtu[1] = GETIFMTU_4(nat->nat_ifps[1]);
+	}
+
+	if ((nat->nat_flags & SI_CLONE) == 0)
+		nat->nat_sync = ipf_sync_new(softc, SMC_NAT, fin, nat);
+
+	if (ipf_nat_insert(softc, softn, nat) == 0) {
+		if (softn->ipf_nat_logging)
+			ipf_nat_log(softc, softn, nat, NL_NEW);
+		fr = nat->nat_fr;
 		if (fr != NULL) {
 			MUTEX_ENTER(&fr->fr_lock);
 			fr->fr_ref++;
@@ -2627,29 +3385,36 @@
 		return 0;
 	}
 
+	NBUMPSIDED(fin->fin_out, ns_unfinalised);
 	/*
 	 * nat_insert failed, so cleanup time...
 	 */
+	if (nat->nat_sync != NULL)
+		ipf_sync_del_nat(softc->ipf_sync_soft, nat->nat_sync);
 	return -1;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:   nat_insert                                                   */
-/* Returns:    int - 0 == sucess, -1 == failure                             */
-/* Parameters: nat(I) - pointer to NAT structure                            */
-/*             rev(I) - flag indicating forward/reverse direction of packet */
-/* Write Lock: ipf_nat                                                      */
+/* Function:    ipf_nat_insert                                              */
+/* Returns:     int - 0 == sucess, -1 == failure                            */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              softn(I) - pointer to NAT context structure                 */
+/*              nat(I) - pointer to NAT structure                           */
+/* Write Lock:  ipf_nat                                                     */
 /*                                                                          */
 /* Insert a NAT entry into the hash tables for searching and add it to the  */
 /* list of active NAT entries.  Adjust global counters when complete.       */
 /* ------------------------------------------------------------------------ */
-int	nat_insert(nat, rev)
-nat_t	*nat;
-int	rev;
+int
+ipf_nat_insert(softc, softn, nat)
+	ipf_main_softc_t *softc;
+	ipf_nat_softc_t *softn;
+	nat_t *nat;
 {
-	u_int hv1, hv2;
-	nat_t **natp;
+	u_int hv0, hv1;
+	u_int sp, dp;
+	ipnat_t *in;
 
 	/*
 	 * Try and return an error as early as possible, so calculate the hash
@@ -2656,83 +3421,188 @@
 	 * entry numbers first and then proceed.
 	 */
 	if ((nat->nat_flags & (SI_W_SPORT|SI_W_DPORT)) == 0) {
-		hv1 = NAT_HASH_FN(nat->nat_inip.s_addr, nat->nat_inport,
-				  0xffffffff);
-		hv1 = NAT_HASH_FN(nat->nat_oip.s_addr, hv1 + nat->nat_oport,
-				  ipf_nattable_sz);
-		hv2 = NAT_HASH_FN(nat->nat_outip.s_addr, nat->nat_outport,
-				  0xffffffff);
-		hv2 = NAT_HASH_FN(nat->nat_oip.s_addr, hv2 + nat->nat_oport,
-				  ipf_nattable_sz);
+		if ((nat->nat_flags & IPN_TCPUDP) != 0) {
+			sp = nat->nat_osport;
+			dp = nat->nat_odport;
+		} else if ((nat->nat_flags & IPN_ICMPQUERY) != 0) {
+			sp = 0;
+			dp = nat->nat_oicmpid;
+		} else {
+			sp = 0;
+			dp = 0;
+		}
+		hv0 = NAT_HASH_FN(nat->nat_osrcaddr, sp, 0xffffffff);
+		hv0 = NAT_HASH_FN(nat->nat_odstaddr, hv0 + dp, 0xffffffff);
+		/*
+		 * TRACE nat_osrcaddr, nat_osport, nat_odstaddr,
+		 * nat_odport, hv0
+		 */
+
+		if ((nat->nat_flags & IPN_TCPUDP) != 0) {
+			sp = nat->nat_nsport;
+			dp = nat->nat_ndport;
+		} else if ((nat->nat_flags & IPN_ICMPQUERY) != 0) {
+			sp = 0;
+			dp = nat->nat_nicmpid;
+		} else {
+			sp = 0;
+			dp = 0;
+		}
+		hv1 = NAT_HASH_FN(nat->nat_nsrcaddr, sp, 0xffffffff);
+		hv1 = NAT_HASH_FN(nat->nat_ndstaddr, hv1 + dp, 0xffffffff);
+		/*
+		 * TRACE nat_nsrcaddr, nat_nsport, nat_ndstaddr,
+		 * nat_ndport, hv1
+		 */
 	} else {
-		hv1 = NAT_HASH_FN(nat->nat_inip.s_addr, 0, 0xffffffff);
-		hv1 = NAT_HASH_FN(nat->nat_oip.s_addr, hv1, ipf_nattable_sz);
-		hv2 = NAT_HASH_FN(nat->nat_outip.s_addr, 0, 0xffffffff);
-		hv2 = NAT_HASH_FN(nat->nat_oip.s_addr, hv2, ipf_nattable_sz);
-	}
+		hv0 = NAT_HASH_FN(nat->nat_osrcaddr, 0, 0xffffffff);
+		hv0 = NAT_HASH_FN(nat->nat_odstaddr, hv0, 0xffffffff);
+		/* TRACE nat_osrcaddr, nat_odstaddr, hv0 */
 
-	if (nat_stats.ns_bucketlen[0][hv1] >= fr_nat_maxbucket ||
-	    nat_stats.ns_bucketlen[1][hv2] >= fr_nat_maxbucket) {
-		return -1;
+		hv1 = NAT_HASH_FN(nat->nat_nsrcaddr, 0, 0xffffffff);
+		hv1 = NAT_HASH_FN(nat->nat_ndstaddr, hv1, 0xffffffff);
+		/* TRACE nat_nsrcaddr, nat_ndstaddr, hv1 */
 	}
 
-	nat->nat_hv[0] = hv1;
-	nat->nat_hv[1] = hv2;
+	nat->nat_hv[0] = hv0;
+	nat->nat_hv[1] = hv1;
 
 	MUTEX_INIT(&nat->nat_lock, "nat entry lock");
 
-	nat->nat_rev = rev;
-	nat->nat_ref = 1;
-	nat->nat_bytes[0] = 0;
-	nat->nat_pkts[0] = 0;
-	nat->nat_bytes[1] = 0;
-	nat->nat_pkts[1] = 0;
+	in = nat->nat_ptr;
+	nat->nat_ref = nat->nat_me ? 2 : 1;
 
 	nat->nat_ifnames[0][LIFNAMSIZ - 1] = '\0';
-	nat->nat_ifps[0] = fr_resolvenic(nat->nat_ifnames[0], 4);
+	nat->nat_ifps[0] = ipf_resolvenic(softc, nat->nat_ifnames[0], 4);
 
 	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 {
-		(void) strncpy(nat->nat_ifnames[1], nat->nat_ifnames[0],
-			       LIFNAMSIZ);
-		nat->nat_ifnames[1][LIFNAMSIZ - 1] = '\0';
-		nat->nat_ifps[1] = nat->nat_ifps[0];
+		nat->nat_ifps[1] = ipf_resolvenic(softc,
+						  nat->nat_ifnames[1], 4);
+	} else if (in->in_ifnames[1] != -1) {
+		char *name;
+
+		name = in->in_names + in->in_ifnames[1];
+		if (name[1] != '\0' && name[0] != '-' && name[0] != '*') {
+			(void) strncpy(nat->nat_ifnames[1],
+				       nat->nat_ifnames[0], LIFNAMSIZ);
+			nat->nat_ifnames[1][LIFNAMSIZ - 1] = '\0';
+			nat->nat_ifps[1] = nat->nat_ifps[0];
+		}
 	}
+	if ((nat->nat_ifps[0] != NULL) && (nat->nat_ifps[0] != (void *)-1)) {
+		nat->nat_mtu[0] = GETIFMTU_4(nat->nat_ifps[0]);
+	}
+	if ((nat->nat_ifps[1] != NULL) && (nat->nat_ifps[1] != (void *)-1)) {
+		nat->nat_mtu[1] = GETIFMTU_4(nat->nat_ifps[1]);
+	}
 
-	nat->nat_next = nat_instances;
-	nat->nat_pnext = &nat_instances;
-	if (nat_instances)
-		nat_instances->nat_pnext = &nat->nat_next;
-	nat_instances = nat;
+	return ipf_nat_hashtab_add(softc, softn, nat);
+}
 
-	natp = &nat_table[0][hv1];
-	if (*natp)
-		(*natp)->nat_phnext[0] = &nat->nat_hnext[0];
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_nat_hashtab_add                                         */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              softn(I) - pointer to NAT context structure                 */
+/*              nat(I) - pointer to NAT structure                           */
+/*                                                                          */
+/* Handle the insertion of a NAT entry into the table/list.                 */
+/* ------------------------------------------------------------------------ */
+int
+ipf_nat_hashtab_add(softc, softn, nat)
+	ipf_main_softc_t *softc;
+	ipf_nat_softc_t *softn;
+	nat_t *nat;
+{
+	nat_t **natp;
+	u_int hv0;
+	u_int hv1;
+
+	hv0 = nat->nat_hv[0] % softn->ipf_nat_table_sz;
+	hv1 = nat->nat_hv[1] % softn->ipf_nat_table_sz;
+
+	if (nat->nat_dir == NAT_INBOUND || nat->nat_dir == NAT_DIVERTIN) {
+		u_int swap;
+
+		swap = hv0;
+		hv0 = hv1;
+		hv1 = swap;
+	}
+
+	if (softn->ipf_nat_stats.ns_side[0].ns_bucketlen[hv0] >=
+	    softn->ipf_nat_maxbucket) {
+		DT1(ns_bucket_max_0, int,
+		    softn->ipf_nat_stats.ns_side[0].ns_bucketlen[hv0]);
+		NBUMPSIDE(0, ns_bucket_max);
+		return -1;
+	}
+
+	if (softn->ipf_nat_stats.ns_side[1].ns_bucketlen[hv1] >=
+	    softn->ipf_nat_maxbucket) {
+		DT1(ns_bucket_max_1, int,
+		    softn->ipf_nat_stats.ns_side[1].ns_bucketlen[hv1]);
+		NBUMPSIDE(1, ns_bucket_max);
+		return -1;
+	}
+
+	/*
+	 * The ordering of operations in the list and hash table insertion
+	 * is very important.  The last operation for each task should be
+	 * to update the top of the list, after all the "nexts" have been
+	 * done so that walking the list while it is being done does not
+	 * find strange pointers.
+	 *
+	 * Global list of NAT instances
+	 */
+	nat->nat_next = softn->ipf_nat_instances;
+	nat->nat_pnext = &softn->ipf_nat_instances;
+	if (softn->ipf_nat_instances)
+		softn->ipf_nat_instances->nat_pnext = &nat->nat_next;
+	softn->ipf_nat_instances = nat;
+
+	/*
+	 * Inbound hash table.
+	 */
+	natp = &softn->ipf_nat_table[0][hv0];
 	nat->nat_phnext[0] = natp;
 	nat->nat_hnext[0] = *natp;
+	if (*natp) {
+		(*natp)->nat_phnext[0] = &nat->nat_hnext[0];
+	} else {
+		NBUMPSIDE(0, ns_inuse);
+	}
 	*natp = nat;
-	nat_stats.ns_bucketlen[0][hv1]++;
+	NBUMPSIDE(0, ns_bucketlen[hv0]);
 
-	natp = &nat_table[1][hv2];
+	/*
+	 * Outbound hash table.
+	 */
+	natp = &softn->ipf_nat_table[1][hv1];
+	nat->nat_phnext[1] = natp;
+	nat->nat_hnext[1] = *natp;
 	if (*natp)
 		(*natp)->nat_phnext[1] = &nat->nat_hnext[1];
-	nat->nat_phnext[1] = natp;
-	nat->nat_hnext[1] = *natp;
+	else {
+		NBUMPSIDE(1, ns_inuse);
+	}
 	*natp = nat;
-	nat_stats.ns_bucketlen[1][hv2]++;
+	NBUMPSIDE(1, ns_bucketlen[hv1]);
 
-	fr_setnatqueue(nat, rev);
+	ipf_nat_setqueue(softc, softn, nat);
 
-	nat_stats.ns_added++;
-	nat_stats.ns_inuse++;
+	if (nat->nat_dir & NAT_OUTBOUND) {
+		NBUMPSIDE(1, ns_added);
+	} else {
+		NBUMPSIDE(0, ns_added);
+	}
+	softn->ipf_nat_stats.ns_active++;
 	return 0;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    nat_icmperrorlookup                                         */
+/* Function:    ipf_nat_icmperrorlookup                                     */
 /* Returns:     nat_t* - point to matching NAT structure                    */
 /* Parameters:  fin(I) - pointer to packet information                      */
 /*              dir(I) - direction of packet (in/out)                       */
@@ -2741,12 +3611,16 @@
 /* ICMP query nat entry.  It is assumed that the packet is already of the   */
 /* the required length.                                                     */
 /* ------------------------------------------------------------------------ */
-nat_t *nat_icmperrorlookup(fin, dir)
-fr_info_t *fin;
-int dir;
+nat_t *
+ipf_nat_icmperrorlookup(fin, dir)
+	fr_info_t *fin;
+	int dir;
 {
+	ipf_main_softc_t *softc = fin->fin_main_soft;
+	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
 	int flags = 0, type, minlen;
 	icmphdr_t *icmp, *orgicmp;
+	nat_stat_side_t *nside;
 	tcphdr_t *tcp = NULL;
 	u_short data[2];
 	nat_t *nat;
@@ -2755,13 +3629,16 @@
 
 	icmp = fin->fin_dp;
 	type = icmp->icmp_type;
+	nside = &softn->ipf_nat_stats.ns_side[fin->fin_out];
 	/*
 	 * Does it at least have the return (basic) IP header ?
 	 * 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)) || !(fin->fin_flx & FI_ICMPERR))
+	if ((fin->fin_hlen != sizeof(ip_t)) || !(fin->fin_flx & FI_ICMPERR)) {
+		ATOMIC_INCL(nside->ns_icmp_basic);
 		return NULL;
+	}
 
 	/*
 	 * Check packet size
@@ -2769,8 +3646,11 @@
 	oip = (ip_t *)((char *)fin->fin_dp + 8);
 	minlen = IP_HL(oip) << 2;
 	if ((minlen < sizeof(ip_t)) ||
-	    (fin->fin_plen < ICMPERR_IPICMPHLEN + minlen))
+	    (fin->fin_plen < ICMPERR_IPICMPHLEN + minlen)) {
+		ATOMIC_INCL(nside->ns_icmp_size);
 		return NULL;
+	}
+
 	/*
 	 * Is the buffer big enough for all of it ?  It's the size of the IP
 	 * header claimed in the encapsulated part which is of concern.  It
@@ -2777,27 +3657,34 @@
 	 * may be too big to be in this buffer but not so big that it's
 	 * outside the ICMP packet, leading to TCP deref's causing problems.
 	 * This is possible because we don't know how big oip_hl is when we
-	 * do the pullup early in fr_check() and thus can't gaurantee it is
+	 * do the pullup early in ipf_check() and thus can't gaurantee it is
 	 * all here now.
 	 */
-#ifdef  _KERNEL
+#ifdef  ipf_nat_KERNEL
 	{
 	mb_t *m;
 
 	m = fin->fin_m;
 # if defined(MENTAT)
-	if ((char *)oip + fin->fin_dlen - ICMPERR_ICMPHLEN > (char *)m->b_wptr)
+	if ((char *)oip + fin->fin_dlen - ICMPERR_ICMPHLEN >
+	    (char *)m->b_wptr) {
+		ATOMIC_INCL(nside->ns_icmp_mbuf);
 		return NULL;
+	}
 # else
 	if ((char *)oip + fin->fin_dlen - ICMPERR_ICMPHLEN >
-	    (char *)fin->fin_ip + M_LEN(m))
+	    (char *)fin->fin_ip + M_LEN(m)) {
+		ATOMIC_INCL(nside->ns_icmp_mbuf);
 		return NULL;
+	}
 # endif
 	}
 #endif
 
-	if (fin->fin_daddr != oip->ip_src.s_addr)
+	if (fin->fin_daddr != oip->ip_src.s_addr) {
+		ATOMIC_INCL(nside->ns_icmp_address);
 		return NULL;
+	}
 
 	p = oip->ip_p;
 	if (p == IPPROTO_TCP)
@@ -2808,7 +3695,7 @@
 		orgicmp = (icmphdr_t *)((char *)oip + (IP_HL(oip) << 2));
 
 		/* see if this is related to an ICMP query */
-		if (nat_icmpquerytype4(orgicmp->icmp_type)) {
+		if (ipf_nat_icmpquerytype(orgicmp->icmp_type)) {
 			data[0] = fin->fin_data[0];
 			data[1] = fin->fin_data[1];
 			fin->fin_data[0] = 0;
@@ -2821,21 +3708,26 @@
 			 *        message flows in the opposite direction.
 			 */
 			if (dir == NAT_INBOUND)
-				nat = nat_inlookup(fin, flags, p, oip->ip_dst,
-						   oip->ip_src);
+				nat = ipf_nat_inlookup(fin, flags, p,
+						       oip->ip_dst,
+						       oip->ip_src);
 			else
-				nat = nat_outlookup(fin, flags, p, oip->ip_dst,
-						    oip->ip_src);
+				nat = ipf_nat_outlookup(fin, flags, p,
+							oip->ip_dst,
+							oip->ip_src);
 			fin->fin_data[0] = data[0];
 			fin->fin_data[1] = data[1];
 			return nat;
 		}
 	}
-		
+
 	if (flags & IPN_TCPUDP) {
 		minlen += 8;		/* + 64bits of data to get ports */
-		if (fin->fin_plen < ICMPERR_IPICMPHLEN + minlen)
+		/* TRACE (fin,minlen) */
+		if (fin->fin_plen < ICMPERR_IPICMPHLEN + minlen) {
+			ATOMIC_INCL(nside->ns_icmp_short);
 			return NULL;
+		}
 
 		data[0] = fin->fin_data[0];
 		data[1] = fin->fin_data[1];
@@ -2844,10 +3736,10 @@
 		fin->fin_data[1] = ntohs(tcp->th_sport);
 
 		if (dir == NAT_INBOUND) {
-			nat = nat_inlookup(fin, flags, p, oip->ip_dst,
-					   oip->ip_src);
+			nat = ipf_nat_inlookup(fin, flags, p, oip->ip_dst,
+					       oip->ip_src);
 		} else {
-			nat = nat_outlookup(fin, flags, p, oip->ip_dst,
+			nat = ipf_nat_outlookup(fin, flags, p, oip->ip_dst,
 					    oip->ip_src);
 		}
 		fin->fin_data[0] = data[0];
@@ -2855,14 +3747,16 @@
 		return nat;
 	}
 	if (dir == NAT_INBOUND)
-		return nat_inlookup(fin, 0, p, oip->ip_dst, oip->ip_src);
+		nat = ipf_nat_inlookup(fin, 0, p, oip->ip_dst, oip->ip_src);
 	else
-		return nat_outlookup(fin, 0, p, oip->ip_dst, oip->ip_src);
+		nat = ipf_nat_outlookup(fin, 0, p, oip->ip_dst, oip->ip_src);
+
+	return nat;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    nat_icmperror                                               */
+/* Function:    ipf_nat_icmperror                                           */
 /* Returns:     nat_t* - point to matching NAT structure                    */
 /* Parameters:  fin(I)    - pointer to packet information                   */
 /*              nflags(I) - NAT flags for this packet                       */
@@ -2874,13 +3768,16 @@
 /* This should *ONLY* be used for incoming ICMP error packets to make sure  */
 /* a NAT'd ICMP packet gets correctly recognised.                           */
 /* ------------------------------------------------------------------------ */
-nat_t *nat_icmperror(fin, nflags, dir)
-fr_info_t *fin;
-u_int *nflags;
-int dir;
+nat_t *
+ipf_nat_icmperror(fin, nflags, dir)
+	fr_info_t *fin;
+	u_int *nflags;
+	int dir;
 {
+	ipf_main_softc_t *softc = fin->fin_main_soft;
+	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
 	u_32_t sum1, sum2, sumd, sumd2;
-	struct in_addr a1, a2;
+	struct in_addr a1, a2, a3, a4;
 	int flags, dlen, odst;
 	icmphdr_t *icmp;
 	u_short *csump;
@@ -2889,13 +3786,18 @@
 	ip_t *oip;
 	void *dp;
 
-	if ((fin->fin_flx & (FI_SHORT|FI_FRAGBODY)))
+	if ((fin->fin_flx & (FI_SHORT|FI_FRAGBODY))) {
+		NBUMPSIDED(fin->fin_out, ns_icmp_short);
 		return NULL;
+	}
+
 	/*
-	 * nat_icmperrorlookup() will return NULL for `defective' packets.
+	 * ipf_nat_icmperrorlookup() will return NULL for `defective' packets.
 	 */
-	if ((fin->fin_v != 4) || !(nat = nat_icmperrorlookup(fin, dir)))
+	if ((fin->fin_v != 4) || !(nat = ipf_nat_icmperrorlookup(fin, dir))) {
+		NBUMPSIDED(fin->fin_out, ns_icmp_notfound);
 		return NULL;
+	}
 
 	tcp = NULL;
 	csump = NULL;
@@ -2923,7 +3825,7 @@
 	/*
 	 * Need to adjust ICMP header to include the real IP#'s and
 	 * port #'s.  Only apply a checksum change relative to the
-	 * IP address change as it will be modified again in fr_checknatout
+	 * IP address change as it will be modified again in ipf_nat_checkout
 	 * for both address and port.  Two checksum changes are
 	 * necessary for the two header address changes.  Be careful
 	 * to only modify the checksum once for the port # and twice
@@ -2949,43 +3851,74 @@
 	 * ------------
 	 * 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
+	 * - OIP_SRC(c)=nat_newsrcip,          OIP_DST(b)=nat_newdstip
+	 *=> OIP_SRC(c)=nat_oldsrcip,          OIP_DST(b)=nat_olddstip
 	 *
 	 * 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
+	 * - OIP_SRC(b)=nat_olddstip,          OIP_DST(a)=nat_oldsrcip
+	 *=> OIP_SRC(b)=nat_newdstip,          OIP_DST(a)=nat_newsrcip
 	 *
+	 * REWRITE out rule, SRC=a,DST=b -> SRC=c,DST=d
+	 * - response to outgoing packet (a,b)=>(c,d) (OIP_SRC=c,OIP_DST=d)
+	 * - OIP_SRC(c)=nat_newsrcip,          OIP_DST(d)=nat_newdstip
+	 *=> OIP_SRC(c)=nat_oldsrcip,          OIP_DST(d)=nat_olddstip
+	 *
+	 * REWRITE in rule, SRC=a,DST=b -> SRC=c,DST=d
+	 * - response to outgoing packet (d,c)=>(b,a) (OIP_SRC=b,OIP_DST=a)
+	 * - OIP_SRC(b)=nat_olddstip,          OIP_DST(a)=nat_oldsrcip
+	 *=> OIP_SRC(b)=nat_newdstip,          OIP_DST(a)=nat_newsrcip
+	 *
 	 * 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
+	 * - OIP_SRC(b)=nat_olddstip,          OIP_DST(a)=nat_oldsrcip
+	 *=> OIP_SRC(b)=nat_newdstip,          OIP_DST(a)=nat_newsrcip
 	 *
 	 * 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
+	 * - OIP_SRC(a)=nat_newsrcip,          OIP_DST(c)=nat_newdstip
+	 *=> OIP_SRC(a)=nat_oldsrcip,          OIP_DST(c)=nat_olddstip
 	 *
+	 * REWRITE out rule, SRC=a,DST=b -> SRC=c,DST=d
+	 * - response to incoming packet (d,c)=>(b,a) (OIP_SRC=c,OIP_DST=d)
+	 * - OIP_SRC(c)=nat_olddstip,          OIP_DST(d)=nat_oldsrcip
+	 *=> OIP_SRC(b)=nat_newdstip,          OIP_DST(a)=nat_newsrcip
+	 *
+	 * REWRITE in rule, SRC=a,DST=b -> SRC=c,DST=d
+	 * - response to incoming packet (a,b)=>(c,d) (OIP_SRC=b,OIP_DST=a)
+	 * - OIP_SRC(b)=nat_newsrcip,          OIP_DST(a)=nat_newdstip
+	 *=> OIP_SRC(a)=nat_oldsrcip,          OIP_DST(c)=nat_olddstip
 	 */
-	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);
+
+	if (((fin->fin_out == 0) && ((nat->nat_redir & NAT_MAP) != 0)) ||
+	    ((fin->fin_out == 1) && ((nat->nat_redir & NAT_REDIRECT) != 0))) {
+		a1.s_addr = ntohl(nat->nat_osrcaddr);
+		a4.s_addr = ntohl(oip->ip_src.s_addr);
+		a3.s_addr = ntohl(nat->nat_odstaddr);
+		a2.s_addr = ntohl(oip->ip_dst.s_addr);
 		oip->ip_src.s_addr = htonl(a1.s_addr);
+		oip->ip_dst.s_addr = htonl(a3.s_addr);
+		odst = 1;
 	} else {
-		a1.s_addr = ntohl(nat->nat_outip.s_addr);
+		a1.s_addr = ntohl(nat->nat_ndstaddr);
 		a2.s_addr = ntohl(oip->ip_dst.s_addr);
-		oip->ip_dst.s_addr = htonl(a1.s_addr);
+		a3.s_addr = ntohl(nat->nat_nsrcaddr);
+		a4.s_addr = ntohl(oip->ip_src.s_addr);
+		oip->ip_dst.s_addr = htonl(a3.s_addr);
+		oip->ip_src.s_addr = htonl(a1.s_addr);
+		odst = 0;
 	}
+	sum1 = 0;
+	sum2 = 0;
+	sumd = 0;
+	CALC_SUMD(a2.s_addr, a3.s_addr, sum1);
+	CALC_SUMD(a4.s_addr, a1.s_addr, sum2);
+	sumd = sum2 + sum1;
+	if (sumd != 0)
+		ipf_fix_datacksum(&oip->ip_sum, sumd);
 
-	sumd = a2.s_addr - a1.s_addr;
-	if (sumd != 0) {
-		if (a1.s_addr > a2.s_addr)
-			sumd--;
-		sumd = ~sumd;
-
-		fix_datacksum(&oip->ip_sum, sumd);
-	}
-
 	sumd2 = sumd;
 	sum1 = 0;
 	sum2 = 0;
@@ -2995,6 +3928,8 @@
 	 * IP address change.
 	 */
 	if (((flags & IPN_TCPUDP) != 0) && (dlen >= 4)) {
+		u_32_t sum3, sum4, sumt;
+
 		/*
 		 * Step 2 :
 		 * For offending TCP/UDP IP packets, translate the ports as
@@ -3003,24 +3938,33 @@
 		 *
 		 * Since the port fields are part of the TCP/UDP checksum
 		 * of the offending IP packet, you need to adjust that checksum
-		 * as well... except that the change in the port numbers should 
+		 * 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);
+			sum1 = ntohs(nat->nat_osport);
+			sum4 = ntohs(tcp->th_sport);
+			sum3 = ntohs(nat->nat_odport);
+			sum2 = ntohs(tcp->th_dport);
 
 			tcp->th_sport = htons(sum1);
+			tcp->th_dport = htons(sum3);
 		} else {
-			sum1 = ntohs(nat->nat_outport);
+			sum1 = ntohs(nat->nat_ndport);
 			sum2 = ntohs(tcp->th_dport);
+			sum3 = ntohs(nat->nat_nsport);
+			sum4 = ntohs(tcp->th_sport);
 
-			tcp->th_dport = htons(sum1);
+			tcp->th_dport = htons(sum3);
+			tcp->th_sport = htons(sum1);
 		}
+		CALC_SUMD(sum4, sum1, sumt);
+		sumd += sumt;
+		CALC_SUMD(sum2, sum3, sumt);
+		sumd += sumt;
 
-		sumd += sum1 - sum2;
 		if (sumd != 0 || sumd2 != 0) {
 			/*
 			 * At this point, sumd is the delta to apply to the
@@ -3038,39 +3982,26 @@
 			 */
 			if (oip->ip_p == IPPROTO_UDP) {
 				if ((dlen >= 8) && (*csump != 0)) {
-					fix_datacksum(csump, sumd);
+					ipf_fix_datacksum(csump, sumd);
 				} else {
-					sumd2 = sum1 - sum2;
-					if (sum2 > sum1)
-						sumd2--;
+					CALC_SUMD(sum1, sum4, sumd2);
+					CALC_SUMD(sum3, sum2, sumt);
+					sumd2 += sumt;
 				}
 			} else if (oip->ip_p == IPPROTO_TCP) {
 				if (dlen >= 18) {
-					fix_datacksum(csump, sumd);
+					ipf_fix_datacksum(csump, sumd);
 				} else {
-					sumd2 = sum2 - sum1;
-					if (sum1 > sum2)
-						sumd2--;
+					CALC_SUMD(sum1, sum4, sumd2);
+					CALC_SUMD(sum3, sum2, sumt);
+					sumd2 += sumt;
 				}
 			}
-
 			if (sumd2 != 0) {
-				ipnat_t *np;
-
-				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 {
-					fix_incksum(fin, &icmp->icmp_cksum,
-						    sumd2);
-				}
+				ipf_fix_incksum(0, &icmp->icmp_cksum, sumd2, 0);
 			}
 		}
 	} else if (((flags & IPN_ICMPQUERY) != 0) && (dlen >= 8)) {
@@ -3078,12 +4009,13 @@
 
 		/*
 		 * XXX - what if this is bogus hl and we go off the end ?
-		 * In this case, nat_icmperrorlookup() will have returned NULL.
+		 * In this case, ipf_nat_icmperrorlookup() will have
+		 * returned NULL.
 		 */
 		orgicmp = (icmphdr_t *)dp;
 
 		if (odst == 1) {
-			if (orgicmp->icmp_id != nat->nat_inport) {
+			if (orgicmp->icmp_id != nat->nat_osport) {
 
 				/*
 				 * Fix ICMP checksum (of the offening ICMP
@@ -3098,10 +4030,10 @@
 				 * overall icmp->icmp_cksum
 				 */
 				sum1 = ntohs(orgicmp->icmp_id);
-				sum2 = ntohs(nat->nat_inport);
+				sum2 = ntohs(nat->nat_oicmpid);
 				CALC_SUMD(sum1, sum2, sumd);
-				orgicmp->icmp_id = nat->nat_inport;
-				fix_datacksum(&orgicmp->icmp_cksum, sumd);
+				orgicmp->icmp_id = nat->nat_oicmpid;
+				ipf_fix_datacksum(&orgicmp->icmp_cksum, sumd);
 			}
 		} /* nat_dir == NAT_INBOUND is impossible for icmp queries */
 	}
@@ -3110,12 +4042,19 @@
 
 
 /*
+ *       MAP-IN    MAP-OUT   RDR-IN   RDR-OUT
+ * osrc    X       == src    == src      X
+ * odst    X       == dst    == dst      X
+ * nsrc  == dst      X         X      == dst
+ * ndst  == src      X         X      == src
+ * MAP = NAT_OUTBOUND, RDR = NAT_INBOUND
+ */
+/*
  * NB: these lookups don't lock access to the list, it assumed that it has
  * already been done!
  */
-
 /* ------------------------------------------------------------------------ */
-/* Function:    nat_inlookup                                                */
+/* Function:    ipf_nat_inlookup                                            */
 /* Returns:     nat_t* - NULL == no match,                                  */
 /*                       else pointer to matching NAT entry                 */
 /* Parameters:  fin(I)    - pointer to packet information                   */
@@ -3130,17 +4069,20 @@
 /*                                                                          */
 /* NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY.         */
 /*                                                                          */
-/* NOTE: IT IS ASSUMED THAT ipf_nat IS ONLY HELD WITH A READ LOCK WHEN      */
+/* NOTE: IT IS ASSUMED THAT  IS ONLY HELD WITH A READ LOCK WHEN             */
 /*       THIS FUNCTION IS CALLED WITH NAT_SEARCH SET IN nflags.             */
 /*                                                                          */
 /* flags   -> relevant are IPN_UDP/IPN_TCP/IPN_ICMPQUERY that indicate if   */
 /*            the packet is of said protocol                                */
 /* ------------------------------------------------------------------------ */
-nat_t *nat_inlookup(fin, flags, p, src, mapdst)
-fr_info_t *fin;
-u_int flags, p;
-struct in_addr src , mapdst;
+nat_t *
+ipf_nat_inlookup(fin, flags, p, src, mapdst)
+	fr_info_t *fin;
+	u_int flags, p;
+	struct in_addr src , mapdst;
 {
+	ipf_main_softc_t *softc = fin->fin_main_soft;
+	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
 	u_short sport, dport;
 	grehdr_t *gre;
 	ipnat_t *ipn;
@@ -3149,11 +4091,9 @@
 	int nflags;
 	u_32_t dst;
 	void *ifp;
-	u_int hv;
+	u_int hv, rhv;
 
 	ifp = fin->fin_ifp;
-	sport = 0;
-	dport = 0;
 	gre = NULL;
 	dst = mapdst.s_addr;
 	sflags = flags & NAT_TCPUDPICMP;
@@ -3166,12 +4106,12 @@
 		dport = htons(fin->fin_data[1]);
 		break;
 	case IPPROTO_ICMP :
-		if (flags & IPN_ICMPERR)
-			sport = fin->fin_data[1];
-		else
-			dport = fin->fin_data[1];
+		sport = 0;
+		dport = fin->fin_data[1];
 		break;
 	default :
+		sport = 0;
+		dport = 0;
 		break;
 	}
 
@@ -3179,57 +4119,81 @@
 	if ((flags & SI_WILDP) != 0)
 		goto find_in_wild_ports;
 
-	hv = NAT_HASH_FN(dst, dport, 0xffffffff);
-	hv = NAT_HASH_FN(src.s_addr, hv + sport, ipf_nattable_sz);
-	nat = nat_table[1][hv];
+	rhv = NAT_HASH_FN(dst, dport, 0xffffffff);
+	rhv = NAT_HASH_FN(src.s_addr, rhv + sport, 0xffffffff);
+	hv = rhv % softn->ipf_nat_table_sz;
+	nat = softn->ipf_nat_table[1][hv];
+	/* TRACE dst, dport, src, sport, hv, nat */
+
 	for (; nat; nat = nat->nat_hnext[1]) {
 		if (nat->nat_ifps[0] != NULL) {
 			if ((ifp != NULL) && (ifp != nat->nat_ifps[0]))
 				continue;
-		} else if (ifp != NULL)
-			nat->nat_ifps[0] = ifp;
+		}
 
-		nflags = nat->nat_flags;
+		if (nat->nat_pr[0] != p)
+			continue;
 
-		if (nat->nat_oip.s_addr == src.s_addr &&
-		    nat->nat_outip.s_addr == dst &&
-		    (((p == 0) &&
-		      (sflags == (nat->nat_flags & IPN_TCPUDPICMP)))
-		     || (p == nat->nat_p))) {
-			switch (p)
-			{
-#if 0
-			case IPPROTO_GRE :
-				if (nat->nat_call[1] != fin->fin_data[0])
+		switch (nat->nat_dir)
+		{
+		case NAT_INBOUND :
+		case NAT_DIVERTIN :
+			if (nat->nat_v[0] != 4)
+				continue;
+			if (nat->nat_osrcaddr != src.s_addr ||
+			    nat->nat_odstaddr != dst)
+				continue;
+			if ((nat->nat_flags & IPN_TCPUDP) != 0) {
+				if (nat->nat_osport != sport)
 					continue;
-				break;
-#endif
-			case IPPROTO_ICMP :
-				if ((flags & IPN_ICMPERR) != 0) {
-					if (nat->nat_outport != sport)
-						continue;
-				} else {
-					if (nat->nat_outport != dport)
-						continue;
+				if (nat->nat_odport != dport)
+					continue;
+
+			} else if (p == IPPROTO_ICMP) {
+				if (nat->nat_osport != dport) {
+					continue;
 				}
-				break;
-			case IPPROTO_TCP :
-			case IPPROTO_UDP :
-				if (nat->nat_oport != sport)
+			}
+			break;
+		case NAT_DIVERTOUT :
+			if (nat->nat_dlocal)
+				continue;
+		case NAT_OUTBOUND :
+			if (nat->nat_v[1] != 4)
+				continue;
+			if (nat->nat_dlocal)
+				continue;
+			if (nat->nat_dlocal)
+				continue;
+			if (nat->nat_ndstaddr != src.s_addr ||
+			    nat->nat_nsrcaddr != dst)
+				continue;
+			if ((nat->nat_flags & IPN_TCPUDP) != 0) {
+				if (nat->nat_ndport != sport)
 					continue;
-				if (nat->nat_outport != dport)
+				if (nat->nat_nsport != dport)
 					continue;
-				break;
-			default :
-				break;
+
+			} else if (p == IPPROTO_ICMP) {
+				if (nat->nat_osport != dport) {
+					continue;
+				}
 			}
+			break;
+		}
 
+
+		if ((nat->nat_flags & IPN_TCPUDP) != 0) {
 			ipn = nat->nat_ptr;
 			if ((ipn != NULL) && (nat->nat_aps != NULL))
-				if (appr_match(fin, nat) != 0)
+				if (ipf_proxy_match(fin, nat) != 0)
 					continue;
-			return nat;
 		}
+		if ((nat->nat_ifps[0] == NULL) && (ifp != NULL)) {
+			nat->nat_ifps[0] = ifp;
+			nat->nat_mtu[0] = GETIFMTU_4(ifp);
+		}
+		return nat;
 	}
 
 	/*
@@ -3240,67 +4204,111 @@
 	 * for "dummy" (FI_IGNORE) lookups.
 	 */
 find_in_wild_ports:
-	if (!(flags & NAT_TCPUDP) || !(flags & NAT_SEARCH))
+	if (!(flags & NAT_TCPUDP) || !(flags & NAT_SEARCH)) {
+		NBUMPSIDEX(0, ns_lookup_miss, ns_lookup_miss_0);
 		return NULL;
-	if (nat_stats.ns_wilds == 0)
+	}
+	if (softn->ipf_nat_stats.ns_wilds == 0 || (fin->fin_flx & FI_NOWILD)) {
+		NBUMPSIDEX(0, ns_lookup_nowild, ns_lookup_nowild_0);
 		return NULL;
+	}
 
-	RWLOCK_EXIT(&ipf_nat);
+	RWLOCK_EXIT(&softc->ipf_nat);
 
 	hv = NAT_HASH_FN(dst, 0, 0xffffffff);
-	hv = NAT_HASH_FN(src.s_addr, hv, ipf_nattable_sz);
+	hv = NAT_HASH_FN(src.s_addr, hv, softn->ipf_nat_table_sz);
+	WRITE_ENTER(&softc->ipf_nat);
 
-	WRITE_ENTER(&ipf_nat);
-
-	nat = nat_table[1][hv];
+	nat = softn->ipf_nat_table[1][hv];
+	/* TRACE dst, src, hv, nat */
 	for (; nat; nat = nat->nat_hnext[1]) {
 		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)
+		if (nat->nat_pr[0] != fin->fin_p)
 			continue;
-		if (nat->nat_oip.s_addr != src.s_addr ||
-		    nat->nat_outip.s_addr != dst)
-			continue;
 
+		switch (nat->nat_dir & (NAT_INBOUND|NAT_OUTBOUND))
+		{
+		case NAT_INBOUND :
+			if (nat->nat_v[0] != 4)
+				continue;
+			if (nat->nat_osrcaddr != src.s_addr ||
+			    nat->nat_odstaddr != dst)
+				continue;
+			break;
+		case NAT_OUTBOUND :
+			if (nat->nat_v[1] != 4)
+				continue;
+			if (nat->nat_ndstaddr != src.s_addr ||
+			    nat->nat_nsrcaddr != dst)
+				continue;
+			break;
+		}
+
 		nflags = nat->nat_flags;
 		if (!(nflags & (NAT_TCPUDP|SI_WILDP)))
 			continue;
 
-		if (nat_wildok(nat, (int)sport, (int)dport, nflags,
-			       NAT_INBOUND) == 1) {
+		if (ipf_nat_wildok(nat, (int)sport, (int)dport, nflags,
+				   NAT_INBOUND) == 1) {
 			if ((fin->fin_flx & FI_IGNORE) != 0)
 				break;
 			if ((nflags & SI_CLONE) != 0) {
-				nat = fr_natclone(fin, nat);
+				nat = ipf_nat_clone(fin, nat);
 				if (nat == NULL)
 					break;
 			} else {
-				MUTEX_ENTER(&ipf_nat_new);
-				nat_stats.ns_wilds--;
-				MUTEX_EXIT(&ipf_nat_new);
+				MUTEX_ENTER(&softn->ipf_nat_new);
+				softn->ipf_nat_stats.ns_wilds--;
+				MUTEX_EXIT(&softn->ipf_nat_new);
 			}
-			nat->nat_oport = sport;
-			nat->nat_outport = dport;
+
+			if (nat->nat_dir == NAT_INBOUND) {
+				if (nat->nat_osport == 0) {
+					nat->nat_osport = sport;
+					nat->nat_nsport = sport;
+				}
+				if (nat->nat_odport == 0) {
+					nat->nat_odport = dport;
+					nat->nat_ndport = dport;
+				}
+			} else if (nat->nat_dir == NAT_OUTBOUND) {
+				if (nat->nat_osport == 0) {
+					nat->nat_osport = dport;
+					nat->nat_nsport = dport;
+				}
+				if (nat->nat_odport == 0) {
+					nat->nat_odport = sport;
+					nat->nat_ndport = sport;
+				}
+			}
+			if ((nat->nat_ifps[0] == NULL) && (ifp != NULL)) {
+				nat->nat_ifps[0] = ifp;
+				nat->nat_mtu[0] = GETIFMTU_4(ifp);
+			}
 			nat->nat_flags &= ~(SI_W_DPORT|SI_W_SPORT);
-			nat_tabmove(nat);
+			ipf_nat_tabmove(softn, nat);
 			break;
 		}
 	}
 
-	MUTEX_DOWNGRADE(&ipf_nat);
+	MUTEX_DOWNGRADE(&softc->ipf_nat);
 
+	if (nat == NULL) {
+		NBUMPSIDE(0, ns_lookup_miss);
+	}
 	return nat;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    nat_tabmove                                                 */
+/* Function:    ipf_nat_tabmove                                             */
 /* Returns:     Nil                                                         */
-/* Parameters:  nat(I) - pointer to NAT structure                           */
+/* Parameters:  softn(I) - pointer to NAT context structure                 */
+/*              nat(I)   - pointer to NAT structure                         */
 /* Write Lock:  ipf_nat                                                     */
 /*                                                                          */
 /* This function is only called for TCP/UDP NAT table entries where the     */
@@ -3307,15 +4315,19 @@
 /* original was placed in the table without hashing on the ports and we now */
 /* want to include hashing on port numbers.                                 */
 /* ------------------------------------------------------------------------ */
-static void nat_tabmove(nat)
-nat_t *nat;
+static void
+ipf_nat_tabmove(softn, nat)
+	ipf_nat_softc_t *softn;
+	nat_t *nat;
 {
+	u_int hv0, hv1, rhv0, rhv1;
+	natstat_t *nsp;
 	nat_t **natp;
-	u_int hv;
 
 	if (nat->nat_flags & SI_CLONE)
 		return;
 
+	nsp = &softn->ipf_nat_stats;
 	/*
 	 * Remove the NAT entry from the old location
 	 */
@@ -3322,44 +4334,61 @@
 	if (nat->nat_hnext[0])
 		nat->nat_hnext[0]->nat_phnext[0] = nat->nat_phnext[0];
 	*nat->nat_phnext[0] = nat->nat_hnext[0];
-	nat_stats.ns_bucketlen[0][nat->nat_hv[0]]--;
+	nsp->ns_side[0].ns_bucketlen[nat->nat_hv[0] %
+				     softn->ipf_nat_table_sz]--;
 
 	if (nat->nat_hnext[1])
 		nat->nat_hnext[1]->nat_phnext[1] = nat->nat_phnext[1];
 	*nat->nat_phnext[1] = nat->nat_hnext[1];
-	nat_stats.ns_bucketlen[1][nat->nat_hv[1]]--;
+	nsp->ns_side[1].ns_bucketlen[nat->nat_hv[1] %
+				     softn->ipf_nat_table_sz]--;
 
 	/*
 	 * Add into the NAT table in the new position
 	 */
-	hv = NAT_HASH_FN(nat->nat_inip.s_addr, nat->nat_inport, 0xffffffff);
-	hv = NAT_HASH_FN(nat->nat_oip.s_addr, hv + nat->nat_oport,
-			 ipf_nattable_sz);
-	nat->nat_hv[0] = hv;
-	natp = &nat_table[0][hv];
+	rhv0 = NAT_HASH_FN(nat->nat_osrcaddr, nat->nat_osport, 0xffffffff);
+	rhv0 = NAT_HASH_FN(nat->nat_odstaddr, rhv0 + nat->nat_odport,
+			   0xffffffff);
+	rhv1 = NAT_HASH_FN(nat->nat_nsrcaddr, nat->nat_nsport, 0xffffffff);
+	rhv1 = NAT_HASH_FN(nat->nat_ndstaddr, rhv1 + nat->nat_ndport,
+			   0xffffffff);
+
+	hv0 = rhv0 % softn->ipf_nat_table_sz;
+	hv1 = rhv1 % softn->ipf_nat_table_sz;
+
+	if (nat->nat_dir == NAT_INBOUND || nat->nat_dir == NAT_DIVERTIN) {
+		u_int swap;
+
+		swap = hv0;
+		hv0 = hv1;
+		hv1 = swap;
+	}
+
+	/* TRACE nat_osrcaddr, nat_osport, nat_odstaddr, nat_odport, hv0 */
+	/* TRACE nat_nsrcaddr, nat_nsport, nat_ndstaddr, nat_ndport, hv1 */
+
+	nat->nat_hv[0] = rhv0;
+	natp = &softn->ipf_nat_table[0][hv0];
 	if (*natp)
 		(*natp)->nat_phnext[0] = &nat->nat_hnext[0];
 	nat->nat_phnext[0] = natp;
 	nat->nat_hnext[0] = *natp;
 	*natp = nat;
-	nat_stats.ns_bucketlen[0][hv]++;
+	nsp->ns_side[0].ns_bucketlen[hv0]++;
 
-	hv = NAT_HASH_FN(nat->nat_outip.s_addr, nat->nat_outport, 0xffffffff);
-	hv = NAT_HASH_FN(nat->nat_oip.s_addr, hv + nat->nat_oport,
-			 ipf_nattable_sz);
-	nat->nat_hv[1] = hv;
-	natp = &nat_table[1][hv];
+	nat->nat_hv[1] = rhv1;
+	natp = &softn->ipf_nat_table[1][hv1];
 	if (*natp)
 		(*natp)->nat_phnext[1] = &nat->nat_hnext[1];
 	nat->nat_phnext[1] = natp;
 	nat->nat_hnext[1] = *natp;
 	*natp = nat;
-	nat_stats.ns_bucketlen[1][hv]++;
+	nsp->ns_side[1].ns_bucketlen[hv1]++;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    nat_outlookup                                               */
+/* Function:    ipf_nat_outlookup                                           */
 /* Returns:     nat_t* - NULL == no match,                                  */
 /*                       else pointer to matching NAT entry                 */
 /* Parameters:  fin(I)   - pointer to packet information                    */
@@ -3367,7 +4396,7 @@
 /*              p(I)     - protocol for this packet                         */
 /*              src(I)   - source IP address                                */
 /*              dst(I)   - destination IP address                           */
-/*              rw(I)    - 1 == write lock on ipf_nat held, 0 == read lock. */
+/*              rw(I)    - 1 == write lock on  held, 0 == read lock.        */
 /*                                                                          */
 /* Lookup a nat entry based on the source 'real' ip address/port and        */
 /* destination address/port.  We use this lookup when sending a packet out, */
@@ -3375,31 +4404,29 @@
 /*                                                                          */
 /* NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY.         */
 /*                                                                          */
-/* NOTE: IT IS ASSUMED THAT ipf_nat IS ONLY HELD WITH A READ LOCK WHEN      */
+/* NOTE: IT IS ASSUMED THAT  IS ONLY HELD WITH A READ LOCK WHEN             */
 /*       THIS FUNCTION IS CALLED WITH NAT_SEARCH SET IN nflags.             */
 /*                                                                          */
 /* flags   -> relevant are IPN_UDP/IPN_TCP/IPN_ICMPQUERY that indicate if   */
 /*            the packet is of said protocol                                */
 /* ------------------------------------------------------------------------ */
-nat_t *nat_outlookup(fin, flags, p, src, dst)
-fr_info_t *fin;
-u_int flags, p;
-struct in_addr src , dst;
+nat_t *
+ipf_nat_outlookup(fin, flags, p, src, dst)
+	fr_info_t *fin;
+	u_int flags, p;
+	struct in_addr src , dst;
 {
+	ipf_main_softc_t *softc = fin->fin_main_soft;
+	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
 	u_short sport, dport;
 	u_int sflags;
 	ipnat_t *ipn;
-	u_32_t srcip;
 	nat_t *nat;
-	int nflags;
 	void *ifp;
 	u_int hv;
 
 	ifp = fin->fin_ifp;
-	srcip = src.s_addr;
 	sflags = flags & IPN_TCPUDPICMP;
-	sport = 0;
-	dport = 0;
 
 	switch (p)
 	{
@@ -3409,12 +4436,12 @@
 		dport = htons(fin->fin_data[1]);
 		break;
 	case IPPROTO_ICMP :
-		if (flags & IPN_ICMPERR)
-			sport = fin->fin_data[1];
-		else
-			dport = fin->fin_data[1];
+		sport = 0;
+		dport = fin->fin_data[1];
 		break;
 	default :
+		sport = 0;
+		dport = 0;
 		break;
 	}
 
@@ -3421,47 +4448,75 @@
 	if ((flags & SI_WILDP) != 0)
 		goto find_out_wild_ports;
 
-	hv = NAT_HASH_FN(srcip, sport, 0xffffffff);
-	hv = NAT_HASH_FN(dst.s_addr, hv + dport, ipf_nattable_sz);
-	nat = nat_table[0][hv];
+	hv = NAT_HASH_FN(src.s_addr, sport, 0xffffffff);
+	hv = NAT_HASH_FN(dst.s_addr, hv + dport, softn->ipf_nat_table_sz);
+	nat = softn->ipf_nat_table[0][hv];
+
+	/* TRACE src, sport, dst, dport, hv, nat */
+
 	for (; nat; nat = nat->nat_hnext[0]) {
 		if (nat->nat_ifps[1] != NULL) {
 			if ((ifp != NULL) && (ifp != nat->nat_ifps[1]))
 				continue;
-		} else if (ifp != NULL)
-			nat->nat_ifps[1] = ifp;
+		}
 
-		nflags = nat->nat_flags;
+		if (nat->nat_pr[1] != p)
+			continue;
 
-		if (nat->nat_inip.s_addr == srcip &&
-		    nat->nat_oip.s_addr == dst.s_addr &&
-		    (((p == 0) && (sflags == (nflags & NAT_TCPUDPICMP)))
-		     || (p == nat->nat_p))) {
-			switch (p)
-			{
-#if 0
-			case IPPROTO_GRE :
-				if (nat->nat_call[1] != fin->fin_data[0])
+		switch (nat->nat_dir)
+		{
+		case NAT_INBOUND :
+		case NAT_DIVERTIN :
+			if (nat->nat_v[1] != 4)
+				continue;
+			if (nat->nat_ndstaddr != src.s_addr ||
+			    nat->nat_nsrcaddr != dst.s_addr)
+				continue;
+
+			if ((nat->nat_flags & IPN_TCPUDP) != 0) {
+				if (nat->nat_ndport != sport)
 					continue;
-				break;
-#endif
-			case IPPROTO_TCP :
-			case IPPROTO_UDP :
-				if (nat->nat_oport != dport)
+				if (nat->nat_nsport != dport)
 					continue;
-				if (nat->nat_inport != sport)
+
+			} else if (p == IPPROTO_ICMP) {
+				if (nat->nat_osport != dport) {
 					continue;
-				break;
-			default :
-				break;
+				}
 			}
+			break;
+		case NAT_OUTBOUND :
+		case NAT_DIVERTOUT :
+			if (nat->nat_v[0] != 4)
+				continue;
+			if (nat->nat_osrcaddr != src.s_addr ||
+			    nat->nat_odstaddr != dst.s_addr)
+				continue;
 
-			ipn = nat->nat_ptr;
-			if ((ipn != NULL) && (nat->nat_aps != NULL))
-				if (appr_match(fin, nat) != 0)
+			if ((nat->nat_flags & IPN_TCPUDP) != 0) {
+				if (nat->nat_odport != dport)
 					continue;
-			return nat;
+				if (nat->nat_osport != sport)
+					continue;
+
+			} else if (p == IPPROTO_ICMP) {
+				if (nat->nat_osport != dport) {
+					continue;
+				}
+			}
+			break;
 		}
+
+		ipn = nat->nat_ptr;
+		if ((ipn != NULL) && (nat->nat_aps != NULL))
+			if (ipf_proxy_match(fin, nat) != 0)
+				continue;
+
+		if ((nat->nat_ifps[1] == NULL) && (ifp != NULL)) {
+			nat->nat_ifps[1] = ifp;
+			nat->nat_mtu[1] = GETIFMTU_4(ifp);
+		}
+		return nat;
 	}
 
 	/*
@@ -3472,67 +4527,107 @@
 	 * for "dummy" (FI_IGNORE) lookups.
 	 */
 find_out_wild_ports:
-	if (!(flags & NAT_TCPUDP) || !(flags & NAT_SEARCH))
+	if (!(flags & NAT_TCPUDP) || !(flags & NAT_SEARCH)) {
+		NBUMPSIDEX(1, ns_lookup_miss, ns_lookup_miss_1);
 		return NULL;
-	if (nat_stats.ns_wilds == 0)
+	}
+	if (softn->ipf_nat_stats.ns_wilds == 0 || (fin->fin_flx & FI_NOWILD)) {
+		NBUMPSIDEX(1, ns_lookup_nowild, ns_lookup_nowild_1);
 		return NULL;
+	}
 
-	RWLOCK_EXIT(&ipf_nat);
+	RWLOCK_EXIT(&softc->ipf_nat);
 
-	hv = NAT_HASH_FN(srcip, 0, 0xffffffff);
-	hv = NAT_HASH_FN(dst.s_addr, hv, ipf_nattable_sz);
+	hv = NAT_HASH_FN(src.s_addr, 0, 0xffffffff);
+	hv = NAT_HASH_FN(dst.s_addr, hv, softn->ipf_nat_table_sz);
 
-	WRITE_ENTER(&ipf_nat);
+	WRITE_ENTER(&softc->ipf_nat);
 
-	nat = nat_table[0][hv];
+	nat = softn->ipf_nat_table[0][hv];
 	for (; nat; nat = nat->nat_hnext[0]) {
 		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)
+		if (nat->nat_pr[1] != fin->fin_p)
 			continue;
-		if ((nat->nat_inip.s_addr != srcip) ||
-		    (nat->nat_oip.s_addr != dst.s_addr))
-			continue;
 
-		nflags = nat->nat_flags;
-		if (!(nflags & (NAT_TCPUDP|SI_WILDP)))
+		switch (nat->nat_dir & (NAT_INBOUND|NAT_OUTBOUND))
+		{
+		case NAT_INBOUND :
+			if (nat->nat_v[1] != 4)
+				continue;
+			if (nat->nat_ndstaddr != src.s_addr ||
+			    nat->nat_nsrcaddr != dst.s_addr)
+				continue;
+			break;
+		case NAT_OUTBOUND :
+			if (nat->nat_v[0] != 4)
+				continue;
+			if (nat->nat_osrcaddr != src.s_addr ||
+			    nat->nat_odstaddr != dst.s_addr)
+				continue;
+			break;
+		}
+
+		if (!(nat->nat_flags & (NAT_TCPUDP|SI_WILDP)))
 			continue;
 
-		if (nat_wildok(nat, (int)sport, (int)dport, nflags,
-			       NAT_OUTBOUND) == 1) {
+		if (ipf_nat_wildok(nat, (int)sport, (int)dport, nat->nat_flags,
+				   NAT_OUTBOUND) == 1) {
 			if ((fin->fin_flx & FI_IGNORE) != 0)
 				break;
-			if ((nflags & SI_CLONE) != 0) {
-				nat = fr_natclone(fin, nat);
+			if ((nat->nat_flags & SI_CLONE) != 0) {
+				nat = ipf_nat_clone(fin, nat);
 				if (nat == NULL)
 					break;
 			} else {
-				MUTEX_ENTER(&ipf_nat_new);
-				nat_stats.ns_wilds--;
-				MUTEX_EXIT(&ipf_nat_new);
+				MUTEX_ENTER(&softn->ipf_nat_new);
+				softn->ipf_nat_stats.ns_wilds--;
+				MUTEX_EXIT(&softn->ipf_nat_new);
 			}
-			nat->nat_inport = sport;
-			nat->nat_oport = dport;
-			if (nat->nat_outport == 0)
-				nat->nat_outport = sport;
+
+			if (nat->nat_dir == NAT_OUTBOUND) {
+				if (nat->nat_osport == 0) {
+					nat->nat_osport = sport;
+					nat->nat_nsport = sport;
+				}
+				if (nat->nat_odport == 0) {
+					nat->nat_odport = dport;
+					nat->nat_ndport = dport;
+				}
+			} else if (nat->nat_dir == NAT_INBOUND) {
+				if (nat->nat_osport == 0) {
+					nat->nat_osport = dport;
+					nat->nat_nsport = dport;
+				}
+				if (nat->nat_odport == 0) {
+					nat->nat_odport = sport;
+					nat->nat_ndport = sport;
+				}
+			}
+			if ((nat->nat_ifps[1] == NULL) && (ifp != NULL)) {
+				nat->nat_ifps[1] = ifp;
+				nat->nat_mtu[1] = GETIFMTU_4(ifp);
+			}
 			nat->nat_flags &= ~(SI_W_DPORT|SI_W_SPORT);
-			nat_tabmove(nat);
+			ipf_nat_tabmove(softn, nat);
 			break;
 		}
 	}
 
-	MUTEX_DOWNGRADE(&ipf_nat);
+	MUTEX_DOWNGRADE(&softc->ipf_nat);
 
+	if (nat == NULL) {
+		NBUMPSIDE(1, ns_lookup_miss);
+	}
 	return nat;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    nat_lookupredir                                             */
+/* Function:    ipf_nat_lookupredir                                         */
 /* Returns:     nat_t* - NULL == no match,                                  */
 /*                       else pointer to matching NAT entry                 */
 /* Parameters:  np(I) - pointer to description of packet to find NAT table  */
@@ -3550,8 +4645,9 @@
 /*     nl_in* = source information (untranslated)                           */
 /*     nl_out* = destination information (translated)                       */
 /* ------------------------------------------------------------------------ */
-nat_t *nat_lookupredir(np)
-natlookup_t *np;
+nat_t *
+ipf_nat_lookupredir(np)
+	natlookup_t *np;
 {
 	fr_info_t fi;
 	nat_t *nat;
@@ -3577,10 +4673,10 @@
 	 * - default: we have the `in' and `out' address, look for `real'.
 	 */
 	if (np->nl_flags & IPN_IN) {
-		if ((nat = nat_inlookup(&fi, np->nl_flags, fi.fin_p,
-					np->nl_realip, np->nl_outip))) {
-			np->nl_inip = nat->nat_inip;
-			np->nl_inport = nat->nat_inport;
+		if ((nat = ipf_nat_inlookup(&fi, np->nl_flags, fi.fin_p,
+					    np->nl_realip, np->nl_outip))) {
+			np->nl_inip = nat->nat_odstip;
+			np->nl_inport = nat->nat_odport;
 		}
 	} else {
 		/*
@@ -3587,24 +4683,24 @@
 		 * If nl_inip is non null, this is a lookup based on the real
 		 * ip address. Else, we use the fake.
 		 */
-		if ((nat = nat_outlookup(&fi, np->nl_flags, fi.fin_p,
+		if ((nat = ipf_nat_outlookup(&fi, np->nl_flags, fi.fin_p,
 					 np->nl_inip, np->nl_outip))) {
 
 			if ((np->nl_flags & IPN_FINDFORWARD) != 0) {
 				fr_info_t fin;
 				bzero((char *)&fin, sizeof(fin));
-				fin.fin_p = nat->nat_p;
-				fin.fin_data[0] = ntohs(nat->nat_outport);
-				fin.fin_data[1] = ntohs(nat->nat_oport);
-				if (nat_inlookup(&fin, np->nl_flags, fin.fin_p,
-						 nat->nat_outip,
-						 nat->nat_oip) != NULL) {
+				fin.fin_p = nat->nat_pr[0];
+				fin.fin_data[0] = ntohs(nat->nat_ndport);
+				fin.fin_data[1] = ntohs(nat->nat_nsport);
+				if (ipf_nat_inlookup(&fin, np->nl_flags,
+						     fin.fin_p, nat->nat_ndstip,
+						     nat->nat_nsrcip) != NULL) {
 					np->nl_flags &= ~IPN_FINDFORWARD;
 				}
 			}
 
-			np->nl_realip = nat->nat_outip;
-			np->nl_realport = nat->nat_outport;
+			np->nl_realip = nat->nat_odstip;
+			np->nl_realport = nat->nat_odport;
 		}
  	}
 
@@ -3613,46 +4709,54 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    nat_match                                                   */
+/* Function:    ipf_nat_match                                               */
 /* Returns:     int - 0 == no match, 1 == match                             */
 /* Parameters:  fin(I)   - pointer to packet information                    */
 /*              np(I)    - pointer to NAT rule                              */
 /*                                                                          */
 /* Pull the matching of a packet against a NAT rule out of that complex     */
-/* loop inside fr_checknatin() and lay it out properly in its own function. */
+/* loop inside ipf_nat_checkin() and lay it out properly in its own function. */
 /* ------------------------------------------------------------------------ */
-static int nat_match(fin, np)
-fr_info_t *fin;
-ipnat_t *np;
+static int
+ipf_nat_match(fin, np)
+	fr_info_t *fin;
+	ipnat_t *np;
 {
+	ipf_main_softc_t *softc = fin->fin_main_soft;
 	frtuc_t *ft;
+	int match;
 
-	if (fin->fin_v != 4)
+	match = 0;
+	switch (np->in_osrcatype)
+	{
+	case FRI_NORMAL :
+		match = ((fin->fin_saddr & np->in_osrcmsk) != np->in_osrcaddr);
+		break;
+	case FRI_LOOKUP :
+		match = (*np->in_osrcfunc)(softc, np->in_osrcptr,
+					   4, &fin->fin_saddr, fin->fin_plen);
+		break;
+	}
+	match ^= ((np->in_flags & IPN_NOTSRC) != 0);
+	if (match)
 		return 0;
 
-	if (np->in_p && fin->fin_p != np->in_p)
+	match = 0;
+	switch (np->in_odstatype)
+	{
+	case FRI_NORMAL :
+		match = ((fin->fin_daddr & np->in_odstmsk) != np->in_odstaddr);
+		break;
+	case FRI_LOOKUP :
+		match = (*np->in_odstfunc)(softc, np->in_odstptr,
+					   4, &fin->fin_daddr, fin->fin_plen);
+		break;
+	}
+
+	match ^= ((np->in_flags & IPN_NOTDST) != 0);
+	if (match)
 		return 0;
 
-	if (fin->fin_out) {
-		if (!(np->in_redir & (NAT_MAP|NAT_MAPBLK)))
-			return 0;
-		if (((fin->fin_fi.fi_saddr & np->in_inmsk) != np->in_inip)
-		    ^ ((np->in_flags & IPN_NOTSRC) != 0))
-			return 0;
-		if (((fin->fin_fi.fi_daddr & np->in_srcmsk) != np->in_srcip)
-		    ^ ((np->in_flags & IPN_NOTDST) != 0))
-			return 0;
-	} else {
-		if (!(np->in_redir & NAT_REDIRECT))
-			return 0;
-		if (((fin->fin_fi.fi_saddr & np->in_srcmsk) != np->in_srcip)
-		    ^ ((np->in_flags & IPN_NOTSRC) != 0))
-			return 0;
-		if (((fin->fin_fi.fi_daddr & np->in_outmsk) != np->in_outip)
-		    ^ ((np->in_flags & IPN_NOTDST) != 0))
-			return 0;
-	}
-
 	ft = &np->in_tuc;
 	if (!(fin->fin_flx & FI_TCPUDP) ||
 	    (fin->fin_flx & (FI_SHORT|FI_FRAGBODY))) {
@@ -3661,28 +4765,33 @@
 		return 1;
 	}
 
-	return fr_tcpudpchk(fin, ft);
+	return ipf_tcpudpchk(&fin->fin_fi, ft);
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    nat_update                                                  */
+/* Function:    ipf_nat_update                                              */
 /* Returns:     Nil                                                         */
-/* Parameters:  nat(I)    - pointer to NAT structure                        */
-/*              np(I)     - pointer to NAT rule                             */
+/* Parameters:  fin(I) - pointer to packet information                      */
+/*              nat(I) - pointer to NAT structure                           */
 /*                                                                          */
 /* Updates the lifetime of a NAT table entry for non-TCP packets.  Must be  */
-/* called with fin_rev updated - i.e. after calling nat_proto().            */
+/* called with fin_rev updated - i.e. after calling ipf_nat_proto().        */
+/*                                                                          */
+/* This *MUST* be called after ipf_nat_proto() as it expects fin_rev to     */
+/* already be set.                                                          */
 /* ------------------------------------------------------------------------ */
-void nat_update(fin, nat, np)
-fr_info_t *fin;
-nat_t *nat;
-ipnat_t *np;
+void
+ipf_nat_update(fin, nat)
+	fr_info_t *fin;
+	nat_t *nat;
 {
+	ipf_main_softc_t *softc = fin->fin_main_soft;
+	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
 	ipftq_t *ifq, *ifq2;
 	ipftqent_t *tqe;
+	ipnat_t *np = nat->nat_ptr;
 
-	MUTEX_ENTER(&nat->nat_lock);
 	tqe = &nat->nat_tqe;
 	ifq = tqe->tqe_ifq;
 
@@ -3691,51 +4800,36 @@
 	 * TCP, however, if it is TCP and there is no rule timeout set,
 	 * then do not update the timeout here.
 	 */
-	if (np != NULL)
+	if (np != NULL) {
+		np->in_bytes[fin->fin_rev] += fin->fin_plen;
 		ifq2 = np->in_tqehead[fin->fin_rev];
-	else
+	} else {
 		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);
+	if (nat->nat_pr[0] == IPPROTO_TCP && ifq2 == NULL) {
+		(void) ipf_tcp_age(&nat->nat_tqe, fin, softn->ipf_nat_tcptq,
+				   0, 2);
 	} else {
 		if (ifq2 == NULL) {
-			if (nat->nat_p == IPPROTO_UDP)
-				ifq2 = &nat_udptq;
-			else if (nat->nat_p == IPPROTO_ICMP)
-				ifq2 = &nat_icmptq;
+			if (nat->nat_pr[0] == IPPROTO_UDP)
+				ifq2 = fin->fin_rev ? &softn->ipf_nat_udpacktq :
+						      &softn->ipf_nat_udptq;
+			else if (nat->nat_pr[0] == IPPROTO_ICMP ||
+				 nat->nat_pr[0] == IPPROTO_ICMPV6)
+				ifq2 = fin->fin_rev ? &softn->ipf_nat_icmpacktq:
+						      &softn->ipf_nat_icmptq;
 			else
-				ifq2 = &nat_iptq;
+				ifq2 = &softn->ipf_nat_iptq;
 		}
 
-		fr_movequeue(tqe, ifq, ifq2);
+		ipf_movequeue(softc->ipf_ticks, tqe, ifq, ifq2);
 	}
-	MUTEX_EXIT(&nat->nat_lock);
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_checknatout                                              */
+/* Function:    ipf_nat_checkout                                            */
 /* Returns:     int - -1 == packet failed NAT checks so block it,           */
 /*                     0 == no packet translation occurred,                 */
 /*                     1 == packet was successfully translated.             */
@@ -3749,15 +4843,18 @@
 /* NAT entry if a we matched a NAT rule.  Lastly, actually change the       */
 /* packet header(s) as required.                                            */
 /* ------------------------------------------------------------------------ */
-int fr_checknatout(fin, passp)
-fr_info_t *fin;
-u_32_t *passp;
+int
+ipf_nat_checkout(fin, passp)
+	fr_info_t *fin;
+	u_32_t *passp;
 {
+	ipnat_t *np = NULL, *npnext;
 	struct ifnet *ifp, *sifp;
+	ipf_main_softc_t *softc;
+	ipf_nat_softc_t *softn;
 	icmphdr_t *icmp = NULL;
 	tcphdr_t *tcp = NULL;
 	int rval, natfailed;
-	ipnat_t *np = NULL;
 	u_int nflags = 0;
 	u_32_t ipa, iph;
 	int natadd = 1;
@@ -3764,14 +4861,28 @@
 	frentry_t *fr;
 	nat_t *nat;
 
-	if (nat_stats.ns_rules == 0 || fr_nat_lock != 0)
+	if (fin->fin_v == 6) {
+#ifdef USE_INET6
+		return ipf_nat6_checkout(fin, passp);
+#else
 		return 0;
+#endif
+	}
 
+	softc = fin->fin_main_soft;
+	softn = softc->ipf_nat_soft;
+
+	if (softn->ipf_nat_lock != 0)
+		return 0;
+	if (softn->ipf_nat_stats.ns_rules == 0 &&
+	    softn->ipf_nat_instances == NULL)
+		return 0;
+
 	natfailed = 0;
 	fr = fin->fin_fr;
 	sifp = fin->fin_ifp;
 	if (fr != NULL) {
-		ifp = fr->fr_tifs[fin->fin_rev].fd_ifp;
+		ifp = fr->fr_tifs[fin->fin_rev].fd_ptr;
 		if ((ifp != NULL) && (ifp != (void *)-1))
 			fin->fin_ifp = ifp;
 	}
@@ -3793,13 +4904,13 @@
 			 * This is an incoming packet, so the destination is
 			 * the icmp_id and the source port equals 0
 			 */
-			if (nat_icmpquerytype4(icmp->icmp_type))
+			if ((fin->fin_flx & FI_ICMPQUERY) != 0)
 				nflags = IPN_ICMPQUERY;
 			break;
 		default :
 			break;
 		}
-		
+
 		if ((nflags & IPN_TCPUDP))
 			tcp = fin->fin_dp;
 	}
@@ -3806,97 +4917,132 @@
 
 	ipa = fin->fin_saddr;
 
-	READ_ENTER(&ipf_nat);
+	READ_ENTER(&softc->ipf_nat);
 
-	if (((fin->fin_flx & FI_ICMPERR) != 0) &&
-	    (nat = nat_icmperror(fin, &nflags, NAT_OUTBOUND)))
+	if ((fin->fin_p == IPPROTO_ICMP) && !(nflags & IPN_ICMPQUERY) &&
+	    (nat = ipf_nat_icmperror(fin, &nflags, NAT_OUTBOUND)))
 		/*EMPTY*/;
-	else if ((fin->fin_flx & FI_FRAG) && (nat = fr_nat_knownfrag(fin)))
+	else if ((fin->fin_flx & FI_FRAG) && (nat = ipf_frag_natknown(fin)))
 		natadd = 0;
-	else if ((nat = nat_outlookup(fin, nflags|NAT_SEARCH, (u_int)fin->fin_p,
-				      fin->fin_src, fin->fin_dst))) {
+	else if ((nat = ipf_nat_outlookup(fin, nflags|NAT_SEARCH,
+				      (u_int)fin->fin_p, fin->fin_src,
+				      fin->fin_dst))) {
 		nflags = nat->nat_flags;
-	} else {
-		u_32_t hv, msk, nmsk;
+	} else if (fin->fin_off == 0) {
+		u_32_t hv, msk, nmsk = 0;
 
 		/*
 		 * If there is no current entry in the nat table for this IP#,
 		 * create one for it (if there is a matching rule).
 		 */
-		RWLOCK_EXIT(&ipf_nat);
-		msk = 0xffffffff;
-		nmsk = nat_masks;
-		WRITE_ENTER(&ipf_nat);
 maskloop:
-		iph = ipa & htonl(msk);
-		hv = NAT_HASH_FN(iph, 0, ipf_natrules_sz);
-		for (np = nat_rules[hv]; np; np = np->in_mnext)
-		{
+		msk = softn->ipf_nat_map_active_masks[nmsk];
+		iph = ipa & msk;
+		hv = NAT_HASH_FN(iph, 0, softn->ipf_nat_maprules_sz);
+retry_roundrobin:
+		for (np = softn->ipf_nat_map_rules[hv]; np; np = npnext) {
+			npnext = np->in_mnext;
 			if ((np->in_ifps[1] && (np->in_ifps[1] != ifp)))
 				continue;
-			if (np->in_v != fin->fin_v)
+			if (np->in_v[0] != 4)
 				continue;
-			if (np->in_p && (np->in_p != fin->fin_p))
+			if (np->in_pr[1] && (np->in_pr[1] != fin->fin_p))
 				continue;
-			if ((np->in_flags & IPN_RF) && !(np->in_flags & nflags))
+			if ((np->in_flags & IPN_RF) &&
+			    !(np->in_flags & nflags))
 				continue;
 			if (np->in_flags & IPN_FILTER) {
-				if (!nat_match(fin, np))
+				switch (ipf_nat_match(fin, np))
+				{
+				case 0 :
 					continue;
-			} else if ((ipa & np->in_inmsk) != np->in_inip)
+				case -1 :
+					rval = -1;
+					goto outmatchfail;
+				case 1 :
+				default :
+					break;
+				}
+			} else if ((ipa & np->in_osrcmsk) != np->in_osrcaddr)
 				continue;
 
 			if ((fr != NULL) &&
-			    !fr_matchtag(&np->in_tag, &fr->fr_nattag))
+			    !ipf_matchtag(&np->in_tag, &fr->fr_nattag))
 				continue;
 
-			if (*np->in_plabel != '\0') {
+			if (np->in_plabel != -1) {
 				if (((np->in_flags & IPN_FILTER) == 0) &&
-				    (np->in_dport != tcp->th_dport))
+				    (np->in_odport != fin->fin_data[1]))
 					continue;
-				if (appr_ok(fin, tcp, np) == 0)
+				if (ipf_proxy_ok(fin, tcp, np) == 0)
 					continue;
 			}
 
-			if ((nat = nat_new(fin, np, NULL, nflags,
-					   NAT_OUTBOUND))) {
+			if (np->in_flags & IPN_NO) {
 				np->in_hits++;
 				break;
-			} else
-				natfailed = -1;
-		}
-		if ((np == NULL) && (nmsk != 0)) {
-			while (nmsk) {
-				msk <<= 1;
-				if (nmsk & 0x80000000)
-					break;
-				nmsk <<= 1;
 			}
-			if (nmsk != 0) {
-				nmsk <<= 1;
-				goto maskloop;
+			MUTEX_ENTER(&softn->ipf_nat_new);
+			/*
+			 * If we've matched a round-robin rule but it has
+			 * moved in the list since we got it, start over as
+			 * this is now no longer correct.
+			 */
+			if (npnext != np->in_mnext) {
+				if ((np->in_flags & IPN_ROUNDR) != 0) {
+					MUTEX_EXIT(&softn->ipf_nat_new);
+					goto retry_roundrobin;
+				}
+				npnext = np->in_mnext;
 			}
+
+			nat = ipf_nat_add(fin, np, NULL, nflags, NAT_OUTBOUND);
+			MUTEX_EXIT(&softn->ipf_nat_new);
+			if (nat != NULL) {
+				natfailed = 0;
+				break;
+			}
+			natfailed = -1;
 		}
-		MUTEX_DOWNGRADE(&ipf_nat);
+		if ((np == NULL) && (nmsk < softn->ipf_nat_map_max)) {
+			nmsk++;
+			goto maskloop;
+		}
 	}
 
 	if (nat != NULL) {
-		rval = fr_natout(fin, nat, natadd, nflags);
+		rval = ipf_nat_out(fin, nat, natadd, nflags);
 		if (rval == 1) {
 			MUTEX_ENTER(&nat->nat_lock);
-			nat->nat_ref++;
+			ipf_nat_update(fin, nat);
+			nat->nat_bytes[1] += fin->fin_plen;
+			nat->nat_pkts[1]++;
+			fin->fin_pktnum = nat->nat_pkts[1];
 			MUTEX_EXIT(&nat->nat_lock);
-			nat->nat_touched = fr_ticks;
-			fin->fin_nat = nat;
 		}
 	} else
 		rval = natfailed;
-	RWLOCK_EXIT(&ipf_nat);
+outmatchfail:
+	RWLOCK_EXIT(&softc->ipf_nat);
 
-	if (rval == -1) {
-		if (passp != NULL)
+	switch (rval)
+	{
+	case -1 :
+		if (passp != NULL) {
+			DT1(frb_natv4out, fr_info_t *, fin);
+			NBUMPSIDED(1, ns_drop);
 			*passp = FR_BLOCK;
+			fin->fin_reason = FRB_NATV4;
+		}
 		fin->fin_flx |= FI_BADNAT;
+		NBUMPSIDED(1, ns_badnat);
+		break;
+	case 0 :
+		NBUMPSIDE(1, ns_ignored);
+		break;
+	case 1 :
+		NBUMPSIDE(1, ns_translated);
+		break;
 	}
 	fin->fin_ifp = sifp;
 	return rval;
@@ -3903,7 +5049,7 @@
 }
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_natout                                                   */
+/* Function:    ipf_nat_out                                                 */
 /* Returns:     int - -1 == packet failed NAT checks so block it,           */
 /*                     1 == packet was successfully translated.             */
 /* Parameters:  fin(I)    - pointer to packet information                   */
@@ -3913,31 +5059,28 @@
 /*                                                                          */
 /* Translate a packet coming "out" on an interface.                         */
 /* ------------------------------------------------------------------------ */
-int fr_natout(fin, nat, natadd, nflags)
-fr_info_t *fin;
-nat_t *nat;
-int natadd;
-u_32_t nflags;
+int
+ipf_nat_out(fin, nat, natadd, nflags)
+	fr_info_t *fin;
+	nat_t *nat;
+	int natadd;
+	u_32_t nflags;
 {
+	ipf_main_softc_t *softc = fin->fin_main_soft;
+	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
 	icmphdr_t *icmp;
-	u_short *csump;
 	tcphdr_t *tcp;
 	ipnat_t *np;
+	int skip;
 	int i;
 
 	tcp = NULL;
 	icmp = NULL;
-	csump = NULL;
 	np = nat->nat_ptr;
 
 	if ((natadd != 0) && (fin->fin_flx & FI_FRAG) && (np != NULL))
-		(void) fr_nat_newfrag(fin, 0, nat);
+		(void) ipf_frag_natnew(softc, fin, 0, nat);
 
-	MUTEX_ENTER(&nat->nat_lock);
-	nat->nat_bytes[1] += fin->fin_plen;
-	nat->nat_pkts[1]++;
-	MUTEX_EXIT(&nat->nat_lock);
-
 	/*
 	 * Fix up checksums, not by recalculating them, but
 	 * simply computing adjustments.
@@ -3946,83 +5089,233 @@
 	 * IPFilter is called before the checksum needs calculating so there
 	 * is no call to modify whatever is in the header now.
 	 */
-	if (fin->fin_v == 4) {
-		if (nflags == IPN_ICMPERR) {
-			u_32_t s1, s2, sumd;
+	if (nflags == IPN_ICMPERR) {
+		u_32_t s1, s2, sumd, msumd;
 
-			s1 = LONG_SUM(ntohl(fin->fin_saddr));
-			s2 = LONG_SUM(ntohl(nat->nat_outip.s_addr));
-			CALC_SUMD(s1, s2, sumd);
-			fix_outcksum(fin, &fin->fin_ip->ip_sum, sumd);
+		s1 = LONG_SUM(ntohl(fin->fin_saddr));
+		if (nat->nat_dir == NAT_OUTBOUND) {
+			s2 = LONG_SUM(ntohl(nat->nat_nsrcaddr));
+		} else {
+			s2 = LONG_SUM(ntohl(nat->nat_odstaddr));
 		}
+		CALC_SUMD(s1, s2, sumd);
+		msumd = sumd;
+
+		s1 = LONG_SUM(ntohl(fin->fin_daddr));
+		if (nat->nat_dir == NAT_OUTBOUND) {
+			s2 = LONG_SUM(ntohl(nat->nat_ndstaddr));
+		} else {
+			s2 = LONG_SUM(ntohl(nat->nat_osrcaddr));
+		}
+		CALC_SUMD(s1, s2, sumd);
+		msumd += sumd;
+
+		ipf_fix_outcksum(0, &fin->fin_ip->ip_sum, msumd, 0);
+	}
 #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);
-			else
-				fix_incksum(fin, &fin->fin_ip->ip_sum,
-					    nat->nat_ipsumd);
+    defined(linux) || defined(BRIDGE_IPF) || defined(__FreeBSD__)
+	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.
+		 */
+		switch (nat->nat_dir)
+		{
+		case NAT_OUTBOUND :
+			ipf_fix_outcksum(fin->fin_cksum & FI_CK_L4PART,
+					 &fin->fin_ip->ip_sum,
+					 nat->nat_ipsumd, 0);
+			break;
+
+		case NAT_INBOUND :
+			ipf_fix_incksum(fin->fin_cksum & FI_CK_L4PART,
+					&fin->fin_ip->ip_sum,
+					nat->nat_ipsumd, 0);
+			break;
+
+		default :
+			break;
 		}
+	}
 #endif
+
+	/*
+	 * Address assignment is after the checksum modification because
+	 * we are using the address in the packet for determining the
+	 * correct checksum offset (the ICMP error could be coming from
+	 * anyone...)
+	 */
+	switch (nat->nat_dir)
+	{
+	case NAT_OUTBOUND :
+		fin->fin_ip->ip_src = nat->nat_nsrcip;
+		fin->fin_saddr = nat->nat_nsrcaddr;
+		fin->fin_ip->ip_dst = nat->nat_ndstip;
+		fin->fin_daddr = nat->nat_ndstaddr;
+		break;
+
+	case NAT_INBOUND :
+		fin->fin_ip->ip_src = nat->nat_odstip;
+		fin->fin_saddr = nat->nat_ndstaddr;
+		fin->fin_ip->ip_dst = nat->nat_osrcip;
+		fin->fin_daddr = nat->nat_nsrcaddr;
+		break;
+
+	case NAT_DIVERTIN :
+	    {
+		mb_t *m;
+
+		skip = ipf_nat_decap(fin, nat);
+		if (skip <= 0) {
+			NBUMPSIDED(1, ns_decap_fail);
+			return -1;
+		}
+
+		m = fin->fin_m;
+
+#if defined(MENTAT) && defined(_KERNEL)
+		m->b_rptr += skip;
+#else
+		m->m_data += skip;
+		m->m_len -= skip;
+
+# ifdef M_PKTHDR
+		if (m->m_flags & M_PKTHDR)
+			m->m_pkthdr.len -= skip;
+# endif
+#endif
+
+		MUTEX_ENTER(&nat->nat_lock);
+		ipf_nat_update(fin, nat);
+		MUTEX_EXIT(&nat->nat_lock);
+		fin->fin_flx |= FI_NATED;
+		if (np != NULL && np->in_tag.ipt_num[0] != 0)
+			fin->fin_nattag = &np->in_tag;
+		return 1;
+		/* NOTREACHED */
+	    }
+
+	case NAT_DIVERTOUT :
+	    {
+		u_32_t s1, s2, sumd;
+		udphdr_t *uh;
+		ip_t *ip;
+		mb_t *m;
+
+		m = M_DUP(np->in_divmp);
+		if (m == NULL) {
+			NBUMPSIDED(1, ns_divert_dup);
+			return -1;
+		}
+
+		ip = MTOD(m, ip_t *);
+		ip->ip_id = htons(ipf_nextipid(fin));
+		s2 = ntohs(ip->ip_id);
+
+		s1 = ip->ip_len;
+		ip->ip_len = ntohs(ip->ip_len);
+		ip->ip_len += fin->fin_plen;
+		ip->ip_len = htons(ip->ip_len);
+		s2 += ntohs(ip->ip_len);
+		CALC_SUMD(s1, s2, sumd);
+
+		uh = (udphdr_t *)(ip + 1);
+		uh->uh_ulen += fin->fin_plen;
+		uh->uh_ulen = htons(uh->uh_ulen);
+#if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) || \
+    defined(linux) || defined(BRIDGE_IPF) || defined(__FreeBSD__)
+		ipf_fix_outcksum(0, &ip->ip_sum, sumd, 0);
+#endif
+
+		PREP_MB_T(fin, m);
+
+		fin->fin_src = ip->ip_src;
+		fin->fin_dst = ip->ip_dst;
+		fin->fin_ip = ip;
+		fin->fin_plen += sizeof(ip_t) + 8;	/* UDP + IPv4 hdr */
+		fin->fin_dlen += sizeof(ip_t) + 8;	/* UDP + IPv4 hdr */
+
+		nflags &= ~IPN_TCPUDPICMP;
+
+		break;
+	    }
+
+	default :
+		break;
 	}
 
 	if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) {
-		if ((nat->nat_outport != 0) && (nflags & IPN_TCPUDP)) {
+		u_short *csump;
+
+		if ((nat->nat_nsport != 0) && (nflags & IPN_TCPUDP)) {
 			tcp = fin->fin_dp;
 
-			tcp->th_sport = nat->nat_outport;
-			fin->fin_data[0] = ntohs(nat->nat_outport);
+			switch (nat->nat_dir)
+			{
+			case NAT_OUTBOUND :
+				tcp->th_sport = nat->nat_nsport;
+				fin->fin_data[0] = ntohs(nat->nat_nsport);
+				tcp->th_dport = nat->nat_ndport;
+				fin->fin_data[1] = ntohs(nat->nat_ndport);
+				break;
+
+			case NAT_INBOUND :
+				tcp->th_sport = nat->nat_odport;
+				fin->fin_data[0] = ntohs(nat->nat_odport);
+				tcp->th_dport = nat->nat_osport;
+				fin->fin_data[1] = ntohs(nat->nat_osport);
+				break;
+			}
 		}
 
-		if ((nat->nat_outport != 0) && (nflags & IPN_ICMPQUERY)) {
+		if ((nat->nat_nsport != 0) && (nflags & IPN_ICMPQUERY)) {
 			icmp = fin->fin_dp;
-			icmp->icmp_id = nat->nat_outport;
+			icmp->icmp_id = nat->nat_nicmpid;
 		}
 
-		csump = nat_proto(fin, nat, nflags);
+		csump = ipf_nat_proto(fin, nat, nflags);
+
+		/*
+		 * The above comments do not hold for layer 4 (or higher)
+		 * checksums...
+		 */
+		if (csump != NULL) {
+			if (nat->nat_dir == NAT_OUTBOUND)
+				ipf_fix_outcksum(fin->fin_cksum, csump,
+						 nat->nat_sumd[0],
+						 nat->nat_sumd[1] +
+						 fin->fin_dlen);
+			else
+				ipf_fix_incksum(fin->fin_cksum, csump,
+						nat->nat_sumd[0],
+						nat->nat_sumd[1] +
+						fin->fin_dlen);
+		}
 	}
 
-	fin->fin_ip->ip_src = nat->nat_outip;
-
-	nat_update(fin, nat, np);
-
-	/*
-	 * The above comments do not hold for layer 4 (or higher) checksums...
-	 */
-	if (csump != NULL) {
-		if (nat->nat_dir == NAT_OUTBOUND)
-			fix_outcksum(fin, csump, nat->nat_sumd[1]);
-		else
-			fix_incksum(fin, csump, nat->nat_sumd[1]);
-	}
-#ifdef	IPFILTER_SYNC
-	ipfsync_update(SMC_NAT, fin, nat->nat_sync);
-#endif
+	ipf_sync_update(softc, SMC_NAT, fin, nat->nat_sync);
 	/* ------------------------------------------------------------- */
-	/* A few quick notes:						 */
-	/*	Following are test conditions prior to calling the 	 */
-	/*	appr_check routine.					 */
-	/*								 */
-	/* 	A NULL tcp indicates a non TCP/UDP packet.  When dealing */
-	/*	with a redirect rule, we attempt to match the packet's	 */
-	/*	source port against in_dport, otherwise	we'd compare the */
-	/*	packet's destination.			 		 */
+	/* A few quick notes:                                            */
+	/*      Following are test conditions prior to calling the       */
+	/*      ipf_proxy_check routine.                                 */
+	/*                                                               */
+	/*      A NULL tcp indicates a non TCP/UDP packet.  When dealing */
+	/*      with a redirect rule, we attempt to match the packet's   */
+	/*      source port against in_dport, otherwise we'd compare the */
+	/*      packet's destination.                                    */
 	/* ------------------------------------------------------------- */
 	if ((np != NULL) && (np->in_apr != NULL)) {
-		i = appr_check(fin, nat);
-		if (i == 0)
+		i = ipf_proxy_check(fin, nat);
+		if (i == 0) {
 			i = 1;
-	} else
+		} else if (i == -1) {
+			NBUMPSIDED(1, ns_ipf_proxy_fail);
+		}
+	} else {
 		i = 1;
-	ATOMIC_INCL(nat_stats.ns_mapped[1]);
+	}
 	fin->fin_flx |= FI_NATED;
 	return i;
 }
@@ -4029,7 +5322,7 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_checknatin                                               */
+/* Function:    ipf_nat_checkin                                             */
 /* Returns:     int - -1 == packet failed NAT checks so block it,           */
 /*                     0 == no packet translation occurred,                 */
 /*                     1 == packet was successfully translated.             */
@@ -4043,11 +5336,15 @@
 /* NAT entry if a we matched a NAT rule.  Lastly, actually change the       */
 /* packet header(s) as required.                                            */
 /* ------------------------------------------------------------------------ */
-int fr_checknatin(fin, passp)
-fr_info_t *fin;
-u_32_t *passp;
+int
+ipf_nat_checkin(fin, passp)
+	fr_info_t *fin;
+	u_32_t *passp;
 {
+	ipf_main_softc_t *softc;
+	ipf_nat_softc_t *softn;
 	u_int nflags, natadd;
+	ipnat_t *np, *npnext;
 	int rval, natfailed;
 	struct ifnet *ifp;
 	struct in_addr in;
@@ -4054,12 +5351,17 @@
 	icmphdr_t *icmp;
 	tcphdr_t *tcp;
 	u_short dport;
-	ipnat_t *np;
 	nat_t *nat;
 	u_32_t iph;
 
-	if (nat_stats.ns_rules == 0 || fr_nat_lock != 0)
+	softc = fin->fin_main_soft;
+	softn = softc->ipf_nat_soft;
+
+	if (softn->ipf_nat_lock != 0)
 		return 0;
+	if (softn->ipf_nat_stats.ns_rules == 0 &&
+	    softn->ipf_nat_instances == NULL)
+		return 0;
 
 	tcp = NULL;
 	icmp = NULL;
@@ -4085,112 +5387,150 @@
 			 * This is an incoming packet, so the destination is
 			 * the icmp_id and the source port equals 0
 			 */
-			if (nat_icmpquerytype4(icmp->icmp_type)) {
+			if ((fin->fin_flx & FI_ICMPQUERY) != 0) {
 				nflags = IPN_ICMPQUERY;
-				dport = icmp->icmp_id;	
+				dport = icmp->icmp_id;
 			} break;
 		default :
 			break;
 		}
-		
+
 		if ((nflags & IPN_TCPUDP)) {
 			tcp = fin->fin_dp;
-			dport = tcp->th_dport;
+			dport = fin->fin_data[1];
 		}
 	}
 
 	in = fin->fin_dst;
 
-	READ_ENTER(&ipf_nat);
+	READ_ENTER(&softc->ipf_nat);
 
-	if (((fin->fin_flx & FI_ICMPERR) != 0) &&
-	    (nat = nat_icmperror(fin, &nflags, NAT_INBOUND)))
+	if ((fin->fin_p == IPPROTO_ICMP) && !(nflags & IPN_ICMPQUERY) &&
+	    (nat = ipf_nat_icmperror(fin, &nflags, NAT_INBOUND)))
 		/*EMPTY*/;
-	else if ((fin->fin_flx & FI_FRAG) && (nat = fr_nat_knownfrag(fin)))
+	else if ((fin->fin_flx & FI_FRAG) && (nat = ipf_frag_natknown(fin)))
 		natadd = 0;
-	else if ((nat = nat_inlookup(fin, nflags|NAT_SEARCH, (u_int)fin->fin_p,
-				     fin->fin_src, in))) {
+	else if ((nat = ipf_nat_inlookup(fin, nflags|NAT_SEARCH,
+					 (u_int)fin->fin_p,
+					 fin->fin_src, in))) {
 		nflags = nat->nat_flags;
-	} else {
-		u_32_t hv, msk, rmsk;
+	} else if (fin->fin_off == 0) {
+		u_32_t hv, msk, rmsk = 0;
 
-		RWLOCK_EXIT(&ipf_nat);
-		rmsk = rdr_masks;
-		msk = 0xffffffff;
-		WRITE_ENTER(&ipf_nat);
 		/*
 		 * If there is no current entry in the nat table for this IP#,
 		 * create one for it (if there is a matching rule).
 		 */
 maskloop:
-		iph = in.s_addr & htonl(msk);
-		hv = NAT_HASH_FN(iph, 0, ipf_rdrrules_sz);
-		for (np = rdr_rules[hv]; np; np = np->in_rnext) {
+		msk = softn->ipf_nat_rdr_active_masks[rmsk];
+		iph = in.s_addr & msk;
+		hv = NAT_HASH_FN(iph, 0, softn->ipf_nat_rdrrules_sz);
+retry_roundrobin:
+		/* TRACE (iph,msk,rmsk,hv,softn->ipf_nat_rdrrules_sz) */
+		for (np = softn->ipf_nat_rdr_rules[hv]; np; np = npnext) {
+			npnext = np->in_rnext;
 			if (np->in_ifps[0] && (np->in_ifps[0] != ifp))
 				continue;
-			if (np->in_v != fin->fin_v)
+			if (np->in_v[0] != 4)
 				continue;
-			if (np->in_p && (np->in_p != fin->fin_p))
+			if (np->in_pr[0] && (np->in_pr[0] != fin->fin_p))
 				continue;
 			if ((np->in_flags & IPN_RF) && !(np->in_flags & nflags))
 				continue;
 			if (np->in_flags & IPN_FILTER) {
-				if (!nat_match(fin, np))
+				switch (ipf_nat_match(fin, np))
+				{
+				case 0 :
 					continue;
+				case -1 :
+					rval = -1;
+					goto inmatchfail;
+				case 1 :
+				default :
+					break;
+				}
 			} else {
-				if ((in.s_addr & np->in_outmsk) != np->in_outip)
+				if ((in.s_addr & np->in_odstmsk) !=
+				    np->in_odstaddr)
 					continue;
-				if (np->in_pmin &&
-				    ((ntohs(np->in_pmax) < ntohs(dport)) ||
-				     (ntohs(dport) < ntohs(np->in_pmin))))
+				if (np->in_odport &&
+				    ((np->in_dtop < dport) ||
+				     (dport < np->in_odport)))
 					continue;
 			}
 
-			if (*np->in_plabel != '\0') {
-				if (!appr_ok(fin, tcp, np)) {
+			if (np->in_plabel != -1) {
+				if (!ipf_proxy_ok(fin, tcp, np)) {
 					continue;
 				}
 			}
 
-			nat = nat_new(fin, np, NULL, nflags, NAT_INBOUND);
-			if (nat != NULL) {
+			if (np->in_flags & IPN_NO) {
 				np->in_hits++;
 				break;
-			} else
-				natfailed = -1;
-		}
+			}
 
-		if ((np == NULL) && (rmsk != 0)) {
-			while (rmsk) {
-				msk <<= 1;
-				if (rmsk & 0x80000000)
-					break;
-				rmsk <<= 1;
+			MUTEX_ENTER(&softn->ipf_nat_new);
+			/*
+			 * If we've matched a round-robin rule but it has
+			 * moved in the list since we got it, start over as
+			 * this is now no longer correct.
+			 */
+			if (npnext != np->in_rnext) {
+				if ((np->in_flags & IPN_ROUNDR) != 0) {
+					MUTEX_EXIT(&softn->ipf_nat_new);
+					goto retry_roundrobin;
+				}
+				npnext = np->in_rnext;
 			}
-			if (rmsk != 0) {
-				rmsk <<= 1;
-				goto maskloop;
+
+			nat = ipf_nat_add(fin, np, NULL, nflags, NAT_INBOUND);
+			MUTEX_EXIT(&softn->ipf_nat_new);
+			if (nat != NULL) {
+				natfailed = 0;
+				break;
 			}
+			natfailed = -1;
 		}
-		MUTEX_DOWNGRADE(&ipf_nat);
+		if ((np == NULL) && (rmsk < softn->ipf_nat_rdr_max)) {
+			rmsk++;
+			goto maskloop;
+		}
 	}
+
 	if (nat != NULL) {
-		rval = fr_natin(fin, nat, natadd, nflags);
+		rval = ipf_nat_in(fin, nat, natadd, nflags);
 		if (rval == 1) {
 			MUTEX_ENTER(&nat->nat_lock);
-			nat->nat_ref++;
+			ipf_nat_update(fin, nat);
+			nat->nat_bytes[0] += fin->fin_plen;
+			nat->nat_pkts[0]++;
+			fin->fin_pktnum = nat->nat_pkts[0];
 			MUTEX_EXIT(&nat->nat_lock);
-			nat->nat_touched = fr_ticks;
-			fin->fin_nat = nat;
 		}
 	} else
 		rval = natfailed;
-	RWLOCK_EXIT(&ipf_nat);
+inmatchfail:
+	RWLOCK_EXIT(&softc->ipf_nat);
 
-	if (rval == -1) {
-		if (passp != NULL)
+	switch (rval)
+	{
+	case -1 :
+		if (passp != NULL) {
+			DT1(frb_natv4in, fr_info_t *, fin);
+			NBUMPSIDED(0, ns_drop);
 			*passp = FR_BLOCK;
+			fin->fin_reason = FRB_NATV4;
+		}
 		fin->fin_flx |= FI_BADNAT;
+		NBUMPSIDED(0, ns_badnat);
+		break;
+	case 0 :
+		NBUMPSIDE(0, ns_ignored);
+		break;
+	case 1 :
+		NBUMPSIDE(0, ns_translated);
+		break;
 	}
 	return rval;
 }
@@ -4197,7 +5537,7 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_natin                                                    */
+/* Function:    ipf_nat_in                                                  */
 /* Returns:     int - -1 == packet failed NAT checks so block it,           */
 /*                     1 == packet was successfully translated.             */
 /* Parameters:  fin(I)    - pointer to packet information                   */
@@ -4204,63 +5544,56 @@
 /*              nat(I)    - pointer to NAT structure                        */
 /*              natadd(I) - flag indicating if it is safe to add frag cache */
 /*              nflags(I) - NAT flags set for this packet                   */
-/* Locks Held:  ipf_nat (READ)                                              */
+/* Locks Held:  ipf_nat(READ)                                               */
 /*                                                                          */
 /* Translate a packet coming "in" on an interface.                          */
 /* ------------------------------------------------------------------------ */
-int fr_natin(fin, nat, natadd, nflags)
-fr_info_t *fin;
-nat_t *nat;
-int natadd;
-u_32_t nflags;
+int
+ipf_nat_in(fin, nat, natadd, nflags)
+	fr_info_t *fin;
+	nat_t *nat;
+	int natadd;
+	u_32_t nflags;
 {
+	ipf_main_softc_t *softc = fin->fin_main_soft;
+	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
+	u_32_t sumd, ipsumd, sum1, sum2;
 	icmphdr_t *icmp;
-	u_short *csump;
 	tcphdr_t *tcp;
 	ipnat_t *np;
+	int skip;
 	int i;
 
 	tcp = NULL;
-	csump = NULL;
 	np = nat->nat_ptr;
 	fin->fin_fr = nat->nat_fr;
 
 	if (np != NULL) {
 		if ((natadd != 0) && (fin->fin_flx & FI_FRAG))
-			(void) fr_nat_newfrag(fin, 0, nat);
+			(void) ipf_frag_natnew(softc, fin, 0, nat);
 
 	/* ------------------------------------------------------------- */
-	/* A few quick notes:						 */
-	/*	Following are test conditions prior to calling the 	 */
-	/*	appr_check routine.					 */
-	/*								 */
-	/* 	A NULL tcp indicates a non TCP/UDP packet.  When dealing */
-	/*	with a map rule, we attempt to match the packet's	 */
-	/*	source port against in_dport, otherwise	we'd compare the */
-	/*	packet's destination.			 		 */
+	/* A few quick notes:                                            */
+	/*      Following are test conditions prior to calling the       */
+	/*      ipf_proxy_check routine.                                 */
+	/*                                                               */
+	/*      A NULL tcp indicates a non TCP/UDP packet.  When dealing */
+	/*      with a map rule, we attempt to match the packet's        */
+	/*      source port against in_dport, otherwise we'd compare the */
+	/*      packet's destination.                                    */
 	/* ------------------------------------------------------------- */
 		if (np->in_apr != NULL) {
-			i = appr_check(fin, nat);
+			i = ipf_proxy_check(fin, nat);
 			if (i == -1) {
+				NBUMPSIDED(0, ns_ipf_proxy_fail);
 				return -1;
 			}
 		}
 	}
 
-#ifdef	IPFILTER_SYNC
-	ipfsync_update(SMC_NAT, fin, nat->nat_sync);
-#endif
+	ipf_sync_update(softc, SMC_NAT, fin, nat->nat_sync);
 
-	MUTEX_ENTER(&nat->nat_lock);
-	nat->nat_bytes[0] += fin->fin_plen;
-	nat->nat_pkts[0]++;
-	MUTEX_EXIT(&nat->nat_lock);
-
-	fin->fin_ip->ip_dst = nat->nat_inip;
-	fin->fin_fi.fi_daddr = nat->nat_inip.s_addr;
-	if (nflags & IPN_TCPUDP)
-		tcp = fin->fin_dp;
-
+	ipsumd = nat->nat_ipsumd;
 	/*
 	 * Fix up checksums, not by recalculating them, but
 	 * simply computing adjustments.
@@ -4271,42 +5604,166 @@
 	 * fast forwarding (so that it doesn't need to be recomputed) but with
 	 * header checksum offloading, perhaps it is a moot point.
 	 */
+
+	switch (nat->nat_dir)
+	{
+	case NAT_INBOUND :
+		if ((fin->fin_flx & FI_ICMPERR) == 0) {
+			fin->fin_ip->ip_src = nat->nat_nsrcip;
+			fin->fin_saddr = nat->nat_nsrcaddr;
+		} else {
+			sum1 = nat->nat_osrcaddr;
+			sum2 = nat->nat_nsrcaddr;
+			CALC_SUMD(sum1, sum2, sumd);
+			ipsumd -= sumd;
+		}
+		fin->fin_ip->ip_dst = nat->nat_ndstip;
+		fin->fin_daddr = nat->nat_ndstaddr;
 #if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) || \
      defined(__osf__) || defined(linux)
-	if (nat->nat_dir == NAT_OUTBOUND)
-		fix_incksum(fin, &fin->fin_ip->ip_sum, nat->nat_ipsumd);
-	else
-		fix_outcksum(fin, &fin->fin_ip->ip_sum, nat->nat_ipsumd);
+		ipf_fix_outcksum(0, &fin->fin_ip->ip_sum, ipsumd, 0);
 #endif
+		break;
 
+	case NAT_OUTBOUND :
+		if ((fin->fin_flx & FI_ICMPERR) == 0) {
+			fin->fin_ip->ip_src = nat->nat_odstip;
+			fin->fin_saddr = nat->nat_odstaddr;
+		} else {
+			sum1 = nat->nat_odstaddr;
+			sum2 = nat->nat_ndstaddr;
+			CALC_SUMD(sum1, sum2, sumd);
+			ipsumd -= sumd;
+		}
+		fin->fin_ip->ip_dst = nat->nat_osrcip;
+		fin->fin_daddr = nat->nat_osrcaddr;
+#if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) || \
+     defined(__osf__) || defined(linux)
+		ipf_fix_incksum(0, &fin->fin_ip->ip_sum, ipsumd, 0);
+#endif
+		break;
+
+	case NAT_DIVERTIN :
+	    {
+		udphdr_t *uh;
+		ip_t *ip;
+		mb_t *m;
+
+		m = M_DUP(np->in_divmp);
+		if (m == NULL) {
+			NBUMPSIDED(0, ns_divert_dup);
+			return -1;
+		}
+
+		ip = MTOD(m, ip_t *);
+		ip->ip_id = htons(ipf_nextipid(fin));
+		sum1 = ntohs(ip->ip_len);
+		ip->ip_len = ntohs(ip->ip_len);
+		ip->ip_len += fin->fin_plen;
+		ip->ip_len = htons(ip->ip_len);
+
+		uh = (udphdr_t *)(ip + 1);
+		uh->uh_ulen += fin->fin_plen;
+		uh->uh_ulen = htons(uh->uh_ulen);
+
+		sum2 = ntohs(ip->ip_id) + ntohs(ip->ip_len);
+		sum2 += ntohs(ip->ip_off) & IP_DF;
+		CALC_SUMD(sum1, sum2, sumd);
+
+#if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) || \
+     defined(__osf__) || defined(linux)
+		ipf_fix_outcksum(0, &ip->ip_sum, sumd, 0);
+#endif
+		PREP_MB_T(fin, m);
+
+		fin->fin_ip = ip;
+		fin->fin_plen += sizeof(ip_t) + 8;	/* UDP + new IPv4 hdr */
+		fin->fin_dlen += sizeof(ip_t) + 8;	/* UDP + old IPv4 hdr */
+
+		nflags &= ~IPN_TCPUDPICMP;
+
+		break;
+	    }
+
+	case NAT_DIVERTOUT :
+	    {
+		mb_t *m;
+
+		skip = ipf_nat_decap(fin, nat);
+		if (skip <= 0) {
+			NBUMPSIDED(0, ns_decap_fail);
+			return -1;
+		}
+
+		m = fin->fin_m;
+
+#if defined(MENTAT) && defined(_KERNEL)
+		m->b_rptr += skip;
+#else
+		m->m_data += skip;
+		m->m_len -= skip;
+
+# ifdef M_PKTHDR
+		if (m->m_flags & M_PKTHDR)
+			m->m_pkthdr.len -= skip;
+# endif
+#endif
+
+		ipf_nat_update(fin, nat);
+		nflags &= ~IPN_TCPUDPICMP;
+		fin->fin_flx |= FI_NATED;
+		if (np != NULL && np->in_tag.ipt_num[0] != 0)
+			fin->fin_nattag = &np->in_tag;
+		return 1;
+		/* NOTREACHED */
+	    }
+	}
+	if (nflags & IPN_TCPUDP)
+		tcp = fin->fin_dp;
+
 	if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) {
-		if ((nat->nat_inport != 0) && (nflags & IPN_TCPUDP)) {
-			tcp->th_dport = nat->nat_inport;
-			fin->fin_data[1] = ntohs(nat->nat_inport);
+		u_short *csump;
+
+		if ((nat->nat_odport != 0) && (nflags & IPN_TCPUDP)) {
+			switch (nat->nat_dir)
+			{
+			case NAT_INBOUND :
+				tcp->th_sport = nat->nat_nsport;
+				fin->fin_data[0] = ntohs(nat->nat_nsport);
+				tcp->th_dport = nat->nat_ndport;
+				fin->fin_data[1] = ntohs(nat->nat_ndport);
+				break;
+
+			case NAT_OUTBOUND :
+				tcp->th_sport = nat->nat_odport;
+				fin->fin_data[0] = ntohs(nat->nat_odport);
+				tcp->th_dport = nat->nat_osport;
+				fin->fin_data[1] = ntohs(nat->nat_osport);
+				break;
+			}
 		}
 
 
-		if ((nat->nat_inport != 0) && (nflags & IPN_ICMPQUERY)) {
+		if ((nat->nat_odport != 0) && (nflags & IPN_ICMPQUERY)) {
 			icmp = fin->fin_dp;
 
-			icmp->icmp_id = nat->nat_inport;
+			icmp->icmp_id = nat->nat_nicmpid;
 		}
 
-		csump = nat_proto(fin, nat, nflags);
+		csump = ipf_nat_proto(fin, nat, nflags);
+
+		/*
+		 * The above comments do not hold for layer 4 (or higher)
+		 * checksums...
+		 */
+		if (csump != NULL) {
+			if (nat->nat_dir == NAT_OUTBOUND)
+				ipf_fix_incksum(0, csump, nat->nat_sumd[0], 0);
+			else
+				ipf_fix_outcksum(0, csump, nat->nat_sumd[0], 0);
+		}
 	}
 
-	nat_update(fin, nat, np);
-
-	/*
-	 * The above comments do not hold for layer 4 (or higher) checksums...
-	 */
-	if (csump != NULL) {
-		if (nat->nat_dir == NAT_OUTBOUND)
-			fix_incksum(fin, csump, nat->nat_sumd[0]);
-		else
-			fix_outcksum(fin, csump, nat->nat_sumd[0]);
-	}
-	ATOMIC_INCL(nat_stats.ns_mapped[0]);
 	fin->fin_flx |= FI_NATED;
 	if (np != NULL && np->in_tag.ipt_num[0] != 0)
 		fin->fin_nattag = &np->in_tag;
@@ -4315,7 +5772,7 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    nat_proto                                                   */
+/* Function:    ipf_nat_proto                                               */
 /* Returns:     u_short* - pointer to transport header checksum to update,  */
 /*                         NULL if the transport protocol is not recognised */
 /*                         as needing a checksum update.                    */
@@ -4328,10 +5785,11 @@
 /* that is not strictly 'address' translation, such as clamping the MSS in  */
 /* TCP down to a specific value, then do it from here.                      */
 /* ------------------------------------------------------------------------ */
-u_short *nat_proto(fin, nat, nflags)
-fr_info_t *fin;
-nat_t *nat;
-u_int nflags;
+u_short *
+ipf_nat_proto(fin, nat, nflags)
+	fr_info_t *fin;
+	nat_t *nat;
+	u_int nflags;
 {
 	icmphdr_t *icmp;
 	u_short *csump;
@@ -4340,9 +5798,9 @@
 
 	csump = NULL;
 	if (fin->fin_out == 0) {
-		fin->fin_rev = (nat->nat_dir == NAT_OUTBOUND);
+		fin->fin_rev = (nat->nat_dir & NAT_OUTBOUND);
 	} else {
-		fin->fin_rev = (nat->nat_dir == NAT_INBOUND);
+		fin->fin_rev = ((nat->nat_dir & NAT_OUTBOUND) == 0);
 	}
 
 	switch (fin->fin_p)
@@ -4350,7 +5808,8 @@
 	case IPPROTO_TCP :
 		tcp = fin->fin_dp;
 
-		csump = &tcp->th_sum;
+		if ((nflags & IPN_TCP) != 0)
+			csump = &tcp->th_sum;
 
 		/*
 		 * Do a MSS CLAMPING on a SYN packet,
@@ -4357,7 +5816,7 @@
 		 * only deal IPv4 for now.
 		 */
 		if ((nat->nat_mssclamp != 0) && (tcp->th_flags & TH_SYN) != 0)
-			nat_mssclamp(tcp, nat->nat_mssclamp, fin, csump);
+			ipf_nat_mssclamp(tcp, nat->nat_mssclamp, fin, csump);
 
 		break;
 
@@ -4364,8 +5823,10 @@
 	case IPPROTO_UDP :
 		udp = fin->fin_dp;
 
-		if (udp->uh_sum)
-			csump = &udp->uh_sum;
+		if ((nflags & IPN_UDP) != 0) {
+			if (udp->uh_sum != 0)
+				csump = &udp->uh_sum;
+		}
 		break;
 
 	case IPPROTO_ICMP :
@@ -4376,100 +5837,39 @@
 				csump = &icmp->icmp_cksum;
 		}
 		break;
-	}
-	return csump;
-}
 
+#ifdef USE_INET6
+	case IPPROTO_ICMPV6 :
+	    {
+		struct icmp6_hdr *icmp6 = (struct icmp6_hdr *)fin->fin_dp;
 
-/* ------------------------------------------------------------------------ */
-/* Function:    fr_natunload                                                */
-/* Returns:     Nil                                                         */
-/* Parameters:  Nil                                                         */
-/*                                                                          */
-/* Free all memory used by NAT structures allocated at runtime.             */
-/* ------------------------------------------------------------------------ */
-void fr_natunload()
-{
-	ipftq_t *ifq, *ifqnext;
+		icmp6 = fin->fin_dp;
 
-	(void) nat_clearlist();
-	(void) nat_flushtable();
-
-	/*
-	 * Proxy timeout queues are not cleaned here because although they
-	 * exist on the NAT list, appr_unload is called after fr_natunload
-	 * and the proxies actually are responsible for them being created.
-	 * Should the proxy timeouts have their own list?  There's no real
-	 * justification as this is the only complication.
-	 */
-	for (ifq = nat_utqe; ifq != NULL; ifq = ifqnext) {
-		ifqnext = ifq->ifq_next;
-		if (((ifq->ifq_flags & IFQF_PROXY) == 0) &&
-		    (fr_deletetimeoutqueue(ifq) == 0))
-			fr_freetimeoutqueue(ifq);
+		if ((nflags & IPN_ICMPQUERY) != 0) {
+			if (icmp6->icmp6_cksum != 0)
+				csump = &icmp6->icmp6_cksum;
+		}
+		break;
+	    }
+#endif
 	}
-
-	if (nat_table[0] != NULL) {
-		KFREES(nat_table[0], sizeof(nat_t *) * ipf_nattable_sz);
-		nat_table[0] = NULL;
-	}
-	if (nat_table[1] != NULL) {
-		KFREES(nat_table[1], sizeof(nat_t *) * ipf_nattable_sz);
-		nat_table[1] = NULL;
-	}
-	if (nat_rules != NULL) {
-		KFREES(nat_rules, sizeof(ipnat_t *) * ipf_natrules_sz);
-		nat_rules = NULL;
-	}
-	if (rdr_rules != NULL) {
-		KFREES(rdr_rules, sizeof(ipnat_t *) * ipf_rdrrules_sz);
-		rdr_rules = 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],
-		       sizeof(u_long *) * ipf_nattable_sz);
-		nat_stats.ns_bucketlen[0] = NULL;
-	}
-	if (nat_stats.ns_bucketlen[1] != NULL) {
-		KFREES(nat_stats.ns_bucketlen[1],
-		       sizeof(u_long *) * ipf_nattable_sz);
-		nat_stats.ns_bucketlen[1] = NULL;
-	}
-
-	if (fr_nat_maxbucket_reset == 1)
-		fr_nat_maxbucket = 0;
-
-	if (fr_nat_init == 1) {
-		fr_nat_init = 0;
-		fr_sttab_destroy(nat_tqb);
-
-		RW_DESTROY(&ipf_natfrag);
-		RW_DESTROY(&ipf_nat);
-
-		MUTEX_DESTROY(&ipf_nat_new);
-		MUTEX_DESTROY(&ipf_natio);
-
-		MUTEX_DESTROY(&nat_udptq.ifq_lock);
-		MUTEX_DESTROY(&nat_icmptq.ifq_lock);
-		MUTEX_DESTROY(&nat_iptq.ifq_lock);
-	}
+	return csump;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_natexpire                                                */
+/* Function:    ipf_nat_expire                                              */
 /* Returns:     Nil                                                         */
-/* Parameters:  Nil                                                         */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
 /*                                                                          */
 /* Check all of the timeout queues for entries at the top which need to be  */
 /* expired.                                                                 */
 /* ------------------------------------------------------------------------ */
-void fr_natexpire()
+void
+ipf_nat_expire(softc)
+	ipf_main_softc_t *softc;
 {
+	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
 	ipftq_t *ifq, *ifqnext;
 	ipftqent_t *tqe, *tqn;
 	int i;
@@ -4476,65 +5876,69 @@
 	SPL_INT(s);
 
 	SPL_NET(s);
-	WRITE_ENTER(&ipf_nat);
-	for (ifq = nat_tqb, i = 0; ifq != NULL; ifq = ifq->ifq_next) {
+	WRITE_ENTER(&softc->ipf_nat);
+	for (ifq = softn->ipf_nat_tcptq, i = 0; ifq != NULL;
+	     ifq = ifq->ifq_next) {
 		for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); i++) {
-			if (tqe->tqe_die > fr_ticks)
+			if (tqe->tqe_die > softc->ipf_ticks)
 				break;
 			tqn = tqe->tqe_next;
-			nat_delete(tqe->tqe_parent, NL_EXPIRE);
+			ipf_nat_delete(softc, tqe->tqe_parent, NL_EXPIRE);
 		}
 	}
 
-	for (ifq = nat_utqe; ifq != NULL; ifq = ifqnext) {
-		ifqnext = ifq->ifq_next;
-
+	for (ifq = softn->ipf_nat_utqe; ifq != NULL; ifq = ifq->ifq_next) {
 		for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); i++) {
-			if (tqe->tqe_die > fr_ticks)
+			if (tqe->tqe_die > softc->ipf_ticks)
 				break;
 			tqn = tqe->tqe_next;
-			nat_delete(tqe->tqe_parent, NL_EXPIRE);
+			ipf_nat_delete(softc, tqe->tqe_parent, NL_EXPIRE);
 		}
 	}
 
-	for (ifq = nat_utqe; ifq != NULL; ifq = ifqnext) {
+	for (ifq = softn->ipf_nat_utqe; ifq != NULL; ifq = ifqnext) {
 		ifqnext = ifq->ifq_next;
 
 		if (((ifq->ifq_flags & IFQF_DELETE) != 0) &&
 		    (ifq->ifq_ref == 0)) {
-			fr_freetimeoutqueue(ifq);
+			ipf_freetimeoutqueue(softc, ifq);
 		}
 	}
 
-	if (fr_nat_doflush != 0) {
-		nat_extraflush(2);
-		fr_nat_doflush = 0;
+	if (softn->ipf_nat_doflush != 0) {
+		ipf_nat_extraflush(softc, softn, 2);
+		softn->ipf_nat_doflush = 0;
 	}
 
-	RWLOCK_EXIT(&ipf_nat);
+	RWLOCK_EXIT(&softc->ipf_nat);
 	SPL_X(s);
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_natsync                                                  */
+/* Function:    ipf_nat_sync                                                */
 /* Returns:     Nil                                                         */
-/* Parameters:  ifp(I) - pointer to network interface                       */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              ifp(I) - pointer to network interface                       */
 /*                                                                          */
 /* Walk through all of the currently active NAT sessions, looking for those */
 /* which need to have their translated address updated.                     */
 /* ------------------------------------------------------------------------ */
-void fr_natsync(ifp)
-void *ifp;
+void
+ipf_nat_sync(softc, ifp)
+	ipf_main_softc_t *softc;
+	void *ifp;
 {
+	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
 	u_32_t sum1, sum2, sumd;
-	struct in_addr in;
+	i6addr_t in;
 	ipnat_t *n;
 	nat_t *nat;
 	void *ifp2;
+	int idx;
 	SPL_INT(s);
 
-	if (fr_running <= 0)
+	if (softc->ipf_running <= 0)
 		return;
 
 	/*
@@ -4544,28 +5948,63 @@
 	 * where the rule specifies the address is taken from the interface.
 	 */
 	SPL_NET(s);
-	WRITE_ENTER(&ipf_nat);
+	WRITE_ENTER(&softc->ipf_nat);
 
-	if (fr_running <= 0) {
-		RWLOCK_EXIT(&ipf_nat);
+	if (softc->ipf_running <= 0) {
+		RWLOCK_EXIT(&softc->ipf_nat);
 		return;
 	}
 
-	for (nat = nat_instances; nat; nat = nat->nat_next) {
+	for (nat = softn->ipf_nat_instances; nat; nat = nat->nat_next) {
 		if ((nat->nat_flags & IPN_TCP) != 0)
 			continue;
+
 		n = nat->nat_ptr;
-		if ((n == NULL) ||
-		    (n->in_outip != 0) || (n->in_outmsk != 0xffffffff))
-			continue;
+		if (n != NULL) {
+			if (n->in_v[1] == 4) {
+				if (n->in_redir & NAT_MAP) {
+					if ((n->in_nsrcaddr != 0) ||
+					    (n->in_nsrcmsk != 0xffffffff))
+						continue;
+				} else if (n->in_redir & NAT_REDIRECT) {
+					if ((n->in_ndstaddr != 0) ||
+					    (n->in_ndstmsk != 0xffffffff))
+						continue;
+				}
+			}
+#ifdef USE_INET6
+			if (n->in_v[1] == 4) {
+				if (n->in_redir & NAT_MAP) {
+					if (!IP6_ISZERO(&n->in_nsrcaddr) ||
+					    !IP6_ISONES(&n->in_nsrcmsk))
+						continue;
+				} else if (n->in_redir & NAT_REDIRECT) {
+					if (!IP6_ISZERO(&n->in_ndstaddr) ||
+					    !IP6_ISONES(&n->in_ndstmsk))
+						continue;
+				}
+			}
+#endif
+		}
+
 		if (((ifp == NULL) || (ifp == nat->nat_ifps[0]) ||
 		     (ifp == nat->nat_ifps[1]))) {
-			nat->nat_ifps[0] = GETIFP(nat->nat_ifnames[0], 4);
+			nat->nat_ifps[0] = GETIFP(nat->nat_ifnames[0],
+						  nat->nat_v[0]);
+			if ((nat->nat_ifps[0] != NULL) &&
+			    (nat->nat_ifps[0] != (void *)-1)) {
+				nat->nat_mtu[0] = GETIFMTU_4(nat->nat_ifps[0]);
+			}
 			if (nat->nat_ifnames[1][0] != '\0') {
 				nat->nat_ifps[1] = GETIFP(nat->nat_ifnames[1],
-							  4);
-			} else
+							  nat->nat_v[1]);
+			} else {
 				nat->nat_ifps[1] = nat->nat_ifps[0];
+			}
+			if ((nat->nat_ifps[1] != NULL) &&
+			    (nat->nat_ifps[1] != (void *)-1)) {
+				nat->nat_mtu[1] = GETIFMTU_4(nat->nat_ifps[1]);
+			}
 			ifp2 = nat->nat_ifps[0];
 			if (ifp2 == NULL)
 				continue;
@@ -4574,10 +6013,13 @@
 			 * Change the map-to address to be the same as the
 			 * new one.
 			 */
-			sum1 = nat->nat_outip.s_addr;
-			if (fr_ifpaddr(4, FRI_NORMAL, ifp2, &in, NULL) != -1)
-				nat->nat_outip = in;
-			sum2 = nat->nat_outip.s_addr;
+			sum1 = NATFSUM(nat, nat->nat_v[1], nat_nsrc6);
+			if (ipf_ifpaddr(softc, nat->nat_v[0], FRI_NORMAL, ifp2,
+				       &in, NULL) != -1) {
+				if (nat->nat_v[0] == 4)
+					nat->nat_nsrcip = in.in4;
+			}
+			sum2 = NATFSUM(nat, nat->nat_v[1], nat_nsrc6);
 
 			if (sum1 == sum2)
 				continue;
@@ -4595,19 +6037,44 @@
 		}
 	}
 
-	for (n = nat_list; (n != NULL); n = n->in_next) {
+	for (n = softn->ipf_nat_list; (n != NULL); n = n->in_next) {
+		char *base = n->in_names;
+
 		if ((ifp == NULL) || (n->in_ifps[0] == ifp))
-			n->in_ifps[0] = fr_resolvenic(n->in_ifnames[0], 4);
+			n->in_ifps[0] = ipf_resolvenic(softc,
+						       base + n->in_ifnames[0],
+						       n->in_v[0]);
 		if ((ifp == NULL) || (n->in_ifps[1] == ifp))
-			n->in_ifps[1] = fr_resolvenic(n->in_ifnames[1], 4);
+			n->in_ifps[1] = ipf_resolvenic(softc,
+						       base + n->in_ifnames[1],
+						       n->in_v[1]);
+
+		if (n->in_redir & NAT_REDIRECT)
+			idx = 1;
+		else
+			idx = 0;
+
+		if (((ifp == NULL) || (n->in_ifps[idx] == ifp)) &&
+		    (n->in_ifps[idx] != NULL &&
+		     n->in_ifps[idx] != (void *)-1)) {
+
+			ipf_nat_nextaddrinit(softc, n->in_names, &n->in_osrc,
+					     0, n->in_ifps[idx]);
+			ipf_nat_nextaddrinit(softc, n->in_names, &n->in_odst,
+					     0, n->in_ifps[idx]);
+			ipf_nat_nextaddrinit(softc, n->in_names, &n->in_nsrc,
+					     0, n->in_ifps[idx]);
+			ipf_nat_nextaddrinit(softc, n->in_names, &n->in_ndst,
+					     0, n->in_ifps[idx]);
+		}
 	}
-	RWLOCK_EXIT(&ipf_nat);
+	RWLOCK_EXIT(&softc->ipf_nat);
 	SPL_X(s);
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    nat_icmpquerytype4                                          */
+/* Function:    ipf_nat_icmpquerytype                                       */
 /* Returns:     int - 1 == success, 0 == failure                            */
 /* Parameters:  icmptype(I) - ICMP type number                              */
 /*                                                                          */
@@ -4614,8 +6081,9 @@
 /* Tests to see if the ICMP type number passed is a query/response type or  */
 /* not.                                                                     */
 /* ------------------------------------------------------------------------ */
-static int nat_icmpquerytype4(icmptype)
-int icmptype;
+static int
+ipf_nat_icmpquerytype(icmptype)
+	int icmptype;
 {
 
 	/*
@@ -4627,14 +6095,12 @@
 	 * altough it seems silly to call a reply a query, this is exactly
 	 * as it is defined in the IPv4 specification
 	 */
-	
 	switch (icmptype)
 	{
-	
 	case ICMP_ECHOREPLY:
 	case ICMP_ECHO:
-	/* route aedvertisement/solliciation is currently unsupported: */
-	/* it would require rewriting the ICMP data section            */
+	/* route advertisement/solicitation is currently unsupported: */
+	/* it would require rewriting the ICMP data section          */
 	case ICMP_TSTAMP:
 	case ICMP_TSTAMPREPLY:
 	case ICMP_IREQ:
@@ -4651,14 +6117,19 @@
 /* ------------------------------------------------------------------------ */
 /* Function:    nat_log                                                     */
 /* Returns:     Nil                                                         */
-/* Parameters:  nat(I)  - pointer to NAT structure                          */
-/*              type(I) - type of log entry to create                       */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              softn(I) - pointer to NAT context structure                 */
+/*              nat(I)    - pointer to NAT structure                        */
+/*              action(I) - action related to NAT structure being performed */
 /*                                                                          */
 /* Creates a NAT log entry.                                                 */
 /* ------------------------------------------------------------------------ */
-void nat_log(nat, type)
-struct nat *nat;
-u_int type;
+void
+ipf_nat_log(softc, softn, nat, action)
+	ipf_main_softc_t *softc;
+	ipf_nat_softc_t *softn;
+	struct nat *nat;
+	u_int action;
 {
 #ifdef	IPFILTER_LOG
 # ifndef LARGE_NAT
@@ -4670,22 +6141,40 @@
 	size_t sizes[1];
 	int types[1];
 
-	natl.nl_inip = nat->nat_inip;
-	natl.nl_outip = nat->nat_outip;
-	natl.nl_origip = nat->nat_oip;
+	bcopy((char *)&nat->nat_osrc6, (char *)&natl.nl_osrcip,
+	      sizeof(natl.nl_osrcip));
+	bcopy((char *)&nat->nat_nsrc6, (char *)&natl.nl_nsrcip,
+	      sizeof(natl.nl_nsrcip));
+	bcopy((char *)&nat->nat_odst6, (char *)&natl.nl_odstip,
+	      sizeof(natl.nl_odstip));
+	bcopy((char *)&nat->nat_ndst6, (char *)&natl.nl_ndstip,
+	      sizeof(natl.nl_ndstip));
+
 	natl.nl_bytes[0] = nat->nat_bytes[0];
 	natl.nl_bytes[1] = nat->nat_bytes[1];
 	natl.nl_pkts[0] = nat->nat_pkts[0];
 	natl.nl_pkts[1] = nat->nat_pkts[1];
-	natl.nl_origport = nat->nat_oport;
-	natl.nl_inport = nat->nat_inport;
-	natl.nl_outport = nat->nat_outport;
-	natl.nl_p = nat->nat_p;
-	natl.nl_type = type;
+	natl.nl_odstport = nat->nat_odport;
+	natl.nl_osrcport = nat->nat_osport;
+	natl.nl_nsrcport = nat->nat_nsport;
+	natl.nl_ndstport = nat->nat_ndport;
+	natl.nl_p[0] = nat->nat_pr[0];
+	natl.nl_p[1] = nat->nat_pr[1];
+	natl.nl_v[0] = nat->nat_v[0];
+	natl.nl_v[1] = nat->nat_v[1];
+	natl.nl_type = nat->nat_redir;
+	natl.nl_action = action;
 	natl.nl_rule = -1;
+
+	bcopy(nat->nat_ifnames[0], natl.nl_ifnames[0],
+	      sizeof(nat->nat_ifnames[0]));
+	bcopy(nat->nat_ifnames[1], natl.nl_ifnames[1],
+	      sizeof(nat->nat_ifnames[1]));
+
 # ifndef LARGE_NAT
 	if (nat->nat_ptr != NULL) {
-		for (rulen = 0, np = nat_list; np; np = np->in_next, rulen++)
+		for (rulen = 0, np = softn->ipf_nat_list; np != NULL;
+		     np = np->in_next, rulen++)
 			if (np == nat->nat_ptr) {
 				natl.nl_rule = rulen;
 				break;
@@ -4696,7 +6185,7 @@
 	sizes[0] = sizeof(natl);
 	types[0] = 0;
 
-	(void) ipllog(IPL_LOGNAT, NULL, items, sizes, types, 1);
+	(void) ipf_log_items(softc, IPL_LOGNAT, NULL, items, sizes, types, 1);
 #endif
 }
 
@@ -4703,7 +6192,7 @@
 
 #if defined(__OpenBSD__)
 /* ------------------------------------------------------------------------ */
-/* Function:    nat_ifdetach                                                */
+/* Function:    ipf_nat_ifdetach                                            */
 /* Returns:     Nil                                                         */
 /* Parameters:  ifp(I) - pointer to network interface                       */
 /*                                                                          */
@@ -4710,10 +6199,15 @@
 /* Compatibility interface for OpenBSD to trigger the correct updating of   */
 /* interface references within IPFilter.                                    */
 /* ------------------------------------------------------------------------ */
-void nat_ifdetach(ifp)
-void *ifp;
+void
+ipf_nat_ifdetach(ifp)
+	void *ifp;
 {
-	frsync(ifp);
+	ipf_main_softc_t *softc;
+
+	softc = ipf_get_softc(0);
+
+	ipf_sync(ifp);
 	return;
 }
 #endif
@@ -4720,39 +6214,79 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_ipnatderef                                               */
+/* Function:    ipf_nat_rule_deref                                          */
 /* Returns:     Nil                                                         */
-/* Parameters:  isp(I) - pointer to pointer to NAT rule                     */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              inp(I)   - pointer to pointer to NAT rule                   */
 /* Write Locks: ipf_nat                                                     */
 /*                                                                          */
+/* Dropping the refernce count for a rule means that whatever held the      */
+/* pointer to this rule (*inp) is no longer interested in it and when the   */
+/* reference count drops to zero, any resources allocated for the rule can  */
+/* be released and the rule itself free'd.                                  */
 /* ------------------------------------------------------------------------ */
-void fr_ipnatderef(inp)
-ipnat_t **inp;
+void
+ipf_nat_rule_deref(softc, inp)
+	ipf_main_softc_t *softc;
+	ipnat_t **inp;
 {
-	ipnat_t *in;
+	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
+	ipnat_t *n;
 
-	in = *inp;
+	n = *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;
+	n->in_use--;
+	if (n->in_use > 0)
+		return;
+
+	if (n->in_apr != NULL)
+		ipf_proxy_deref(n->in_apr);
+
+	ipf_nat_rule_fini(softc, n);
+
+	if (n->in_redir & NAT_REDIRECT) {
+		if ((n->in_flags & IPN_PROXYRULE) == 0) {
+			ATOMIC_DEC32(softn->ipf_nat_stats.ns_rules_rdr);
+		}
+	}
+	if (n->in_redir & (NAT_MAP|NAT_MAPBLK)) {
+		if ((n->in_flags & IPN_PROXYRULE) == 0) {
+			ATOMIC_DEC32(softn->ipf_nat_stats.ns_rules_map);
+		}
+	}
+
+	if (n->in_tqehead[0] != NULL) {
+		if (ipf_deletetimeoutqueue(n->in_tqehead[0]) == 0) {
+			ipf_freetimeoutqueue(softc, n->in_tqehead[1]);
+		}
+	}
+
+	if (n->in_tqehead[1] != NULL) {
+		if (ipf_deletetimeoutqueue(n->in_tqehead[1]) == 0) {
+			ipf_freetimeoutqueue(softc, n->in_tqehead[1]);
+		}
+	}
+
+	if ((n->in_flags & IPN_PROXYRULE) == 0) {
+		ATOMIC_DEC32(softn->ipf_nat_stats.ns_rules);
+	}
+
+	MUTEX_DESTROY(&n->in_lock);
+
+	KFREES(n, n->in_size);
+
+#if SOLARIS && !defined(INSTANCES)
+	if (softn->ipf_nat_stats.ns_rules == 0)
+		pfil_delayed_copy = 1;
 #endif
-	}
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_natderef                                                 */
+/* Function:    ipf_nat_deref                                               */
 /* Returns:     Nil                                                         */
-/* Parameters:  isp(I) - pointer to pointer to NAT table entry              */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              natp(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.                                       */
@@ -4765,8 +6299,10 @@
 /* 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;
+void
+ipf_nat_deref(softc, natp)
+	ipf_main_softc_t *softc;
+	nat_t **natp;
 {
 	nat_t *nat;
 
@@ -4776,19 +6312,20 @@
 	MUTEX_ENTER(&nat->nat_lock);
 	if (nat->nat_ref > 1) {
 		nat->nat_ref--;
+		ASSERT(nat->nat_ref >= 0);
 		MUTEX_EXIT(&nat->nat_lock);
 		return;
 	}
 	MUTEX_EXIT(&nat->nat_lock);
 
-	WRITE_ENTER(&ipf_nat);
-	nat_delete(nat, NL_EXPIRE);
-	RWLOCK_EXIT(&ipf_nat);
+	WRITE_ENTER(&softc->ipf_nat);
+	ipf_nat_delete(softc, nat, NL_EXPIRE);
+	RWLOCK_EXIT(&softc->ipf_nat);
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_natclone                                                 */
+/* Function:    ipf_nat_clone                                               */
 /* Returns:     ipstate_t* - NULL == cloning failed,                        */
 /*                           else pointer to new state structure            */
 /* Parameters:  fin(I) - pointer to packet information                      */
@@ -4797,24 +6334,30 @@
 /*                                                                          */
 /* Create a "duplcate" state table entry from the master.                   */
 /* ------------------------------------------------------------------------ */
-static nat_t *fr_natclone(fin, nat)
-fr_info_t *fin;
-nat_t *nat;
+nat_t *
+ipf_nat_clone(fin, nat)
+	fr_info_t *fin;
+	nat_t *nat;
 {
+	ipf_main_softc_t *softc = fin->fin_main_soft;
+	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
 	frentry_t *fr;
 	nat_t *clone;
 	ipnat_t *np;
 
 	KMALLOC(clone, nat_t *);
-	if (clone == NULL)
+	if (clone == NULL) {
+		NBUMPSIDED(fin->fin_out, ns_clone_nomem);
 		return NULL;
+	}
 	bcopy((char *)nat, (char *)clone, sizeof(*clone));
 
 	MUTEX_NUKE(&clone->nat_lock);
 
+	clone->nat_rev = fin->fin_rev;
 	clone->nat_aps = NULL;
 	/*
-	 * Initialize all these so that nat_delete() doesn't cause a crash.
+	 * Initialize all these so that ipf_nat_delete() doesn't cause a crash.
 	 */
 	clone->nat_tqe.tqe_pnext = NULL;
 	clone->nat_tqe.tqe_next = NULL;
@@ -4827,14 +6370,16 @@
 	if (clone->nat_hm)
 		clone->nat_hm->hm_ref++;
 
-	if (nat_insert(clone, fin->fin_rev) == -1) {
+	if (ipf_nat_insert(softc, softn, clone) == -1) {
 		KFREE(clone);
+		NBUMPSIDED(fin->fin_out, ns_insert_fail);
 		return NULL;
 	}
+
 	np = clone->nat_ptr;
 	if (np != NULL) {
-		if (nat_logging)
-			nat_log(clone, (u_int)np->in_redir);
+		if (softn->ipf_nat_logging)
+			ipf_nat_log(softc, softn, clone, NL_CLONE);
 		np->in_use++;
 	}
 	fr = clone->nat_fr;
@@ -4844,26 +6389,25 @@
 		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,
-				  clone->nat_flags);
+	if (clone->nat_pr[0] == IPPROTO_TCP) {
+		(void) ipf_tcp_age(&clone->nat_tqe, fin, softn->ipf_nat_tcptq,
+				   clone->nat_flags, 2);
 	}
-#ifdef	IPFILTER_SYNC
-	clone->nat_sync = ipfsync_new(SMC_NAT, fin, clone);
-#endif
-	if (nat_logging)
-		nat_log(clone, NL_CLONE);
+	clone->nat_sync = ipf_sync_new(softc, SMC_NAT, fin, clone);
+	if (softn->ipf_nat_logging)
+		ipf_nat_log(softc, softn, clone, NL_CLONE);
 	return clone;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:   nat_wildok                                                   */
+/* Function:   ipf_nat_wildok                                               */
 /* Returns:    int - 1 == packet's ports match wildcards                    */
 /*                   0 == packet's ports don't match wildcards              */
 /* Parameters: nat(I)   - NAT entry                                         */
@@ -4875,12 +6419,10 @@
 /* Use NAT entry and packet direction to determine which combination of     */
 /* wildcard flags should be used.                                           */
 /* ------------------------------------------------------------------------ */
-static int nat_wildok(nat, sport, dport, flags, dir)
-nat_t *nat;
-int sport;
-int dport;
-int flags;
-int dir;
+int
+ipf_nat_wildok(nat, sport, dport, flags, dir)
+	nat_t *nat;
+	int sport, dport, flags, dir;
 {
 	/*
 	 * When called by       dir is set to
@@ -4891,34 +6433,33 @@
 	 * "intended" direction of that NAT entry in nat->nat_dir to decide
 	 * which combination of wildcard flags to allow.
 	 */
-
-	switch ((dir << 1) | nat->nat_dir)
+	switch ((dir << 1) | (nat->nat_dir & (NAT_INBOUND|NAT_OUTBOUND)))
 	{
 	case 3: /* outbound packet / outbound entry */
-		if (((nat->nat_inport == sport) ||
+		if (((nat->nat_osport == sport) ||
 		    (flags & SI_W_SPORT)) &&
-		    ((nat->nat_oport == dport) ||
+		    ((nat->nat_odport == dport) ||
 		    (flags & SI_W_DPORT)))
 			return 1;
 		break;
 	case 2: /* outbound packet / inbound entry */
-		if (((nat->nat_outport == sport) ||
-		    (flags & SI_W_DPORT)) &&
-		    ((nat->nat_oport == dport) ||
-		    (flags & SI_W_SPORT)))
+		if (((nat->nat_osport == dport) ||
+		    (flags & SI_W_SPORT)) &&
+		    ((nat->nat_odport == sport) ||
+		    (flags & SI_W_DPORT)))
 			return 1;
 		break;
 	case 1: /* inbound packet / outbound entry */
-		if (((nat->nat_oport == sport) ||
-		    (flags & SI_W_DPORT)) &&
-		    ((nat->nat_outport == dport) ||
-		    (flags & SI_W_SPORT)))
+		if (((nat->nat_osport == dport) ||
+		    (flags & SI_W_SPORT)) &&
+		    ((nat->nat_odport == sport) ||
+		    (flags & SI_W_DPORT)))
 			return 1;
 		break;
 	case 0: /* inbound packet / inbound entry */
-		if (((nat->nat_oport == sport) ||
+		if (((nat->nat_osport == sport) ||
 		    (flags & SI_W_SPORT)) &&
-		    ((nat->nat_outport == dport) ||
+		    ((nat->nat_odport == dport) ||
 		    (flags & SI_W_DPORT)))
 			return 1;
 		break;
@@ -4942,11 +6483,12 @@
 /* then the TCP header checksum will be updated to reflect the change in    */
 /* the MSS.                                                                 */
 /* ------------------------------------------------------------------------ */
-static void nat_mssclamp(tcp, maxmss, fin, csump)
-tcphdr_t *tcp;
-u_32_t maxmss;
-fr_info_t *fin;
-u_short *csump;
+static void
+ipf_nat_mssclamp(tcp, maxmss, fin, csump)
+	tcphdr_t *tcp;
+	u_32_t maxmss;
+	fr_info_t *fin;
+	u_short *csump;
 {
 	u_char *cp, *ep, opt;
 	int hlen, advance;
@@ -4981,7 +6523,7 @@
 					cp[2] = maxmss / 256;
 					cp[3] = maxmss & 0xff;
 					CALC_SUMD(mss, maxmss, sumd);
-					fix_outcksum(fin, csump, sumd);
+					ipf_fix_outcksum(0, csump, sumd, 0);
 				}
 				break;
 			default:
@@ -4996,20 +6538,24 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_setnatqueue                                              */
+/* Function:    ipf_nat_setqueue                                            */
 /* Returns:     Nil                                                         */
-/* Parameters:  nat(I)- pointer to NAT structure                            */
-/*              rev(I) - forward(0) or reverse(1) direction                 */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              softn(I) - pointer to NAT context structure                 */
+/*              nat(I)- pointer to NAT structure                            */
 /* Locks:       ipf_nat (read or write)                                     */
 /*                                                                          */
 /* Put the NAT entry on its default queue entry, using rev as a helped in   */
 /* determining which queue it should be placed on.                          */
 /* ------------------------------------------------------------------------ */
-void fr_setnatqueue(nat, rev)
-nat_t *nat;
-int rev;
+void
+ipf_nat_setqueue(softc, softn, nat)
+	ipf_main_softc_t *softc;
+	ipf_nat_softc_t *softn;
+	nat_t *nat;
 {
 	ipftq_t *oifq, *nifq;
+	int rev = nat->nat_rev;
 
 	if (nat->nat_ptr != NULL)
 		nifq = nat->nat_ptr->in_tqehead[rev];
@@ -5017,19 +6563,20 @@
 		nifq = NULL;
 
 	if (nifq == NULL) {
-		switch (nat->nat_p)
+		switch (nat->nat_pr[0])
 		{
 		case IPPROTO_UDP :
-			nifq = &nat_udptq;
+			nifq = &softn->ipf_nat_udptq;
 			break;
 		case IPPROTO_ICMP :
-			nifq = &nat_icmptq;
+			nifq = &softn->ipf_nat_icmptq;
 			break;
 		case IPPROTO_TCP :
-			nifq = nat_tqb + nat->nat_tqe.tqe_state[rev];
+			nifq = softn->ipf_nat_tcptq +
+			       nat->nat_tqe.tqe_state[rev];
 			break;
 		default :
-			nifq = &nat_iptq;
+			nifq = &softn->ipf_nat_iptq;
 			break;
 		}
 	}
@@ -5040,9 +6587,9 @@
 	 * another, else put it on the end of the newly determined queue.
 	 */
 	if (oifq != NULL)
-		fr_movequeue(&nat->nat_tqe, oifq, nifq);
+		ipf_movequeue(softc->ipf_ticks, &nat->nat_tqe, oifq, nifq);
 	else
-		fr_queueappend(&nat->nat_tqe, nifq, nat);
+		ipf_queueappend(softc->ipf_ticks, &nat->nat_tqe, nifq, nat);
 	return;
 }
 
@@ -5050,31 +6597,34 @@
 /* ------------------------------------------------------------------------ */
 /* Function:    nat_getnext                                                 */
 /* Returns:     int - 0 == ok, else error                                   */
-/* Parameters:  t(I)   - pointer to ipftoken structure                      */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              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;
+static int
+ipf_nat_getnext(softc, t, itp, objp)
+	ipf_main_softc_t *softc;
+	ipftoken_t *t;
+	ipfgeniter_t *itp;
+	ipfobj_t *objp;
 {
+	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
 	hostmap_t *hm, *nexthm = NULL, zerohm;
 	ipnat_t *ipn, *nextipnat = NULL, zeroipn;
 	nat_t *nat, *nextnat = NULL, zeronat;
-	int error = 0, count;
-	char *dst;
+	int error = 0;
+	void *nnext;
 
-	count = itp->igi_nitems;
-	if (count < 1)
+	if (itp->igi_nitems != 1) {
+		IPFERROR(60075);
 		return ENOSPC;
+	}
 
-	READ_ENTER(&ipf_nat);
+	READ_ENTER(&softc->ipf_nat);
 
 	switch (itp->igi_type)
 	{
@@ -5081,214 +6631,108 @@
 	case IPFGENITER_HOSTMAP :
 		hm = t->ipt_data;
 		if (hm == NULL) {
-			nexthm = ipf_hm_maplist;
+			nexthm = softn->ipf_hm_maplist;
 		} else {
 			nexthm = hm->hm_next;
 		}
+		if (nexthm != NULL) {
+			ATOMIC_INC32(nexthm->hm_ref);
+			t->ipt_data = nexthm;
+		} else {
+			bzero(&zerohm, sizeof(zerohm));
+			nexthm = &zerohm;
+			t->ipt_data = NULL;
+		}
+		nnext = nexthm->hm_next;
 		break;
 
 	case IPFGENITER_IPNAT :
 		ipn = t->ipt_data;
 		if (ipn == NULL) {
-			nextipnat = nat_list;
+			nextipnat = softn->ipf_nat_list;
 		} else {
 			nextipnat = ipn->in_next;
 		}
+		if (nextipnat != NULL) {
+			ATOMIC_INC32(nextipnat->in_use);
+			t->ipt_data = nextipnat;
+		} else {
+			bzero(&zeroipn, sizeof(zeroipn));
+			nextipnat = &zeroipn;
+			t->ipt_data = NULL;
+		}
+		nnext = nextipnat->in_next;
 		break;
 
 	case IPFGENITER_NAT :
 		nat = t->ipt_data;
 		if (nat == NULL) {
-			nextnat = nat_instances;
+			nextnat = softn->ipf_nat_instances;
 		} else {
 			nextnat = nat->nat_next;
 		}
+		if (nextnat != NULL) {
+			MUTEX_ENTER(&nextnat->nat_lock);
+			nextnat->nat_ref++;
+			MUTEX_EXIT(&nextnat->nat_lock);
+			t->ipt_data = nextnat;
+		} else {
+			bzero(&zeronat, sizeof(zeronat));
+			nextnat = &zeronat;
+			t->ipt_data = NULL;
+		}
+		nnext = nextnat->nat_next;
 		break;
+
 	default :
-		RWLOCK_EXIT(&ipf_nat);
+		RWLOCK_EXIT(&softc->ipf_nat);
+		IPFERROR(60055);
 		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;
+	RWLOCK_EXIT(&softc->ipf_nat);
 
-		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;
+	objp->ipfo_ptr = itp->igi_data;
 
-		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 :
+		error = COPYOUT(nexthm, objp->ipfo_ptr, sizeof(*nexthm));
+		if (error != 0) {
+			IPFERROR(60049);
+			error = EFAULT;
+		}
 		if (hm != NULL) {
-			WRITE_ENTER(&ipf_nat);
-			fr_hostmapdel(&hm);
-			RWLOCK_EXIT(&ipf_nat);
+			WRITE_ENTER(&softc->ipf_nat);
+			ipf_nat_hostmapdel(softc, &hm);
+			RWLOCK_EXIT(&softc->ipf_nat);
 		}
 		break;
+
 	case IPFGENITER_IPNAT :
+		objp->ipfo_size = nextipnat->in_size;
+		objp->ipfo_type = IPFOBJ_IPNAT;
+		error = ipf_outobjk(softc, objp, nextipnat);
 		if (ipn != NULL) {
-			fr_ipnatderef(&ipn);
+			WRITE_ENTER(&softc->ipf_nat);
+			ipf_nat_rule_deref(softc, &ipn);
+			RWLOCK_EXIT(&softc->ipf_nat);
 		}
 		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;
+		objp->ipfo_size = sizeof(nat_t);
+		objp->ipfo_type = IPFOBJ_NAT;
+		error = ipf_outobjk(softc, objp, nextnat);
+		if (nat != NULL)
+			ipf_nat_deref(softc, &nat);
 
-	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;
 	}
 
+	if (nnext == NULL)
+		ipf_token_mark_complete(t);
+
 	return error;
 }
 
@@ -5296,7 +6740,9 @@
 /* ------------------------------------------------------------------------ */
 /* Function:    nat_extraflush                                              */
 /* Returns:     int - 0 == success, -1 == failure                           */
-/* Parameters:  which(I) - how to flush the active NAT table                */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              softn(I) - pointer to NAT context structure                 */
+/*              which(I) - how to flush the active NAT table                */
 /* Write Locks: ipf_nat                                                     */
 /*                                                                          */
 /* Flush nat tables.  Three actions currently defined:                      */
@@ -5310,12 +6756,15 @@
 /*            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;
+static int
+ipf_nat_extraflush(softc, softn, which)
+	ipf_main_softc_t *softc;
+	ipf_nat_softc_t *softn;
+	int which;
 {
-	ipftq_t *ifq, *ifqnext;
 	nat_t *nat, **natp;
 	ipftqent_t *tqn;
+	ipftq_t *ifq;
 	int removed;
 	SPL_INT(s);
 
@@ -5322,33 +6771,36 @@
 	removed = 0;
 
 	SPL_NET(s);
-
 	switch (which)
 	{
 	case 0 :
+		softn->ipf_nat_stats.ns_flush_all++;
 		/*
 		 * Style 0 flush removes everything...
 		 */
-		for (natp = &nat_instances; ((nat = *natp) != NULL); ) {
-			nat_delete(nat, NL_FLUSH);
+		for (natp = &softn->ipf_nat_instances;
+		     ((nat = *natp) != NULL); ) {
+			ipf_nat_delete(softc, nat, NL_FLUSH);
 			removed++;
 		}
 		break;
 
 	case 1 :
+		softn->ipf_nat_stats.ns_flush_closing++;
 		/*
 		 * 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 (ifq = softn->ipf_nat_tcptq + 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)
+				if (nat->nat_pr[0] != IPPROTO_TCP ||
+				    nat->nat_pr[1] != IPPROTO_TCP)
 					break;
-				nat_delete(nat, NL_EXPIRE);
+				ipf_nat_delete(softc, nat, NL_EXPIRE);
 				removed++;
 			}
 		}
@@ -5356,12 +6808,13 @@
 		/*
 		 * Also need to look through the user defined queues.
 		 */
-		for (ifq = nat_utqe; ifq != NULL; ifq = ifqnext) {
-			ifqnext = ifq->ifq_next;
+		for (ifq = softn->ipf_nat_utqe; 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)
+				if (nat->nat_pr[0] != IPPROTO_TCP ||
+				    nat->nat_pr[1] != IPPROTO_TCP)
 					continue;
 
 				if ((nat->nat_tcpstate[0] >
@@ -5368,7 +6821,7 @@
 				     IPF_TCPS_ESTABLISHED) &&
 				    (nat->nat_tcpstate[1] >
 				     IPF_TCPS_ESTABLISHED)) {
-					nat_delete(nat, NL_EXPIRE);
+					ipf_nat_delete(softc, nat, NL_EXPIRE);
 					removed++;
 				}
 			}
@@ -5386,19 +6839,21 @@
 	case IPF_TCPS_FIN_WAIT_2 :
 	case IPF_TCPS_TIME_WAIT :
 	case IPF_TCPS_CLOSED :
-		tqn = nat_tqb[which].ifq_head;
+		softn->ipf_nat_stats.ns_flush_state++;
+		tqn = softn->ipf_nat_tcptq[which].ifq_head;
 		while (tqn != NULL) {
 			nat = tqn->tqe_parent;
 			tqn = tqn->tqe_next;
-			nat_delete(nat, NL_FLUSH);
+			ipf_nat_delete(softc, nat, NL_FLUSH);
 			removed++;
 		}
 		break;
-	 
+
 	default :
 		if (which < 30)
 			break;
-	   
+
+		softn->ipf_nat_stats.ns_flush_timeout++;
 		/*
 		 * Take a large arbitrary number to mean the number of seconds
 		 * for which which consider to be the maximum value we'll allow
@@ -5405,9 +6860,10 @@
 		 * 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);
+		for (natp = &softn->ipf_nat_instances;
+		     ((nat = *natp) != NULL); ) {
+			if (softc->ipf_ticks - nat->nat_touched > which) {
+				ipf_nat_delete(softc, nat, NL_FLUSH);
 				removed++;
 			} else
 				natp = &nat->nat_next;
@@ -5420,12 +6876,25 @@
 		return removed;
 	}
 
+	softn->ipf_nat_stats.ns_flush_queue++;
+
 	/*
-	 * Asked to remove inactive entries because the table is full.
+	 * 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.
 	 */
-	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);
+	if (softc->ipf_ticks - softn->ipf_nat_last_force_flush >
+	    IPF_TTLVAL(5)) {
+		softn->ipf_nat_last_force_flush = softc->ipf_ticks;
+
+		removed = ipf_queueflush(softc, ipf_nat_flush_entry,
+					 softn->ipf_nat_tcptq,
+					 softn->ipf_nat_utqe,
+					 &softn->ipf_nat_stats.ns_active,
+					 softn->ipf_nat_table_sz,
+					 softn->ipf_nat_table_wm_low);
 	}
 
 	SPL_X(s);
@@ -5434,9 +6903,10 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    nat_flush_entry                                             */
+/* Function:    ipf_nat_flush_entry                                         */
 /* Returns:     0 - always succeeds                                         */
-/* Parameters:  entry(I) - pointer to NAT entry                             */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              entry(I) - pointer to NAT entry                             */
 /* Write Locks: ipf_nat                                                     */
 /*                                                                          */
 /* This function is a stepping stone between ipf_queueflush() and           */
@@ -5444,29 +6914,1045 @@
 /* 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;
+static int
+ipf_nat_flush_entry(softc, entry)
+	ipf_main_softc_t *softc;
+	void *entry;
 {
-	nat_delete(entry, NL_FLUSH);
+	ipf_nat_delete(softc, entry, NL_FLUSH);
 	return 0;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    nat_gettable                                                */
+/* Function:    ipf_nat_iterator                                            */
+/* Returns:     int - 0 == ok, else error                                   */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              token(I) - pointer to ipftoken structure                    */
+/*              itp(I)   - pointer to ipfgeniter_t structure                */
+/*              obj(I)   - pointer to data description 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
+ipf_nat_iterator(softc, token, itp, obj)
+	ipf_main_softc_t *softc;
+	ipftoken_t *token;
+	ipfgeniter_t *itp;
+	ipfobj_t *obj;
+{
+	int error;
+
+	if (itp->igi_data == NULL) {
+		IPFERROR(60052);
+		return EFAULT;
+	}
+
+	switch (itp->igi_type)
+	{
+	case IPFGENITER_HOSTMAP :
+	case IPFGENITER_IPNAT :
+	case IPFGENITER_NAT :
+		error = ipf_nat_getnext(softc, token, itp, obj);
+		break;
+
+	case IPFGENITER_NATFRAG :
+		error = ipf_frag_nat_next(softc, token, itp);
+		break;
+	default :
+		IPFERROR(60053);
+		error = EINVAL;
+		break;
+	}
+
+	return error;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_nat_setpending                                          */
+/* Returns:     Nil                                                         */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              nat(I)   - pointer to NAT structure                         */
+/* Locks:       ipf_nat (read or write)                                     */
+/*                                                                          */
+/* Put the NAT entry on to the pending queue - this queue has a very short  */
+/* lifetime where items are put that can't be deleted straight away because */
+/* of locking issues but we want to delete them ASAP, anyway.  In calling   */
+/* this function, it is assumed that the owner (if there is one, as shown   */
+/* by nat_me) is no longer interested in it.                                */
+/* ------------------------------------------------------------------------ */
+void
+ipf_nat_setpending(softc, nat)
+	ipf_main_softc_t *softc;
+	nat_t *nat;
+{
+	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
+	ipftq_t *oifq;
+
+	oifq = nat->nat_tqe.tqe_ifq;
+	if (oifq != NULL)
+		ipf_movequeue(softc->ipf_ticks, &nat->nat_tqe, oifq,
+			      &softn->ipf_nat_pending);
+	else
+		ipf_queueappend(softc->ipf_ticks, &nat->nat_tqe,
+				&softn->ipf_nat_pending, nat);
+
+	if (nat->nat_me != NULL) {
+		*nat->nat_me = NULL;
+		nat->nat_me = NULL;
+		nat->nat_ref--;
+		ASSERT(nat->nat_ref >= 0);
+	}
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    nat_newrewrite                                              */
+/* Returns:     int - -1 == error, 0 == success (no move), 1 == success and */
+/*                    allow rule to be moved if IPN_ROUNDR is set.          */
+/* Parameters:  fin(I) - pointer to packet information                      */
+/*              nat(I) - pointer to NAT entry                               */
+/*              ni(I)  - pointer to structure with misc. information needed */
+/*                       to create new NAT entry.                           */
+/* Write Lock:  ipf_nat                                                     */
+/*                                                                          */
+/* This function is responsible for setting up an active NAT session where  */
+/* we are changing both the source and destination parameters at the same   */
+/* time.  The loop in here works differently to elsewhere - each iteration  */
+/* is responsible for changing a single parameter that can be incremented.  */
+/* So one pass may increase the source IP#, next source port, next dest. IP#*/
+/* and the last destination port for a total of 4 iterations to try each.   */
+/* This is done to try and exhaustively use the translation space available.*/
+/* ------------------------------------------------------------------------ */
+static int
+ipf_nat_newrewrite(fin, nat, nai)
+	fr_info_t *fin;
+	nat_t *nat;
+	natinfo_t *nai;
+{
+	int src_search = 1;
+	int dst_search = 1;
+	fr_info_t frnat;
+	u_32_t flags;
+	u_short swap;
+	ipnat_t *np;
+	nat_t *natl;
+	int l = 0;
+	int changed;
+
+	natl = NULL;
+	changed = -1;
+	np = nai->nai_np;
+	flags = nat->nat_flags;
+	bcopy((char *)fin, (char *)&frnat, sizeof(*fin));
+
+	nat->nat_hm = NULL;
+
+	do {
+		changed = -1;
+		/* TRACE (l, src_search, dst_search, np) */
+
+		if ((src_search == 0) && (np->in_spnext == 0) &&
+		    (dst_search == 0) && (np->in_dpnext == 0)) {
+			if (l > 0)
+				return -1;
+		}
+
+		/*
+		 * Find a new source address
+		 */
+		if (ipf_nat_nextaddr(fin, &np->in_nsrc, &frnat.fin_saddr,
+				     &frnat.fin_saddr) == -1) {
+			return -1;
+		}
+
+		if ((np->in_nsrcaddr == 0) && (np->in_nsrcmsk == 0xffffffff)) {
+			src_search = 0;
+			if (np->in_stepnext == 0)
+				np->in_stepnext = 1;
+
+		} else if ((np->in_nsrcaddr == 0) && (np->in_nsrcmsk == 0)) {
+			src_search = 0;
+			if (np->in_stepnext == 0)
+				np->in_stepnext = 1;
+
+		} else if (np->in_nsrcmsk == 0xffffffff) {
+			src_search = 0;
+			if (np->in_stepnext == 0)
+				np->in_stepnext = 1;
+
+		} else if (np->in_nsrcmsk != 0xffffffff) {
+			if (np->in_stepnext == 0 && changed == -1) {
+				np->in_snip++;
+				np->in_stepnext++;
+				changed = 0;
+			}
+		}
+
+		if ((flags & IPN_TCPUDPICMP) != 0) {
+			if (np->in_spnext != 0)
+				frnat.fin_data[0] = np->in_spnext;
+
+			/*
+			 * Standard port translation.  Select next port.
+			 */
+			if ((flags & IPN_FIXEDSPORT) != 0) {
+				np->in_stepnext = 2;
+			} else if ((np->in_stepnext == 1) &&
+				   (changed == -1) && (natl != NULL)) {
+				np->in_spnext++;
+				np->in_stepnext++;
+				changed = 1;
+				if (np->in_spnext > np->in_spmax)
+					np->in_spnext = np->in_spmin;
+			}
+		} else {
+			np->in_stepnext = 2;
+		}
+		np->in_stepnext &= 0x3;
+
+		/*
+		 * Find a new destination address
+		 */
+		/* TRACE (fin, np, l, frnat) */
+
+		if (ipf_nat_nextaddr(fin, &np->in_ndst, &frnat.fin_daddr,
+				     &frnat.fin_daddr) == -1)
+			return -1;
+		if ((np->in_ndstaddr == 0) && (np->in_ndstmsk == 0xffffffff)) {
+			dst_search = 0;
+			if (np->in_stepnext == 2)
+				np->in_stepnext = 3;
+
+		} else if ((np->in_ndstaddr == 0) && (np->in_ndstmsk == 0)) {
+			dst_search = 0;
+			if (np->in_stepnext == 2)
+				np->in_stepnext = 3;
+
+		} else if (np->in_ndstmsk == 0xffffffff) {
+			dst_search = 0;
+			if (np->in_stepnext == 2)
+				np->in_stepnext = 3;
+
+		} else if (np->in_ndstmsk != 0xffffffff) {
+			if ((np->in_stepnext == 2) && (changed == -1) &&
+			    (natl != NULL)) {
+				changed = 2;
+				np->in_stepnext++;
+				np->in_dnip++;
+			}
+		}
+
+		if ((flags & IPN_TCPUDPICMP) != 0) {
+			if (np->in_dpnext != 0)
+				frnat.fin_data[1] = np->in_dpnext;
+
+			/*
+			 * Standard port translation.  Select next port.
+			 */
+			if ((flags & IPN_FIXEDDPORT) != 0) {
+				np->in_stepnext = 0;
+			} else if (np->in_stepnext == 3 && changed == -1) {
+				np->in_dpnext++;
+				np->in_stepnext++;
+				changed = 3;
+				if (np->in_dpnext > np->in_dpmax)
+					np->in_dpnext = np->in_dpmin;
+			}
+		} else {
+			if (np->in_stepnext == 3)
+				np->in_stepnext = 0;
+		}
+
+		/* TRACE (frnat) */
+
+		/*
+		 * Here we do a lookup of the connection as seen from
+		 * the outside.  If an IP# pair already exists, try
+		 * again.  So if you have A->B becomes C->B, you can
+		 * also have D->E become C->E but not D->B causing
+		 * another C->B.  Also take protocol and ports into
+		 * account when determining whether a pre-existing
+		 * NAT setup will cause an external conflict where
+		 * this is appropriate.
+		 *
+		 * fin_data[] is swapped around because we are doing a
+		 * lookup of the packet is if it were moving in the opposite
+		 * direction of the one we are working with now.
+		 */
+		if (flags & IPN_TCPUDP) {
+			swap = frnat.fin_data[0];
+			frnat.fin_data[0] = frnat.fin_data[1];
+			frnat.fin_data[1] = swap;
+		}
+		if (fin->fin_out == 1) {
+			natl = ipf_nat_inlookup(&frnat,
+						flags & ~(SI_WILDP|NAT_SEARCH),
+						(u_int)frnat.fin_p,
+						frnat.fin_dst, frnat.fin_src);
+
+		} else {
+			natl = ipf_nat_outlookup(&frnat,
+						 flags & ~(SI_WILDP|NAT_SEARCH),
+						 (u_int)frnat.fin_p,
+						 frnat.fin_dst, frnat.fin_src);
+		}
+		if (flags & IPN_TCPUDP) {
+			swap = frnat.fin_data[0];
+			frnat.fin_data[0] = frnat.fin_data[1];
+			frnat.fin_data[1] = swap;
+		}
+
+		/* TRACE natl, in_stepnext, l */
+
+		if ((natl != NULL) && (l > 8))	/* XXX 8 is arbitrary */
+			return -1;
+
+		np->in_stepnext &= 0x3;
+
+		l++;
+		changed = -1;
+	} while (natl != NULL);
+
+	nat->nat_osrcip = fin->fin_src;
+	nat->nat_odstip = fin->fin_dst;
+	nat->nat_nsrcip = frnat.fin_src;
+	nat->nat_ndstip = frnat.fin_dst;
+
+	if ((flags & IPN_TCPUDP) != 0) {
+		nat->nat_osport = htons(fin->fin_data[0]);
+		nat->nat_odport = htons(fin->fin_data[1]);
+		nat->nat_nsport = htons(frnat.fin_data[0]);
+		nat->nat_ndport = htons(frnat.fin_data[1]);
+	} else if ((flags & IPN_ICMPQUERY) != 0) {
+		nat->nat_oicmpid = fin->fin_data[1];
+		nat->nat_nicmpid = frnat.fin_data[1];
+	}
+
+	return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    nat_newdivert                                               */
+/* Returns:     int - -1 == error, 0 == success                             */
+/* Parameters:  fin(I) - pointer to packet information                      */
+/*              nat(I) - pointer to NAT entry                               */
+/*              ni(I)  - pointer to structure with misc. information needed */
+/*                       to create new NAT entry.                           */
+/* Write Lock:  ipf_nat                                                     */
+/*                                                                          */
+/* Create a new NAT  divert session as defined by the NAT rule.  This is    */
+/* somewhat different to other NAT session creation routines because we     */
+/* do not iterate through either port numbers or IP addresses, searching    */
+/* for a unique mapping, however, a complimentary duplicate check is made.  */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_nat_newdivert(fin, nat, nai)
+	fr_info_t *fin;
+	nat_t *nat;
+	natinfo_t *nai;
+{
+	ipf_main_softc_t *softc = fin->fin_main_soft;
+	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
+	fr_info_t frnat;
+	ipnat_t *np;
+	nat_t *natl;
+	int p;
+
+	np = nai->nai_np;
+	bcopy((char *)fin, (char *)&frnat, sizeof(*fin));
+
+	nat->nat_pr[0] = 0;
+	nat->nat_osrcaddr = fin->fin_saddr;
+	nat->nat_odstaddr = fin->fin_daddr;
+	frnat.fin_saddr = htonl(np->in_snip);
+	frnat.fin_daddr = htonl(np->in_dnip);
+	if ((nat->nat_flags & IPN_TCPUDP) != 0) {
+		nat->nat_osport = htons(fin->fin_data[0]);
+		nat->nat_odport = htons(fin->fin_data[1]);
+	} else if ((nat->nat_flags & IPN_ICMPQUERY) != 0) {
+		nat->nat_oicmpid = fin->fin_data[1];
+	}
+
+	if (np->in_redir & NAT_DIVERTUDP) {
+		frnat.fin_data[0] = np->in_spnext;
+		frnat.fin_data[1] = np->in_dpnext;
+		frnat.fin_flx |= FI_TCPUDP;
+		p = IPPROTO_UDP;
+	} else {
+		frnat.fin_flx &= ~FI_TCPUDP;
+		p = IPPROTO_IPIP;
+	}
+
+	if (fin->fin_out == 1) {
+		natl = ipf_nat_inlookup(&frnat, 0, p,
+					frnat.fin_dst, frnat.fin_src);
+
+	} else {
+		natl = ipf_nat_outlookup(&frnat, 0, p,
+					 frnat.fin_dst, frnat.fin_src);
+	}
+
+	if (natl != NULL) {
+		NBUMPSIDED(fin->fin_out, ns_divert_exist);
+		return -1;
+	}
+
+	nat->nat_nsrcaddr = frnat.fin_saddr;
+	nat->nat_ndstaddr = frnat.fin_daddr;
+	if ((nat->nat_flags & IPN_TCPUDP) != 0) {
+		nat->nat_nsport = htons(frnat.fin_data[0]);
+		nat->nat_ndport = htons(frnat.fin_data[1]);
+	} else if ((nat->nat_flags & IPN_ICMPQUERY) != 0) {
+		nat->nat_nicmpid = frnat.fin_data[1];
+	}
+
+	nat->nat_pr[fin->fin_out] = fin->fin_p;
+	nat->nat_pr[1 - fin->fin_out] = p;
+
+	if (np->in_redir & NAT_REDIRECT)
+		nat->nat_dir = NAT_DIVERTIN;
+	else
+		nat->nat_dir = NAT_DIVERTOUT;
+
+	return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    nat_builddivertmp                                           */
+/* Returns:     int - -1 == error, 0 == success                             */
+/* Parameters:  softn(I) - pointer to NAT context structure                 */
+/*              np(I)    - pointer to a NAT rule                            */
+/*                                                                          */
+/* For divert rules, a skeleton packet representing what will be prepended  */
+/* to the real packet is created.  Even though we don't have the full       */
+/* packet here, a checksum is calculated that we update later when we       */
+/* fill in the final details.  At present a 0 checksum for UDP is being set */
+/* here because it is expected that divert will be used for localhost.      */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_nat_builddivertmp(softn, np)
+	ipf_nat_softc_t *softn;
+	ipnat_t *np;
+{
+	udphdr_t *uh;
+	size_t len;
+	ip_t *ip;
+
+	if ((np->in_redir & NAT_DIVERTUDP) != 0)
+		len = sizeof(ip_t) + sizeof(udphdr_t);
+	else
+		len = sizeof(ip_t);
+
+	ALLOC_MB_T(np->in_divmp, len);
+	if (np->in_divmp == NULL) {
+		NBUMPD(ipf_nat_stats, ns_divert_build);
+		return -1;
+	}
+
+	/*
+	 * First, the header to get the packet diverted to the new destination
+	 */
+	ip = MTOD(np->in_divmp, ip_t *);
+	IP_V_A(ip, 4);
+	IP_HL_A(ip, 5);
+	ip->ip_tos = 0;
+	if ((np->in_redir & NAT_DIVERTUDP) != 0)
+		ip->ip_p = IPPROTO_UDP;
+	else
+		ip->ip_p = IPPROTO_IPIP;
+	ip->ip_ttl = 255;
+	ip->ip_off = 0;
+	ip->ip_sum = 0;
+	ip->ip_len = htons(len);
+	ip->ip_id = 0;
+	ip->ip_src.s_addr = htonl(np->in_snip);
+	ip->ip_dst.s_addr = htonl(np->in_dnip);
+	ip->ip_sum = ipf_cksum((u_short *)ip, sizeof(*ip));
+
+	if (np->in_redir & NAT_DIVERTUDP) {
+		uh = (udphdr_t *)(ip + 1);
+		uh->uh_sum = 0;
+		uh->uh_ulen = 8;
+		uh->uh_sport = htons(np->in_spnext);
+		uh->uh_dport = htons(np->in_dpnext);
+	}
+
+	return 0;
+}
+
+
+#define	MINDECAP	(sizeof(ip_t) + sizeof(udphdr_t) + sizeof(ip_t))
+
+/* ------------------------------------------------------------------------ */
+/* Function:    nat_decap                                                   */
+/* Returns:     int - -1 == error, 0 == success                             */
+/* Parameters:  fin(I) - pointer to packet information                      */
+/*              nat(I) - pointer to current NAT session                     */
+/*                                                                          */
+/* This function is responsible for undoing a packet's encapsulation in the */
+/* reverse of an encap/divert rule.  After removing the outer encapsulation */
+/* it is necessary to call ipf_makefrip() again so that the contents of 'fin'*/
+/* match the "new" packet as it may still be used by IPFilter elsewhere.    */
+/* We use "dir" here as the basis for some of the expectations about the    */
+/* outer header.  If we return an error, the goal is to leave the original  */
+/* packet information undisturbed - this falls short at the end where we'd  */
+/* need to back a backup copy of "fin" - expensive.                         */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_nat_decap(fin, nat)
+	fr_info_t *fin;
+	nat_t *nat;
+{
+	ipf_main_softc_t *softc = fin->fin_main_soft;
+	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
+	char *hdr;
+	int hlen;
+	int skip;
+	mb_t *m;
+
+	if ((fin->fin_flx & FI_ICMPERR) != 0) {
+		/*
+		 * ICMP packets don't get decapsulated, instead what we need
+		 * to do is change the ICMP reply from including (in the data
+		 * portion for errors) the encapsulated packet that we sent
+		 * out to something that resembles the original packet prior
+		 * to encapsulation.  This isn't done here - all we're doing
+		 * here is changing the outer address to ensure that it gets
+		 * targetted back to the correct system.
+		 */
+
+		if (nat->nat_dir & NAT_OUTBOUND) {
+			u_32_t sum1, sum2, sumd;
+
+			sum1 = ntohl(fin->fin_daddr);
+			sum2 = ntohl(nat->nat_osrcaddr);
+			CALC_SUMD(sum1, sum2, sumd);
+			fin->fin_ip->ip_dst = nat->nat_osrcip;
+			fin->fin_daddr = nat->nat_osrcaddr;
+#if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) || \
+     defined(__osf__) || defined(linux)
+			ipf_fix_outcksum(0, &fin->fin_ip->ip_sum, sumd, 0);
+#endif
+		}
+		return 0;
+	}
+
+	m = fin->fin_m;
+	skip = fin->fin_hlen;
+
+	switch (nat->nat_dir)
+	{
+	case NAT_DIVERTIN :
+	case NAT_DIVERTOUT :
+		if (fin->fin_plen < MINDECAP)
+			return -1;
+		skip += sizeof(udphdr_t);
+		break;
+
+	case NAT_ENCAPIN :
+	case NAT_ENCAPOUT :
+		if (fin->fin_plen < (skip + sizeof(ip_t)))
+			return -1;
+		break;
+	default :
+		return -1;
+		/* NOTREACHED */
+	}
+
+	/*
+	 * The aim here is to keep the original packet details in "fin" for
+	 * as long as possible so that returning with an error is for the
+	 * original packet and there is little undoing work to do.
+	 */
+	if (M_LEN(m) < skip + sizeof(ip_t)) {
+		if (ipf_pr_pullup(fin, skip + sizeof(ip_t)) == -1)
+			return -1;
+	}
+
+	hdr = MTOD(fin->fin_m, char *);
+	fin->fin_ip = (ip_t *)(hdr + skip);
+	hlen = IP_HL(fin->fin_ip) << 2;
+
+	if (ipf_pr_pullup(fin, skip + hlen) == -1) {
+		NBUMPSIDED(fin->fin_out, ns_decap_pullup);
+		return -1;
+	}
+
+	fin->fin_hlen = hlen;
+	fin->fin_dlen -= skip;
+	fin->fin_plen -= skip;
+	fin->fin_ipoff += skip;
+
+	if (ipf_makefrip(hlen, (ip_t *)hdr, fin) == -1) {
+		NBUMPSIDED(fin->fin_out, ns_decap_bad);
+		return -1;
+	}
+
+	return skip;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    nat_nextaddr                                                */
+/* Returns:     int - -1 == bad input (no new address),                     */
+/*                     0 == success and dst has new address                 */
+/* Parameters:  fin(I) - pointer to packet information                      */
+/*              na(I)  - how to generate new address                        */
+/*              old(I) - original address being replaced                    */
+/*              dst(O) - where to put the new address                       */
+/* Write Lock:  ipf_nat                                                     */
+/*                                                                          */
+/* This function uses the contents of the "na" structure, in combination    */
+/* with "old" to produce a new address to store in "dst".  Not all of the   */
+/* possible uses of "na" will result in a new address.                      */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_nat_nextaddr(fin, na, old, dst)
+	fr_info_t *fin;
+	nat_addr_t *na;
+	u_32_t *old, *dst;
+{
+	ipf_main_softc_t *softc = fin->fin_main_soft;
+	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
+	u_32_t amin, amax, new;
+	i6addr_t newip;
+	int error;
+
+	new = 0;
+	amin = na->na_addr[0].in4.s_addr;
+
+	switch (na->na_atype)
+	{
+	case FRI_RANGE :
+		amax = na->na_addr[1].in4.s_addr;
+		break;
+
+	case FRI_NETMASKED :
+	case FRI_DYNAMIC :
+	case FRI_NORMAL :
+		/*
+		 * Compute the maximum address by adding the inverse of the
+		 * netmask to the minimum address.
+		 */
+		amax = ~na->na_addr[1].in4.s_addr;
+		amax |= amin;
+		break;
+
+	case FRI_LOOKUP :
+		break;
+
+	case FRI_BROADCAST :
+	case FRI_PEERADDR :
+	case FRI_NETWORK :
+	default :
+		return -1;
+	}
+
+	error = -1;
+
+	if (na->na_atype == FRI_LOOKUP) {
+		if (na->na_type == IPLT_DSTLIST) {
+			error = ipf_dstlist_select_node(fin, na->na_ptr, dst,
+							NULL);
+		} else {
+			NBUMPSIDE(fin->fin_out, ns_badnextaddr);
+		}
+
+	} else if (na->na_atype == IPLT_NONE) {
+		/*
+		 * 0/0 as the new address means leave it alone.
+		 */
+		if (na->na_addr[0].in4.s_addr == 0 &&
+		    na->na_addr[1].in4.s_addr == 0) {
+			new = *old;
+
+		/*
+		 * 0/32 means get the interface's address
+		 */
+		} else if (na->na_addr[0].in4.s_addr == 0 &&
+			   na->na_addr[1].in4.s_addr == 0xffffffff) {
+			if (ipf_ifpaddr(softc, 4, na->na_atype,
+					fin->fin_ifp, &newip, NULL) == -1) {
+				NBUMPSIDED(fin->fin_out, ns_ifpaddrfail);
+				return -1;
+			}
+			new = newip.in4.s_addr;
+		} else {
+			new = htonl(na->na_nextip);
+		}
+		*dst = new;
+		error = 0;
+
+	} else {
+		NBUMPSIDE(fin->fin_out, ns_badnextaddr);
+	}
+
+	return error;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    nat_nextaddrinit                                            */
+/* Returns:     int - 0 == success, else error number                       */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              na(I)      - NAT address information for generating new addr*/
+/*              initial(I) - flag indicating if it is the first call for    */
+/*                           this "na" structure.                           */
+/*              ifp(I)     - network interface to derive address            */
+/*                           information from.                              */
+/*                                                                          */
+/* This function is expected to be called in two scenarious: when a new NAT */
+/* rule is loaded into the kernel and when the list of NAT rules is sync'd  */
+/* up with the valid network interfaces (possibly due to them changing.)    */
+/* To distinguish between these, the "initial" parameter is used.  If it is */
+/* 1 then this indicates the rule has just been reloaded and 0 for when we  */
+/* are updating information.  This difference is important because in       */
+/* instances where we are not updating address information associated with  */
+/* a network interface, we don't want to disturb what the "next" address to */
+/* come out of ipf_nat_nextaddr() will be.                                  */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_nat_nextaddrinit(softc, base, na, initial, ifp)
+	ipf_main_softc_t *softc;
+	char *base;
+	nat_addr_t *na;
+	int initial;
+	void *ifp;
+{
+
+	switch (na->na_atype)
+	{
+	case FRI_LOOKUP :
+		if (na->na_subtype == 0) {
+			na->na_ptr = ipf_lookup_res_num(softc, IPL_LOGNAT,
+							na->na_type,
+							na->na_num,
+							&na->na_func);
+		} else if (na->na_subtype == 1) {
+			na->na_ptr = ipf_lookup_res_name(softc, IPL_LOGNAT,
+							 na->na_type,
+							 base + na->na_num,
+							 &na->na_func);
+		}
+		if (na->na_func == NULL) {
+			IPFERROR(60060);
+			return ESRCH;
+		}
+		if (na->na_ptr == NULL) {
+			IPFERROR(60056);
+			return ESRCH;
+		}
+		break;
+
+	case FRI_DYNAMIC :
+	case FRI_BROADCAST :
+	case FRI_NETWORK :
+	case FRI_NETMASKED :
+	case FRI_PEERADDR :
+		if (ifp != NULL)
+			(void )ipf_ifpaddr(softc, 4, na->na_atype, ifp,
+					   &na->na_addr[0], &na->na_addr[1]);
+		break;
+
+	case FRI_SPLIT :
+	case FRI_RANGE :
+		if (initial)
+			na->na_nextip = ntohl(na->na_addr[0].in4.s_addr);
+		break;
+
+	case FRI_NONE :
+		na->na_addr[0].in4.s_addr &= na->na_addr[1].in4.s_addr;
+		return 0;
+
+	case FRI_NORMAL :
+		na->na_addr[0].in4.s_addr &= na->na_addr[1].in4.s_addr;
+		break;
+
+	default :
+		IPFERROR(60054);
+		return EINVAL;
+	}
+
+	if (initial && (na->na_atype == FRI_NORMAL)) {
+		if (na->na_addr[0].in4.s_addr == 0) {
+			if ((na->na_addr[1].in4.s_addr == 0xffffffff) ||
+			    (na->na_addr[1].in4.s_addr == 0)) {
+				return 0;
+			}
+		}
+
+		if (na->na_addr[1].in4.s_addr == 0xffffffff) {
+			na->na_nextip = ntohl(na->na_addr[0].in4.s_addr);
+		} else {
+			na->na_nextip = ntohl(na->na_addr[0].in4.s_addr) + 1;
+		}
+	}
+
+	return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_nat_matchflush                                          */
+/* Returns:     int - -1 == error, 0 == success                             */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              softn(I) - pointer to NAT context structure                 */
+/*              nat(I)   - pointer to current NAT session                   */
+/*                                                                          */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_nat_matchflush(softc, softn, data)
+	ipf_main_softc_t *softc;
+	ipf_nat_softc_t *softn;
+	caddr_t data;
+{
+	int *array, flushed, error;
+	nat_t *nat, *natnext;
+	ipfobj_t obj;
+
+	error = ipf_matcharray_load(softc, data, &obj, &array);
+	if (error != 0)
+		return error;
+
+	flushed = 0;
+
+	for (nat = softn->ipf_nat_instances; nat != NULL; nat = natnext) {
+		natnext = nat->nat_next;
+		if (ipf_nat_matcharray(nat, array, softc->ipf_ticks) == 0) {
+			ipf_nat_delete(softc, nat, NL_FLUSH);
+			flushed++;
+		}
+	}
+
+	obj.ipfo_retval = flushed;
+	error = BCOPYOUT(&obj, data, sizeof(obj));
+
+	KFREES(array, array[0] * sizeof(*array));
+
+	return error;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_nat_matcharray                                          */
+/* Returns:     int - -1 == error, 0 == success                             */
+/* Parameters:  fin(I) - pointer to packet information                      */
+/*              nat(I) - pointer to current NAT session                     */
+/*                                                                          */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_nat_matcharray(nat, array, ticks)
+	nat_t *nat;
+	int *array;
+	u_long ticks;
+{
+	int i, n, *x, e, p;
+
+	e = 0;
+	n = array[0];
+	x = array + 1;
+
+	for (; n > 0; x += 3 + x[2]) {
+		if (x[0] == IPF_EXP_END)
+			break;
+		e = 0;
+
+		n -= x[2] + 3;
+		if (n < 0)
+			break;
+
+		p = x[0] >> 16;
+		if (p != 0 && p != nat->nat_pr[1])
+			break;
+
+		switch (x[0])
+		{
+		case IPF_EXP_IP_PR :
+			for (i = 0; !e && i < x[2]; i++) {
+				e |= (nat->nat_pr[1] == x[i + 3]);
+			}
+			break;
+
+		case IPF_EXP_IP_SRCADDR :
+			if (nat->nat_v[0] == 4) {
+				for (i = 0; !e && i < x[2]; i++) {
+					e |= ((nat->nat_osrcaddr & x[i + 4]) ==
+					      x[i + 3]);
+				}
+			}
+			if (nat->nat_v[1] == 4) {
+				for (i = 0; !e && i < x[2]; i++) {
+					e |= ((nat->nat_nsrcaddr & x[i + 4]) ==
+					      x[i + 3]);
+				}
+			}
+			break;
+
+		case IPF_EXP_IP_DSTADDR :
+			if (nat->nat_v[0] == 4) {
+				for (i = 0; !e && i < x[2]; i++) {
+					e |= ((nat->nat_odstaddr & x[i + 4]) ==
+					      x[i + 3]);
+				}
+			}
+			if (nat->nat_v[1] == 4) {
+				for (i = 0; !e && i < x[2]; i++) {
+					e |= ((nat->nat_ndstaddr & x[i + 4]) ==
+					      x[i + 3]);
+				}
+			}
+			break;
+
+		case IPF_EXP_IP_ADDR :
+			for (i = 0; !e && i < x[2]; i++) {
+				if (nat->nat_v[0] == 4) {
+					e |= ((nat->nat_osrcaddr & x[i + 4]) ==
+					      x[i + 3]);
+				}
+				if (nat->nat_v[1] == 4) {
+					e |= ((nat->nat_nsrcaddr & x[i + 4]) ==
+					      x[i + 3]);
+				}
+				if (nat->nat_v[0] == 4) {
+					e |= ((nat->nat_odstaddr & x[i + 4]) ==
+					      x[i + 3]);
+				}
+				if (nat->nat_v[1] == 4) {
+					e |= ((nat->nat_ndstaddr & x[i + 4]) ==
+					      x[i + 3]);
+				}
+			}
+			break;
+
+#ifdef USE_INET6
+		case IPF_EXP_IP6_SRCADDR :
+			if (nat->nat_v[0] == 6) {
+				for (i = 0; !e && i < x[3]; i++) {
+					e |= IP6_MASKEQ(&nat->nat_osrc6,
+							x + i + 7, x + i + 3);
+				}
+			}
+			if (nat->nat_v[1] == 6) {
+				for (i = 0; !e && i < x[3]; i++) {
+					e |= IP6_MASKEQ(&nat->nat_nsrc6,
+							x + i + 7, x + i + 3);
+				}
+			}
+			break;
+
+		case IPF_EXP_IP6_DSTADDR :
+			if (nat->nat_v[0] == 6) {
+				for (i = 0; !e && i < x[3]; i++) {
+					e |= IP6_MASKEQ(&nat->nat_odst6,
+							x + i + 7,
+							x + i + 3);
+				}
+			}
+			if (nat->nat_v[1] == 6) {
+				for (i = 0; !e && i < x[3]; i++) {
+					e |= IP6_MASKEQ(&nat->nat_ndst6,
+							x + i + 7,
+							x + i + 3);
+				}
+			}
+			break;
+
+		case IPF_EXP_IP6_ADDR :
+			for (i = 0; !e && i < x[3]; i++) {
+				if (nat->nat_v[0] == 6) {
+					e |= IP6_MASKEQ(&nat->nat_osrc6,
+							x + i + 7,
+							x + i + 3);
+				}
+				if (nat->nat_v[0] == 6) {
+					e |= IP6_MASKEQ(&nat->nat_odst6,
+							x + i + 7,
+							x + i + 3);
+				}
+				if (nat->nat_v[1] == 6) {
+					e |= IP6_MASKEQ(&nat->nat_nsrc6,
+							x + i + 7,
+							x + i + 3);
+				}
+				if (nat->nat_v[1] == 6) {
+					e |= IP6_MASKEQ(&nat->nat_ndst6,
+							x + i + 7,
+							x + i + 3);
+				}
+			}
+			break;
+#endif
+
+		case IPF_EXP_UDP_PORT :
+		case IPF_EXP_TCP_PORT :
+			for (i = 0; !e && i < x[2]; i++) {
+				e |= (nat->nat_nsport == x[i + 3]) ||
+				     (nat->nat_ndport == x[i + 3]);
+			}
+			break;
+
+		case IPF_EXP_UDP_SPORT :
+		case IPF_EXP_TCP_SPORT :
+			for (i = 0; !e && i < x[2]; i++) {
+				e |= (nat->nat_nsport == x[i + 3]);
+			}
+			break;
+
+		case IPF_EXP_UDP_DPORT :
+		case IPF_EXP_TCP_DPORT :
+			for (i = 0; !e && i < x[2]; i++) {
+				e |= (nat->nat_ndport == x[i + 3]);
+			}
+			break;
+
+		case IPF_EXP_TCP_STATE :
+			for (i = 0; !e && i < x[2]; i++) {
+				e |= (nat->nat_tcpstate[0] == x[i + 3]) ||
+				     (nat->nat_tcpstate[1] == x[i + 3]);
+			}
+			break;
+
+		case IPF_EXP_IDLE_GT :
+			e |= (ticks - nat->nat_touched > x[3]);
+			break;
+		}
+		e ^= x[1];
+
+		if (!e)
+			break;
+	}
+
+	return e;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_nat_gettable                                            */
 /* Returns:     int     - 0 = success, else error                           */
-/* Parameters:  data(I) - pointer to ioctl data                             */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              softn(I) - pointer to NAT context structure                 */
+/*              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;
+static int
+ipf_nat_gettable(softc, softn, data)
+	ipf_main_softc_t *softc;
+	ipf_nat_softc_t *softn;
+	char *data;
 {
 	ipftable_t table;
 	int error;
 
-	error = fr_inobj(data, &table, IPFOBJ_GTABLE);
+	error = ipf_inobj(softc, data, NULL, &table, IPFOBJ_GTABLE);
 	if (error != 0)
 		return error;
 
@@ -5473,21 +7959,628 @@
 	switch (table.ita_type)
 	{
 	case IPFTABLE_BUCKETS_NATIN :
-		error = COPYOUT(nat_stats.ns_bucketlen[0], table.ita_table, 
-				ipf_nattable_sz * sizeof(u_long));
+		error = COPYOUT(softn->ipf_nat_stats.ns_side[0].ns_bucketlen,
+				table.ita_table,
+				softn->ipf_nat_table_sz * sizeof(u_int));
 		break;
 
 	case IPFTABLE_BUCKETS_NATOUT :
-		error = COPYOUT(nat_stats.ns_bucketlen[1], table.ita_table, 
-				ipf_nattable_sz * sizeof(u_long));
+		error = COPYOUT(softn->ipf_nat_stats.ns_side[1].ns_bucketlen,
+				table.ita_table,
+				softn->ipf_nat_table_sz * sizeof(u_int));
 		break;
 
 	default :
+		IPFERROR(60058);
 		return EINVAL;
 	}
 
 	if (error != 0) {
+		IPFERROR(60059);
 		error = EFAULT;
 	}
 	return error;
 }
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_nat_settimeout                                          */
+/* Returns:     int  - 0 = success, else failure			    */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              t(I) - pointer to tunable                                   */
+/*              p(I) - pointer to new tuning data                           */
+/*                                                                          */
+/* Apply the timeout change to the NAT timeout queues.                      */
+/* ------------------------------------------------------------------------ */
+int
+ipf_nat_settimeout(softc, t, p)
+	struct ipf_main_softc_s *softc;
+	ipftuneable_t *t;
+	ipftuneval_t *p;
+{
+	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
+
+	if (!strncmp(t->ipft_name, "tcp_", 4))
+		return ipf_settimeout_tcp(t, p, softn->ipf_nat_tcptq);
+
+	if (!strcmp(t->ipft_name, "udp_timeout")) {
+		ipf_apply_timeout(&softn->ipf_nat_udptq, p->ipftu_int);
+	} else if (!strcmp(t->ipft_name, "udp_ack_timeout")) {
+		ipf_apply_timeout(&softn->ipf_nat_udpacktq, p->ipftu_int);
+	} else if (!strcmp(t->ipft_name, "icmp_timeout")) {
+		ipf_apply_timeout(&softn->ipf_nat_icmptq, p->ipftu_int);
+	} else if (!strcmp(t->ipft_name, "icmp_ack_timeout")) {
+		ipf_apply_timeout(&softn->ipf_nat_icmpacktq, p->ipftu_int);
+	} else if (!strcmp(t->ipft_name, "ip_timeout")) {
+		ipf_apply_timeout(&softn->ipf_nat_iptq, p->ipftu_int);
+	} else {
+		IPFERROR(60062);
+		return ESRCH;
+	}
+	return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_nat_rehash                                              */
+/* Returns:     int  - 0 = success, else failure			    */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              t(I) - pointer to tunable                                   */
+/*              p(I) - pointer to new tuning data                           */
+/*                                                                          */
+/* To change the size of the basic NAT table, we need to first allocate the */
+/* new tables (lest it fails and we've got nowhere to store all of the NAT  */
+/* sessions currently active) and then walk through the entire list and     */
+/* insert them into the table.  There are two tables here: an inbound one   */
+/* and an outbound one.  Each NAT entry goes into each table once.          */
+/* ------------------------------------------------------------------------ */
+int
+ipf_nat_rehash(softc, t, p)
+	ipf_main_softc_t *softc;
+	ipftuneable_t *t;
+	ipftuneval_t *p;
+{
+	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
+	nat_t **newtab[2], *nat, **natp;
+	u_int *bucketlens[2];
+	u_int maxbucket;
+	u_int newsize;
+	int error;
+	u_int hv;
+	int i;
+
+	newsize = p->ipftu_int;
+	/*
+	 * In case there is nothing to do...
+	 */
+	if (newsize == softn->ipf_nat_table_sz)
+		return 0;
+
+	newtab[0] = NULL;
+	newtab[1] = NULL;
+	bucketlens[0] = NULL;
+	bucketlens[1] = NULL;
+	/*
+	 * 4 tables depend on the NAT table size: the inbound looking table,
+	 * the outbound lookup table and the hash chain length for each.
+	 */
+	KMALLOCS(newtab[0], nat_t **, newsize * sizeof(nat_t *));
+	if (newtab == NULL) {
+		error = 60063;
+		goto badrehash;
+	}
+
+	KMALLOCS(newtab[1], nat_t **, newsize * sizeof(nat_t *));
+	if (newtab == NULL) {
+		error = 60064;
+		goto badrehash;
+	}
+
+	KMALLOCS(bucketlens[0], u_int *, newsize * sizeof(u_int));
+	if (bucketlens[0] == NULL) {
+		error = 60065;
+		goto badrehash;
+	}
+
+	KMALLOCS(bucketlens[1], u_int *, newsize * sizeof(u_int));
+	if (bucketlens[1] == NULL) {
+		error = 60066;
+		goto badrehash;
+	}
+
+	/*
+	 * Recalculate the maximum length based on the new size.
+	 */
+	for (maxbucket = 0, i = newsize; i > 0; i >>= 1)
+		maxbucket++;
+	maxbucket *= 2;
+
+	bzero((char *)newtab[0], newsize * sizeof(nat_t *));
+	bzero((char *)newtab[1], newsize * sizeof(nat_t *));
+	bzero((char *)bucketlens[0], newsize * sizeof(u_int));
+	bzero((char *)bucketlens[1], newsize * sizeof(u_int));
+
+	WRITE_ENTER(&softc->ipf_nat);
+
+	if (softn->ipf_nat_table[0] != NULL) {
+		KFREES(softn->ipf_nat_table[0],
+		       softn->ipf_nat_table_sz *
+		       sizeof(*softn->ipf_nat_table[0]));
+	}
+	softn->ipf_nat_table[0] = newtab[0];
+
+	if (softn->ipf_nat_table[1] != NULL) {
+		KFREES(softn->ipf_nat_table[1],
+		       softn->ipf_nat_table_sz *
+		       sizeof(*softn->ipf_nat_table[1]));
+	}
+	softn->ipf_nat_table[1] = newtab[1];
+
+	if (softn->ipf_nat_stats.ns_side[0].ns_bucketlen != NULL) {
+		KFREES(softn->ipf_nat_stats.ns_side[0].ns_bucketlen,
+		       softn->ipf_nat_table_sz * sizeof(u_int));
+	}
+	softn->ipf_nat_stats.ns_side[0].ns_bucketlen = bucketlens[0];
+
+	if (softn->ipf_nat_stats.ns_side[1].ns_bucketlen != NULL) {
+		KFREES(softn->ipf_nat_stats.ns_side[1].ns_bucketlen,
+		       softn->ipf_nat_table_sz * sizeof(u_int));
+	}
+	softn->ipf_nat_stats.ns_side[1].ns_bucketlen = bucketlens[1];
+
+#ifdef USE_INET6
+	if (softn->ipf_nat_stats.ns_side6[0].ns_bucketlen != NULL) {
+		KFREES(softn->ipf_nat_stats.ns_side6[0].ns_bucketlen,
+		       softn->ipf_nat_table_sz * sizeof(u_int));
+	}
+	softn->ipf_nat_stats.ns_side6[0].ns_bucketlen = bucketlens[0];
+
+	if (softn->ipf_nat_stats.ns_side6[1].ns_bucketlen != NULL) {
+		KFREES(softn->ipf_nat_stats.ns_side6[1].ns_bucketlen,
+		       softn->ipf_nat_table_sz * sizeof(u_int));
+	}
+	softn->ipf_nat_stats.ns_side6[1].ns_bucketlen = bucketlens[1];
+#endif
+
+	softn->ipf_nat_maxbucket = maxbucket;
+	softn->ipf_nat_table_sz = newsize;
+	/*
+	 * Walk through the entire list of NAT table entries and put them
+	 * in the new NAT table, somewhere.  Because we have a new table,
+	 * we need to restart the counter of how many chains are in use.
+	 */
+	softn->ipf_nat_stats.ns_side[0].ns_inuse = 0;
+	softn->ipf_nat_stats.ns_side[1].ns_inuse = 0;
+#ifdef USE_INET6
+	softn->ipf_nat_stats.ns_side6[0].ns_inuse = 0;
+	softn->ipf_nat_stats.ns_side6[1].ns_inuse = 0;
+#endif
+
+	for (nat = softn->ipf_nat_instances; nat != NULL; nat = nat->nat_next) {
+		nat->nat_hnext[0] = NULL;
+		nat->nat_phnext[0] = NULL;
+		hv = nat->nat_hv[0] % softn->ipf_nat_table_sz;
+
+		natp = &softn->ipf_nat_table[0][hv];
+		if (*natp) {
+			(*natp)->nat_phnext[0] = &nat->nat_hnext[0];
+		} else {
+			NBUMPSIDE(0, ns_inuse);
+		}
+		nat->nat_phnext[0] = natp;
+		nat->nat_hnext[0] = *natp;
+		*natp = nat;
+		NBUMPSIDE(0, ns_bucketlen[hv]);
+
+		nat->nat_hnext[1] = NULL;
+		nat->nat_phnext[1] = NULL;
+		hv = nat->nat_hv[1] % softn->ipf_nat_table_sz;
+
+		natp = &softn->ipf_nat_table[1][hv];
+		if (*natp) {
+			(*natp)->nat_phnext[1] = &nat->nat_hnext[1];
+		} else {
+			NBUMPSIDE(1, ns_inuse);
+		}
+		nat->nat_phnext[1] = natp;
+		nat->nat_hnext[1] = *natp;
+		*natp = nat;
+		NBUMPSIDE(1, ns_bucketlen[hv]);
+	}
+	RWLOCK_EXIT(&softc->ipf_nat);
+
+	return 0;
+
+badrehash:
+	if (bucketlens[1] != NULL) {
+		KFREES(bucketlens[0], newsize * sizeof(u_int));
+	}
+	if (bucketlens[0] != NULL) {
+		KFREES(bucketlens[0], newsize * sizeof(u_int));
+	}
+	if (newtab[0] != NULL) {
+		KFREES(newtab[0], newsize * sizeof(nat_t *));
+	}
+	if (newtab[1] != NULL) {
+		KFREES(newtab[1], newsize * sizeof(nat_t *));
+	}
+	IPFERROR(error);
+	return ENOMEM;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_nat_rehash_rules                                        */
+/* Returns:     int  - 0 = success, else failure			    */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              t(I) - pointer to tunable                                   */
+/*              p(I) - pointer to new tuning data                           */
+/*                                                                          */
+/* All of the NAT rules hang off of a hash table that is searched with a    */
+/* hash on address after the netmask is applied.  There is a different table*/
+/* for both inbound rules (rdr) and outbound (map.)  The resizing will only */
+/* affect one of these two tables.                                          */
+/* ------------------------------------------------------------------------ */
+int
+ipf_nat_rehash_rules(softc, t, p)
+	ipf_main_softc_t *softc;
+	ipftuneable_t *t;
+	ipftuneval_t *p;
+{
+	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
+	ipnat_t **newtab, *np, ***old, **npp;
+	u_int newsize;
+	u_int mask;
+	u_int hv;
+
+	newsize = p->ipftu_int;
+	/*
+	 * In case there is nothing to do...
+	 */
+	if (newsize == *t->ipft_pint)
+		return 0;
+
+	/*
+	 * All inbound rules have the NAT_REDIRECT bit set in in_redir and
+	 * all outbound rules have either NAT_MAP or MAT_MAPBLK set.
+	 * This if statement allows for some more generic code to be below,
+	 * rather than two huge gobs of code that almost do the same thing.
+	 */
+	if (t->ipft_pint == &softn->ipf_nat_rdrrules_sz) {
+		old = &softn->ipf_nat_rdr_rules;
+		mask = NAT_REDIRECT;
+	} else {
+		old = &softn->ipf_nat_map_rules;
+		mask = NAT_MAP|NAT_MAPBLK;
+	}
+
+	KMALLOCS(newtab, ipnat_t **, newsize * sizeof(ipnat_t *));
+	if (newtab == NULL) {
+		IPFERROR(60067);
+		return ENOMEM;
+	}
+
+	bzero((char *)newtab, newsize * sizeof(ipnat_t *));
+
+	WRITE_ENTER(&softc->ipf_nat);
+
+	if (*old != NULL) {
+		KFREES(*old, *t->ipft_pint * sizeof(ipnat_t **));
+	}
+	*old = newtab;
+	*t->ipft_pint = newsize;
+
+	for (np = softn->ipf_nat_list; np != NULL; np = np->in_next) {
+		if ((np->in_redir & mask) == 0)
+			continue;
+
+		if (np->in_redir & NAT_REDIRECT) {
+			np->in_rnext = NULL;
+			hv = np->in_hv[0] % newsize;
+			for (npp = newtab + hv; *npp != NULL; )
+				npp = &(*npp)->in_rnext;
+			np->in_prnext = npp;
+			*npp = np;
+		}
+		if (np->in_redir & NAT_MAP) {
+			np->in_mnext = NULL;
+			hv = np->in_hv[1] % newsize;
+			for (npp = newtab + hv; *npp != NULL; )
+				npp = &(*npp)->in_mnext;
+			np->in_pmnext = npp;
+			*npp = np;
+		}
+
+	}
+	RWLOCK_EXIT(&softc->ipf_nat);
+
+	return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_nat_hostmap_rehash                                      */
+/* Returns:     int  - 0 = success, else failure			    */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              t(I) - pointer to tunable                                   */
+/*              p(I) - pointer to new tuning data                           */
+/*                                                                          */
+/* Allocate and populate a new hash table that will contain a reference to  */
+/* all of the active IP# translations currently in place.                   */
+/* ------------------------------------------------------------------------ */
+int
+ipf_nat_hostmap_rehash(softc, t, p)
+	ipf_main_softc_t *softc;
+	ipftuneable_t *t;
+	ipftuneval_t *p;
+{
+	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
+	hostmap_t *hm, **newtab;
+	u_int newsize;
+	u_int hv;
+
+	newsize = p->ipftu_int;
+	/*
+	 * In case there is nothing to do...
+	 */
+	if (newsize == *t->ipft_pint)
+		return 0;
+
+	KMALLOCS(newtab, hostmap_t **, newsize * sizeof(hostmap_t *));
+	if (newtab == NULL) {
+		IPFERROR(60068);
+		return ENOMEM;
+	}
+
+	bzero((char *)newtab, newsize * sizeof(hostmap_t *));
+
+	WRITE_ENTER(&softc->ipf_nat);
+	if (softn->ipf_hm_maptable != NULL) {
+		KFREES(softn->ipf_hm_maptable,
+		       softn->ipf_nat_hostmap_sz * sizeof(hostmap_t *));
+	}
+	softn->ipf_hm_maptable = newtab;
+	softn->ipf_nat_hostmap_sz = newsize;
+
+	for (hm = softn->ipf_hm_maplist; hm != NULL; hm = hm->hm_next) {
+		hv = hm->hm_hv % softn->ipf_nat_hostmap_sz;
+		hm->hm_hnext = softn->ipf_hm_maptable[hv];
+		hm->hm_phnext = softn->ipf_hm_maptable + hv;
+		if (softn->ipf_hm_maptable[hv] != NULL)
+			softn->ipf_hm_maptable[hv]->hm_phnext = &hm->hm_hnext;
+		softn->ipf_hm_maptable[hv] = hm;
+	}
+	RWLOCK_EXIT(&softc->ipf_nat);
+
+	return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_nat_add_tq                                              */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*                                                                          */
+/* ------------------------------------------------------------------------ */
+ipftq_t *
+ipf_nat_add_tq(softc, ttl)
+	ipf_main_softc_t *softc;
+	int ttl;
+{
+	ipf_nat_softc_t *softs = softc->ipf_nat_soft;
+
+	return ipf_addtimeoutqueue(softc, &softs->ipf_nat_utqe, ttl);
+}
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_nat_uncreate                                            */
+/* Returns:     Nil                                                         */
+/* Parameters:  fin(I) - pointer to packet information                      */
+/*                                                                          */
+/* This function is used to remove a NAT entry from the NAT table when we   */
+/* decide that the create was actually in error. It is thus assumed that    */
+/* fin_flx will have both FI_NATED and FI_NATNEW set. Because we're dealing */
+/* with the translated packet (not the original), we have to reverse the    */
+/* lookup. Although doing the lookup is expensive (relatively speaking), it */
+/* is not anticipated that this will be a frequent occurance for normal     */
+/* traffic patterns.                                                        */
+/* ------------------------------------------------------------------------ */
+void
+ipf_nat_uncreate(fin)
+	fr_info_t *fin;
+{
+	ipf_main_softc_t *softc = fin->fin_main_soft;
+	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
+	int nflags;
+	nat_t *nat;
+
+	switch (fin->fin_p)
+	{
+	case IPPROTO_TCP :
+		nflags = IPN_TCP;
+		break;
+	case IPPROTO_UDP :
+		nflags = IPN_UDP;
+		break;
+	default :
+		nflags = 0;
+		break;
+	}
+
+	WRITE_ENTER(&softc->ipf_nat);
+
+	if (fin->fin_out == 0) {
+		nat = ipf_nat_outlookup(fin, nflags, (u_int)fin->fin_p,
+					fin->fin_dst, fin->fin_src);
+	} else {
+		nat = ipf_nat_inlookup(fin, nflags, (u_int)fin->fin_p,
+				       fin->fin_src, fin->fin_dst);
+	}
+
+	if (nat != NULL) {
+		NBUMPSIDE(fin->fin_out, ns_uncreate[0]);
+		ipf_nat_delete(softc, nat, NL_DESTROY);
+	} else {
+		NBUMPSIDE(fin->fin_out, ns_uncreate[1]);
+	}
+
+	RWLOCK_EXIT(&softc->ipf_nat);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_nat_cmp_rules                                           */
+/* Returns:     int   - 0 == success, else rules do not match.              */
+/* Parameters:  n1(I) - first rule to compare                               */
+/*              n2(I) - first rule to compare                               */
+/*                                                                          */
+/* Compare two rules using pointers to each rule. A straight bcmp will not  */
+/* work as some fields (such as in_dst, in_pkts) actually do change once    */
+/* the rule has been loaded into the kernel. Whilst this function returns   */
+/* various non-zero returns, they're strictly to aid in debugging. Use of   */
+/* this function should simply care if the result is zero or not.           */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_nat_cmp_rules(n1, n2)
+	ipnat_t *n1, *n2;
+{
+	if (n1->in_size != n2->in_size)
+		return 1;
+
+	if (bcmp((char *)&n1->in_v, (char *)&n2->in_v,
+		 offsetof(ipnat_t, in_ndst) - offsetof(ipnat_t, in_v)) != 0)
+		return 2;
+
+	if (bcmp((char *)&n1->in_tuc, (char *)&n2->in_tuc,
+		 n1->in_size - offsetof(ipnat_t, in_tuc)) != 0)
+		return 3;
+	if (n1->in_ndst.na_atype != n2->in_ndst.na_atype)
+		return 5;
+	if (n1->in_ndst.na_function != n2->in_ndst.na_function)
+		return 6;
+	if (bcmp((char *)&n1->in_ndst.na_addr, (char *)&n2->in_ndst.na_addr,
+		 sizeof(n1->in_ndst.na_addr)))
+		return 7;
+	if (n1->in_nsrc.na_atype != n2->in_nsrc.na_atype)
+		return 8;
+	if (n1->in_nsrc.na_function != n2->in_nsrc.na_function)
+		return 9;
+	if (bcmp((char *)&n1->in_nsrc.na_addr, (char *)&n2->in_nsrc.na_addr,
+		 sizeof(n1->in_nsrc.na_addr)))
+		return 10;
+	if (n1->in_odst.na_atype != n2->in_odst.na_atype)
+		return 11;
+	if (n1->in_odst.na_function != n2->in_odst.na_function)
+		return 12;
+	if (bcmp((char *)&n1->in_odst.na_addr, (char *)&n2->in_odst.na_addr,
+		 sizeof(n1->in_odst.na_addr)))
+		return 13;
+	if (n1->in_osrc.na_atype != n2->in_osrc.na_atype)
+		return 14;
+	if (n1->in_osrc.na_function != n2->in_osrc.na_function)
+		return 15;
+	if (bcmp((char *)&n1->in_osrc.na_addr, (char *)&n2->in_osrc.na_addr,
+		 sizeof(n1->in_osrc.na_addr)))
+		return 16;
+	return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_nat_rule_init                                           */
+/* Returns:     int   - 0 == success, else rules do not match.              */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              softn(I) - pointer to NAT context structure                 */
+/*              n(I)     - first rule to compare                            */
+/*                                                                          */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_nat_rule_init(softc, softn, n)
+	ipf_main_softc_t *softc;
+	ipf_nat_softc_t *softn;
+	ipnat_t *n;
+{
+	int error = 0;
+
+	if ((n->in_flags & IPN_SIPRANGE) != 0)
+		n->in_nsrcatype = FRI_RANGE;
+
+	if ((n->in_flags & IPN_DIPRANGE) != 0)
+		n->in_ndstatype = FRI_RANGE;
+
+	if ((n->in_flags & IPN_SPLIT) != 0)
+		n->in_ndstatype = FRI_SPLIT;
+
+	if ((n->in_redir & (NAT_MAP|NAT_REWRITE|NAT_DIVERTUDP)) != 0)
+		n->in_spnext = n->in_spmin;
+
+	if ((n->in_redir & (NAT_REWRITE|NAT_DIVERTUDP)) != 0) {
+		n->in_dpnext = n->in_dpmin;
+	} else if (n->in_redir == NAT_REDIRECT) {
+		n->in_dpnext = n->in_dpmin;
+	}
+
+	n->in_stepnext = 0;
+
+	switch (n->in_v[0])
+	{
+	case 4 :
+		error = ipf_nat_ruleaddrinit(softc, softn, n);
+		if (error != 0)
+			return error;
+		break;
+#ifdef USE_INET6
+	case 6 :
+		error = ipf_nat6_ruleaddrinit(softc, softn, n);
+		if (error != 0)
+			return error;
+		break;
+#endif
+	default :
+		break;
+	}
+
+	if (n->in_redir == (NAT_DIVERTUDP|NAT_MAP)) {
+		/*
+		 * Prerecord whether or not the destination of the divert
+		 * is local or not to the interface the packet is going
+		 * to be sent out.
+		 */
+		n->in_dlocal = ipf_deliverlocal(softc, n->in_v[1],
+						n->in_ifps[1], &n->in_ndstip6);
+	}
+
+	return error;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_nat_rule_fini                                           */
+/* Returns:     int   - 0 == success, else rules do not match.              */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              n(I)     - rule to work on                                  */
+/*                                                                          */
+/* This function is used to release any objects that were referenced during */
+/* the rule initialisation. This is useful both when free'ing the rule and  */
+/* when handling ioctls that need to initialise these fields but not        */
+/* actually use them after the ioctl processing has finished.               */
+/* ------------------------------------------------------------------------ */
+static void
+ipf_nat_rule_fini(softc, n)
+	ipf_main_softc_t *softc;
+	ipnat_t *n;
+{
+	if (n->in_odst.na_atype == FRI_LOOKUP && n->in_odst.na_ptr != NULL)
+		ipf_lookup_deref(softc, n->in_odst.na_type, n->in_odst.na_ptr);
+
+	if (n->in_osrc.na_atype == FRI_LOOKUP && n->in_osrc.na_ptr != NULL)
+		ipf_lookup_deref(softc, n->in_osrc.na_type, n->in_osrc.na_ptr);
+
+	if (n->in_ndst.na_atype == FRI_LOOKUP && n->in_ndst.na_ptr != NULL)
+		ipf_lookup_deref(softc, n->in_ndst.na_type, n->in_ndst.na_ptr);
+
+	if (n->in_nsrc.na_atype == FRI_LOOKUP && n->in_nsrc.na_ptr != NULL)
+		ipf_lookup_deref(softc, n->in_nsrc.na_type, n->in_nsrc.na_ptr);
+
+	if (n->in_divmp != NULL)
+		FREE_MB_T(n->in_divmp);
+}

Modified: trunk/sys/contrib/ipfilter/netinet/ip_nat.h
===================================================================
--- trunk/sys/contrib/ipfilter/netinet/ip_nat.h	2018-05-28 18:55:30 UTC (rev 10138)
+++ trunk/sys/contrib/ipfilter/netinet/ip_nat.h	2018-05-28 18:56:30 UTC (rev 10139)
@@ -1,12 +1,13 @@
-/*	$FreeBSD$	*/
+/* $MidnightBSD$ */
+/*	$FreeBSD: stable/10/sys/contrib/ipfilter/netinet/ip_nat.h 305138 2016-08-31 18:00:41Z dim $	*/
 
 /*
- * Copyright (C) 1995-2001, 2003 by Darren Reed.
+ * Copyright (C) 2012 by Darren Reed.
  *
  * See the IPFILTER.LICENCE file for details on licencing.
  *
  * @(#)ip_nat.h	1.5 2/4/96
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/contrib/ipfilter/netinet/ip_nat.h 305138 2016-08-31 18:00:41Z dim $
  * Id: ip_nat.h,v 2.90.2.20 2007/09/25 08:27:32 darrenr Exp $
  */
 
@@ -13,8 +14,12 @@
 #ifndef	__IP_NAT_H__
 #define	__IP_NAT_H__
 
-#ifndef SOLARIS
-#define	SOLARIS	(defined(sun) && (defined(__svr4__) || defined(__SVR4)))
+#ifndef	SOLARIS
+# if defined(sun) && (defined(__svr4__) || defined(__SVR4))
+#  define	SOLARIS		1
+# else
+#  define	SOLARIS		0
+# endif
 #endif
 
 #if defined(__STDC__) || defined(__GNUC__) || defined(_AIX51)
@@ -22,11 +27,13 @@
 #define	SIOCRMNAT	_IOW('r', 61, struct ipfobj)
 #define	SIOCGNATS	_IOWR('r', 62, struct ipfobj)
 #define	SIOCGNATL	_IOWR('r', 63, struct ipfobj)
+#define	SIOCPURGENAT	_IOWR('r', 100, struct ipfobj)
 #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)
+#define	SIOCPURGENAT	_IOWR(r, 100, struct ipfobj)
 #endif
 
 #undef	LARGE_NAT	/* define	this if you're setting up a system to NAT
@@ -78,7 +85,8 @@
 #ifndef	APR_LABELLEN
 #define	APR_LABELLEN	16
 #endif
-#define	NAT_HW_CKSUM	0x80000000
+#define	NAT_HW_CKSUM		0x80000000
+#define	NAT_HW_CKSUM_PART	0x40000000
 
 #define	DEF_NAT_AGE	1200     /* 10 minutes (600 seconds) */
 
@@ -85,6 +93,10 @@
 struct ipstate;
 struct ap_session;
 
+/*
+ * This structure is used in the active NAT table and represents an
+ * active NAT session.
+ */
 typedef	struct	nat	{
 	ipfmutex_t	nat_lock;
 	struct	nat	*nat_next;
@@ -101,13 +113,15 @@
 	void		*nat_ifps[2];
 	void		*nat_sync;
 	ipftqent_t	nat_tqe;
+	int		nat_mtu[2];
 	u_32_t		nat_flags;
 	u_32_t		nat_sumd[2];	/* ip checksum delta for data segment*/
 	u_32_t		nat_ipsumd;	/* ip checksum delta for ip header */
 	u_32_t		nat_mssclamp;	/* if != zero clamp MSS to this */
-	i6addr_t	nat_inip6;
-	i6addr_t	nat_outip6;
-	i6addr_t	nat_oip6;		/* other ip */
+	i6addr_t	nat_odst6;
+	i6addr_t	nat_osrc6;
+	i6addr_t	nat_ndst6;
+	i6addr_t	nat_nsrc6;
 	U_QUAD_T	nat_pkts[2];
 	U_QUAD_T	nat_bytes[2];
 	union	{
@@ -115,28 +129,37 @@
 		tcpinfo_t	nat_unt;
 		icmpinfo_t	nat_uni;
 		greinfo_t	nat_ugre;
-	} nat_un;
-	u_short		nat_oport;		/* other port */
-	u_short		nat_use;
-	u_char		nat_p;			/* protocol for NAT */
+	} nat_unold, nat_unnew;
+	int		nat_use;
+	int		nat_pr[2];		/* protocol for NAT */
 	int		nat_dir;
 	int		nat_ref;		/* reference count */
-	int		nat_hv[2];
+	u_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];
+	int		nat_dlocal;
+	int		nat_v[2];		/* 0 = old, 1 = new */
+	u_int		nat_redir;		/* copy of in_redir */
 } nat_t;
 
-#define	nat_inip	nat_inip6.in4
-#define	nat_outip	nat_outip6.in4
-#define	nat_oip		nat_oip6.in4
+#define	nat_osrcip	nat_osrc6.in4
+#define	nat_odstip	nat_odst6.in4
+#define	nat_nsrcip	nat_nsrc6.in4
+#define	nat_ndstip	nat_ndst6.in4
+#define	nat_osrcaddr	nat_osrc6.in4.s_addr
+#define	nat_odstaddr	nat_odst6.in4.s_addr
+#define	nat_nsrcaddr	nat_nsrc6.in4.s_addr
+#define	nat_ndstaddr	nat_ndst6.in4.s_addr
 #define	nat_age		nat_tqe.tqe_die
-#define	nat_inport	nat_un.nat_unt.ts_sport
-#define	nat_outport	nat_un.nat_unt.ts_dport
-#define	nat_type	nat_un.nat_uni.ici_type
-#define	nat_seq		nat_un.nat_uni.ici_seq
-#define	nat_id		nat_un.nat_uni.ici_id
+#define	nat_osport	nat_unold.nat_unt.ts_sport
+#define	nat_odport	nat_unold.nat_unt.ts_dport
+#define	nat_nsport	nat_unnew.nat_unt.ts_sport
+#define	nat_ndport	nat_unnew.nat_unt.ts_dport
+#define	nat_oicmpid	nat_unold.nat_uni.ici_id
+#define	nat_nicmpid	nat_unnew.nat_uni.ici_id
+#define	nat_type	nat_unold.nat_uni.ici_type
+#define	nat_oseq	nat_unold.nat_uni.ici_seq
+#define	nat_nseq	nat_unnew.nat_uni.ici_seq
 #define	nat_tcpstate	nat_tqe.tqe_state
 #define	nat_die		nat_tqe.tqe_die
 #define	nat_touched	nat_tqe.tqe_touched
@@ -146,6 +169,10 @@
  */
 #define	NAT_INBOUND	0
 #define	NAT_OUTBOUND	1
+#define	NAT_ENCAPIN	2
+#define	NAT_ENCAPOUT	3
+#define	NAT_DIVERTIN	4
+#define	NAT_DIVERTOUT	5
 
 /*
  * Definitions for nat_flags
@@ -174,9 +201,29 @@
 
 #define	NAT_DEBUG	0x800000
 
+typedef	struct nat_addr_s {
+	i6addr_t	na_addr[2];
+	i6addr_t	na_nextaddr;
+	int		na_atype;
+	int		na_function;
+} nat_addr_t;
+
+#define	na_nextip	na_nextaddr.in4.s_addr
+#define	na_nextip6	na_nextaddr.in6
+#define	na_num		na_addr[0].iplookupnum
+#define	na_type		na_addr[0].iplookuptype
+#define	na_subtype	na_addr[0].iplookupsubtype
+#define	na_ptr		na_addr[1].iplookupptr
+#define	na_func		na_addr[1].iplookupfunc
+
+
+/*
+ * This structure represents an actual NAT rule, loaded by ipnat.
+ */
 typedef	struct	ipnat	{
 	ipfmutex_t	in_lock;
 	struct	ipnat	*in_next;		/* NAT rule list next */
+	struct	ipnat	**in_pnext;		/* prior rdr next ptr */
 	struct	ipnat	*in_rnext;		/* rdr rule hash next */
 	struct	ipnat	**in_prnext;		/* prior rdr next ptr */
 	struct	ipnat	*in_mnext;		/* map rule hash next */
@@ -185,49 +232,114 @@
 	void		*in_ifps[2];
 	void		*in_apr;
 	char		*in_comment;
-	i6addr_t	in_next6;
+	mb_t		*in_divmp;
+	void		*in_pconf;
+	U_QUAD_T	in_pkts[2];
+	U_QUAD_T	in_bytes[2];
 	u_long		in_space;
 	u_long		in_hits;
-	u_int		in_use;
-	u_int		in_hv;
+	int		in_size;
+	int		in_use;
+	u_int		in_hv[2];
 	int		in_flineno;		/* conf. file line number */
-	u_short		in_pnext;
-	u_char		in_v;
-	u_char		in_xxx;
+	int		in_stepnext;
+	int		in_dlocal;
+	u_short		in_dpnext;
+	u_short		in_spnext;
 	/* From here to the end is covered by IPN_CMPSIZ */
+	u_char		in_v[2];		/* 0 = old, 1 = new */
 	u_32_t		in_flags;
 	u_32_t		in_mssclamp;		/* if != 0 clamp MSS to this */
 	u_int		in_age[2];
 	int		in_redir;		/* see below for values */
-	int		in_p;			/* protocol. */
-	i6addr_t	in_in[2];
-	i6addr_t	in_out[2];
-	i6addr_t	in_src[2];
+	int		in_pr[2];		/* protocol. */
+	nat_addr_t	in_ndst;
+	nat_addr_t	in_nsrc;
+	nat_addr_t	in_osrc;
+	nat_addr_t	in_odst;
 	frtuc_t		in_tuc;
-	u_short		in_port[2];
 	u_short		in_ppip;		/* ports per IP. */
 	u_short		in_ippip;		/* IP #'s per IP# */
-	char		in_ifnames[2][LIFNAMSIZ];
-	char		in_plabel[APR_LABELLEN];	/* proxy label. */
+	u_short		in_ndports[2];
+	u_short		in_nsports[2];
+	int		in_ifnames[2];
+	int		in_plabel;	/* proxy label. */
+	int		in_pconfig;	/* proxy label. */
 	ipftag_t	in_tag;
+	int		in_namelen;
+	char		in_names[1];
 } ipnat_t;
 
-#define	in_pmin		in_port[0]	/* Also holds static redir port */
-#define	in_pmax		in_port[1]
-#define	in_nextip	in_next6.in4
-#define	in_nip		in_next6.in4.s_addr
-#define	in_inip		in_in[0].in4.s_addr
-#define	in_inmsk	in_in[1].in4.s_addr
-#define	in_outip	in_out[0].in4.s_addr
-#define	in_outmsk	in_out[1].in4.s_addr
-#define	in_srcip	in_src[0].in4.s_addr
-#define	in_srcmsk	in_src[1].in4.s_addr
+/*
+ *      MAP-IN MAP-OUT RDR-IN RDR-OUT
+ * osrc    X   == src  == src    X
+ * odst    X   == dst  == dst    X
+ * nsrc == dst   X       X    == dst
+ * ndst == src   X       X    == src
+ */
+#define	in_dpmin	in_ndports[0]	/* Also holds static redir port */
+#define	in_dpmax	in_ndports[1]
+#define	in_spmin	in_nsports[0]	/* Also holds static redir port */
+#define	in_spmax	in_nsports[1]
+#define	in_ndport	in_ndports[0]
+#define	in_nsport	in_nsports[0]
+#define	in_dipnext	in_ndst.na_nextaddr.in4
+#define	in_dipnext6	in_ndst.na_nextaddr
+#define	in_dnip		in_ndst.na_nextaddr.in4.s_addr
+#define	in_dnip6	in_ndst.na_nextaddr
+#define	in_sipnext	in_nsrc.na_nextaddr.in4
+#define	in_snip		in_nsrc.na_nextaddr.in4.s_addr
+#define	in_snip6	in_nsrc.na_nextaddr
+#define	in_odstip	in_odst.na_addr[0].in4
+#define	in_odstip6	in_odst.na_addr[0]
+#define	in_odstaddr	in_odst.na_addr[0].in4.s_addr
+#define	in_odstmsk	in_odst.na_addr[1].in4.s_addr
+#define	in_odstmsk6	in_odst.na_addr[1]
+#define	in_odstatype	in_odst.na_atype
+#define	in_osrcip	in_osrc.na_addr[0].in4
+#define	in_osrcip6	in_osrc.na_addr[0]
+#define	in_osrcaddr	in_osrc.na_addr[0].in4.s_addr
+#define	in_osrcmsk	in_osrc.na_addr[1].in4.s_addr
+#define	in_osrcmsk6	in_osrc.na_addr[1]
+#define	in_osrcatype	in_osrc.na_atype
+#define	in_ndstip	in_ndst.na_addr[0].in4
+#define	in_ndstip6	in_ndst.na_addr[0]
+#define	in_ndstaddr	in_ndst.na_addr[0].in4.s_addr
+#define	in_ndstmsk	in_ndst.na_addr[1].in4.s_addr
+#define	in_ndstmsk6	in_ndst.na_addr[1]
+#define	in_ndstatype	in_ndst.na_atype
+#define	in_ndstafunc	in_ndst.na_function
+#define	in_nsrcip	in_nsrc.na_addr[0].in4
+#define	in_nsrcip6	in_nsrc.na_addr[0]
+#define	in_nsrcaddr	in_nsrc.na_addr[0].in4.s_addr
+#define	in_nsrcmsk	in_nsrc.na_addr[1].in4.s_addr
+#define	in_nsrcmsk6	in_nsrc.na_addr[1]
+#define	in_nsrcatype	in_nsrc.na_atype
+#define	in_nsrcafunc	in_nsrc.na_function
 #define	in_scmp		in_tuc.ftu_scmp
 #define	in_dcmp		in_tuc.ftu_dcmp
 #define	in_stop		in_tuc.ftu_stop
 #define	in_dtop		in_tuc.ftu_dtop
-#define	in_sport	in_tuc.ftu_sport
-#define	in_dport	in_tuc.ftu_dport
+#define	in_osport	in_tuc.ftu_sport
+#define	in_odport	in_tuc.ftu_dport
+#define	in_ndstnum	in_ndst.na_addr[0].iplookupnum
+#define	in_ndsttype	in_ndst.na_addr[0].iplookuptype
+#define	in_ndstptr	in_ndst.na_addr[1].iplookupptr
+#define	in_ndstfunc	in_ndst.na_addr[1].iplookupfunc
+#define	in_nsrcnum	in_nsrc.na_addr[0].iplookupnum
+#define	in_nsrctype	in_nsrc.na_addr[0].iplookuptype
+#define	in_nsrcptr	in_nsrc.na_addr[1].iplookupptr
+#define	in_nsrcfunc	in_nsrc.na_addr[1].iplookupfunc
+#define	in_odstnum	in_odst.na_addr[0].iplookupnum
+#define	in_odsttype	in_odst.na_addr[0].iplookuptype
+#define	in_odstptr	in_odst.na_addr[1].iplookupptr
+#define	in_odstfunc	in_odst.na_addr[1].iplookupfunc
+#define	in_osrcnum	in_osrc.na_addr[0].iplookupnum
+#define	in_osrctype	in_osrc.na_addr[0].iplookuptype
+#define	in_osrcptr	in_osrc.na_addr[1].iplookupptr
+#define	in_osrcfunc	in_osrc.na_addr[1].iplookupfunc
+#define	in_icmpidmin	in_nsports[0]
+#define	in_icmpidmax	in_nsports[1]
 
 /*
  * Bit definitions for in_flags
@@ -242,25 +354,30 @@
 #define	IPN_TCPUDPICMPQ	(IPN_TCP|IPN_UDP|IPN_ICMPQUERY)
 #define	IPN_RF		(IPN_TCPUDP|IPN_DELETE|IPN_ICMPERR)
 #define	IPN_AUTOPORTMAP	0x00010
-#define	IPN_IPRANGE	0x00020
-#define	IPN_FILTER	0x00040
-#define	IPN_SPLIT	0x00080
-#define	IPN_ROUNDR	0x00100
-#define	IPN_NOTSRC	0x04000
-#define	IPN_NOTDST	0x08000
-#define	IPN_DYNSRCIP	0x10000	/* dynamic src IP# */
-#define	IPN_DYNDSTIP	0x20000	/* dynamic dst IP# */
-#define	IPN_DELETE	0x40000
-#define	IPN_STICKY	0x80000
-#define	IPN_FRAG	0x100000
-#define	IPN_FIXEDDPORT	0x200000
-#define	IPN_FINDFORWARD	0x400000
-#define	IPN_IN		0x800000
-#define	IPN_SEQUENTIAL	0x1000000
-#define	IPN_USERFLAGS	(IPN_TCPUDP|IPN_AUTOPORTMAP|IPN_IPRANGE|IPN_SPLIT|\
-			 IPN_ROUNDR|IPN_FILTER|IPN_NOTSRC|IPN_NOTDST|\
+#define	IPN_FILTER	0x00020
+#define	IPN_SPLIT	0x00040
+#define	IPN_ROUNDR	0x00080
+#define	IPN_SIPRANGE	0x00100
+#define	IPN_DIPRANGE	0x00200
+#define	IPN_NOTSRC	0x00400
+#define	IPN_NOTDST	0x00800
+#define	IPN_NO		0x01000
+#define	IPN_DYNSRCIP	0x02000	/* dynamic src IP# */
+#define	IPN_DYNDSTIP	0x04000	/* dynamic dst IP# */
+#define	IPN_DELETE	0x08000
+#define	IPN_STICKY	0x10000
+#define	IPN_FRAG	0x20000
+#define	IPN_FIXEDSPORT	0x40000
+#define	IPN_FIXEDDPORT	0x80000
+#define	IPN_FINDFORWARD	0x100000
+#define	IPN_IN		0x200000
+#define	IPN_SEQUENTIAL	0x400000
+#define	IPN_PURGE	0x800000
+#define	IPN_PROXYRULE	0x1000000
+#define	IPN_USERFLAGS	(IPN_TCPUDP|IPN_AUTOPORTMAP|IPN_SIPRANGE|IPN_SPLIT|\
+			 IPN_ROUNDR|IPN_FILTER|IPN_NOTSRC|IPN_NOTDST|IPN_NO|\
 			 IPN_FRAG|IPN_STICKY|IPN_FIXEDDPORT|IPN_ICMPQUERY|\
-			 IPN_SEQUENTIAL)
+			 IPN_DIPRANGE|IPN_SEQUENTIAL|IPN_PURGE)
 
 /*
  * Values for in_redir
@@ -269,23 +386,34 @@
 #define	NAT_REDIRECT	0x02
 #define	NAT_BIMAP	(NAT_MAP|NAT_REDIRECT)
 #define	NAT_MAPBLK	0x04
+#define	NAT_REWRITE	0x08
+#define	NAT_ENCAP	0x10
+#define	NAT_DIVERTUDP	0x20
 
 #define	MAPBLK_MINPORT	1024	/* don't use reserved ports for src port */
 #define	USABLE_PORTS	(65536 - MAPBLK_MINPORT)
 
-#define	IPN_CMPSIZ	(sizeof(ipnat_t) - offsetof(ipnat_t, in_flags))
+#define	IPN_CMPSIZ	(sizeof(ipnat_t) - offsetof(ipnat_t, in_v))
 
 typedef	struct	natlookup {
-	struct	in_addr	nl_inip;
-	struct	in_addr	nl_outip;
-	struct	in_addr	nl_realip;
-	int	nl_flags;
-	u_short	nl_inport;
-	u_short	nl_outport;
-	u_short	nl_realport;
+	i6addr_t	nl_inipaddr;
+	i6addr_t	nl_outipaddr;
+	i6addr_t	nl_realipaddr;
+	int		nl_v;
+	int		nl_flags;
+	u_short		nl_inport;
+	u_short		nl_outport;
+	u_short		nl_realport;
 } natlookup_t;
 
+#define	nl_inip		nl_inipaddr.in4
+#define	nl_outip	nl_outipaddr.in4
+#define	nl_realip	nl_realipaddr.in4
+#define	nl_inip6	nl_inipaddr.in6
+#define	nl_outip6	nl_outipaddr.in6
+#define	nl_realip6	nl_realipaddr.in6
 
+
 typedef struct  nat_save    {
 	void	*ipn_next;
 	struct	nat	ipn_nat;
@@ -315,14 +443,26 @@
 	struct	hostmap	*hm_next;
 	struct	hostmap	**hm_pnext;
 	struct	ipnat	*hm_ipnat;
-	struct	in_addr	hm_srcip;
-	struct	in_addr	hm_dstip;
-	struct	in_addr	hm_mapip;
+	i6addr_t	hm_osrcip6;
+	i6addr_t	hm_odstip6;
+	i6addr_t	hm_nsrcip6;
+	i6addr_t	hm_ndstip6;
 	u_32_t		hm_port;
 	int		hm_ref;
+	int		hm_hv;
+	int		hm_v;
 } hostmap_t;
 
+#define	hm_osrcip	hm_osrcip6.in4
+#define	hm_odstip	hm_odstip6.in4
+#define	hm_nsrcip	hm_nsrcip6.in4
+#define	hm_ndstip	hm_ndstip6.in4
+#define	hm_osrc6	hm_osrcip6.in6
+#define	hm_odst6	hm_odstip6.in6
+#define	hm_nsrc6	hm_nsrcip6.in6
+#define	hm_ndst6	hm_ndstip6.in6
 
+
 /*
  * Structure used to pass information in to nat_newmap and nat_newrdr.
  */
@@ -330,9 +470,7 @@
 	ipnat_t		*nai_np;
 	u_32_t		nai_sum1;
 	u_32_t		nai_sum2;
-	u_32_t		nai_nflags;
-	u_32_t		nai_flags;
-	struct	in_addr	nai_ip;
+	struct	in_addr	nai_ip;		/* In host byte order */
 	u_short		nai_port;
 	u_short		nai_nport;
 	u_short		nai_sport;
@@ -340,62 +478,134 @@
 } natinfo_t;
 
 
-typedef	struct	natstat	{
-	u_long	ns_mapped[2];
-	u_long	ns_rules;
+typedef	struct nat_stat_side {
+	u_int	*ns_bucketlen;
+	nat_t	**ns_table;
 	u_long	ns_added;
-	u_long	ns_expire;
+	u_long	ns_appr_fail;
+	u_long	ns_badnat;
+	u_long	ns_badnatnew;
+	u_long	ns_badnextaddr;
+	u_long	ns_bucket_max;
+	u_long	ns_clone_nomem;
+	u_long	ns_decap_bad;
+	u_long	ns_decap_fail;
+	u_long	ns_decap_pullup;
+	u_long	ns_divert_dup;
+	u_long	ns_divert_exist;
+	u_long	ns_drop;
+	u_long	ns_encap_dup;
+	u_long	ns_encap_pullup;
+	u_long	ns_exhausted;
+	u_long	ns_icmp_address;
+	u_long	ns_icmp_basic;
+	u_long	ns_icmp_mbuf;
+	u_long	ns_icmp_notfound;
+	u_long	ns_icmp_rebuild;
+	u_long	ns_icmp_short;
+	u_long	ns_icmp_size;
+	u_long	ns_ifpaddrfail;
+	u_long	ns_ignored;
+	u_long	ns_insert_fail;
 	u_long	ns_inuse;
-	u_long	ns_logged;
-	u_long	ns_logfail;
+	u_long	ns_log;
+	u_long	ns_lookup_miss;
+	u_long	ns_lookup_nowild;
+	u_long	ns_new_ifpaddr;
 	u_long	ns_memfail;
-	u_long	ns_badnat;
-	u_long	ns_addtrpnt;
-	nat_t	**ns_table[2];
-	hostmap_t **ns_maptable;
-	ipnat_t	*ns_list;
-	void	*ns_apslist;
-	u_int	ns_wilds;
-	u_int	ns_nattab_sz;
-	u_int	ns_nattab_max;
-	u_int	ns_rultab_sz;
-	u_int	ns_rdrtab_sz;
-	u_int	ns_trpntab_sz;
-	u_int	ns_hostmap_sz;
-	nat_t	*ns_instances;
-	hostmap_t *ns_maplist;
-	u_long	*ns_bucketlen[2];
-	u_long	ns_ticks;
-	u_int	ns_orphans;
+	u_long	ns_table_max;
+	u_long	ns_translated;
+	u_long	ns_unfinalised;
+	u_long	ns_wrap;
+	u_long	ns_xlate_null;
+	u_long	ns_xlate_exists;
+	u_long	ns_ipf_proxy_fail;
+	u_long	ns_uncreate[2];
+} nat_stat_side_t;
+
+
+typedef	struct	natstat	{
+	nat_t		*ns_instances;
+	ipnat_t		*ns_list;
+	hostmap_t	*ns_maplist;
+	hostmap_t	**ns_maptable;
+	u_int		ns_active;
+	u_long		ns_addtrpnt;
+	u_long		ns_divert_build;
+	u_long		ns_expire;
+	u_long		ns_flush_all;
+	u_long		ns_flush_closing;
+	u_long		ns_flush_queue;
+	u_long		ns_flush_state;
+	u_long		ns_flush_timeout;
+	u_long		ns_hm_new;
+	u_long		ns_hm_newfail;
+	u_long		ns_hm_addref;
+	u_long		ns_hm_nullnp;
+	u_long		ns_log_ok;
+	u_long		ns_log_fail;
+	u_int		ns_hostmap_sz;
+	u_int		ns_nattab_sz;
+	u_int		ns_nattab_max;
+	u_int		ns_orphans;
+	u_int		ns_rules;
+	u_int		ns_rules_map;
+	u_int		ns_rules_rdr;
+	u_int		ns_rultab_sz;
+	u_int		ns_rdrtab_sz;
+	u_32_t		ns_ticks;
+	u_int		ns_trpntab_sz;
+	u_int		ns_wilds;
+	u_long		ns_proto[256];
+	nat_stat_side_t	ns_side[2];
+#ifdef USE_INET6
+	nat_stat_side_t	ns_side6[2];
+#endif
 } natstat_t;
 
 typedef	struct	natlog {
-	struct	in_addr	nl_origip;
-	struct	in_addr	nl_outip;
-	struct	in_addr	nl_inip;
-	u_short	nl_origport;
-	u_short	nl_outport;
-	u_short	nl_inport;
-	u_short	nl_type;
-	int	nl_rule;
+	i6addr_t	nl_osrcip;
+	i6addr_t	nl_odstip;
+	i6addr_t	nl_nsrcip;
+	i6addr_t	nl_ndstip;
+	u_short		nl_osrcport;
+	u_short		nl_odstport;
+	u_short		nl_nsrcport;
+	u_short		nl_ndstport;
+	int		nl_action;
+	int		nl_type;
+	int		nl_rule;
 	U_QUAD_T	nl_pkts[2];
 	U_QUAD_T	nl_bytes[2];
-	u_char	nl_p;
+	u_char		nl_p[2];
+	u_char		nl_v[2];
+	u_char		nl_ifnames[2][LIFNAMSIZ];
 } natlog_t;
 
 
-#define	NL_NEWMAP	NAT_MAP
-#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_NEW		0
+#define	NL_CLONE	1
+#define	NL_PURGE	0xfffc
+#define	NL_DESTROY	0xfffd
 #define	NL_FLUSH	0xfffe
 #define	NL_EXPIRE	0xffff
 
-#define	NAT_HASH_FN(k,l,m)	(((k) + ((k) >> 12) + l) % (m))
+#define	NAT_HASH_FN(_k,_l,_m)	(((_k) + ((_k) >> 12) + _l) % (_m))
+#define	NAT_HASH_FN6(_k,_l,_m)	((((u_32_t *)(_k))[3] \
+				 + (((u_32_t *)(_k))[3] >> 12) \
+				 + (((u_32_t *)(_k))[2]) \
+				 + (((u_32_t *)(_k))[2] >> 12) \
+				 + (((u_32_t *)(_k))[1]) \
+				 + (((u_32_t *)(_k))[1] >> 12) \
+				 + (((u_32_t *)(_k))[0]) \
+				 + (((u_32_t *)(_k))[0] >> 12) \
+				 + _l) % (_m))
 
-#define	LONG_SUM(in)	(((in) & 0xffff) + ((in) >> 16))
+#define	LONG_SUM(_i)	(((_i) & 0xffff) + ((_i) >> 16))
+#define	LONG_SUM6(_i)	(LONG_SUM(ntohl(((u_32_t *)(_i))[0])) + \
+			 LONG_SUM(ntohl(((u_32_t *)(_i))[1])) + \
+			 LONG_SUM(ntohl(((u_32_t *)(_i))[2])) + \
+			 LONG_SUM(ntohl(((u_32_t *)(_i))[3])))
 
 #define	CALC_SUMD(s1, s2, sd) { \
 			    (s1) = ((s1) & 0xffff) + ((s1) >> 16); \
@@ -411,64 +621,159 @@
 #define	NAT_SYSSPACE		0x80000000
 #define	NAT_LOCKHELD		0x40000000
 
+/*
+ * This is present in ip_nat.h because it needs to be shared between
+ * ip_nat.c and ip_nat6.c
+ */
+typedef struct ipf_nat_softc_s {
+	ipfmutex_t	ipf_nat_new;
+	ipfmutex_t	ipf_nat_io;
+	int		ipf_nat_doflush;
+	int		ipf_nat_logging;
+	int		ipf_nat_lock;
+	int		ipf_nat_inited;
+	int		ipf_nat_table_wm_high;
+	int		ipf_nat_table_wm_low;
+	u_int		ipf_nat_table_max;
+	u_int		ipf_nat_table_sz;
+	u_int		ipf_nat_maprules_sz;
+	u_int		ipf_nat_rdrrules_sz;
+	u_int		ipf_nat_hostmap_sz;
+	u_int		ipf_nat_maxbucket;
+	u_int		ipf_nat_last_force_flush;
+	u_int		ipf_nat_defage;
+	u_int		ipf_nat_defipage;
+	u_int		ipf_nat_deficmpage;
+	ipf_v4_masktab_t	ipf_nat_map_mask;
+	ipf_v6_masktab_t	ipf_nat6_map_mask;
+	ipf_v4_masktab_t	ipf_nat_rdr_mask;
+	ipf_v6_masktab_t	ipf_nat6_rdr_mask;
+	nat_t		**ipf_nat_table[2];
+	nat_t		*ipf_nat_instances;
+	ipnat_t		*ipf_nat_list;
+	ipnat_t		**ipf_nat_list_tail;
+	ipnat_t		**ipf_nat_map_rules;
+	ipnat_t		**ipf_nat_rdr_rules;
+	ipftq_t		*ipf_nat_utqe;
+	hostmap_t	**ipf_hm_maptable ;
+	hostmap_t	*ipf_hm_maplist ;
+	ipftuneable_t	*ipf_nat_tune;
+	ipftq_t		ipf_nat_udptq;
+	ipftq_t		ipf_nat_udpacktq;
+	ipftq_t		ipf_nat_icmptq;
+	ipftq_t		ipf_nat_icmpacktq;
+	ipftq_t		ipf_nat_iptq;
+	ipftq_t		ipf_nat_pending;
+	ipftq_t		ipf_nat_tcptq[IPF_TCP_NSTATES];
+	natstat_t	ipf_nat_stats;
+} ipf_nat_softc_t ;
 
-extern	u_int	ipf_nattable_sz;
-extern	u_int	ipf_nattable_max;
-extern	u_int	ipf_natrules_sz;
-extern	u_int	ipf_rdrrules_sz;
-extern	u_int	ipf_hostmap_sz;
-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;
-extern	u_long	fr_defnatipage;
-	/* nat_table[0] -> hashed list sorted by inside (ip, port) */
-	/* nat_table[1] -> hashed list sorted by outside (ip, port) */
-extern	nat_t	**nat_table[2];
-extern	nat_t	*nat_instances;
-extern	ipnat_t	*nat_list;
-extern	ipnat_t	**nat_rules;
-extern	ipnat_t	**rdr_rules;
-extern	ipftq_t	*nat_utqe;
-extern	natstat_t	nat_stats;
+#define	ipf_nat_map_max			ipf_nat_map_mask.imt4_max
+#define	ipf_nat_rdr_max			ipf_nat_rdr_mask.imt4_max
+#define	ipf_nat6_map_max		ipf_nat6_map_mask.imt6_max
+#define	ipf_nat6_rdr_max		ipf_nat6_rdr_mask.imt6_max
+#define	ipf_nat_map_active_masks	ipf_nat_map_mask.imt4_active
+#define	ipf_nat_rdr_active_masks	ipf_nat_rdr_mask.imt4_active
+#define	ipf_nat6_map_active_masks	ipf_nat6_map_mask.imt6_active
+#define	ipf_nat6_rdr_active_masks	ipf_nat6_rdr_mask.imt6_active
 
+extern	frentry_t 	ipfnatblock;
+
+extern	void	ipf_fix_datacksum __P((u_short *, u_32_t));
+extern	void	ipf_fix_incksum __P((int, u_short *, u_32_t, u_32_t));
+extern	void	ipf_fix_outcksum __P((int, u_short *, u_32_t, u_32_t));
+
+extern	int	ipf_nat_checkin __P((fr_info_t *, u_32_t *));
+extern	int	ipf_nat_checkout __P((fr_info_t *, u_32_t *));
+extern	void	ipf_nat_delete __P((ipf_main_softc_t *, struct nat *, int));
+extern	void	ipf_nat_deref __P((ipf_main_softc_t *, nat_t **));
+extern	void	ipf_nat_expire __P((ipf_main_softc_t *));
+extern	int	ipf_nat_hashtab_add __P((ipf_main_softc_t *,
+					 ipf_nat_softc_t *, nat_t *));
+extern	void	ipf_nat_hostmapdel __P((ipf_main_softc_t *, hostmap_t **));
+extern	int	ipf_nat_hostmap_rehash __P((ipf_main_softc_t *,
+					    ipftuneable_t *, ipftuneval_t *));
+extern	nat_t	*ipf_nat_icmperrorlookup __P((fr_info_t *, int));
+extern	nat_t	*ipf_nat_icmperror __P((fr_info_t *, u_int *, int));
 #if defined(__OpenBSD__)
-extern	void	nat_ifdetach __P((void *));
+extern	void	ipf_nat_ifdetach __P((void *));
 #endif
-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,
-				 struct in_addr));
-extern	void	fix_datacksum __P((u_short *, u_32_t));
-extern	nat_t	*nat_inlookup __P((fr_info_t *, u_int, u_int, struct in_addr,
+extern	int	ipf_nat_init __P((void));
+extern	nat_t	*ipf_nat_inlookup __P((fr_info_t *, u_int, u_int,
+				      struct in_addr, struct in_addr));
+extern	int	ipf_nat_in __P((fr_info_t *, nat_t *, int, u_32_t));
+extern	int	ipf_nat_insert __P((ipf_main_softc_t *, ipf_nat_softc_t *,
+				    nat_t *));
+extern	int	ipf_nat_ioctl __P((ipf_main_softc_t *, caddr_t, ioctlcmd_t,
+				   int, int, void *));
+extern	void	ipf_nat_log __P((ipf_main_softc_t *, ipf_nat_softc_t *,
+				 struct nat *, u_int));
+extern	nat_t	*ipf_nat_lookupredir __P((natlookup_t *));
+extern	nat_t	*ipf_nat_maplookup __P((void *, u_int, struct in_addr,
 				struct in_addr));
-extern	nat_t	*nat_tnlookup __P((fr_info_t *, int));
-extern	nat_t	*nat_maplookup __P((void *, u_int, struct in_addr,
-				struct in_addr));
-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	nat_t	*ipf_nat_add __P((fr_info_t *, ipnat_t *, nat_t **,
+				 u_int, int));
+extern	int	ipf_nat_out __P((fr_info_t *, nat_t *, int, u_32_t));
+extern	nat_t	*ipf_nat_outlookup __P((fr_info_t *, u_int, u_int,
+				       struct in_addr, struct in_addr));
+extern	u_short	*ipf_nat_proto __P((fr_info_t *, nat_t *, u_int));
+extern	void	ipf_nat_rule_deref __P((ipf_main_softc_t *, ipnat_t **));
+extern	void	ipf_nat_setqueue __P((ipf_main_softc_t *, ipf_nat_softc_t *,
+				      nat_t *));
+extern	void	ipf_nat_setpending __P((ipf_main_softc_t *, nat_t *));
+extern	nat_t	*ipf_nat_tnlookup __P((fr_info_t *, int));
+extern	void	ipf_nat_update __P((fr_info_t *, nat_t *));
+extern	int	ipf_nat_rehash __P((ipf_main_softc_t *, ipftuneable_t *,
+				    ipftuneval_t *));
+extern	int	ipf_nat_rehash_rules __P((ipf_main_softc_t *, ipftuneable_t *,
+					  ipftuneval_t *));
+extern	int	ipf_nat_settimeout __P((struct ipf_main_softc_s *,
+					ipftuneable_t *, ipftuneval_t *));
+extern	void	ipf_nat_sync __P((ipf_main_softc_t *, void *));
 
-extern	int	fr_checknatout __P((fr_info_t *, u_32_t *));
-extern	int	fr_natout __P((fr_info_t *, nat_t *, int, u_32_t));
-extern	int	fr_checknatin __P((fr_info_t *, u_32_t *));
-extern	int	fr_natin __P((fr_info_t *, nat_t *, int, u_32_t));
-extern	void	fr_natunload __P((void));
-extern	void	fr_natexpire __P((void));
-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 **));
+extern	nat_t	*ipf_nat_clone __P((fr_info_t *, nat_t *));
+extern	void	ipf_nat_delmap __P((ipf_nat_softc_t *, ipnat_t *));
+extern	void	ipf_nat_delrdr __P((ipf_nat_softc_t *, ipnat_t *));
+extern	int	ipf_nat_wildok __P((nat_t *, int, int, int, int));
+extern	void	ipf_nat_setlock __P((void *, int));
+extern	void	ipf_nat_load __P((void));
+extern	void	*ipf_nat_soft_create __P((ipf_main_softc_t *));
+extern	int	ipf_nat_soft_init __P((ipf_main_softc_t *, void *));
+extern	void	ipf_nat_soft_destroy __P((ipf_main_softc_t *, void *));
+extern	int	ipf_nat_soft_fini __P((ipf_main_softc_t *, void *));
+extern	int	ipf_nat_main_load __P((void));
+extern	int	ipf_nat_main_unload __P((void));
+extern	ipftq_t	*ipf_nat_add_tq __P((ipf_main_softc_t *, int));
+extern	void	ipf_nat_uncreate __P((fr_info_t *));
 
+#ifdef USE_INET6
+extern	nat_t	*ipf_nat6_add __P((fr_info_t *, ipnat_t *, nat_t **,
+				   u_int, int));
+extern	void	ipf_nat6_addrdr __P((ipf_nat_softc_t *, ipnat_t *));
+extern	void	ipf_nat6_addmap __P((ipf_nat_softc_t *, ipnat_t *));
+extern	void	ipf_nat6_addencap __P((ipf_nat_softc_t *, ipnat_t *));
+extern	int	ipf_nat6_checkout __P((fr_info_t *, u_32_t *));
+extern	int	ipf_nat6_checkin __P((fr_info_t *, u_32_t *));
+extern	void	ipf_nat6_delmap __P((ipf_nat_softc_t *, ipnat_t *));
+extern	void	ipf_nat6_delrdr __P((ipf_nat_softc_t *, ipnat_t *));
+extern	int	ipf_nat6_finalise __P((fr_info_t *, nat_t *));
+extern	nat_t	*ipf_nat6_icmperror __P((fr_info_t *, u_int *, int));
+extern	nat_t	*ipf_nat6_icmperrorlookup __P((fr_info_t *, int));
+extern	nat_t	*ipf_nat6_inlookup __P((fr_info_t *, u_int, u_int,
+					struct in6_addr *, struct in6_addr *));
+extern	u_32_t	ipf_nat6_ip6subtract __P((i6addr_t *, i6addr_t *));
+extern	frentry_t *ipf_nat6_ipfin __P((fr_info_t *, u_32_t *));
+extern	frentry_t *ipf_nat6_ipfout __P((fr_info_t *, u_32_t *));
+extern	nat_t	*ipf_nat6_lookupredir __P((natlookup_t *));
+extern	int	ipf_nat6_newmap __P((fr_info_t *, nat_t *, natinfo_t *));
+extern	int	ipf_nat6_newrdr __P((fr_info_t *, nat_t *, natinfo_t *));
+extern	nat_t	*ipf_nat6_outlookup __P((fr_info_t *, u_int, u_int,
+					 struct in6_addr *, struct in6_addr *));
+extern	int	ipf_nat6_newrewrite __P((fr_info_t *, nat_t *, natinfo_t *));
+extern	int	ipf_nat6_newdivert __P((fr_info_t *, nat_t *, natinfo_t *));
+extern	int	ipf_nat6_ruleaddrinit __P((ipf_main_softc_t *, ipf_nat_softc_t *, ipnat_t *));
+
+#endif
+
+
 #endif /* __IP_NAT_H__ */

Added: trunk/sys/contrib/ipfilter/netinet/ip_nat6.c
===================================================================
--- trunk/sys/contrib/ipfilter/netinet/ip_nat6.c	                        (rev 0)
+++ trunk/sys/contrib/ipfilter/netinet/ip_nat6.c	2018-05-28 18:56:30 UTC (rev 10139)
@@ -0,0 +1,4099 @@
+/* $MidnightBSD$ */
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ */
+#if defined(KERNEL) || defined(_KERNEL)
+# undef KERNEL
+# undef _KERNEL
+# define        KERNEL	1
+# define        _KERNEL	1
+#endif
+#include <sys/errno.h>
+#include <sys/types.h>
+#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(_KERNEL)
+# include <stdio.h>
+# include <string.h>
+# include <stdlib.h>
+# define _KERNEL
+# ifdef ipf_nat6__OpenBSD__
+struct file;
+# endif
+# include <sys/uio.h>
+# undef _KERNEL
+#endif
+#if defined(_KERNEL) && (__FreeBSD_version >= 220000)
+# include <sys/filio.h>
+# include <sys/fcntl.h>
+#else
+# include <sys/ioctl.h>
+#endif
+#if !defined(AIX)
+# include <sys/fcntl.h>
+#endif
+#if !defined(linux)
+# include <sys/protosw.h>
+#endif
+#include <sys/socket.h>
+#if defined(_KERNEL)
+# include <sys/systm.h>
+# if !defined(__SVR4) && !defined(__svr4__)
+#  include <sys/mbuf.h>
+# endif
+#endif
+#if defined(__SVR4) || defined(__svr4__)
+# include <sys/filio.h>
+# include <sys/byteorder.h>
+# ifdef _KERNEL
+#  include <sys/dditypes.h>
+# endif
+# include <sys/stream.h>
+# include <sys/kmem.h>
+#endif
+#if __FreeBSD_version >= 300000
+# include <sys/queue.h>
+#endif
+#include <net/if.h>
+#if __FreeBSD_version >= 300000
+# include <net/if_var.h>
+#endif
+#ifdef sun
+# include <net/af.h>
+#endif
+#include <net/route.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+
+#ifdef RFC1825
+# include <vpn/md5.h>
+# include <vpn/ipsec.h>
+extern struct ifnet vpnif;
+#endif
+
+#if !defined(linux)
+# include <netinet/ip_var.h>
+#endif
+#include <netinet/tcp.h>
+#include <netinet/udp.h>
+#include <netinet/ip_icmp.h>
+#include "netinet/ip_compat.h"
+#include <netinet/tcpip.h>
+#include "netinet/ip_fil.h"
+#include "netinet/ip_nat.h"
+#include "netinet/ip_frag.h"
+#include "netinet/ip_state.h"
+#include "netinet/ip_proxy.h"
+#include "netinet/ip_lookup.h"
+#include "netinet/ip_dstlist.h"
+#include "netinet/ip_sync.h"
+#if (__FreeBSD_version >= 300000)
+# include <sys/malloc.h>
+#endif
+#ifdef HAS_SYS_MD5_H
+# include <sys/md5.h>
+#else
+# include "md5.h"
+#endif
+/* END OF INCLUDES */
+
+#undef	SOCKADDR_IN
+#define	SOCKADDR_IN	struct sockaddr_in
+
+#if !defined(lint)
+static const char rcsid[] = "@(#)$Id: ip_nat6.c,v 1.22.2.20 2012/07/22 08:04:23 darren_r Exp $";
+#endif
+
+#ifdef USE_INET6
+static struct hostmap *ipf_nat6_hostmap __P((ipf_nat_softc_t *, ipnat_t *,
+					     i6addr_t *, i6addr_t *,
+					     i6addr_t *, u_32_t));
+static int ipf_nat6_match __P((fr_info_t *, ipnat_t *));
+static void ipf_nat6_tabmove __P((ipf_nat_softc_t *, nat_t *));
+static int ipf_nat6_decap __P((fr_info_t *, nat_t *));
+static int ipf_nat6_nextaddr __P((fr_info_t *, nat_addr_t *, i6addr_t *,
+				  i6addr_t *));
+static int ipf_nat6_icmpquerytype __P((int));
+static int ipf_nat6_out __P((fr_info_t *, nat_t *, int, u_32_t));
+static int ipf_nat6_in __P((fr_info_t *, nat_t *, int, u_32_t));
+static int ipf_nat6_builddivertmp __P((ipf_nat_softc_t *, ipnat_t *));
+static int ipf_nat6_nextaddrinit __P((ipf_main_softc_t *, char *,
+				      nat_addr_t *, int, void *));
+static int ipf_nat6_insert __P((ipf_main_softc_t *, ipf_nat_softc_t *,
+				nat_t *));
+
+
+#define	NINCLSIDE6(y,x)	ATOMIC_INCL(softn->ipf_nat_stats.ns_side6[y].x)
+#define	NBUMPSIDE(y,x)	softn->ipf_nat_stats.ns_side[y].x++
+#define	NBUMPSIDE6(y,x)	softn->ipf_nat_stats.ns_side6[y].x++
+#define	NBUMPSIDE6D(y,x) \
+			do { \
+				softn->ipf_nat_stats.ns_side6[y].x++; \
+				DT(x); \
+			} while (0)
+#define	NBUMPSIDE6DX(y,x,z) \
+			do { \
+				softn->ipf_nat_stats.ns_side6[y].x++; \
+				DT(z); \
+			} while (0)
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_nat6_ruleaddrinit                                       */
+/* Returns:     int   - 0 == success, else failure                          */
+/* Parameters:  in(I) - NAT rule that requires address fields to be init'd  */
+/*                                                                          */
+/* For each of the source/destination address fields in a NAT rule, call    */
+/* ipf_nat6_nextaddrinit() to prepare the structure for active duty.  Other */
+/* IPv6 specific actions can also be taken care of here.                    */
+/* ------------------------------------------------------------------------ */
+int
+ipf_nat6_ruleaddrinit(softc, softn, n)
+	ipf_main_softc_t *softc;
+	ipf_nat_softc_t *softn;
+	ipnat_t *n;
+{
+	int idx, error;
+
+	if (n->in_redir == NAT_BIMAP) {
+		n->in_ndstip6 = n->in_osrcip6;
+		n->in_ndstmsk6 = n->in_osrcmsk6;
+		n->in_odstip6 = n->in_nsrcip6;
+		n->in_odstmsk6 = n->in_nsrcmsk6;
+
+	}
+
+	if (n->in_redir & NAT_REDIRECT)
+		idx = 1;
+	else
+		idx = 0;
+	/*
+	 * Initialise all of the address fields.
+	 */
+	error = ipf_nat6_nextaddrinit(softc, n->in_names, &n->in_osrc, 1,
+				      n->in_ifps[idx]);
+	if (error != 0)
+		return error;
+
+	error = ipf_nat6_nextaddrinit(softc, n->in_names, &n->in_odst, 1,
+				      n->in_ifps[idx]);
+	if (error != 0)
+		return error;
+
+	error = ipf_nat6_nextaddrinit(softc, n->in_names, &n->in_nsrc, 1,
+				      n->in_ifps[idx]);
+	if (error != 0)
+		return error;
+
+	error = ipf_nat6_nextaddrinit(softc, n->in_names, &n->in_ndst, 1,
+				      n->in_ifps[idx]);
+	if (error != 0)
+		return error;
+
+	if (n->in_redir & NAT_DIVERTUDP)
+		ipf_nat6_builddivertmp(softn, n);
+	return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_nat6_addrdr                                             */
+/* Returns:     Nil                                                         */
+/* Parameters:  n(I) - pointer to NAT rule to add                           */
+/*                                                                          */
+/* Adds a redirect rule to the hash table of redirect rules and the list of */
+/* loaded NAT rules.  Updates the bitmask indicating which netmasks are in  */
+/* use by redirect rules.                                                   */
+/* ------------------------------------------------------------------------ */
+void
+ipf_nat6_addrdr(softn, n)
+	ipf_nat_softc_t *softn;
+	ipnat_t *n;
+{
+	i6addr_t *mask;
+	ipnat_t **np;
+	i6addr_t j;
+	u_int hv;
+	int k;
+
+	if ((n->in_redir & NAT_BIMAP) == NAT_BIMAP) {
+		k = count6bits(n->in_nsrcmsk6.i6);
+		mask = &n->in_nsrcmsk6;
+		IP6_AND(&n->in_odstip6, &n->in_odstmsk6, &j);
+		hv = NAT_HASH_FN6(&j, 0, softn->ipf_nat_rdrrules_sz);
+
+	} else if (n->in_odstatype == FRI_NORMAL) {
+		k = count6bits(n->in_odstmsk6.i6);
+		mask = &n->in_odstmsk6;
+		IP6_AND(&n->in_odstip6, &n->in_odstmsk6, &j);
+		hv = NAT_HASH_FN6(&j, 0, softn->ipf_nat_rdrrules_sz);
+	} else {
+		k = 0;
+		hv = 0;
+		mask = NULL;
+	}
+	ipf_inet6_mask_add(k, mask, &softn->ipf_nat6_rdr_mask);
+
+	np = softn->ipf_nat_rdr_rules + hv;
+	while (*np != NULL)
+		np = &(*np)->in_rnext;
+	n->in_rnext = NULL;
+	n->in_prnext = np;
+	n->in_hv[0] = hv;
+	n->in_use++;
+	*np = n;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_nat6_addmap                                             */
+/* Returns:     Nil                                                         */
+/* Parameters:  n(I) - pointer to NAT rule to add                           */
+/*                                                                          */
+/* Adds a NAT map rule to the hash table of rules and the list of  loaded   */
+/* NAT rules.  Updates the bitmask indicating which netmasks are in use by  */
+/* redirect rules.                                                          */
+/* ------------------------------------------------------------------------ */
+void
+ipf_nat6_addmap(softn, n)
+	ipf_nat_softc_t *softn;
+	ipnat_t *n;
+{
+	i6addr_t *mask;
+	ipnat_t **np;
+	i6addr_t j;
+	u_int hv;
+	int k;
+
+	if (n->in_osrcatype == FRI_NORMAL) {
+		k = count6bits(n->in_osrcmsk6.i6);
+		mask = &n->in_osrcmsk6;
+		IP6_AND(&n->in_osrcip6, &n->in_osrcmsk6, &j);
+		hv = NAT_HASH_FN6(&j, 0, softn->ipf_nat_maprules_sz);
+	} else {
+		k = 0;
+		hv = 0;
+		mask = NULL;
+	}
+	ipf_inet6_mask_add(k, mask, &softn->ipf_nat6_map_mask);
+
+	np = softn->ipf_nat_map_rules + hv;
+	while (*np != NULL)
+		np = &(*np)->in_mnext;
+	n->in_mnext = NULL;
+	n->in_pmnext = np;
+	n->in_hv[1] = hv;
+	n->in_use++;
+	*np = n;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_nat6_del_rdr                                             */
+/* Returns:     Nil                                                         */
+/* Parameters:  n(I) - pointer to NAT rule to delete                        */
+/*                                                                          */
+/* Removes a NAT rdr rule from the hash table of NAT rdr rules.             */
+/* ------------------------------------------------------------------------ */
+void
+ipf_nat6_delrdr(softn, n)
+	ipf_nat_softc_t *softn;
+	ipnat_t *n;
+{
+	i6addr_t *mask;
+	int k;
+
+	if ((n->in_redir & NAT_BIMAP) == NAT_BIMAP) {
+		k = count6bits(n->in_nsrcmsk6.i6);
+		mask = &n->in_nsrcmsk6;
+	} else if (n->in_odstatype == FRI_NORMAL) {
+		k = count6bits(n->in_odstmsk6.i6);
+		mask = &n->in_odstmsk6;
+	} else {
+		k = 0;
+		mask = NULL;
+	}
+	ipf_inet6_mask_del(k, mask, &softn->ipf_nat6_rdr_mask);
+
+	if (n->in_rnext != NULL)
+		n->in_rnext->in_prnext = n->in_prnext;
+	*n->in_prnext = n->in_rnext;
+	n->in_use--;
+}
+                                        
+                       
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_nat6_delmap                                             */
+/* Returns:     Nil                                                         */
+/* Parameters:  n(I) - pointer to NAT rule to delete                        */
+/*                                                                          */
+/* Removes a NAT map rule from the hash table of NAT map rules.             */
+/* ------------------------------------------------------------------------ */
+void
+ipf_nat6_delmap(softn, n)
+	ipf_nat_softc_t *softn;
+	ipnat_t *n;
+{
+	i6addr_t *mask;
+	int k;
+
+	if (n->in_osrcatype == FRI_NORMAL) {
+		k = count6bits(n->in_osrcmsk6.i6);
+		mask = &n->in_osrcmsk6;
+	} else {
+		k = 0;
+		mask = NULL;
+	}
+	ipf_inet6_mask_del(k, mask, &softn->ipf_nat6_map_mask);
+
+	if (n->in_mnext != NULL)
+		n->in_mnext->in_pmnext = n->in_pmnext;
+	*n->in_pmnext = n->in_mnext;
+	n->in_use--;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_nat6_hostmap                                            */
+/* Returns:     struct hostmap* - NULL if no hostmap could be created,      */
+/*                                else a pointer to the hostmapping to use  */
+/* Parameters:  np(I)   - pointer to NAT rule                               */
+/*              real(I) - real IP address                                   */
+/*              map(I)  - mapped IP address                                 */
+/*              port(I) - destination port number                           */
+/* Write Locks: ipf_nat                                                     */
+/*                                                                          */
+/* Check if an ip address has already been allocated for a given mapping    */
+/* that is not doing port based translation.  If is not yet allocated, then */
+/* create a new entry if a non-NULL NAT rule pointer has been supplied.     */
+/* ------------------------------------------------------------------------ */
+static struct hostmap *
+ipf_nat6_hostmap(softn, np, src, dst, map, port)
+	ipf_nat_softc_t *softn;
+	ipnat_t *np;
+	i6addr_t *src, *dst, *map;
+	u_32_t port;
+{
+	hostmap_t *hm;
+	u_int hv;
+
+	hv = (src->i6[3] ^ dst->i6[3]);
+	hv += (src->i6[2] ^ dst->i6[2]);
+	hv += (src->i6[1] ^ dst->i6[1]);
+	hv += (src->i6[0] ^ dst->i6[0]);
+	hv += src->i6[3];
+	hv += src->i6[2];
+	hv += src->i6[1];
+	hv += src->i6[0];
+	hv += dst->i6[3];
+	hv += dst->i6[2];
+	hv += dst->i6[1];
+	hv += dst->i6[0];
+	hv %= HOSTMAP_SIZE;
+	for (hm = softn->ipf_hm_maptable[hv]; hm; hm = hm->hm_next)
+		if (IP6_EQ(&hm->hm_osrc6, src) &&
+		    IP6_EQ(&hm->hm_odst6, dst) &&
+		    ((np == NULL) || (np == hm->hm_ipnat)) &&
+		    ((port == 0) || (port == hm->hm_port))) {
+			softn->ipf_nat_stats.ns_hm_addref++;
+			hm->hm_ref++;
+			return hm;
+		}
+
+	if (np == NULL) {
+		softn->ipf_nat_stats.ns_hm_nullnp++;
+		return NULL;
+	}
+
+	KMALLOC(hm, hostmap_t *);
+	if (hm) {
+		hm->hm_next = softn->ipf_hm_maplist;
+		hm->hm_pnext = &softn->ipf_hm_maplist;
+		if (softn->ipf_hm_maplist != NULL)
+			softn->ipf_hm_maplist->hm_pnext = &hm->hm_next;
+		softn->ipf_hm_maplist = hm;
+		hm->hm_hnext = softn->ipf_hm_maptable[hv];
+		hm->hm_phnext = softn->ipf_hm_maptable + hv;
+		if (softn->ipf_hm_maptable[hv] != NULL)
+			softn->ipf_hm_maptable[hv]->hm_phnext = &hm->hm_hnext;
+		softn->ipf_hm_maptable[hv] = hm;
+		hm->hm_ipnat = np;
+		np->in_use++;
+		hm->hm_osrcip6 = *src;
+		hm->hm_odstip6 = *dst;
+		hm->hm_nsrcip6 = *map;
+		hm->hm_ndstip6.i6[0] = 0;
+		hm->hm_ndstip6.i6[1] = 0;
+		hm->hm_ndstip6.i6[2] = 0;
+		hm->hm_ndstip6.i6[3] = 0;
+		hm->hm_ref = 1;
+		hm->hm_port = port;
+		hm->hm_hv = hv;
+		hm->hm_v = 6;
+		softn->ipf_nat_stats.ns_hm_new++;
+	} else {
+		softn->ipf_nat_stats.ns_hm_newfail++;
+	}
+	return hm;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_nat6_newmap                                             */
+/* Returns:     int - -1 == error, 0 == success                             */
+/* Parameters:  fin(I) - pointer to packet information                      */
+/*              nat(I) - pointer to NAT entry                               */
+/*              ni(I)  - pointer to structure with misc. information needed */
+/*                       to create new NAT entry.                           */
+/*                                                                          */
+/* Given an empty NAT structure, populate it with new information about a   */
+/* new NAT session, as defined by the matching NAT rule.                    */
+/* ni.nai_ip is passed in uninitialised and must be set, in host byte order,*/
+/* to the new IP address for the translation.                               */
+/* ------------------------------------------------------------------------ */
+int
+ipf_nat6_newmap(fin, nat, ni)
+	fr_info_t *fin;
+	nat_t *nat;
+	natinfo_t *ni;
+{
+	ipf_main_softc_t *softc = fin->fin_main_soft;
+	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
+	u_short st_port, dport, sport, port, sp, dp;
+	i6addr_t in, st_ip;
+	hostmap_t *hm;
+	u_32_t flags;
+	ipnat_t *np;
+	nat_t *natl;
+	int l;
+
+	/*
+	 * If it's an outbound packet which doesn't match any existing
+	 * record, then create a new port
+	 */
+	l = 0;
+	hm = NULL;
+	np = ni->nai_np;
+	st_ip = np->in_snip6;
+	st_port = np->in_spnext;
+	flags = nat->nat_flags;
+
+	if (flags & IPN_ICMPQUERY) {
+		sport = fin->fin_data[1];
+		dport = 0;
+	} else {
+		sport = htons(fin->fin_data[0]);
+		dport = htons(fin->fin_data[1]);
+	}
+
+	/*
+	 * Do a loop until we either run out of entries to try or we find
+	 * a NAT mapping that isn't currently being used.  This is done
+	 * because the change to the source is not (usually) being fixed.
+	 */
+	do {
+		port = 0;
+		in = np->in_nsrc.na_nextaddr;
+		if (l == 0) {
+			/*
+			 * Check to see if there is an existing NAT
+			 * setup for this IP address pair.
+			 */
+			hm = ipf_nat6_hostmap(softn, np, &fin->fin_src6,
+					      &fin->fin_dst6, &in, 0);
+			if (hm != NULL)
+				in = hm->hm_nsrcip6;
+		} else if ((l == 1) && (hm != NULL)) {
+			ipf_nat_hostmapdel(softc, &hm);
+		}
+
+		nat->nat_hm = hm;
+
+		if (IP6_ISONES(&np->in_nsrcmsk6) && (np->in_spnext == 0)) {
+			if (l > 0) {
+				NBUMPSIDE6DX(1, ns_exhausted, ns_exhausted_1);
+				return -1;
+			}
+		}
+
+		if ((np->in_redir == NAT_BIMAP) &&
+		    IP6_EQ(&np->in_osrcmsk6, &np->in_nsrcmsk6)) {
+			i6addr_t temp;
+			/*
+			 * map the address block in a 1:1 fashion
+			 */
+			temp.i6[0] = fin->fin_src6.i6[0] &
+				     ~np->in_osrcmsk6.i6[0];
+			temp.i6[1] = fin->fin_src6.i6[1] &
+				     ~np->in_osrcmsk6.i6[1];
+			temp.i6[2] = fin->fin_src6.i6[2] &
+				     ~np->in_osrcmsk6.i6[0];
+			temp.i6[3] = fin->fin_src6.i6[3] &
+				     ~np->in_osrcmsk6.i6[3];
+			in = np->in_nsrcip6;
+			IP6_MERGE(&in, &temp, &np->in_osrc);
+
+#ifdef NEED_128BIT_MATH
+		} else if (np->in_redir & NAT_MAPBLK) {
+			if ((l >= np->in_ppip) || ((l > 0) &&
+			     !(flags & IPN_TCPUDP))) {
+				NBUMPSIDE6DX(1, ns_exhausted, ns_exhausted_2);
+				return -1;
+			}
+			/*
+			 * map-block - Calculate destination address.
+			 */
+			IP6_MASK(&in, &fin->fin_src6, &np->in_osrcmsk6);
+			in = ntohl(in);
+			inb = in;
+			in.s_addr /= np->in_ippip;
+			in.s_addr &= ntohl(~np->in_nsrcmsk6);
+			in.s_addr += ntohl(np->in_nsrcaddr6);
+			/*
+			 * Calculate destination port.
+			 */
+			if ((flags & IPN_TCPUDP) &&
+			    (np->in_ppip != 0)) {
+				port = ntohs(sport) + l;
+				port %= np->in_ppip;
+				port += np->in_ppip *
+					(inb.s_addr % np->in_ippip);
+				port += MAPBLK_MINPORT;
+				port = htons(port);
+			}
+#endif
+
+		} else if (IP6_ISZERO(&np->in_nsrcaddr) &&
+			   IP6_ISONES(&np->in_nsrcmsk)) {
+			/*
+			 * 0/32 - use the interface's IP address.
+			 */
+			if ((l > 0) ||
+			    ipf_ifpaddr(softc, 6, FRI_NORMAL, fin->fin_ifp,
+				       &in, NULL) == -1) {
+				NBUMPSIDE6DX(1, ns_new_ifpaddr,
+					     ns_new_ifpaddr_1);
+				return -1;
+			}
+
+		} else if (IP6_ISZERO(&np->in_nsrcip6) &&
+			   IP6_ISZERO(&np->in_nsrcmsk6)) {
+			/*
+			 * 0/0 - use the original source address/port.
+			 */
+			if (l > 0) {
+				NBUMPSIDE6DX(1, ns_exhausted, ns_exhausted_3);
+				return -1;
+			}
+			in = fin->fin_src6;
+
+		} else if (!IP6_ISONES(&np->in_nsrcmsk6) &&
+			   (np->in_spnext == 0) && ((l > 0) || (hm == NULL))) {
+			IP6_INC(&np->in_snip6);
+		}
+
+		natl = NULL;
+
+		if ((flags & IPN_TCPUDP) &&
+		    ((np->in_redir & NAT_MAPBLK) == 0) &&
+		    (np->in_flags & IPN_AUTOPORTMAP)) {
+#ifdef NEED_128BIT_MATH
+			/*
+			 * "ports auto" (without map-block)
+			 */
+			if ((l > 0) && (l % np->in_ppip == 0)) {
+				if ((l > np->in_ppip) &&
+				    !IP6_ISONES(&np->in_nsrcmsk)) {
+					IP6_INC(&np->in_snip6)
+				}
+			}
+			if (np->in_ppip != 0) {
+				port = ntohs(sport);
+				port += (l % np->in_ppip);
+				port %= np->in_ppip;
+				port += np->in_ppip *
+					(ntohl(fin->fin_src6) %
+					 np->in_ippip);
+				port += MAPBLK_MINPORT;
+				port = htons(port);
+			}
+#endif
+
+		} else if (((np->in_redir & NAT_MAPBLK) == 0) &&
+			   (flags & IPN_TCPUDPICMP) && (np->in_spnext != 0)) {
+                        /*
+                         * Standard port translation.  Select next port.
+                         */
+                        if (np->in_flags & IPN_SEQUENTIAL) {
+                                port = np->in_spnext;
+                        } else {
+				port = ipf_random() % (np->in_spmax -
+						       np->in_spmin + 1);
+                                port += np->in_spmin;
+                        }
+                        port = htons(port);
+                        np->in_spnext++;
+
+			if (np->in_spnext > np->in_spmax) {
+				np->in_spnext = np->in_spmin;
+				if (!IP6_ISONES(&np->in_nsrcmsk6)) {
+					IP6_INC(&np->in_snip6);
+				}
+			}
+		}
+
+		if (np->in_flags & IPN_SIPRANGE) {
+			if (IP6_GT(&np->in_snip, &np->in_nsrcmsk))
+				np->in_snip6 = np->in_nsrcip6;
+		} else {
+			i6addr_t a1, a2;
+
+			a1 = np->in_snip6;
+			IP6_INC(&a1);
+			IP6_AND(&a1, &np->in_nsrcmsk6, &a2);
+
+			if (!IP6_ISONES(&np->in_nsrcmsk6) &&
+			    IP6_GT(&a2, &np->in_nsrcip6)) {
+				IP6_ADD(&np->in_nsrcip6, 1, &np->in_snip6);
+			}
+		}
+
+		if ((port == 0) && (flags & (IPN_TCPUDPICMP|IPN_ICMPQUERY)))
+			port = sport;
+
+		/*
+		 * Here we do a lookup of the connection as seen from
+		 * the outside.  If an IP# pair already exists, try
+		 * again.  So if you have A->B becomes C->B, you can
+		 * also have D->E become C->E but not D->B causing
+		 * another C->B.  Also take protocol and ports into
+		 * account when determining whether a pre-existing
+		 * NAT setup will cause an external conflict where
+		 * this is appropriate.
+		 */
+		sp = fin->fin_data[0];
+		dp = fin->fin_data[1];
+		fin->fin_data[0] = fin->fin_data[1];
+		fin->fin_data[1] = ntohs(port);
+		natl = ipf_nat6_inlookup(fin, flags & ~(SI_WILDP|NAT_SEARCH),
+					 (u_int)fin->fin_p, &fin->fin_dst6.in6,
+					 &in.in6);
+		fin->fin_data[0] = sp;
+		fin->fin_data[1] = dp;
+
+		/*
+		 * Has the search wrapped around and come back to the
+		 * start ?
+		 */
+		if ((natl != NULL) &&
+		    (np->in_spnext != 0) && (st_port == np->in_spnext) &&
+		    (!IP6_ISZERO(&np->in_snip6) &&
+		     IP6_EQ(&st_ip, &np->in_snip6))) {
+			NBUMPSIDE6D(1, ns_wrap);
+			return -1;
+		}
+		l++;
+	} while (natl != NULL);
+
+	/* Setup the NAT table */
+	nat->nat_osrc6 = fin->fin_src6;
+	nat->nat_nsrc6 = in;
+	nat->nat_odst6 = fin->fin_dst6;
+	nat->nat_ndst6 = fin->fin_dst6;
+	if (nat->nat_hm == NULL)
+		nat->nat_hm = ipf_nat6_hostmap(softn, np, &fin->fin_src6,
+					       &fin->fin_dst6,
+					       &nat->nat_nsrc6, 0);
+
+	if (flags & IPN_TCPUDP) {
+		nat->nat_osport = sport;
+		nat->nat_nsport = port;	/* sport */
+		nat->nat_odport = dport;
+		nat->nat_ndport = dport;
+		((tcphdr_t *)fin->fin_dp)->th_sport = port;
+	} else if (flags & IPN_ICMPQUERY) {
+		nat->nat_oicmpid = fin->fin_data[1];
+		((struct icmp6_hdr *)fin->fin_dp)->icmp6_id = port;
+		nat->nat_nicmpid = port;
+	}
+	return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_nat6_newrdr                                             */
+/* Returns:     int - -1 == error, 0 == success (no move), 1 == success and */
+/*                    allow rule to be moved if IPN_ROUNDR is set.          */
+/* Parameters:  fin(I) - pointer to packet information                      */
+/*              nat(I) - pointer to NAT entry                               */
+/*              ni(I)  - pointer to structure with misc. information needed */
+/*                       to create new NAT entry.                           */
+/*                                                                          */
+/* ni.nai_ip is passed in uninitialised and must be set, in host byte order,*/
+/* to the new IP address for the translation.                               */
+/* ------------------------------------------------------------------------ */
+int
+ipf_nat6_newrdr(fin, nat, ni)
+	fr_info_t *fin;
+	nat_t *nat;
+	natinfo_t *ni;
+{
+	ipf_main_softc_t *softc = fin->fin_main_soft;
+	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
+	u_short nport, dport, sport;
+	u_short sp, dp;
+	hostmap_t *hm;
+	u_32_t flags;
+	i6addr_t in;
+	ipnat_t *np;
+	nat_t *natl;
+	int move;
+
+	move = 1;
+	hm = NULL;
+	in.i6[0] = 0;
+	in.i6[1] = 0;
+	in.i6[2] = 0;
+	in.i6[3] = 0;
+	np = ni->nai_np;
+	flags = nat->nat_flags;
+
+	if (flags & IPN_ICMPQUERY) {
+		dport = fin->fin_data[1];
+		sport = 0;
+	} else {
+		sport = htons(fin->fin_data[0]);
+		dport = htons(fin->fin_data[1]);
+	}
+
+	/* TRACE sport, dport */
+
+
+	/*
+	 * If the matching rule has IPN_STICKY set, then we want to have the
+	 * same rule kick in as before.  Why would this happen?  If you have
+	 * a collection of rdr rules with "round-robin sticky", the current
+	 * 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_SPLIT)) != 0) &&
+	    ((np->in_flags & IPN_STICKY) != 0)) {
+		hm = ipf_nat6_hostmap(softn, NULL, &fin->fin_src6,
+				      &fin->fin_dst6, &in, (u_32_t)dport);
+		if (hm != NULL) {
+			in = hm->hm_ndstip6;
+			np = hm->hm_ipnat;
+			ni->nai_np = np;
+			move = 0;
+		}
+	}
+
+	/*
+	 * Otherwise, it's an inbound packet. Most likely, we don't
+	 * want to rewrite source ports and source addresses. Instead,
+	 * we want to rewrite to a fixed internal address and fixed
+	 * internal port.
+	 */
+	if (np->in_flags & IPN_SPLIT) {
+		in = np->in_dnip6;
+
+		if ((np->in_flags & (IPN_ROUNDR|IPN_STICKY)) == IPN_STICKY) {
+			hm = ipf_nat6_hostmap(softn, NULL, &fin->fin_src6,
+					      &fin->fin_dst6, &in,
+					      (u_32_t)dport);
+			if (hm != NULL) {
+				in = hm->hm_ndstip6;
+				move = 0;
+			}
+		}
+
+		if (hm == NULL || hm->hm_ref == 1) {
+			if (IP6_EQ(&np->in_ndstip6, &in)) {
+				np->in_dnip6 = np->in_ndstmsk6;
+				move = 0;
+			} else {
+				np->in_dnip6 = np->in_ndstip6;
+			}
+		}
+
+	} else if (IP6_ISZERO(&np->in_ndstaddr) &&
+		   IP6_ISONES(&np->in_ndstmsk)) {
+		/*
+		 * 0/32 - use the interface's IP address.
+		 */
+		if (ipf_ifpaddr(softc, 6, FRI_NORMAL, fin->fin_ifp,
+			       &in, NULL) == -1) {
+			NBUMPSIDE6DX(0, ns_new_ifpaddr, ns_new_ifpaddr_2);
+			return -1;
+		}
+
+	} else if (IP6_ISZERO(&np->in_ndstip6) &&
+		   IP6_ISZERO(&np->in_ndstmsk6)) {
+		/*
+		 * 0/0 - use the original destination address/port.
+		 */
+		in = fin->fin_dst6;
+
+	} else if (np->in_redir == NAT_BIMAP &&
+		   IP6_EQ(&np->in_ndstmsk6, &np->in_odstmsk6)) {
+		i6addr_t temp;
+		/*
+		 * map the address block in a 1:1 fashion
+		 */
+		temp.i6[0] = fin->fin_dst6.i6[0] & ~np->in_osrcmsk6.i6[0];
+		temp.i6[1] = fin->fin_dst6.i6[1] & ~np->in_osrcmsk6.i6[1];
+		temp.i6[2] = fin->fin_dst6.i6[2] & ~np->in_osrcmsk6.i6[0];
+		temp.i6[3] = fin->fin_dst6.i6[3] & ~np->in_osrcmsk6.i6[3];
+		in = np->in_ndstip6;
+		IP6_MERGE(&in, &temp, &np->in_ndstmsk6);
+	} else {
+		in = np->in_ndstip6;
+	}
+
+	if ((np->in_dpnext == 0) || ((flags & NAT_NOTRULEPORT) != 0))
+		nport = dport;
+	else {
+		/*
+		 * Whilst not optimized for the case where
+		 * pmin == pmax, the gain is not significant.
+		 */
+		if (((np->in_flags & IPN_FIXEDDPORT) == 0) &&
+		    (np->in_odport != np->in_dtop)) {
+			nport = ntohs(dport) - np->in_odport + np->in_dpmax;
+			nport = htons(nport);
+		} else {
+			nport = htons(np->in_dpnext);
+			np->in_dpnext++;
+			if (np->in_dpnext > np->in_dpmax)
+				np->in_dpnext = np->in_dpmin;
+		}
+	}
+
+	/*
+	 * When the redirect-to address is set to 0.0.0.0, just
+	 * assume a blank `forwarding' of the packet.  We don't
+	 * setup any translation for this either.
+	 */
+	if (IP6_ISZERO(&in)) {
+		if (nport == dport) {
+			NBUMPSIDE6D(0, ns_xlate_null);
+			return -1;
+		}
+		in = fin->fin_dst6;
+	}
+
+	/*
+	 * 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.)
+	 */
+	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 = ipf_nat6_outlookup(fin, flags & ~(SI_WILDP|NAT_SEARCH),
+				  (u_int)fin->fin_p, &in.in6,
+				  &fin->fin_src6.in6);
+	fin->fin_data[0] = sp;
+	fin->fin_data[1] = dp;
+	if (natl != NULL) {
+		NBUMPSIDE6D(0, ns_xlate_exists);
+		return -1;
+	}
+
+	nat->nat_ndst6 = in;
+	nat->nat_odst6 = fin->fin_dst6;
+	nat->nat_nsrc6 = fin->fin_src6;
+	nat->nat_osrc6 = fin->fin_src6;
+	if ((nat->nat_hm == NULL) && ((np->in_flags & IPN_STICKY) != 0))
+		nat->nat_hm = ipf_nat6_hostmap(softn, np, &fin->fin_src6,
+					       &fin->fin_dst6, &in,
+					       (u_32_t)dport);
+
+	if (flags & IPN_TCPUDP) {
+		nat->nat_odport = dport;
+		nat->nat_ndport = nport;
+		nat->nat_osport = sport;
+		nat->nat_nsport = sport;
+		((tcphdr_t *)fin->fin_dp)->th_dport = nport;
+	} else if (flags & IPN_ICMPQUERY) {
+		nat->nat_oicmpid = fin->fin_data[1];
+		((struct icmp6_hdr *)fin->fin_dp)->icmp6_id = nport;
+		nat->nat_nicmpid = nport;
+	}
+
+	return move;
+}
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_nat6_add                                                */
+/* Returns:     nat6_t*      - NULL == failure to create new NAT structure, */
+/*                             else pointer to new NAT structure            */
+/* Parameters:  fin(I)       - pointer to packet information                */
+/*              np(I)        - pointer to NAT rule                          */
+/*              natsave(I)   - pointer to where to store NAT struct pointer */
+/*              flags(I)     - flags describing the current packet          */
+/*              direction(I) - direction of packet (in/out)                 */
+/* Write Lock:  ipf_nat                                                     */
+/*                                                                          */
+/* Attempts to create a new NAT entry.  Does not actually change the packet */
+/* in any way.                                                              */
+/*                                                                          */
+/* This fucntion is in three main parts: (1) deal with creating a new NAT   */
+/* 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 *
+ipf_nat6_add(fin, np, natsave, flags, direction)
+	fr_info_t *fin;
+	ipnat_t *np;
+	nat_t **natsave;
+	u_int flags;
+	int direction;
+{
+	ipf_main_softc_t *softc = fin->fin_main_soft;
+	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
+	hostmap_t *hm = NULL;
+	nat_t *nat, *natl;
+	natstat_t *nsp;
+	u_int nflags;
+	natinfo_t ni;
+	int move;
+#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) && defined(ICK_M_CTL_MAGIC)
+	qpktinfo_t *qpi = fin->fin_qpi;
+#endif
+
+	nsp = &softn->ipf_nat_stats;
+
+	if ((nsp->ns_active * 100 / softn->ipf_nat_table_max) >
+	    softn->ipf_nat_table_wm_high) {
+		softn->ipf_nat_doflush = 1;
+	}
+
+	if (nsp->ns_active >= softn->ipf_nat_table_max) {
+		NBUMPSIDE6(fin->fin_out, ns_table_max);
+		return NULL;
+	}
+
+	move = 1;
+	nflags = np->in_flags & flags;
+	nflags &= NAT_FROMRULE;
+
+	ni.nai_np = np;
+	ni.nai_dport = 0;
+	ni.nai_sport = 0;
+
+	/* Give me a new nat */
+	KMALLOC(nat, nat_t *);
+	if (nat == NULL) {
+		NBUMPSIDE6(fin->fin_out, ns_memfail);
+		/*
+		 * Try to automatically tune the max # of entries in the
+		 * table allowed to be less than what will cause kmem_alloc()
+		 * to fail and try to eliminate panics due to out of memory
+		 * conditions arising.
+		 */
+		if ((softn->ipf_nat_table_max > softn->ipf_nat_table_sz) &&
+		    (nsp->ns_active > 100)) {
+			softn->ipf_nat_table_max = nsp->ns_active - 100;
+			printf("table_max reduced to %d\n",
+				softn->ipf_nat_table_max);
+		}
+		return NULL;
+	}
+
+	if (flags & IPN_ICMPQUERY) {
+		/*
+		 * In the ICMP query NAT code, we translate the ICMP id fields
+		 * to make them unique. This is indepedent of the ICMP type
+		 * (e.g. in the unlikely event that a host sends an echo and
+		 * an tstamp request with the same id, both packets will have
+		 * their ip address/id field changed in the same way).
+		 */
+		/* The icmp6_id field is used by the sender to identify the
+		 * process making the icmp request. (the receiver justs
+		 * copies it back in its response). So, it closely matches
+		 * the concept of source port. We overlay sport, so we can
+		 * maximally reuse the existing code.
+		 */
+		ni.nai_sport = fin->fin_data[1];
+		ni.nai_dport = 0;
+	}
+
+	bzero((char *)nat, sizeof(*nat));
+	nat->nat_flags = flags;
+	nat->nat_redir = np->in_redir;
+	nat->nat_dir = direction;
+	nat->nat_pr[0] = fin->fin_p;
+	nat->nat_pr[1] = fin->fin_p;
+
+	/*
+	 * Search the current table for a match and create a new mapping
+	 * if there is none found.
+	 */
+	if (np->in_redir & NAT_DIVERTUDP) {
+		move = ipf_nat6_newdivert(fin, nat, &ni);
+
+	} else if (np->in_redir & NAT_REWRITE) {
+		move = ipf_nat6_newrewrite(fin, nat, &ni);
+
+	} else if (direction == NAT_OUTBOUND) {
+		/*
+		 * We can now arrange to call this for the same connection
+		 * because ipf_nat6_new doesn't protect the code path into
+		 * this function.
+		 */
+		natl = ipf_nat6_outlookup(fin, nflags, (u_int)fin->fin_p,
+					  &fin->fin_src6.in6,
+					  &fin->fin_dst6.in6);
+		if (natl != NULL) {
+			KFREE(nat);
+			nat = natl;
+			goto done;
+		}
+
+		move = ipf_nat6_newmap(fin, nat, &ni);
+	} else {
+		/*
+		 * NAT_INBOUND is used for redirects rules
+		 */
+		natl = ipf_nat6_inlookup(fin, nflags, (u_int)fin->fin_p,
+					 &fin->fin_src6.in6,
+					 &fin->fin_dst6.in6);
+		if (natl != NULL) {
+			KFREE(nat);
+			nat = natl;
+			goto done;
+		}
+
+		move = ipf_nat6_newrdr(fin, nat, &ni);
+	}
+	if (move == -1)
+		goto badnat;
+
+	np = ni.nai_np;
+
+	nat->nat_mssclamp = np->in_mssclamp;
+	nat->nat_me = natsave;
+	nat->nat_fr = fin->fin_fr;
+	nat->nat_rev = fin->fin_rev;
+	nat->nat_ptr = np;
+	nat->nat_dlocal = np->in_dlocal;
+
+	if ((np->in_apr != NULL) && ((nat->nat_flags & NAT_SLAVE) == 0)) {
+		if (ipf_proxy_new(fin, nat) == -1) {
+			NBUMPSIDE6D(fin->fin_out, ns_appr_fail);
+			goto badnat;
+		}
+	}
+
+	nat->nat_ifps[0] = np->in_ifps[0];
+	if (np->in_ifps[0] != NULL) {
+		COPYIFNAME(np->in_v[0], np->in_ifps[0], nat->nat_ifnames[0]);
+	}
+
+	nat->nat_ifps[1] = np->in_ifps[1];
+	if (np->in_ifps[1] != NULL) {
+		COPYIFNAME(np->in_v[1], np->in_ifps[1], nat->nat_ifnames[1]);
+	}
+
+	if (ipf_nat6_finalise(fin, nat) == -1) {
+		goto badnat;
+	}
+
+	np->in_use++;
+
+	if ((move == 1) && (np->in_flags & IPN_ROUNDR)) {
+		if ((np->in_redir & (NAT_REDIRECT|NAT_MAP)) == NAT_REDIRECT) {
+			ipf_nat6_delrdr(softn, np);
+			ipf_nat6_addrdr(softn, np);
+		} else if ((np->in_redir & (NAT_REDIRECT|NAT_MAP)) == NAT_MAP) {
+			ipf_nat6_delmap(softn, np);
+			ipf_nat6_addmap(softn, np);
+		}
+	}
+
+	if (flags & SI_WILDP)
+		nsp->ns_wilds++;
+	softn->ipf_nat_stats.ns_proto[nat->nat_pr[0]]++;
+
+	goto done;
+badnat:
+	NBUMPSIDE6(fin->fin_out, ns_badnatnew);
+	if ((hm = nat->nat_hm) != NULL)
+		ipf_nat_hostmapdel(softc, &hm);
+	KFREE(nat);
+	nat = NULL;
+done:
+	if (nat != NULL && np != NULL)
+		np->in_hits++;
+	if (natsave != NULL)
+		*natsave = nat;
+	return nat;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_nat6_finalise                                           */
+/* Returns:     int - 0 == sucess, -1 == failure                            */
+/* Parameters:  fin(I) - pointer to packet information                      */
+/*              nat(I) - pointer to NAT entry                               */
+/* Write Lock:  ipf_nat                                                     */
+/*                                                                          */
+/* This is the tail end of constructing a new NAT entry and is the same     */
+/* for both IPv4 and IPv6.                                                  */
+/* ------------------------------------------------------------------------ */
+/*ARGSUSED*/
+int
+ipf_nat6_finalise(fin, nat)
+	fr_info_t *fin;
+	nat_t *nat;
+{
+	ipf_main_softc_t *softc = fin->fin_main_soft;
+	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
+	u_32_t sum1, sum2, sumd;
+	frentry_t *fr;
+	u_32_t flags;
+
+	flags = nat->nat_flags;
+
+	switch (fin->fin_p)
+	{
+	case IPPROTO_ICMPV6 :
+		sum1 = LONG_SUM6(&nat->nat_osrc6);
+		sum1 += ntohs(nat->nat_oicmpid);
+		sum2 = LONG_SUM6(&nat->nat_nsrc6);
+		sum2 += ntohs(nat->nat_nicmpid);
+		CALC_SUMD(sum1, sum2, sumd);
+		nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16);
+
+		sum1 = LONG_SUM6(&nat->nat_odst6);
+		sum2 = LONG_SUM6(&nat->nat_ndst6);
+		CALC_SUMD(sum1, sum2, sumd);
+		nat->nat_sumd[0] += (sumd & 0xffff) + (sumd >> 16);
+		break;
+
+	case IPPROTO_TCP :
+	case IPPROTO_UDP :
+		sum1 = LONG_SUM6(&nat->nat_osrc6);
+		sum1 += ntohs(nat->nat_osport);
+		sum2 = LONG_SUM6(&nat->nat_nsrc6);
+		sum2 += ntohs(nat->nat_nsport);
+		CALC_SUMD(sum1, sum2, sumd);
+		nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16);
+
+		sum1 = LONG_SUM6(&nat->nat_odst6);
+		sum1 += ntohs(nat->nat_odport);
+		sum2 = LONG_SUM6(&nat->nat_ndst6);
+		sum2 += ntohs(nat->nat_ndport);
+		CALC_SUMD(sum1, sum2, sumd);
+		nat->nat_sumd[0] += (sumd & 0xffff) + (sumd >> 16);
+		break;
+
+	default :
+		sum1 = LONG_SUM6(&nat->nat_osrc6);
+		sum2 = LONG_SUM6(&nat->nat_nsrc6);
+		CALC_SUMD(sum1, sum2, sumd);
+		nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16);
+
+		sum1 = LONG_SUM6(&nat->nat_odst6);
+		sum2 = LONG_SUM6(&nat->nat_ndst6);
+		CALC_SUMD(sum1, sum2, sumd);
+		nat->nat_sumd[0] += (sumd & 0xffff) + (sumd >> 16);
+		break;
+	}
+
+	/*
+	 * Compute the partial checksum, just in case.
+	 * This is only ever placed into outbound packets so care needs
+	 * to be taken over which pair of addresses are used.
+	 */
+	if (nat->nat_dir == NAT_OUTBOUND) {
+		sum1 = LONG_SUM6(&nat->nat_nsrc6);
+		sum1 += LONG_SUM6(&nat->nat_ndst6);
+	} else {
+		sum1 = LONG_SUM6(&nat->nat_osrc6);
+		sum1 += LONG_SUM6(&nat->nat_odst6);
+	}
+	sum1 += nat->nat_pr[1];
+	nat->nat_sumd[1] = (sum1 & 0xffff) + (sum1 >> 16);
+
+	if ((nat->nat_flags & SI_CLONE) == 0)
+		nat->nat_sync = ipf_sync_new(softc, SMC_NAT, fin, nat);
+
+	if ((nat->nat_ifps[0] != NULL) && (nat->nat_ifps[0] != (void *)-1)) {
+		nat->nat_mtu[0] = GETIFMTU_6(nat->nat_ifps[0]);
+	}
+
+	if ((nat->nat_ifps[1] != NULL) && (nat->nat_ifps[1] != (void *)-1)) {
+		nat->nat_mtu[1] = GETIFMTU_6(nat->nat_ifps[1]);
+	}
+
+	nat->nat_v[0] = 6;
+	nat->nat_v[1] = 6;
+
+	if (ipf_nat6_insert(softc, softn, nat) == 0) {
+		if (softn->ipf_nat_logging)
+			ipf_nat_log(softc, softn, nat, NL_NEW);
+		fr = nat->nat_fr;
+		if (fr != NULL) {
+			MUTEX_ENTER(&fr->fr_lock);
+			fr->fr_ref++;
+			MUTEX_EXIT(&fr->fr_lock);
+		}
+		return 0;
+	}
+
+	NBUMPSIDE6D(fin->fin_out, ns_unfinalised);
+	/*
+	 * nat6_insert failed, so cleanup time...
+	 */
+	if (nat->nat_sync != NULL)
+		ipf_sync_del_nat(softc->ipf_sync_soft, nat->nat_sync);
+	return -1;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_nat6_insert                                             */
+/* Returns:     int - 0 == sucess, -1 == failure                            */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              softn(I) - pointer to NAT context structure                 */
+/*              nat(I) - pointer to NAT structure                           */
+/* Write Lock:  ipf_nat                                                     */
+/*                                                                          */
+/* Insert a NAT entry into the hash tables for searching and add it to the  */
+/* list of active NAT entries.  Adjust global counters when complete.       */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_nat6_insert(softc, softn, nat)
+	ipf_main_softc_t *softc;
+	ipf_nat_softc_t *softn;
+	nat_t *nat;
+{
+	u_int hv1, hv2;
+	u_32_t sp, dp;
+	ipnat_t *in;
+
+	/*
+	 * Try and return an error as early as possible, so calculate the hash
+	 * entry numbers first and then proceed.
+	 */
+	if ((nat->nat_flags & (SI_W_SPORT|SI_W_DPORT)) == 0) {
+		if ((nat->nat_flags & IPN_TCPUDP) != 0) {
+			sp = nat->nat_osport;
+			dp = nat->nat_odport;
+		} else if ((nat->nat_flags & IPN_ICMPQUERY) != 0) {
+			sp = 0;
+			dp = nat->nat_oicmpid;
+		} else {
+			sp = 0;
+			dp = 0;
+		}
+		hv1 = NAT_HASH_FN6(&nat->nat_osrc6, sp, 0xffffffff);
+		hv1 = NAT_HASH_FN6(&nat->nat_odst6, hv1 + dp,
+				   softn->ipf_nat_table_sz);
+
+		/*
+		 * TRACE nat6_osrc6, nat6_osport, nat6_odst6,
+		 * nat6_odport, hv1
+		 */
+
+		if ((nat->nat_flags & IPN_TCPUDP) != 0) {
+			sp = nat->nat_nsport;
+			dp = nat->nat_ndport;
+		} else if ((nat->nat_flags & IPN_ICMPQUERY) != 0) {
+			sp = 0;
+			dp = nat->nat_nicmpid;
+		} else {
+			sp = 0;
+			dp = 0;
+		}
+		hv2 = NAT_HASH_FN6(&nat->nat_nsrc6, sp, 0xffffffff);
+		hv2 = NAT_HASH_FN6(&nat->nat_ndst6, hv2 + dp,
+				   softn->ipf_nat_table_sz);
+		/*
+		 * TRACE nat6_nsrcaddr, nat6_nsport, nat6_ndstaddr,
+		 * nat6_ndport, hv1
+		 */
+	} else {
+		hv1 = NAT_HASH_FN6(&nat->nat_osrc6, 0, 0xffffffff);
+		hv1 = NAT_HASH_FN6(&nat->nat_odst6, hv1,
+				   softn->ipf_nat_table_sz);
+		/* TRACE nat6_osrcip6, nat6_odstip6, hv1 */
+
+		hv2 = NAT_HASH_FN6(&nat->nat_nsrc6, 0, 0xffffffff);
+		hv2 = NAT_HASH_FN6(&nat->nat_ndst6, hv2,
+				   softn->ipf_nat_table_sz);
+		/* TRACE nat6_nsrcip6, nat6_ndstip6, hv2 */
+	}
+
+	nat->nat_hv[0] = hv1;
+	nat->nat_hv[1] = hv2;
+
+	MUTEX_INIT(&nat->nat_lock, "nat entry lock");
+
+	in = nat->nat_ptr;
+	nat->nat_ref = nat->nat_me ? 2 : 1;
+
+	nat->nat_ifnames[0][LIFNAMSIZ - 1] = '\0';
+	nat->nat_ifps[0] = ipf_resolvenic(softc, nat->nat_ifnames[0],
+					  nat->nat_v[0]);
+
+	if (nat->nat_ifnames[1][0] != '\0') {
+		nat->nat_ifnames[1][LIFNAMSIZ - 1] = '\0';
+		nat->nat_ifps[1] = ipf_resolvenic(softc, nat->nat_ifnames[1],
+						  nat->nat_v[1]);
+	} else if (in->in_ifnames[1] != -1) {
+		char *name;
+
+		name = in->in_names + in->in_ifnames[1];
+		if (name[1] != '\0' && name[0] != '-' && name[0] != '*') {
+			(void) strncpy(nat->nat_ifnames[1],
+				       nat->nat_ifnames[0], LIFNAMSIZ);
+			nat->nat_ifnames[1][LIFNAMSIZ - 1] = '\0';
+			nat->nat_ifps[1] = nat->nat_ifps[0];
+		}
+	}
+	if ((nat->nat_ifps[0] != NULL) && (nat->nat_ifps[0] != (void *)-1)) {
+		nat->nat_mtu[0] = GETIFMTU_6(nat->nat_ifps[0]);
+	}
+	if ((nat->nat_ifps[1] != NULL) && (nat->nat_ifps[1] != (void *)-1)) {
+		nat->nat_mtu[1] = GETIFMTU_6(nat->nat_ifps[1]);
+	}
+
+	return ipf_nat_hashtab_add(softc, softn, nat);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_nat6_icmperrorlookup                                    */
+/* Returns:     nat6_t* - point to matching NAT structure                    */
+/* Parameters:  fin(I) - pointer to packet information                      */
+/*              dir(I) - direction of packet (in/out)                       */
+/*                                                                          */
+/* Check if the ICMP error message is related to an existing TCP, UDP or    */
+/* ICMP query nat entry.  It is assumed that the packet is already of the   */
+/* the required length.                                                     */
+/* ------------------------------------------------------------------------ */
+nat_t *
+ipf_nat6_icmperrorlookup(fin, dir)
+	fr_info_t *fin;
+	int dir;
+{
+	ipf_main_softc_t *softc = fin->fin_main_soft;
+	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
+	struct icmp6_hdr *icmp6, *orgicmp;
+	int flags = 0, type, minlen;
+	nat_stat_side_t *nside;
+	tcphdr_t *tcp = NULL;
+	u_short data[2];
+	ip6_t *oip6;
+	nat_t *nat;
+	u_int p;
+
+	minlen = 40;
+	icmp6 = fin->fin_dp;
+	type = icmp6->icmp6_type;
+	nside = &softn->ipf_nat_stats.ns_side6[fin->fin_out];
+	/*
+	 * Does it at least have the return (basic) IP header ?
+	 * 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_flx & FI_ICMPERR)) {
+		ATOMIC_INCL(nside->ns_icmp_basic);
+		return NULL;
+	}
+
+	/*
+	 * Check packet size
+	 */
+	if (fin->fin_plen < ICMP6ERR_IPICMPHLEN) {
+		ATOMIC_INCL(nside->ns_icmp_size);
+		return NULL;
+	}
+	oip6 = (ip6_t *)((char *)fin->fin_dp + 8);
+
+	/*
+	 * Is the buffer big enough for all of it ?  It's the size of the IP
+	 * header claimed in the encapsulated part which is of concern.  It
+	 * may be too big to be in this buffer but not so big that it's
+	 * outside the ICMP packet, leading to TCP deref's causing problems.
+	 * This is possible because we don't know how big oip_hl is when we
+	 * do the pullup early in ipf_check() and thus can't gaurantee it is
+	 * all here now.
+	 */
+#ifdef  _KERNEL
+	{
+	mb_t *m;
+
+	m = fin->fin_m;
+# if defined(MENTAT)
+	if ((char *)oip6 + fin->fin_dlen - ICMPERR_ICMPHLEN >
+	    (char *)m->b_wptr) {
+		ATOMIC_INCL(nside->ns_icmp_mbuf);
+		return NULL;
+	}
+# else
+	if ((char *)oip6 + fin->fin_dlen - ICMPERR_ICMPHLEN >
+	    (char *)fin->fin_ip + M_LEN(m)) {
+		ATOMIC_INCL(nside->ns_icmp_mbuf);
+		return NULL;
+	}
+# endif
+	}
+#endif
+
+	if (IP6_NEQ(&fin->fin_dst6, &oip6->ip6_src)) {
+		ATOMIC_INCL(nside->ns_icmp_address);
+		return NULL;
+	}
+
+	p = oip6->ip6_nxt;
+	if (p == IPPROTO_TCP)
+		flags = IPN_TCP;
+	else if (p == IPPROTO_UDP)
+		flags = IPN_UDP;
+	else if (p == IPPROTO_ICMPV6) {
+		orgicmp = (struct icmp6_hdr *)(oip6 + 1);
+
+		/* see if this is related to an ICMP query */
+		if (ipf_nat6_icmpquerytype(orgicmp->icmp6_type)) {
+			data[0] = fin->fin_data[0];
+			data[1] = fin->fin_data[1];
+			fin->fin_data[0] = 0;
+			fin->fin_data[1] = orgicmp->icmp6_id;
+
+			flags = IPN_ICMPERR|IPN_ICMPQUERY;
+			/*
+			 * NOTE : dir refers to the direction of the original
+			 *        ip packet. By definition the icmp error
+			 *        message flows in the opposite direction.
+			 */
+			if (dir == NAT_INBOUND)
+				nat = ipf_nat6_inlookup(fin, flags, p,
+						        &oip6->ip6_dst,
+						        &oip6->ip6_src);
+			else
+				nat = ipf_nat6_outlookup(fin, flags, p,
+							 &oip6->ip6_dst,
+							 &oip6->ip6_src);
+			fin->fin_data[0] = data[0];
+			fin->fin_data[1] = data[1];
+			return nat;
+		}
+	}
+
+	if (flags & IPN_TCPUDP) {
+		minlen += 8;		/* + 64bits of data to get ports */
+		/* TRACE (fin,minlen) */
+		if (fin->fin_plen < ICMPERR_IPICMPHLEN + minlen) {
+			ATOMIC_INCL(nside->ns_icmp_short);
+			return NULL;
+		}
+
+		data[0] = fin->fin_data[0];
+		data[1] = fin->fin_data[1];
+		tcp = (tcphdr_t *)(oip6 + 1);
+		fin->fin_data[0] = ntohs(tcp->th_dport);
+		fin->fin_data[1] = ntohs(tcp->th_sport);
+
+		if (dir == NAT_INBOUND) {
+			nat = ipf_nat6_inlookup(fin, flags, p, &oip6->ip6_dst,
+						&oip6->ip6_src);
+		} else {
+			nat = ipf_nat6_outlookup(fin, flags, p, &oip6->ip6_dst,
+						 &oip6->ip6_src);
+		}
+		fin->fin_data[0] = data[0];
+		fin->fin_data[1] = data[1];
+		return nat;
+	}
+	if (dir == NAT_INBOUND)
+		nat = ipf_nat6_inlookup(fin, 0, p, &oip6->ip6_dst,
+					&oip6->ip6_src);
+	else
+		nat = ipf_nat6_outlookup(fin, 0, p, &oip6->ip6_dst,
+					 &oip6->ip6_src);
+
+	return nat;
+}
+
+
+/* result = ip1 - ip2 */
+u_32_t
+ipf_nat6_ip6subtract(ip1, ip2)
+	i6addr_t *ip1, *ip2;
+{
+	i6addr_t l1, l2, d;
+	u_short *s1, *s2, *ds;
+	u_32_t r;
+	int i, neg;
+
+	neg = 0;
+	l1 = *ip1;
+	l2 = *ip2;
+	s1 = (u_short *)&l1;
+	s2 = (u_short *)&l2;
+	ds = (u_short *)&d;
+
+	for (i = 7; i > 0; i--) {
+		if (s1[i] > s2[i]) {
+			ds[i] = s2[i] + 0x10000 - s1[i];
+			s2[i - 1] += 0x10000;
+		} else {
+			ds[i] = s2[i] - s1[i];
+		}
+	}
+	if (s2[0] > s1[0]) {
+		ds[0] = s2[0] + 0x10000 - s1[0];
+		neg = 1;
+	} else {
+		ds[0] = s2[0] - s1[0];
+	}
+
+	for (i = 0, r = 0; i < 8; i++) {
+		r += ds[i];
+	}
+
+	return r;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_nat6_icmperror                                          */
+/* Returns:     nat6_t* - point to matching NAT structure                    */
+/* Parameters:  fin(I)    - pointer to packet information                   */
+/*              nflags(I) - NAT flags for this packet                       */
+/*              dir(I)    - direction of packet (in/out)                    */
+/*                                                                          */
+/* Fix up an ICMP packet which is an error message for an existing NAT      */
+/* session.  This will correct both packet header data and checksums.       */
+/*                                                                          */
+/* This should *ONLY* be used for incoming ICMP error packets to make sure  */
+/* a NAT'd ICMP packet gets correctly recognised.                           */
+/* ------------------------------------------------------------------------ */
+nat_t *
+ipf_nat6_icmperror(fin, nflags, dir)
+	fr_info_t *fin;
+	u_int *nflags;
+	int dir;
+{
+	ipf_main_softc_t *softc = fin->fin_main_soft;
+	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
+	u_32_t sum1, sum2, sumd, sumd2;
+	i6addr_t a1, a2, a3, a4;
+	struct icmp6_hdr *icmp6;
+	int flags, dlen, odst;
+	u_short *csump;
+	tcphdr_t *tcp;
+	ip6_t *oip6;
+	nat_t *nat;
+	void *dp;
+
+	if ((fin->fin_flx & (FI_SHORT|FI_FRAGBODY))) {
+		NBUMPSIDE6D(fin->fin_out, ns_icmp_short);
+		return NULL;
+	}
+
+	/*
+	 * ipf_nat6_icmperrorlookup() will return NULL for `defective' packets.
+	 */
+	if ((fin->fin_v != 6) || !(nat = ipf_nat6_icmperrorlookup(fin, dir))) {
+		NBUMPSIDE6D(fin->fin_out, ns_icmp_notfound);
+		return NULL;
+	}
+
+	tcp = NULL;
+	csump = NULL;
+	flags = 0;
+	sumd2 = 0;
+	*nflags = IPN_ICMPERR;
+	icmp6 = fin->fin_dp;
+	oip6 = (ip6_t *)((u_char *)icmp6 + sizeof(*icmp6));
+	dp = (u_char *)oip6 + sizeof(*oip6);
+	if (oip6->ip6_nxt == IPPROTO_TCP) {
+		tcp = (tcphdr_t *)dp;
+		csump = (u_short *)&tcp->th_sum;
+		flags = IPN_TCP;
+	} else if (oip6->ip6_nxt == IPPROTO_UDP) {
+		udphdr_t *udp;
+
+		udp = (udphdr_t *)dp;
+		tcp = (tcphdr_t *)dp;
+		csump = (u_short *)&udp->uh_sum;
+		flags = IPN_UDP;
+	} else if (oip6->ip6_nxt == IPPROTO_ICMPV6)
+		flags = IPN_ICMPQUERY;
+	dlen = fin->fin_plen - ((char *)dp - (char *)fin->fin_ip);
+
+	/*
+	 * Need to adjust ICMP header to include the real IP#'s and
+	 * port #'s.  Only apply a checksum change relative to the
+	 * IP address change as it will be modified again in ipf_nat6_checkout
+	 * for both address and port.  Two checksum changes are
+	 * necessary for the two header address changes.  Be careful
+	 * to only modify the checksum once for the port # and twice
+	 * for the IP#.
+	 */
+
+	/*
+	 * 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.
+	 *
+	 * Normally, you would expect that the ICMP checksum of the
+	 * ICMP error message needs to be adjusted as well for the
+	 * IP address change in oip.
+	 * However, this is a NOP, because the ICMP checksum is
+	 * calculated over the complete ICMP packet, which includes the
+	 * changed oip IP addresses and oip6->ip6_sum. However, these
+	 * two changes cancel each other out (if the delta for
+	 * the IP address is x, then the delta for ip_sum is minus x),
+	 * so no change in the icmp_cksum is necessary.
+	 *
+	 * 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)=nat6_newsrcip,          OIP_DST(b)=nat6_newdstip
+	 *=> OIP_SRC(c)=nat6_oldsrcip,          OIP_DST(b)=nat6_olddstip
+	 *
+	 * 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)=nat6_olddstip,          OIP_DST(a)=nat6_oldsrcip
+	 *=> OIP_SRC(b)=nat6_newdstip,          OIP_DST(a)=nat6_newsrcip
+	 *
+	 * REWRITE out rule, SRC=a,DST=b -> SRC=c,DST=d
+	 * - response to outgoing packet (a,b)=>(c,d) (OIP_SRC=c,OIP_DST=d)
+	 * - OIP_SRC(c)=nat6_newsrcip,          OIP_DST(d)=nat6_newdstip
+	 *=> OIP_SRC(c)=nat6_oldsrcip,          OIP_DST(d)=nat6_olddstip
+	 *
+	 * REWRITE in rule, SRC=a,DST=b -> SRC=c,DST=d
+	 * - response to outgoing packet (d,c)=>(b,a) (OIP_SRC=b,OIP_DST=a)
+	 * - OIP_SRC(b)=nat6_olddstip,          OIP_DST(a)=nat6_oldsrcip
+	 *=> OIP_SRC(b)=nat6_newdstip,          OIP_DST(a)=nat6_newsrcip
+	 *
+	 * 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(b)=nat6_olddstip,          OIP_DST(a)=nat6_oldsrcip
+	 *=> OIP_SRC(b)=nat6_newdstip,          OIP_DST(a)=nat6_newsrcip
+	 *
+	 * 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)=nat6_newsrcip,          OIP_DST(c)=nat6_newdstip
+	 *=> OIP_SRC(a)=nat6_oldsrcip,          OIP_DST(c)=nat6_olddstip
+	 *
+	 * REWRITE out rule, SRC=a,DST=b -> SRC=c,DST=d
+	 * - response to incoming packet (d,c)=>(b,a) (OIP_SRC=c,OIP_DST=d)
+	 * - OIP_SRC(c)=nat6_olddstip,          OIP_DST(d)=nat6_oldsrcip
+	 *=> OIP_SRC(b)=nat6_newdstip,          OIP_DST(a)=nat6_newsrcip
+	 *
+	 * REWRITE in rule, SRC=a,DST=b -> SRC=c,DST=d
+	 * - response to incoming packet (a,b)=>(c,d) (OIP_SRC=b,OIP_DST=a)
+	 * - OIP_SRC(b)=nat6_newsrcip,          OIP_DST(a)=nat6_newdstip
+	 *=> OIP_SRC(a)=nat6_oldsrcip,          OIP_DST(c)=nat6_olddstip
+	 */
+
+	if (((fin->fin_out == 0) && ((nat->nat_redir & NAT_MAP) != 0)) ||
+	    ((fin->fin_out == 1) && ((nat->nat_redir & NAT_REDIRECT) != 0))) {
+		a1 = nat->nat_osrc6;
+		a4.in6 = oip6->ip6_src;
+		a3 = nat->nat_odst6;
+		a2.in6 = oip6->ip6_dst;
+		oip6->ip6_src = a1.in6;
+		oip6->ip6_dst = a3.in6;
+		odst = 1;
+	} else {
+		a1 = nat->nat_ndst6;
+		a2.in6 = oip6->ip6_dst;
+		a3 = nat->nat_nsrc6;
+		a4.in6 = oip6->ip6_src;
+		oip6->ip6_dst = a3.in6;
+		oip6->ip6_src = a1.in6;
+		odst = 0;
+	}
+
+	sumd = 0;
+	if (IP6_NEQ(&a3, &a2) || IP6_NEQ(&a1, &a4)) {
+		if (IP6_GT(&a3, &a2)) {
+			sumd = ipf_nat6_ip6subtract(&a2, &a3);
+			sumd--;
+		} else {
+			sumd = ipf_nat6_ip6subtract(&a2, &a3);
+		}
+		if (IP6_GT(&a1, &a4)) {
+			sumd += ipf_nat6_ip6subtract(&a4, &a1);
+			sumd--;
+		} else {
+			sumd += ipf_nat6_ip6subtract(&a4, &a1);
+		}
+		sumd = ~sumd;
+	}
+
+	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)) {
+		u_32_t sum3, sum4;
+		/*
+		 * Step 2 :
+		 * For offending TCP/UDP IP packets, translate the ports as
+		 * well, based on the NAT specification. Of course such
+		 * 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... 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_osport);
+			sum4 = ntohs(tcp->th_sport);
+			sum3 = ntohs(nat->nat_odport);
+			sum2 = ntohs(tcp->th_dport);
+
+			tcp->th_sport = htons(sum1);
+			tcp->th_dport = htons(sum3);
+		} else {
+			sum1 = ntohs(nat->nat_ndport);
+			sum2 = ntohs(tcp->th_dport);
+			sum3 = ntohs(nat->nat_nsport);
+			sum4 = ntohs(tcp->th_sport);
+
+			tcp->th_dport = htons(sum3);
+			tcp->th_sport = htons(sum1);
+		}
+		sumd += sum1 - sum4;
+		sumd += sum3 - sum2;
+
+		if (sumd != 0 || sumd2 != 0) {
+			/*
+			 * 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.
+			 *
+			 * 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 (oip6->ip6_nxt == IPPROTO_UDP) {
+				if ((dlen >= 8) && (*csump != 0)) {
+					ipf_fix_datacksum(csump, sumd);
+				} else {
+					sumd2 = sum4 - sum1;
+					if (sum1 > sum4)
+						sumd2--;
+					sumd2 += sum2 - sum3;
+					if (sum3 > sum2)
+						sumd2--;
+				}
+			} else if (oip6->ip6_nxt == IPPROTO_TCP) {
+				if (dlen >= 18) {
+					ipf_fix_datacksum(csump, sumd);
+				} else {
+					sumd2 = sum4 - sum1;
+					if (sum1 > sum4)
+						sumd2--;
+					sumd2 += sum2 - sum3;
+					if (sum3 > sum2)
+						sumd2--;
+				}
+			}
+			if (sumd2 != 0) {
+				sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16);
+				sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16);
+				sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16);
+				ipf_fix_incksum(0, &icmp6->icmp6_cksum,
+						sumd2, 0);
+			}
+		}
+	} else if (((flags & IPN_ICMPQUERY) != 0) && (dlen >= 8)) {
+		struct icmp6_hdr *orgicmp;
+
+		/*
+		 * XXX - what if this is bogus hl and we go off the end ?
+		 * In this case, ipf_nat6_icmperrorlookup() will have
+		 * returned NULL.
+		 */
+		orgicmp = (struct icmp6_hdr *)dp;
+
+		if (odst == 1) {
+			if (orgicmp->icmp6_id != nat->nat_osport) {
+
+				/*
+				 * Fix ICMP checksum (of the offening ICMP
+				 * query packet) to compensate the change
+				 * in the ICMP id of the offending ICMP
+				 * packet.
+				 *
+				 * Since you modify orgicmp->icmp6_id with
+				 * a delta (say x) and you compensate that
+				 * in origicmp->icmp6_cksum with a delta
+				 * minus x, you don't have to adjust the
+				 * overall icmp->icmp6_cksum
+				 */
+				sum1 = ntohs(orgicmp->icmp6_id);
+				sum2 = ntohs(nat->nat_osport);
+				CALC_SUMD(sum1, sum2, sumd);
+				orgicmp->icmp6_id = nat->nat_oicmpid;
+				ipf_fix_datacksum(&orgicmp->icmp6_cksum, sumd);
+			}
+		} /* nat6_dir == NAT_INBOUND is impossible for icmp queries */
+	}
+	return nat;
+}
+
+
+/*
+ *       MAP-IN    MAP-OUT   RDR-IN   RDR-OUT
+ * osrc    X       == src    == src      X
+ * odst    X       == dst    == dst      X
+ * nsrc  == dst      X         X      == dst
+ * ndst  == src      X         X      == src
+ * MAP = NAT_OUTBOUND, RDR = NAT_INBOUND
+ */
+/*
+ * NB: these lookups don't lock access to the list, it assumed that it has
+ * already been done!
+ */
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_nat6_inlookup                                           */
+/* Returns:     nat6_t*   - NULL == no match,                               */
+/*                          else pointer to matching NAT entry              */
+/* Parameters:  fin(I)    - pointer to packet information                   */
+/*              flags(I)  - NAT flags for this packet                       */
+/*              p(I)      - protocol for this packet                        */
+/*              src(I)    - source IP address                               */
+/*              mapdst(I) - destination IP address                          */
+/*                                                                          */
+/* Lookup a nat entry based on the mapped destination ip address/port and   */
+/* real source address/port.  We use this lookup when receiving a packet,   */
+/* we're looking for a table entry, based on the destination address.       */
+/*                                                                          */
+/* NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY.         */
+/*                                                                          */
+/* NOTE: IT IS ASSUMED THAT  IS ONLY HELD WITH A READ LOCK WHEN             */
+/*       THIS FUNCTION IS CALLED WITH NAT_SEARCH SET IN nflags.             */
+/*                                                                          */
+/* flags   -> relevant are IPN_UDP/IPN_TCP/IPN_ICMPQUERY that indicate if   */
+/*            the packet is of said protocol                                */
+/* ------------------------------------------------------------------------ */
+nat_t *
+ipf_nat6_inlookup(fin, flags, p, src, mapdst)
+	fr_info_t *fin;
+	u_int flags, p;
+	struct in6_addr *src , *mapdst;
+{
+	ipf_main_softc_t *softc = fin->fin_main_soft;
+	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
+	u_short sport, dport;
+	grehdr_t *gre;
+	ipnat_t *ipn;
+	u_int sflags;
+	nat_t *nat;
+	int nflags;
+	i6addr_t dst;
+	void *ifp;
+	u_int hv;
+
+	ifp = fin->fin_ifp;
+	sport = 0;
+	dport = 0;
+	gre = NULL;
+	dst.in6 = *mapdst;
+	sflags = flags & NAT_TCPUDPICMP;
+
+	switch (p)
+	{
+	case IPPROTO_TCP :
+	case IPPROTO_UDP :
+		sport = htons(fin->fin_data[0]);
+		dport = htons(fin->fin_data[1]);
+		break;
+	case IPPROTO_ICMPV6 :
+		if (flags & IPN_ICMPERR)
+			sport = fin->fin_data[1];
+		else
+			dport = fin->fin_data[1];
+		break;
+	default :
+		break;
+	}
+
+
+	if ((flags & SI_WILDP) != 0)
+		goto find_in_wild_ports;
+
+	hv = NAT_HASH_FN6(&dst, dport, 0xffffffff);
+	hv = NAT_HASH_FN6(src, hv + sport, softn->ipf_nat_table_sz);
+	nat = softn->ipf_nat_table[1][hv];
+	/* TRACE dst, dport, src, sport, hv, nat */
+
+	for (; nat; nat = nat->nat_hnext[1]) {
+		if (nat->nat_ifps[0] != NULL) {
+			if ((ifp != NULL) && (ifp != nat->nat_ifps[0]))
+				continue;
+		}
+
+		if (nat->nat_pr[0] != p)
+			continue;
+
+		switch (nat->nat_dir)
+		{
+		case NAT_INBOUND :
+			if (nat->nat_v[0] != 6)
+				continue;
+			if (IP6_NEQ(&nat->nat_osrc6, src) ||
+			    IP6_NEQ(&nat->nat_odst6, &dst))
+				continue;
+			if ((nat->nat_flags & IPN_TCPUDP) != 0) {
+				if (nat->nat_osport != sport)
+					continue;
+				if (nat->nat_odport != dport)
+					continue;
+
+			} else if (p == IPPROTO_ICMPV6) {
+				if (nat->nat_osport != dport) {
+					continue;
+				}
+			}
+			break;
+		case NAT_OUTBOUND :
+			if (nat->nat_v[1] != 6)
+				continue;
+			if (IP6_NEQ(&nat->nat_ndst6, src) ||
+			    IP6_NEQ(&nat->nat_nsrc6, &dst))
+				continue;
+			if ((nat->nat_flags & IPN_TCPUDP) != 0) {
+				if (nat->nat_ndport != sport)
+					continue;
+				if (nat->nat_nsport != dport)
+					continue;
+
+			} else if (p == IPPROTO_ICMPV6) {
+				if (nat->nat_osport != dport) {
+					continue;
+				}
+			}
+			break;
+		}
+
+
+		if ((nat->nat_flags & IPN_TCPUDP) != 0) {
+			ipn = nat->nat_ptr;
+#ifdef IPF_V6_PROXIES
+			if ((ipn != NULL) && (nat->nat_aps != NULL))
+				if (appr_match(fin, nat) != 0)
+					continue;
+#endif
+		}
+		if ((nat->nat_ifps[0] == NULL) && (ifp != NULL)) {
+			nat->nat_ifps[0] = ifp;
+			nat->nat_mtu[0] = GETIFMTU_6(ifp);
+		}
+		return nat;
+	}
+
+	/*
+	 * So if we didn't find it but there are wildcard members in the hash
+	 * table, go back and look for them.  We do this search and update here
+	 * because it is modifying the NAT table and we want to do this only
+	 * for the first packet that matches.  The exception, of course, is
+	 * for "dummy" (FI_IGNORE) lookups.
+	 */
+find_in_wild_ports:
+	if (!(flags & NAT_TCPUDP) || !(flags & NAT_SEARCH)) {
+		NBUMPSIDE6DX(0, ns_lookup_miss, ns_lookup_miss_1);
+		return NULL;
+	}
+	if (softn->ipf_nat_stats.ns_wilds == 0 || (fin->fin_flx & FI_NOWILD)) {
+		NBUMPSIDE6D(0, ns_lookup_nowild);
+		return NULL;
+	}
+
+	RWLOCK_EXIT(&softc->ipf_nat);
+
+	hv = NAT_HASH_FN6(&dst, 0, 0xffffffff);
+	hv = NAT_HASH_FN6(src, hv, softn->ipf_nat_table_sz);
+	WRITE_ENTER(&softc->ipf_nat);
+
+	nat = softn->ipf_nat_table[1][hv];
+	/* TRACE dst, src, hv, nat */
+	for (; nat; nat = nat->nat_hnext[1]) {
+		if (nat->nat_ifps[0] != NULL) {
+			if ((ifp != NULL) && (ifp != nat->nat_ifps[0]))
+				continue;
+		}
+
+		if (nat->nat_pr[0] != fin->fin_p)
+			continue;
+
+		switch (nat->nat_dir)
+		{
+		case NAT_INBOUND :
+			if (nat->nat_v[0] != 6)
+				continue;
+			if (IP6_NEQ(&nat->nat_osrc6, src) ||
+			    IP6_NEQ(&nat->nat_odst6, &dst))
+				continue;
+			break;
+		case NAT_OUTBOUND :
+			if (nat->nat_v[1] != 6)
+				continue;
+			if (IP6_NEQ(&nat->nat_ndst6, src) ||
+			    IP6_NEQ(&nat->nat_nsrc6, &dst))
+				continue;
+			break;
+		}
+
+		nflags = nat->nat_flags;
+		if (!(nflags & (NAT_TCPUDP|SI_WILDP)))
+			continue;
+
+		if (ipf_nat_wildok(nat, (int)sport, (int)dport, nflags,
+				   NAT_INBOUND) == 1) {
+			if ((fin->fin_flx & FI_IGNORE) != 0)
+				break;
+			if ((nflags & SI_CLONE) != 0) {
+				nat = ipf_nat_clone(fin, nat);
+				if (nat == NULL)
+					break;
+			} else {
+				MUTEX_ENTER(&softn->ipf_nat_new);
+				softn->ipf_nat_stats.ns_wilds--;
+				MUTEX_EXIT(&softn->ipf_nat_new);
+			}
+
+			if (nat->nat_dir == NAT_INBOUND) {
+				if (nat->nat_osport == 0) {
+					nat->nat_osport = sport;
+					nat->nat_nsport = sport;
+				}
+				if (nat->nat_odport == 0) {
+					nat->nat_odport = dport;
+					nat->nat_ndport = dport;
+				}
+			} else {
+				if (nat->nat_osport == 0) {
+					nat->nat_osport = dport;
+					nat->nat_nsport = dport;
+				}
+				if (nat->nat_odport == 0) {
+					nat->nat_odport = sport;
+					nat->nat_ndport = sport;
+				}
+			}
+			if ((nat->nat_ifps[0] == NULL) && (ifp != NULL)) {
+				nat->nat_ifps[0] = ifp;
+				nat->nat_mtu[0] = GETIFMTU_6(ifp);
+			}
+			nat->nat_flags &= ~(SI_W_DPORT|SI_W_SPORT);
+			ipf_nat6_tabmove(softn, nat);
+			break;
+		}
+	}
+
+	MUTEX_DOWNGRADE(&softc->ipf_nat);
+
+	if (nat == NULL) {
+		NBUMPSIDE6DX(0, ns_lookup_miss, ns_lookup_miss_2);
+	}
+	return nat;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_nat6_tabmove                                            */
+/* Returns:     Nil                                                         */
+/* Parameters:  nat(I) - pointer to NAT structure                           */
+/* Write Lock:  ipf_nat                                                     */
+/*                                                                          */
+/* This function is only called for TCP/UDP NAT table entries where the     */
+/* original was placed in the table without hashing on the ports and we now */
+/* want to include hashing on port numbers.                                 */
+/* ------------------------------------------------------------------------ */
+static void
+ipf_nat6_tabmove(softn, nat)
+	ipf_nat_softc_t *softn;
+	nat_t *nat;
+{
+	nat_t **natp;
+	u_int hv0, hv1;
+
+	if (nat->nat_flags & SI_CLONE)
+		return;
+
+	/*
+	 * Remove the NAT entry from the old location
+	 */
+	if (nat->nat_hnext[0])
+		nat->nat_hnext[0]->nat_phnext[0] = nat->nat_phnext[0];
+	*nat->nat_phnext[0] = nat->nat_hnext[0];
+	softn->ipf_nat_stats.ns_side[0].ns_bucketlen[nat->nat_hv[0]]--;
+
+	if (nat->nat_hnext[1])
+		nat->nat_hnext[1]->nat_phnext[1] = nat->nat_phnext[1];
+	*nat->nat_phnext[1] = nat->nat_hnext[1];
+	softn->ipf_nat_stats.ns_side[1].ns_bucketlen[nat->nat_hv[1]]--;
+
+	/*
+	 * Add into the NAT table in the new position
+	 */
+	hv0 = NAT_HASH_FN6(&nat->nat_osrc6, nat->nat_osport, 0xffffffff);
+	hv0 = NAT_HASH_FN6(&nat->nat_odst6, hv0 + nat->nat_odport,
+			   softn->ipf_nat_table_sz);
+	hv1 = NAT_HASH_FN6(&nat->nat_nsrc6, nat->nat_nsport, 0xffffffff);
+	hv1 = NAT_HASH_FN6(&nat->nat_ndst6, hv1 + nat->nat_ndport,
+			   softn->ipf_nat_table_sz);
+
+	if (nat->nat_dir == NAT_INBOUND || nat->nat_dir == NAT_DIVERTIN) {
+		u_int swap;
+
+		swap = hv0;
+		hv0 = hv1;
+		hv1 = swap;
+	}
+
+	/* TRACE nat_osrc6, nat_osport, nat_odst6, nat_odport, hv0 */
+	/* TRACE nat_nsrc6, nat_nsport, nat_ndst6, nat_ndport, hv1 */
+
+	nat->nat_hv[0] = hv0;
+	natp = &softn->ipf_nat_table[0][hv0];
+	if (*natp)
+		(*natp)->nat_phnext[0] = &nat->nat_hnext[0];
+	nat->nat_phnext[0] = natp;
+	nat->nat_hnext[0] = *natp;
+	*natp = nat;
+	softn->ipf_nat_stats.ns_side[0].ns_bucketlen[hv0]++;
+
+	nat->nat_hv[1] = hv1;
+	natp = &softn->ipf_nat_table[1][hv1];
+	if (*natp)
+		(*natp)->nat_phnext[1] = &nat->nat_hnext[1];
+	nat->nat_phnext[1] = natp;
+	nat->nat_hnext[1] = *natp;
+	*natp = nat;
+	softn->ipf_nat_stats.ns_side[1].ns_bucketlen[hv1]++;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_nat6_outlookup                                          */
+/* Returns:     nat6_t*  - NULL == no match,                                */
+/*                         else pointer to matching NAT entry               */
+/* Parameters:  fin(I)   - pointer to packet information                    */
+/*              flags(I) - NAT flags for this packet                        */
+/*              p(I)     - protocol for this packet                         */
+/*              src(I)   - source IP address                                */
+/*              dst(I)   - destination IP address                           */
+/*              rw(I)    - 1 == write lock on  held, 0 == read lock.        */
+/*                                                                          */
+/* Lookup a nat entry based on the source 'real' ip address/port and        */
+/* destination address/port.  We use this lookup when sending a packet out, */
+/* we're looking for a table entry, based on the source address.            */
+/*                                                                          */
+/* NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY.         */
+/*                                                                          */
+/* NOTE: IT IS ASSUMED THAT  IS ONLY HELD WITH A READ LOCK WHEN             */
+/*       THIS FUNCTION IS CALLED WITH NAT_SEARCH SET IN nflags.             */
+/*                                                                          */
+/* flags   -> relevant are IPN_UDP/IPN_TCP/IPN_ICMPQUERY that indicate if   */
+/*            the packet is of said protocol                                */
+/* ------------------------------------------------------------------------ */
+nat_t *
+ipf_nat6_outlookup(fin, flags, p, src, dst)
+	fr_info_t *fin;
+	u_int flags, p;
+	struct in6_addr *src , *dst;
+{
+	ipf_main_softc_t *softc = fin->fin_main_soft;
+	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
+	u_short sport, dport;
+	u_int sflags;
+	ipnat_t *ipn;
+	nat_t *nat;
+	void *ifp;
+	u_int hv;
+
+	ifp = fin->fin_ifp;
+	sflags = flags & IPN_TCPUDPICMP;
+	sport = 0;
+	dport = 0;
+
+	switch (p)
+	{
+	case IPPROTO_TCP :
+	case IPPROTO_UDP :
+		sport = htons(fin->fin_data[0]);
+		dport = htons(fin->fin_data[1]);
+		break;
+	case IPPROTO_ICMPV6 :
+		if (flags & IPN_ICMPERR)
+			sport = fin->fin_data[1];
+		else
+			dport = fin->fin_data[1];
+		break;
+	default :
+		break;
+	}
+
+	if ((flags & SI_WILDP) != 0)
+		goto find_out_wild_ports;
+
+	hv = NAT_HASH_FN6(src, sport, 0xffffffff);
+	hv = NAT_HASH_FN6(dst, hv + dport, softn->ipf_nat_table_sz);
+	nat = softn->ipf_nat_table[0][hv];
+
+	/* TRACE src, sport, dst, dport, hv, nat */
+
+	for (; nat; nat = nat->nat_hnext[0]) {
+		if (nat->nat_ifps[1] != NULL) {
+			if ((ifp != NULL) && (ifp != nat->nat_ifps[1]))
+				continue;
+		}
+
+		if (nat->nat_pr[1] != p)
+			continue;
+
+		switch (nat->nat_dir)
+		{
+		case NAT_INBOUND :
+			if (nat->nat_v[1] != 6)
+				continue;
+			if (IP6_NEQ(&nat->nat_ndst6, src) ||
+			    IP6_NEQ(&nat->nat_nsrc6, dst))
+				continue;
+
+			if ((nat->nat_flags & IPN_TCPUDP) != 0) {
+				if (nat->nat_ndport != sport)
+					continue;
+				if (nat->nat_nsport != dport)
+					continue;
+
+			} else if (p == IPPROTO_ICMPV6) {
+				if (nat->nat_osport != dport) {
+					continue;
+				}
+			}
+			break;
+		case NAT_OUTBOUND :
+			if (nat->nat_v[0] != 6)
+				continue;
+			if (IP6_NEQ(&nat->nat_osrc6, src) ||
+			    IP6_NEQ(&nat->nat_odst6, dst))
+				continue;
+
+			if ((nat->nat_flags & IPN_TCPUDP) != 0) {
+				if (nat->nat_odport != dport)
+					continue;
+				if (nat->nat_osport != sport)
+					continue;
+
+			} else if (p == IPPROTO_ICMPV6) {
+				if (nat->nat_osport != dport) {
+					continue;
+				}
+			}
+			break;
+		}
+
+		ipn = nat->nat_ptr;
+#ifdef IPF_V6_PROXIES
+		if ((ipn != NULL) && (nat->nat_aps != NULL))
+			if (appr_match(fin, nat) != 0)
+				continue;
+#endif
+
+		if ((nat->nat_ifps[1] == NULL) && (ifp != NULL)) {
+			nat->nat_ifps[1] = ifp;
+			nat->nat_mtu[1] = GETIFMTU_6(ifp);
+		}
+		return nat;
+	}
+
+	/*
+	 * So if we didn't find it but there are wildcard members in the hash
+	 * table, go back and look for them.  We do this search and update here
+	 * because it is modifying the NAT table and we want to do this only
+	 * for the first packet that matches.  The exception, of course, is
+	 * for "dummy" (FI_IGNORE) lookups.
+	 */
+find_out_wild_ports:
+	if (!(flags & NAT_TCPUDP) || !(flags & NAT_SEARCH)) {
+		NBUMPSIDE6DX(1, ns_lookup_miss, ns_lookup_miss_3);
+		return NULL;
+	}
+	if (softn->ipf_nat_stats.ns_wilds == 0 || (fin->fin_flx & FI_NOWILD)) {
+		NBUMPSIDE6D(1, ns_lookup_nowild);
+		return NULL;
+	}
+
+	RWLOCK_EXIT(&softc->ipf_nat);
+
+	hv = NAT_HASH_FN6(src, 0, 0xffffffff);
+	hv = NAT_HASH_FN6(dst, hv, softn->ipf_nat_table_sz);
+
+	WRITE_ENTER(&softc->ipf_nat);
+
+	nat = softn->ipf_nat_table[0][hv];
+	for (; nat; nat = nat->nat_hnext[0]) {
+		if (nat->nat_ifps[1] != NULL) {
+			if ((ifp != NULL) && (ifp != nat->nat_ifps[1]))
+				continue;
+		}
+
+		if (nat->nat_pr[1] != fin->fin_p)
+			continue;
+
+		switch (nat->nat_dir)
+		{
+		case NAT_INBOUND :
+			if (nat->nat_v[1] != 6)
+				continue;
+			if (IP6_NEQ(&nat->nat_ndst6, src) ||
+			    IP6_NEQ(&nat->nat_nsrc6, dst))
+				continue;
+			break;
+		case NAT_OUTBOUND :
+			if (nat->nat_v[0] != 6)
+			continue;
+			if (IP6_NEQ(&nat->nat_osrc6, src) ||
+			    IP6_NEQ(&nat->nat_odst6, dst))
+				continue;
+			break;
+		}
+
+		if (!(nat->nat_flags & (NAT_TCPUDP|SI_WILDP)))
+			continue;
+
+		if (ipf_nat_wildok(nat, (int)sport, (int)dport, nat->nat_flags,
+				   NAT_OUTBOUND) == 1) {
+			if ((fin->fin_flx & FI_IGNORE) != 0)
+				break;
+			if ((nat->nat_flags & SI_CLONE) != 0) {
+				nat = ipf_nat_clone(fin, nat);
+				if (nat == NULL)
+					break;
+			} else {
+				MUTEX_ENTER(&softn->ipf_nat_new);
+				softn->ipf_nat_stats.ns_wilds--;
+				MUTEX_EXIT(&softn->ipf_nat_new);
+			}
+
+			if (nat->nat_dir == NAT_OUTBOUND) {
+				if (nat->nat_osport == 0) {
+					nat->nat_osport = sport;
+					nat->nat_nsport = sport;
+				}
+				if (nat->nat_odport == 0) {
+					nat->nat_odport = dport;
+					nat->nat_ndport = dport;
+				}
+			} else {
+				if (nat->nat_osport == 0) {
+					nat->nat_osport = dport;
+					nat->nat_nsport = dport;
+				}
+				if (nat->nat_odport == 0) {
+					nat->nat_odport = sport;
+					nat->nat_ndport = sport;
+				}
+			}
+			if ((nat->nat_ifps[1] == NULL) && (ifp != NULL)) {
+				nat->nat_ifps[1] = ifp;
+				nat->nat_mtu[1] = GETIFMTU_6(ifp);
+			}
+			nat->nat_flags &= ~(SI_W_DPORT|SI_W_SPORT);
+			ipf_nat6_tabmove(softn, nat);
+			break;
+		}
+	}
+
+	MUTEX_DOWNGRADE(&softc->ipf_nat);
+
+	if (nat == NULL) {
+		NBUMPSIDE6DX(1, ns_lookup_miss, ns_lookup_miss_4);
+	}
+	return nat;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_nat6_lookupredir                                        */
+/* Returns:     nat6_t* - NULL == no match,                                 */
+/*                       else pointer to matching NAT entry                 */
+/* Parameters:  np(I) - pointer to description of packet to find NAT table  */
+/*                      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 *
+ipf_nat6_lookupredir(np)
+	natlookup_t *np;
+{
+	fr_info_t fi;
+	nat_t *nat;
+
+	bzero((char *)&fi, sizeof(fi));
+	if (np->nl_flags & IPN_IN) {
+		fi.fin_data[0] = ntohs(np->nl_realport);
+		fi.fin_data[1] = ntohs(np->nl_outport);
+	} else {
+		fi.fin_data[0] = ntohs(np->nl_inport);
+		fi.fin_data[1] = ntohs(np->nl_outport);
+	}
+	if (np->nl_flags & IPN_TCP)
+		fi.fin_p = IPPROTO_TCP;
+	else if (np->nl_flags & IPN_UDP)
+		fi.fin_p = IPPROTO_UDP;
+	else if (np->nl_flags & (IPN_ICMPERR|IPN_ICMPQUERY))
+		fi.fin_p = IPPROTO_ICMPV6;
+
+	/*
+	 * We can do two sorts of lookups:
+	 * - IPN_IN: we have the `real' and `out' address, look for `in'.
+	 * - default: we have the `in' and `out' address, look for `real'.
+	 */
+	if (np->nl_flags & IPN_IN) {
+		if ((nat = ipf_nat6_inlookup(&fi, np->nl_flags, fi.fin_p,
+					     &np->nl_realip6,
+					     &np->nl_outip6))) {
+			np->nl_inip6 = nat->nat_odst6.in6;
+			np->nl_inport = nat->nat_odport;
+		}
+	} else {
+		/*
+		 * If nl_inip is non null, this is a lookup based on the real
+		 * ip address. Else, we use the fake.
+		 */
+		if ((nat = ipf_nat6_outlookup(&fi, np->nl_flags, fi.fin_p,
+					      &np->nl_inip6, &np->nl_outip6))) {
+
+			if ((np->nl_flags & IPN_FINDFORWARD) != 0) {
+				fr_info_t fin;
+				bzero((char *)&fin, sizeof(fin));
+				fin.fin_p = nat->nat_pr[0];
+				fin.fin_data[0] = ntohs(nat->nat_ndport);
+				fin.fin_data[1] = ntohs(nat->nat_nsport);
+				if (ipf_nat6_inlookup(&fin, np->nl_flags,
+						     fin.fin_p,
+						     &nat->nat_ndst6.in6,
+						     &nat->nat_nsrc6.in6) !=
+				    NULL) {
+					np->nl_flags &= ~IPN_FINDFORWARD;
+				}
+			}
+
+			np->nl_realip6 = nat->nat_odst6.in6;
+			np->nl_realport = nat->nat_odport;
+		}
+ 	}
+
+	return nat;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_nat6_match                                              */
+/* Returns:     int - 0 == no match, 1 == match                             */
+/* Parameters:  fin(I)   - pointer to packet information                    */
+/*              np(I)    - pointer to NAT rule                              */
+/*                                                                          */
+/* Pull the matching of a packet against a NAT rule out of that complex     */
+/* loop inside ipf_nat6_checkin() and lay it out properly in its own        */
+/* function.                                                                */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_nat6_match(fin, np)
+	fr_info_t *fin;
+	ipnat_t *np;
+{
+	frtuc_t *ft;
+	int match;
+
+	match = 0;
+	switch (np->in_osrcatype)
+	{
+	case FRI_NORMAL :
+		match = IP6_MASKNEQ(&fin->fin_src6, &np->in_osrcmsk6,
+				    &np->in_osrcip6);
+		break;
+	case FRI_LOOKUP :
+		match = (*np->in_osrcfunc)(fin->fin_main_soft, np->in_osrcptr,
+					   6, &fin->fin_src6, fin->fin_plen);
+		break;
+	}
+	match ^= ((np->in_flags & IPN_NOTSRC) != 0);
+	if (match)
+		return 0;
+
+	match = 0;
+	switch (np->in_odstatype)
+	{
+	case FRI_NORMAL :
+		match = IP6_MASKNEQ(&fin->fin_dst6, &np->in_odstmsk6,
+				    &np->in_odstip6);
+		break;
+	case FRI_LOOKUP :
+		match = (*np->in_odstfunc)(fin->fin_main_soft, np->in_odstptr,
+					   6, &fin->fin_dst6, fin->fin_plen);
+		break;
+	}
+
+	match ^= ((np->in_flags & IPN_NOTDST) != 0);
+	if (match)
+		return 0;
+
+	ft = &np->in_tuc;
+	if (!(fin->fin_flx & FI_TCPUDP) ||
+	    (fin->fin_flx & (FI_SHORT|FI_FRAGBODY))) {
+		if (ft->ftu_scmp || ft->ftu_dcmp)
+			return 0;
+		return 1;
+	}
+
+	return ipf_tcpudpchk(&fin->fin_fi, ft);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_nat6_checkout                                           */
+/* Returns:     int - -1 == packet failed NAT checks so block it,           */
+/*                     0 == no packet translation occurred,                 */
+/*                     1 == packet was successfully translated.             */
+/* Parameters:  fin(I)   - pointer to packet information                    */
+/*              passp(I) - pointer to filtering result flags                */
+/*                                                                          */
+/* Check to see if an outcoming packet should be changed.  ICMP packets are */
+/* first checked to see if they match an existing entry (if an error),      */
+/* otherwise a search of the current NAT table is made.  If neither results */
+/* in a match then a search for a matching NAT rule is made.  Create a new  */
+/* NAT entry if a we matched a NAT rule.  Lastly, actually change the       */
+/* packet header(s) as required.                                            */
+/* ------------------------------------------------------------------------ */
+int
+ipf_nat6_checkout(fin, passp)
+	fr_info_t *fin;
+	u_32_t *passp;
+{
+	ipf_main_softc_t *softc = fin->fin_main_soft;
+	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
+	struct icmp6_hdr *icmp6 = NULL;
+	struct ifnet *ifp, *sifp;
+	tcphdr_t *tcp = NULL;
+	int rval, natfailed;
+	ipnat_t *np = NULL;
+	u_int nflags = 0;
+	i6addr_t ipa, iph;
+	int natadd = 1;
+	frentry_t *fr;
+	nat_t *nat;
+
+	if (softn->ipf_nat_stats.ns_rules == 0 || softn->ipf_nat_lock != 0)
+		return 0;
+
+	icmp6 = NULL;
+	natfailed = 0;
+	fr = fin->fin_fr;
+	sifp = fin->fin_ifp;
+	if (fr != NULL) {
+		ifp = fr->fr_tifs[fin->fin_rev].fd_ptr;
+		if ((ifp != NULL) && (ifp != (void *)-1))
+			fin->fin_ifp = ifp;
+	}
+	ifp = fin->fin_ifp;
+
+	if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) {
+		switch (fin->fin_p)
+		{
+		case IPPROTO_TCP :
+			nflags = IPN_TCP;
+			break;
+		case IPPROTO_UDP :
+			nflags = IPN_UDP;
+			break;
+		case IPPROTO_ICMPV6 :
+			icmp6 = fin->fin_dp;
+
+			/*
+			 * Apart from ECHO request and reply, all other
+			 * informational messages should not be translated
+			 * so as to keep IPv6 working.
+			 */
+			if (icmp6->icmp6_type > ICMP6_ECHO_REPLY)
+				return 0;
+
+			/*
+			 * This is an incoming packet, so the destination is
+			 * the icmp6_id and the source port equals 0
+			 */
+			if ((fin->fin_flx & FI_ICMPQUERY) != 0)
+				nflags = IPN_ICMPQUERY;
+			break;
+		default :
+			break;
+		}
+
+		if ((nflags & IPN_TCPUDP))
+			tcp = fin->fin_dp;
+	}
+
+	ipa = fin->fin_src6;
+
+	READ_ENTER(&softc->ipf_nat);
+
+	if ((fin->fin_p == IPPROTO_ICMPV6) && !(nflags & IPN_ICMPQUERY) &&
+	    (nat = ipf_nat6_icmperror(fin, &nflags, NAT_OUTBOUND)))
+		/*EMPTY*/;
+	else if ((fin->fin_flx & FI_FRAG) && (nat = ipf_frag_natknown(fin)))
+		natadd = 0;
+	else if ((nat = ipf_nat6_outlookup(fin, nflags|NAT_SEARCH,
+					   (u_int)fin->fin_p,
+					   &fin->fin_src6.in6,
+					   &fin->fin_dst6.in6))) {
+		nflags = nat->nat_flags;
+	} else if (fin->fin_off == 0) {
+		u_32_t hv, nmsk = 0;
+		i6addr_t *msk;
+
+		/*
+		 * If there is no current entry in the nat table for this IP#,
+		 * create one for it (if there is a matching rule).
+		 */
+maskloop:
+		msk = &softn->ipf_nat6_map_active_masks[nmsk];
+		IP6_AND(&ipa, msk, &iph);
+		hv = NAT_HASH_FN6(&iph, 0, softn->ipf_nat_maprules_sz);
+		for (np = softn->ipf_nat_map_rules[hv]; np; np = np->in_mnext) {
+			if ((np->in_ifps[1] && (np->in_ifps[1] != ifp)))
+				continue;
+			if (np->in_v[0] != 6)
+				continue;
+			if (np->in_pr[1] && (np->in_pr[1] != fin->fin_p))
+				continue;
+			if ((np->in_flags & IPN_RF) &&
+			    !(np->in_flags & nflags))
+				continue;
+			if (np->in_flags & IPN_FILTER) {
+				switch (ipf_nat6_match(fin, np))
+				{
+				case 0 :
+					continue;
+				case -1 :
+					rval = -1;
+					goto outmatchfail;
+				case 1 :
+				default :
+					break;
+				}
+			} else if (!IP6_MASKEQ(&ipa, &np->in_osrcmsk,
+					       &np->in_osrcip6))
+				continue;
+
+			if ((fr != NULL) &&
+			    !ipf_matchtag(&np->in_tag, &fr->fr_nattag))
+				continue;
+
+#ifdef IPF_V6_PROXIES
+			if (np->in_plabel != -1) {
+				if (((np->in_flags & IPN_FILTER) == 0) &&
+				    (np->in_odport != fin->fin_data[1]))
+					continue;
+				if (appr_ok(fin, tcp, np) == 0)
+					continue;
+			}
+#endif
+
+			if (np->in_flags & IPN_NO) {
+				np->in_hits++;
+				break;
+			}
+
+			MUTEX_ENTER(&softn->ipf_nat_new);
+			nat = ipf_nat6_add(fin, np, NULL, nflags, NAT_OUTBOUND);
+			MUTEX_EXIT(&softn->ipf_nat_new);
+			if (nat != NULL) {
+				np->in_hits++;
+				break;
+			}
+			natfailed = -1;
+		}
+		if ((np == NULL) && (nmsk < softn->ipf_nat6_map_max)) {
+			nmsk++;
+			goto maskloop;
+		}
+	}
+
+	if (nat != NULL) {
+		rval = ipf_nat6_out(fin, nat, natadd, nflags);
+		if (rval == 1) {
+			MUTEX_ENTER(&nat->nat_lock);
+			ipf_nat_update(fin, nat);
+			nat->nat_bytes[1] += fin->fin_plen;
+			nat->nat_pkts[1]++;
+			MUTEX_EXIT(&nat->nat_lock);
+		}
+	} else
+		rval = natfailed;
+outmatchfail:
+	RWLOCK_EXIT(&softc->ipf_nat);
+
+	switch (rval)
+	{
+	case -1 :
+		if (passp != NULL) {
+			NBUMPSIDE6D(1, ns_drop);
+			*passp = FR_BLOCK;
+			fin->fin_reason = FRB_NATV6;
+		}
+		fin->fin_flx |= FI_BADNAT;
+		NBUMPSIDE6D(1, ns_badnat);
+		break;
+	case 0 :
+		NBUMPSIDE6D(1, ns_ignored);
+		break;
+	case 1 :
+		NBUMPSIDE6D(1, ns_translated);
+		break;
+	}
+	fin->fin_ifp = sifp;
+	return rval;
+}
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_nat6_out                                                */
+/* Returns:     int - -1 == packet failed NAT checks so block it,           */
+/*                     1 == packet was successfully translated.             */
+/* Parameters:  fin(I)    - pointer to packet information                   */
+/*              nat(I)    - pointer to NAT structure                        */
+/*              natadd(I) - flag indicating if it is safe to add frag cache */
+/*              nflags(I) - NAT flags set for this packet                   */
+/*                                                                          */
+/* Translate a packet coming "out" on an interface.                         */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_nat6_out(fin, nat, natadd, nflags)
+	fr_info_t *fin;
+	nat_t *nat;
+	int natadd;
+	u_32_t nflags;
+{
+	ipf_main_softc_t *softc = fin->fin_main_soft;
+	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
+	struct icmp6_hdr *icmp6;
+	tcphdr_t *tcp;
+	ipnat_t *np;
+	int skip;
+	int i;
+
+	tcp = NULL;
+	icmp6 = NULL;
+	np = nat->nat_ptr;
+
+	if ((natadd != 0) && (fin->fin_flx & FI_FRAG) && (np != NULL))
+		(void) ipf_frag_natnew(softc, fin, 0, nat);
+
+	/*
+	 * Address assignment is after the checksum modification because
+	 * we are using the address in the packet for determining the
+	 * correct checksum offset (the ICMP error could be coming from
+	 * anyone...)
+	 */
+	switch (nat->nat_dir)
+	{
+	case NAT_OUTBOUND :
+		fin->fin_ip6->ip6_src = nat->nat_nsrc6.in6;
+		fin->fin_src6 = nat->nat_nsrc6;
+		fin->fin_ip6->ip6_dst = nat->nat_ndst6.in6;
+		fin->fin_dst6 = nat->nat_ndst6;
+		break;
+
+	case NAT_INBOUND :
+		fin->fin_ip6->ip6_src = nat->nat_odst6.in6;
+		fin->fin_src6 = nat->nat_ndst6;
+		fin->fin_ip6->ip6_dst = nat->nat_osrc6.in6;
+		fin->fin_dst6 = nat->nat_nsrc6;
+		break;
+
+	case NAT_DIVERTIN :
+	    {
+		mb_t *m;
+
+		skip = ipf_nat6_decap(fin, nat);
+		if (skip <= 0) {
+			NBUMPSIDE6D(1, ns_decap_fail);
+			return -1;
+		}
+
+		m = fin->fin_m;
+
+#if defined(MENTAT) && defined(_KERNEL)
+		m->b_rptr += skip;
+#else
+		m->m_data += skip;
+		m->m_len -= skip;
+
+# ifdef M_PKTHDR
+		if (m->m_flags & M_PKTHDR)
+			m->m_pkthdr.len -= skip;
+# endif
+#endif
+
+		MUTEX_ENTER(&nat->nat_lock);
+		ipf_nat_update(fin, nat);
+		MUTEX_EXIT(&nat->nat_lock);
+		fin->fin_flx |= FI_NATED;
+		if (np != NULL && np->in_tag.ipt_num[0] != 0)
+			fin->fin_nattag = &np->in_tag;
+		return 1;
+		/* NOTREACHED */
+	    }
+
+	case NAT_DIVERTOUT :
+	    {
+		udphdr_t *uh;
+		ip6_t *ip6;
+		mb_t *m;
+
+		m = M_DUP(np->in_divmp);
+		if (m == NULL) {
+			NBUMPSIDE6D(1, ns_divert_dup);
+			return -1;
+		}
+
+		ip6 = MTOD(m, ip6_t *);
+
+		ip6->ip6_plen = htons(fin->fin_plen + 8);
+
+		uh = (udphdr_t *)(ip6 + 1);
+		uh->uh_ulen = htons(fin->fin_plen);
+
+		PREP_MB_T(fin, m);
+
+		fin->fin_ip6 = ip6;
+		fin->fin_plen += sizeof(ip6_t) + 8;	/* UDP + new IPv4 hdr */
+		fin->fin_dlen += sizeof(ip6_t) + 8;	/* UDP + old IPv4 hdr */
+
+		nflags &= ~IPN_TCPUDPICMP;
+
+		break;
+	    }
+
+	default :
+		break;
+	}
+
+	if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) {
+		u_short *csump;
+
+		if ((nat->nat_nsport != 0) && (nflags & IPN_TCPUDP)) {
+			tcp = fin->fin_dp;
+
+			switch (nat->nat_dir)
+			{
+			case NAT_OUTBOUND :
+				tcp->th_sport = nat->nat_nsport;
+				fin->fin_data[0] = ntohs(nat->nat_nsport);
+				tcp->th_dport = nat->nat_ndport;
+				fin->fin_data[1] = ntohs(nat->nat_ndport);
+				break;
+
+			case NAT_INBOUND :
+				tcp->th_sport = nat->nat_odport;
+				fin->fin_data[0] = ntohs(nat->nat_odport);
+				tcp->th_dport = nat->nat_osport;
+				fin->fin_data[1] = ntohs(nat->nat_osport);
+				break;
+			}
+		}
+
+		if ((nat->nat_nsport != 0) && (nflags & IPN_ICMPQUERY)) {
+			icmp6 = fin->fin_dp;
+			icmp6->icmp6_id = nat->nat_nicmpid;
+		}
+
+		csump = ipf_nat_proto(fin, nat, nflags);
+
+		/*
+		 * The above comments do not hold for layer 4 (or higher)
+		 * checksums...
+		 */
+		if (csump != NULL) {
+			if (nat->nat_dir == NAT_OUTBOUND)
+				ipf_fix_outcksum(fin->fin_cksum, csump,
+						 nat->nat_sumd[0],
+						 nat->nat_sumd[1] +
+						 fin->fin_dlen);
+			else
+				ipf_fix_incksum(fin->fin_cksum, csump,
+						nat->nat_sumd[0],
+						nat->nat_sumd[1] +
+						fin->fin_dlen);
+		}
+	}
+
+	ipf_sync_update(softc, SMC_NAT, fin, nat->nat_sync);
+	/* ------------------------------------------------------------- */
+	/* A few quick notes:                                            */
+	/*      Following are test conditions prior to calling the       */
+	/*      ipf_proxy_check routine.                                 */
+	/*                                                               */
+	/*      A NULL tcp indicates a non TCP/UDP packet.  When dealing */
+	/*      with a redirect rule, we attempt to match the packet's   */
+	/*      source port against in_dport, otherwise we'd compare the */
+	/*      packet's destination.                                    */
+	/* ------------------------------------------------------------- */
+	if ((np != NULL) && (np->in_apr != NULL)) {
+		i = ipf_proxy_check(fin, nat);
+		if (i == 0) {
+			i = 1;
+		} else if (i == -1) {
+			NBUMPSIDE6D(1, ns_ipf_proxy_fail);
+		}
+	} else {
+		i = 1;
+	}
+	fin->fin_flx |= FI_NATED;
+	return i;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_nat6_checkin                                            */
+/* Returns:     int - -1 == packet failed NAT checks so block it,           */
+/*                     0 == no packet translation occurred,                 */
+/*                     1 == packet was successfully translated.             */
+/* Parameters:  fin(I)   - pointer to packet information                    */
+/*              passp(I) - pointer to filtering result flags                */
+/*                                                                          */
+/* Check to see if an incoming packet should be changed.  ICMP packets are  */
+/* first checked to see if they match an existing entry (if an error),      */
+/* otherwise a search of the current NAT table is made.  If neither results */
+/* in a match then a search for a matching NAT rule is made.  Create a new  */
+/* NAT entry if a we matched a NAT rule.  Lastly, actually change the       */
+/* packet header(s) as required.                                            */
+/* ------------------------------------------------------------------------ */
+int
+ipf_nat6_checkin(fin, passp)
+	fr_info_t *fin;
+	u_32_t *passp;
+{
+	ipf_main_softc_t *softc = fin->fin_main_soft;
+	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
+	struct icmp6_hdr *icmp6;
+	u_int nflags, natadd;
+	int rval, natfailed;
+	struct ifnet *ifp;
+	i6addr_t ipa, iph;
+	tcphdr_t *tcp;
+	u_short dport;
+	ipnat_t *np;
+	nat_t *nat;
+
+	if (softn->ipf_nat_stats.ns_rules == 0 || softn->ipf_nat_lock != 0)
+		return 0;
+
+	tcp = NULL;
+	icmp6 = NULL;
+	dport = 0;
+	natadd = 1;
+	nflags = 0;
+	natfailed = 0;
+	ifp = fin->fin_ifp;
+
+	if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) {
+		switch (fin->fin_p)
+		{
+		case IPPROTO_TCP :
+			nflags = IPN_TCP;
+			break;
+		case IPPROTO_UDP :
+			nflags = IPN_UDP;
+			break;
+		case IPPROTO_ICMPV6 :
+			icmp6 = fin->fin_dp;
+
+			/*
+			 * Apart from ECHO request and reply, all other
+			 * informational messages should not be translated
+			 * so as to keep IPv6 working.
+			 */
+			if (icmp6->icmp6_type > ICMP6_ECHO_REPLY)
+				return 0;
+
+			/*
+			 * This is an incoming packet, so the destination is
+			 * the icmp6_id and the source port equals 0
+			 */
+			if ((fin->fin_flx & FI_ICMPQUERY) != 0) {
+				nflags = IPN_ICMPQUERY;
+				dport = icmp6->icmp6_id;
+			} break;
+		default :
+			break;
+		}
+
+		if ((nflags & IPN_TCPUDP)) {
+			tcp = fin->fin_dp;
+			dport = fin->fin_data[1];
+		}
+	}
+
+	ipa = fin->fin_dst6;
+
+	READ_ENTER(&softc->ipf_nat);
+
+	if ((fin->fin_p == IPPROTO_ICMPV6) && !(nflags & IPN_ICMPQUERY) &&
+	    (nat = ipf_nat6_icmperror(fin, &nflags, NAT_INBOUND)))
+		/*EMPTY*/;
+	else if ((fin->fin_flx & FI_FRAG) && (nat = ipf_frag_natknown(fin)))
+		natadd = 0;
+	else if ((nat = ipf_nat6_inlookup(fin, nflags|NAT_SEARCH,
+					  (u_int)fin->fin_p,
+					  &fin->fin_src6.in6, &ipa.in6))) {
+		nflags = nat->nat_flags;
+	} else if (fin->fin_off == 0) {
+		u_32_t hv, rmsk = 0;
+		i6addr_t *msk;
+
+		/*
+		 * If there is no current entry in the nat table for this IP#,
+		 * create one for it (if there is a matching rule).
+		 */
+maskloop:
+		msk = &softn->ipf_nat6_rdr_active_masks[rmsk];
+		IP6_AND(&ipa, msk, &iph);
+		hv = NAT_HASH_FN6(&iph, 0, softn->ipf_nat_rdrrules_sz);
+		for (np = softn->ipf_nat_rdr_rules[hv]; np; np = np->in_rnext) {
+			if (np->in_ifps[0] && (np->in_ifps[0] != ifp))
+				continue;
+			if (np->in_v[0] != 6)
+				continue;
+			if (np->in_pr[0] && (np->in_pr[0] != fin->fin_p))
+				continue;
+			if ((np->in_flags & IPN_RF) && !(np->in_flags & nflags))
+				continue;
+			if (np->in_flags & IPN_FILTER) {
+				switch (ipf_nat6_match(fin, np))
+				{
+				case 0 :
+					continue;
+				case -1 :
+					rval = -1;
+					goto inmatchfail;
+				case 1 :
+				default :
+					break;
+				}
+			} else {
+				if (!IP6_MASKEQ(&ipa, &np->in_odstmsk6,
+						&np->in_odstip6)) {
+					continue;
+				}
+				if (np->in_odport &&
+				    ((np->in_dtop < dport) ||
+				     (dport < np->in_odport)))
+					continue;
+			}
+
+#ifdef IPF_V6_PROXIES
+			if (np->in_plabel != -1) {
+				if (!appr_ok(fin, tcp, np)) {
+					continue;
+				}
+			}
+#endif
+
+			if (np->in_flags & IPN_NO) {
+				np->in_hits++;
+				break;
+			}
+
+			MUTEX_ENTER(&softn->ipf_nat_new);
+			nat = ipf_nat6_add(fin, np, NULL, nflags, NAT_INBOUND);
+			MUTEX_EXIT(&softn->ipf_nat_new);
+			if (nat != NULL) {
+				np->in_hits++;
+				break;
+			}
+			natfailed = -1;
+		}
+
+		if ((np == NULL) && (rmsk < softn->ipf_nat6_rdr_max)) {
+			rmsk++;
+			goto maskloop;
+		}
+	}
+	if (nat != NULL) {
+		rval = ipf_nat6_in(fin, nat, natadd, nflags);
+		if (rval == 1) {
+			MUTEX_ENTER(&nat->nat_lock);
+			ipf_nat_update(fin, nat);
+			nat->nat_bytes[0] += fin->fin_plen;
+			nat->nat_pkts[0]++;
+			MUTEX_EXIT(&nat->nat_lock);
+		}
+	} else
+		rval = natfailed;
+inmatchfail:
+	RWLOCK_EXIT(&softc->ipf_nat);
+
+	switch (rval)
+	{
+	case -1 :
+		if (passp != NULL) {
+			NBUMPSIDE6D(0, ns_drop);
+			*passp = FR_BLOCK;
+			fin->fin_reason = FRB_NATV6;
+		}
+		fin->fin_flx |= FI_BADNAT;
+		NBUMPSIDE6D(0, ns_badnat);
+		break;
+	case 0 :
+		NBUMPSIDE6D(0, ns_ignored);
+		break;
+	case 1 :
+		NBUMPSIDE6D(0, ns_translated);
+		break;
+	}
+	return rval;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_nat6_in                                                 */
+/* Returns:     int - -1 == packet failed NAT checks so block it,           */
+/*                     1 == packet was successfully translated.             */
+/* Parameters:  fin(I)    - pointer to packet information                   */
+/*              nat(I)    - pointer to NAT structure                        */
+/*              natadd(I) - flag indicating if it is safe to add frag cache */
+/*              nflags(I) - NAT flags set for this packet                   */
+/* Locks Held:   (READ)                                              */
+/*                                                                          */
+/* Translate a packet coming "in" on an interface.                          */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_nat6_in(fin, nat, natadd, nflags)
+	fr_info_t *fin;
+	nat_t *nat;
+	int natadd;
+	u_32_t nflags;
+{
+	ipf_main_softc_t *softc = fin->fin_main_soft;
+	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
+	struct icmp6_hdr *icmp6;
+	u_short *csump;
+	tcphdr_t *tcp;
+	ipnat_t *np;
+	int skip;
+	int i;
+
+	tcp = NULL;
+	csump = NULL;
+	np = nat->nat_ptr;
+	fin->fin_fr = nat->nat_fr;
+
+	if (np != NULL) {
+		if ((natadd != 0) && (fin->fin_flx & FI_FRAG))
+			(void) ipf_frag_natnew(softc, fin, 0, nat);
+
+	/* ------------------------------------------------------------- */
+	/* A few quick notes:                                            */
+	/*      Following are test conditions prior to calling the       */
+	/*      ipf_proxy_check routine.                                 */
+	/*                                                               */
+	/*      A NULL tcp indicates a non TCP/UDP packet.  When dealing */
+	/*      with a map rule, we attempt to match the packet's        */
+	/*      source port against in_dport, otherwise we'd compare the */
+	/*      packet's destination.                                    */
+	/* ------------------------------------------------------------- */
+		if (np->in_apr != NULL) {
+			i = ipf_proxy_check(fin, nat);
+			if (i == -1) {
+				NBUMPSIDE6D(0, ns_ipf_proxy_fail);
+				return -1;
+			}
+		}
+	}
+
+	ipf_sync_update(softc, SMC_NAT, fin, nat->nat_sync);
+
+	/*
+	 * Fix up checksums, not by recalculating them, but
+	 * simply computing adjustments.
+	 * Why only do this for some platforms on inbound packets ?
+	 * Because for those that it is done, IP processing is yet to happen
+	 * and so the IPv4 header checksum has not yet been evaluated.
+	 * Perhaps it should always be done for the benefit of things like
+	 * fast forwarding (so that it doesn't need to be recomputed) but with
+	 * header checksum offloading, perhaps it is a moot point.
+	 */
+
+	switch (nat->nat_dir)
+	{
+	case NAT_INBOUND :
+		if ((fin->fin_flx & FI_ICMPERR) == 0) {
+			fin->fin_ip6->ip6_src = nat->nat_nsrc6.in6;
+			fin->fin_src6 = nat->nat_nsrc6;
+		}
+		fin->fin_ip6->ip6_dst = nat->nat_ndst6.in6;
+		fin->fin_dst6 = nat->nat_ndst6;
+		break;
+
+	case NAT_OUTBOUND :
+		if ((fin->fin_flx & FI_ICMPERR) == 0) {
+			fin->fin_ip6->ip6_src = nat->nat_odst6.in6;
+			fin->fin_src6 = nat->nat_odst6;
+		}
+		fin->fin_ip6->ip6_dst = nat->nat_osrc6.in6;
+		fin->fin_dst6 = nat->nat_osrc6;
+		break;
+
+	case NAT_DIVERTIN :
+	    {
+		udphdr_t *uh;
+		ip6_t *ip6;
+		mb_t *m;
+
+		m = M_DUP(np->in_divmp);
+		if (m == NULL) {
+			NBUMPSIDE6D(0, ns_divert_dup);
+			return -1;
+		}
+
+		ip6 = MTOD(m, ip6_t *);
+		ip6->ip6_plen = htons(fin->fin_plen + sizeof(udphdr_t));
+
+		uh = (udphdr_t *)(ip6 + 1);
+		uh->uh_ulen = ntohs(fin->fin_plen);
+
+		PREP_MB_T(fin, m);
+
+		fin->fin_ip6 = ip6;
+		fin->fin_plen += sizeof(ip6_t) + 8;	/* UDP + new IPv6 hdr */
+		fin->fin_dlen += sizeof(ip6_t) + 8;	/* UDP + old IPv6 hdr */
+
+		nflags &= ~IPN_TCPUDPICMP;
+
+		break;
+	    }
+
+	case NAT_DIVERTOUT :
+	    {
+		mb_t *m;
+
+		skip = ipf_nat6_decap(fin, nat);
+		if (skip <= 0) {
+			NBUMPSIDE6D(0, ns_decap_fail);
+			return -1;
+		}
+
+		m = fin->fin_m;
+
+#if defined(MENTAT) && defined(_KERNEL)
+		m->b_rptr += skip;
+#else
+		m->m_data += skip;
+		m->m_len -= skip;
+
+# ifdef M_PKTHDR
+		if (m->m_flags & M_PKTHDR)
+			m->m_pkthdr.len -= skip;
+# endif
+#endif
+
+		ipf_nat_update(fin, nat);
+		fin->fin_flx |= FI_NATED;
+		if (np != NULL && np->in_tag.ipt_num[0] != 0)
+			fin->fin_nattag = &np->in_tag;
+		return 1;
+		/* NOTREACHED */
+	    }
+	}
+	if (nflags & IPN_TCPUDP)
+		tcp = fin->fin_dp;
+
+	if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) {
+		if ((nat->nat_odport != 0) && (nflags & IPN_TCPUDP)) {
+			switch (nat->nat_dir)
+			{
+			case NAT_INBOUND :
+				tcp->th_sport = nat->nat_nsport;
+				fin->fin_data[0] = ntohs(nat->nat_nsport);
+				tcp->th_dport = nat->nat_ndport;
+				fin->fin_data[1] = ntohs(nat->nat_ndport);
+				break;
+
+			case NAT_OUTBOUND :
+				tcp->th_sport = nat->nat_odport;
+				fin->fin_data[0] = ntohs(nat->nat_odport);
+				tcp->th_dport = nat->nat_osport;
+				fin->fin_data[1] = ntohs(nat->nat_osport);
+				break;
+			}
+		}
+
+
+		if ((nat->nat_odport != 0) && (nflags & IPN_ICMPQUERY)) {
+			icmp6 = fin->fin_dp;
+
+			icmp6->icmp6_id = nat->nat_nicmpid;
+		}
+
+		csump = ipf_nat_proto(fin, nat, nflags);
+	}
+
+	/*
+	 * The above comments do not hold for layer 4 (or higher) checksums...
+	 */
+	if (csump != NULL) {
+		if (nat->nat_dir == NAT_OUTBOUND)
+			ipf_fix_incksum(0, csump, nat->nat_sumd[0], 0);
+		else
+			ipf_fix_outcksum(0, csump, nat->nat_sumd[0], 0);
+	}
+	fin->fin_flx |= FI_NATED;
+	if (np != NULL && np->in_tag.ipt_num[0] != 0)
+		fin->fin_nattag = &np->in_tag;
+	return 1;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_nat6_newrewrite                                         */
+/* Returns:     int - -1 == error, 0 == success (no move), 1 == success and */
+/*                    allow rule to be moved if IPN_ROUNDR is set.          */
+/* Parameters:  fin(I) - pointer to packet information                      */
+/*              nat(I) - pointer to NAT entry                               */
+/*              ni(I)  - pointer to structure with misc. information needed */
+/*                       to create new NAT entry.                           */
+/* Write Lock:  ipf_nat                                                     */
+/*                                                                          */
+/* This function is responsible for setting up an active NAT session where  */
+/* we are changing both the source and destination parameters at the same   */
+/* time.  The loop in here works differently to elsewhere - each iteration  */
+/* is responsible for changing a single parameter that can be incremented.  */
+/* So one pass may increase the source IP#, next source port, next dest. IP#*/
+/* and the last destination port for a total of 4 iterations to try each.   */
+/* This is done to try and exhaustively use the translation space available.*/
+/* ------------------------------------------------------------------------ */
+int
+ipf_nat6_newrewrite(fin, nat, nai)
+	fr_info_t *fin;
+	nat_t *nat;
+	natinfo_t *nai;
+{
+	int src_search = 1;
+	int dst_search = 1;
+	fr_info_t frnat;
+	u_32_t flags;
+	u_short swap;
+	ipnat_t *np;
+	nat_t *natl;
+	int l = 0;
+	int changed;
+
+	natl = NULL;
+	changed = -1;
+	np = nai->nai_np;
+	flags = nat->nat_flags;
+	bcopy((char *)fin, (char *)&frnat, sizeof(*fin));
+
+	nat->nat_hm = NULL;
+
+	do {
+		changed = -1;
+		/* TRACE (l, src_search, dst_search, np) */
+
+		if ((src_search == 0) && (np->in_spnext == 0) &&
+		    (dst_search == 0) && (np->in_dpnext == 0)) {
+			if (l > 0)
+				return -1;
+		}
+
+		/*
+		 * Find a new source address
+		 */
+		if (ipf_nat6_nextaddr(fin, &np->in_nsrc, &frnat.fin_src6,
+				 &frnat.fin_src6) == -1) {
+			return -1;
+		}
+
+		if (IP6_ISZERO(&np->in_nsrcip6) &&
+		    IP6_ISONES(&np->in_nsrcmsk6)) {
+			src_search = 0;
+			if (np->in_stepnext == 0)
+				np->in_stepnext = 1;
+
+		} else if (IP6_ISZERO(&np->in_nsrcip6) &&
+			   IP6_ISZERO(&np->in_nsrcmsk6)) {
+			src_search = 0;
+			if (np->in_stepnext == 0)
+				np->in_stepnext = 1;
+
+		} else if (IP6_ISONES(&np->in_nsrcmsk)) {
+			src_search = 0;
+			if (np->in_stepnext == 0)
+				np->in_stepnext = 1;
+
+		} else if (!IP6_ISONES(&np->in_nsrcmsk6)) {
+			if (np->in_stepnext == 0 && changed == -1) {
+				IP6_INC(&np->in_snip);
+				np->in_stepnext++;
+				changed = 0;
+			}
+		}
+
+		if ((flags & IPN_TCPUDPICMP) != 0) {
+			if (np->in_spnext != 0)
+				frnat.fin_data[0] = np->in_spnext;
+
+			/*
+			 * Standard port translation.  Select next port.
+			 */
+			if ((flags & IPN_FIXEDSPORT) != 0) {
+				np->in_stepnext = 2;
+			} else if ((np->in_stepnext == 1) &&
+				   (changed == -1) && (natl != NULL)) {
+				np->in_spnext++;
+				np->in_stepnext++;
+				changed = 1;
+				if (np->in_spnext > np->in_spmax)
+					np->in_spnext = np->in_spmin;
+			}
+		} else {
+			np->in_stepnext = 2;
+		}
+		np->in_stepnext &= 0x3;
+
+		/*
+		 * Find a new destination address
+		 */
+		/* TRACE (fin, np, l, frnat) */
+
+		if (ipf_nat6_nextaddr(fin, &np->in_ndst, &frnat.fin_dst6,
+				      &frnat.fin_dst6) == -1)
+			return -1;
+
+		if (IP6_ISZERO(&np->in_ndstip6) &&
+		    IP6_ISONES(&np->in_ndstmsk6)) {
+			dst_search = 0;
+			if (np->in_stepnext == 2)
+				np->in_stepnext = 3;
+
+		} else if (IP6_ISZERO(&np->in_ndstip6) &&
+			   IP6_ISZERO(&np->in_ndstmsk6)) {
+			dst_search = 0;
+			if (np->in_stepnext == 2)
+				np->in_stepnext = 3;
+
+		} else if (IP6_ISONES(&np->in_ndstmsk6)) {
+			dst_search = 0;
+			if (np->in_stepnext == 2)
+				np->in_stepnext = 3;
+
+		} else if (!IP6_ISONES(&np->in_ndstmsk6)) {
+			if ((np->in_stepnext == 2) && (changed == -1) &&
+			    (natl != NULL)) {
+				changed = 2;
+				np->in_stepnext++;
+				IP6_INC(&np->in_dnip6);
+			}
+		}
+
+		if ((flags & IPN_TCPUDPICMP) != 0) {
+			if (np->in_dpnext != 0)
+				frnat.fin_data[1] = np->in_dpnext;
+
+			/*
+			 * Standard port translation.  Select next port.
+			 */
+			if ((flags & IPN_FIXEDDPORT) != 0) {
+				np->in_stepnext = 0;
+			} else if (np->in_stepnext == 3 && changed == -1) {
+				np->in_dpnext++;
+				np->in_stepnext++;
+				changed = 3;
+				if (np->in_dpnext > np->in_dpmax)
+					np->in_dpnext = np->in_dpmin;
+			}
+		} else {
+			if (np->in_stepnext == 3)
+				np->in_stepnext = 0;
+		}
+
+		/* TRACE (frnat) */
+
+		/*
+		 * Here we do a lookup of the connection as seen from
+		 * the outside.  If an IP# pair already exists, try
+		 * again.  So if you have A->B becomes C->B, you can
+		 * also have D->E become C->E but not D->B causing
+		 * another C->B.  Also take protocol and ports into
+		 * account when determining whether a pre-existing
+		 * NAT setup will cause an external conflict where
+		 * this is appropriate.
+		 *
+		 * fin_data[] is swapped around because we are doing a
+		 * lookup of the packet is if it were moving in the opposite
+		 * direction of the one we are working with now.
+		 */
+		if (flags & IPN_TCPUDP) {
+			swap = frnat.fin_data[0];
+			frnat.fin_data[0] = frnat.fin_data[1];
+			frnat.fin_data[1] = swap;
+		}
+		if (fin->fin_out == 1) {
+			natl = ipf_nat6_inlookup(&frnat,
+					    flags & ~(SI_WILDP|NAT_SEARCH),
+					    (u_int)frnat.fin_p,
+					    &frnat.fin_dst6.in6,
+					    &frnat.fin_src6.in6);
+
+		} else {
+			natl = ipf_nat6_outlookup(&frnat,
+					     flags & ~(SI_WILDP|NAT_SEARCH),
+					     (u_int)frnat.fin_p,
+					     &frnat.fin_dst6.in6,
+					     &frnat.fin_src6.in6);
+		}
+		if (flags & IPN_TCPUDP) {
+			swap = frnat.fin_data[0];
+			frnat.fin_data[0] = frnat.fin_data[1];
+			frnat.fin_data[1] = swap;
+		}
+
+		/* TRACE natl, in_stepnext, l */
+
+		if ((natl != NULL) && (l > 8))	/* XXX 8 is arbitrary */
+			return -1;
+
+		np->in_stepnext &= 0x3;
+
+		l++;
+		changed = -1;
+	} while (natl != NULL);
+	nat->nat_osrc6 = fin->fin_src6;
+	nat->nat_odst6 = fin->fin_dst6;
+	nat->nat_nsrc6 = frnat.fin_src6;
+	nat->nat_ndst6 = frnat.fin_dst6;
+
+	if ((flags & IPN_TCPUDP) != 0) {
+		nat->nat_osport = htons(fin->fin_data[0]);
+		nat->nat_odport = htons(fin->fin_data[1]);
+		nat->nat_nsport = htons(frnat.fin_data[0]);
+		nat->nat_ndport = htons(frnat.fin_data[1]);
+	} else if ((flags & IPN_ICMPQUERY) != 0) {
+		nat->nat_oicmpid = fin->fin_data[1];
+		nat->nat_nicmpid = frnat.fin_data[1];
+	}
+
+	return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_nat6_newdivert                                          */
+/* Returns:     int - -1 == error, 0 == success                             */
+/* Parameters:  fin(I) - pointer to packet information                      */
+/*              nat(I) - pointer to NAT entry                               */
+/*              ni(I)  - pointer to structure with misc. information needed */
+/*                       to create new NAT entry.                           */
+/* Write Lock:  ipf_nat                                                     */
+/*                                                                          */
+/* Create a new NAT divert session as defined by the NAT rule.  This is     */
+/* somewhat different to other NAT session creation routines because we     */
+/* do not iterate through either port numbers or IP addresses, searching    */
+/* for a unique mapping, however, a complimentary duplicate check is made.  */
+/* ------------------------------------------------------------------------ */
+int
+ipf_nat6_newdivert(fin, nat, nai)
+	fr_info_t *fin;
+	nat_t *nat;
+	natinfo_t *nai;
+{
+	ipf_main_softc_t *softc = fin->fin_main_soft;
+	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
+	fr_info_t frnat;
+	ipnat_t *np;
+	nat_t *natl;
+	int p;
+
+	np = nai->nai_np;
+	bcopy((char *)fin, (char *)&frnat, sizeof(*fin));
+
+	nat->nat_pr[0] = 0;
+	nat->nat_osrc6 = fin->fin_src6;
+	nat->nat_odst6 = fin->fin_dst6;
+	nat->nat_osport = htons(fin->fin_data[0]);
+	nat->nat_odport = htons(fin->fin_data[1]);
+	frnat.fin_src6 = np->in_snip6;
+	frnat.fin_dst6 = np->in_dnip6;
+
+	if (np->in_redir & NAT_DIVERTUDP) {
+		frnat.fin_data[0] = np->in_spnext;
+		frnat.fin_data[1] = np->in_dpnext;
+		frnat.fin_flx |= FI_TCPUDP;
+		p = IPPROTO_UDP;
+	} else {
+		frnat.fin_flx &= ~FI_TCPUDP;
+		p = IPPROTO_IPIP;
+	}
+
+	if (fin->fin_out == 1) {
+		natl = ipf_nat6_inlookup(&frnat, 0, p, &frnat.fin_dst6.in6,
+					 &frnat.fin_src6.in6);
+
+	} else {
+		natl = ipf_nat6_outlookup(&frnat, 0, p, &frnat.fin_dst6.in6,
+					  &frnat.fin_src6.in6);
+	}
+
+	if (natl != NULL) {
+		NBUMPSIDE6D(fin->fin_out, ns_divert_exist);
+		return -1;
+	}
+
+	nat->nat_nsrc6 = frnat.fin_src6;
+	nat->nat_ndst6 = frnat.fin_dst6;
+	if (np->in_redir & NAT_DIVERTUDP) {
+		nat->nat_nsport = htons(frnat.fin_data[0]);
+		nat->nat_ndport = htons(frnat.fin_data[1]);
+	}
+	nat->nat_pr[fin->fin_out] = fin->fin_p;
+	nat->nat_pr[1 - fin->fin_out] = p;
+
+	if (np->in_redir & NAT_REDIRECT)
+		nat->nat_dir = NAT_DIVERTIN;
+	else
+		nat->nat_dir = NAT_DIVERTOUT;
+
+	return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    nat6_builddivertmp                                          */
+/* Returns:     int - -1 == error, 0 == success                             */
+/* Parameters:  np(I) - pointer to a NAT rule                               */
+/*                                                                          */
+/* For divert rules, a skeleton packet representing what will be prepended  */
+/* to the real packet is created.  Even though we don't have the full       */
+/* packet here, a checksum is calculated that we update later when we       */
+/* fill in the final details.  At present a 0 checksum for UDP is being set */
+/* here because it is expected that divert will be used for localhost.      */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_nat6_builddivertmp(softn, np)
+	ipf_nat_softc_t *softn;
+	ipnat_t *np;
+{
+	udphdr_t *uh;
+	size_t len;
+	ip6_t *ip6;
+
+	if ((np->in_redir & NAT_DIVERTUDP) != 0)
+		len = sizeof(ip6_t) + sizeof(udphdr_t);
+	else
+		len = sizeof(ip6_t);
+
+	ALLOC_MB_T(np->in_divmp, len);
+	if (np->in_divmp == NULL) {
+		ATOMIC_INCL(softn->ipf_nat_stats.ns_divert_build);
+		return -1;
+	}
+
+	/*
+	 * First, the header to get the packet diverted to the new destination
+	 */
+	ip6 = MTOD(np->in_divmp, ip6_t *);
+	ip6->ip6_vfc = 0x60;
+	if ((np->in_redir & NAT_DIVERTUDP) != 0)
+		ip6->ip6_nxt = IPPROTO_UDP;
+	else
+		ip6->ip6_nxt = IPPROTO_IPIP;
+	ip6->ip6_hlim = 255;
+	ip6->ip6_plen = 0;
+	ip6->ip6_src = np->in_snip6.in6;
+	ip6->ip6_dst = np->in_dnip6.in6;
+
+	if (np->in_redir & NAT_DIVERTUDP) {
+		uh = (udphdr_t *)((u_char *)ip6 + sizeof(*ip6));
+		uh->uh_sum = 0;
+		uh->uh_ulen = 8;
+		uh->uh_sport = htons(np->in_spnext);
+		uh->uh_dport = htons(np->in_dpnext);
+	}
+
+	return 0;
+}
+
+
+#define	MINDECAP	(sizeof(ip6_t) + sizeof(udphdr_t) + sizeof(ip6_t))
+
+/* ------------------------------------------------------------------------ */
+/* Function:    nat6_decap                                                  */
+/* Returns:     int - -1 == error, 0 == success                             */
+/* Parameters:  fin(I) - pointer to packet information                      */
+/*              nat(I) - pointer to current NAT session                     */
+/*                                                                          */
+/* This function is responsible for undoing a packet's encapsulation in the */
+/* reverse of an encap/divert rule.  After removing the outer encapsulation */
+/* it is necessary to call ipf_makefrip() again so that the contents of 'fin'*/
+/* match the "new" packet as it may still be used by IPFilter elsewhere.    */
+/* We use "dir" here as the basis for some of the expectations about the    */
+/* outer header.  If we return an error, the goal is to leave the original  */
+/* packet information undisturbed - this falls short at the end where we'd  */
+/* need to back a backup copy of "fin" - expensive.                         */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_nat6_decap(fin, nat)
+	fr_info_t *fin;
+	nat_t *nat;
+{
+	ipf_main_softc_t *softc = fin->fin_main_soft;
+	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
+	char *hdr;
+	int skip;
+	mb_t *m;
+
+	if ((fin->fin_flx & FI_ICMPERR) != 0) {
+		return 0;
+	}
+
+	m = fin->fin_m;
+	skip = fin->fin_hlen;
+
+	switch (nat->nat_dir)
+	{
+	case NAT_DIVERTIN :
+	case NAT_DIVERTOUT :
+		if (fin->fin_plen < MINDECAP)
+			return -1;
+		skip += sizeof(udphdr_t);
+		break;
+
+	case NAT_ENCAPIN :
+	case NAT_ENCAPOUT :
+		if (fin->fin_plen < (skip + sizeof(ip6_t)))
+			return -1;
+		break;
+	default :
+		return -1;
+		/* NOTREACHED */
+	}
+
+	/*
+	 * The aim here is to keep the original packet details in "fin" for
+	 * as long as possible so that returning with an error is for the
+	 * original packet and there is little undoing work to do.
+	 */
+	if (M_LEN(m) < skip + sizeof(ip6_t)) {
+		if (ipf_pr_pullup(fin, skip + sizeof(ip6_t)) == -1)
+			return -1;
+	}
+
+	hdr = MTOD(fin->fin_m, char *);
+	fin->fin_ip6 = (ip6_t *)(hdr + skip);
+
+	if (ipf_pr_pullup(fin, skip + sizeof(ip6_t)) == -1) {
+		NBUMPSIDE6D(fin->fin_out, ns_decap_pullup);
+		return -1;
+	}
+
+	fin->fin_hlen = sizeof(ip6_t);
+	fin->fin_dlen -= skip;
+	fin->fin_plen -= skip;
+	fin->fin_ipoff += skip;
+
+	if (ipf_makefrip(sizeof(ip6_t), (ip_t *)hdr, fin) == -1) {
+		NBUMPSIDE6D(fin->fin_out, ns_decap_bad);
+		return -1;
+	}
+
+	return skip;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    nat6_nextaddr                                               */
+/* Returns:     int - -1 == bad input (no new address),                     */
+/*                     0 == success and dst has new address                 */
+/* Parameters:  fin(I) - pointer to packet information                      */
+/*              na(I)  - how to generate new address                        */
+/*              old(I) - original address being replaced                    */
+/*              dst(O) - where to put the new address                       */
+/* Write Lock:  ipf_nat                                                     */
+/*                                                                          */
+/* This function uses the contents of the "na" structure, in combination    */
+/* with "old" to produce a new address to store in "dst".  Not all of the   */
+/* possible uses of "na" will result in a new address.                      */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_nat6_nextaddr(fin, na, old, dst)
+	fr_info_t *fin;
+	nat_addr_t *na;
+	i6addr_t *old, *dst;
+{
+	ipf_main_softc_t *softc = fin->fin_main_soft;
+	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
+	i6addr_t newip, new;
+	u_32_t amin, amax;
+	int error;
+
+	new.i6[0] = 0;
+	new.i6[1] = 0;
+	new.i6[2] = 0;
+	new.i6[3] = 0;
+	amin = na->na_addr[0].in4.s_addr;
+
+	switch (na->na_atype)
+	{
+	case FRI_RANGE :
+		amax = na->na_addr[1].in4.s_addr;
+		break;
+
+	case FRI_NETMASKED :
+	case FRI_DYNAMIC :
+	case FRI_NORMAL :
+		/*
+		 * Compute the maximum address by adding the inverse of the
+		 * netmask to the minimum address.
+		 */
+		amax = ~na->na_addr[1].in4.s_addr;
+		amax |= amin;
+		break;
+
+	case FRI_LOOKUP :
+		break;
+
+	case FRI_BROADCAST :
+	case FRI_PEERADDR :
+	case FRI_NETWORK :
+	default :
+		return -1;
+	}
+
+	error = -1;
+	switch (na->na_function)
+	{
+	case IPLT_DSTLIST :
+		error = ipf_dstlist_select_node(fin, na->na_ptr, dst->i6,
+						NULL);
+		break;
+
+	case IPLT_NONE :
+		/*
+		 * 0/0 as the new address means leave it alone.
+		 */
+		if (na->na_addr[0].in4.s_addr == 0 &&
+		    na->na_addr[1].in4.s_addr == 0) {
+			new = *old;
+
+		/*
+		 * 0/32 means get the interface's address
+		 */
+		} else if (IP6_ISZERO(&na->na_addr[0].in6) &&
+			   IP6_ISONES(&na->na_addr[1].in6)) {
+			if (ipf_ifpaddr(softc, 6, na->na_atype,
+				       fin->fin_ifp, &newip, NULL) == -1) {
+				NBUMPSIDE6(fin->fin_out, ns_ifpaddrfail);
+				return -1;
+			}
+			new = newip;
+		} else {
+			new.in6 = na->na_nextip6;
+		}
+		*dst = new;
+		error = 0;
+		break;
+
+	default :
+		NBUMPSIDE6(fin->fin_out, ns_badnextaddr);
+		break;
+	}
+
+	return error;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_nat6_nextaddrinit                                       */
+/* Returns:     int - 0 == success, else error number                       */
+/* Parameters:  na(I)      - NAT address information for generating new addr*/
+/*              base(I)    - start of where to find strings                 */
+/*              initial(I) - flag indicating if it is the first call for    */
+/*                           this "na" structure.                           */
+/*              ifp(I)     - network interface to derive address            */
+/*                           information from.                              */
+/*                                                                          */
+/* This function is expected to be called in two scenarious: when a new NAT */
+/* rule is loaded into the kernel and when the list of NAT rules is sync'd  */
+/* up with the valid network interfaces (possibly due to them changing.)    */
+/* To distinguish between these, the "initial" parameter is used.  If it is */
+/* 1 then this indicates the rule has just been reloaded and 0 for when we  */
+/* are updating information.  This difference is important because in       */
+/* instances where we are not updating address information associated with  */
+/* a network interface, we don't want to disturb what the "next" address to */
+/* come out of ipf_nat6_nextaddr() will be.                                 */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_nat6_nextaddrinit(softc, base, na, initial, ifp)
+	ipf_main_softc_t *softc;
+	char *base;
+	nat_addr_t *na;
+	int initial;
+	void *ifp;
+{
+	switch (na->na_atype)
+	{
+	case FRI_LOOKUP :
+		if (na->na_subtype == 0) {
+			na->na_ptr = ipf_lookup_res_num(softc, IPL_LOGNAT,
+							na->na_type,
+							na->na_num,
+							&na->na_func);
+		} else if (na->na_subtype == 1) {
+			na->na_ptr = ipf_lookup_res_name(softc, IPL_LOGNAT,
+							 na->na_type,
+							 base + na->na_num,
+							 &na->na_func);
+		}
+		if (na->na_func == NULL) {
+			IPFERROR(60072);
+			return ESRCH;
+		}
+		if (na->na_ptr == NULL) {
+			IPFERROR(60073);
+			return ESRCH;
+		}
+		break;
+	case FRI_DYNAMIC :
+	case FRI_BROADCAST :
+	case FRI_NETWORK :
+	case FRI_NETMASKED :
+	case FRI_PEERADDR :
+		if (ifp != NULL)
+			(void )ipf_ifpaddr(softc, 6, na->na_atype, ifp,
+					   &na->na_addr[0],
+					   &na->na_addr[1]);
+		break;
+
+	case FRI_SPLIT :
+	case FRI_RANGE :
+		if (initial)
+			na->na_nextip6 = na->na_addr[0].in6;
+		break;
+
+	case FRI_NONE :
+		IP6_ANDASSIGN(&na->na_addr[0].in6, &na->na_addr[1].in6);
+		return 0;
+
+	case FRI_NORMAL :
+		IP6_ANDASSIGN(&na->na_addr[0].in6, &na->na_addr[1].in6);
+		break;
+
+	default :
+		IPFERROR(60074);
+		return EINVAL;
+	}
+
+	if (initial && (na->na_atype == FRI_NORMAL)) {
+		if (IP6_ISZERO(&na->na_addr[0].in6)) {
+			if (IP6_ISONES(&na->na_addr[1].in6) ||
+			    IP6_ISZERO(&na->na_addr[1].in6)) {
+				return 0;
+			}
+		}
+
+		na->na_nextip6 = na->na_addr[0].in6;
+		if (!IP6_ISONES(&na->na_addr[1].in6)) {
+			IP6_INC(&na->na_nextip6);
+		}
+	}
+
+	return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_nat6_icmpquerytype                                      */
+/* Returns:     int - 1 == success, 0 == failure                            */
+/* Parameters:  icmptype(I) - ICMP type number                              */
+/*                                                                          */
+/* Tests to see if the ICMP type number passed is a query/response type or  */
+/* not.                                                                     */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_nat6_icmpquerytype(icmptype)
+	int icmptype;
+{
+
+	/*
+	 * For the ICMP query NAT code, it is essential that both the query
+	 * and the reply match on the NAT rule. Because the NAT structure
+	 * does not keep track of the icmptype, and a single NAT structure
+	 * is used for all icmp types with the same src, dest and id, we
+	 * simply define the replies as queries as well. The funny thing is,
+	 * altough it seems silly to call a reply a query, this is exactly
+	 * as it is defined in the IPv4 specification
+	 */
+
+	switch (icmptype)
+	{
+
+	case ICMP6_ECHO_REPLY:
+	case ICMP6_ECHO_REQUEST:
+	/* route aedvertisement/solliciation is currently unsupported: */
+	/* it would require rewriting the ICMP data section            */
+	case ICMP6_MEMBERSHIP_QUERY:
+	case ICMP6_MEMBERSHIP_REPORT:
+	case ICMP6_MEMBERSHIP_REDUCTION:
+	case ICMP6_WRUREQUEST:
+	case ICMP6_WRUREPLY:
+	case MLD6_MTRACE_RESP:
+	case MLD6_MTRACE:
+		return 1;
+	default:
+		return 0;
+	}
+}
+#endif /* USE_INET6 */


Property changes on: trunk/sys/contrib/ipfilter/netinet/ip_nat6.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Modified: trunk/sys/contrib/ipfilter/netinet/ip_netbios_pxy.c
===================================================================
--- trunk/sys/contrib/ipfilter/netinet/ip_netbios_pxy.c	2018-05-28 18:55:30 UTC (rev 10138)
+++ trunk/sys/contrib/ipfilter/netinet/ip_netbios_pxy.c	2018-05-28 18:56:30 UTC (rev 10139)
@@ -1,7 +1,8 @@
+/* $MidnightBSD$ */
 /*
  * Simple netbios-dgm transparent proxy for in-kernel use.
  * For use with the NAT code.
- * $Id: ip_netbios_pxy.c,v 1.2 2008-09-19 02:15:13 laffer1 Exp $
+ * $Id$
  */
 
 /*-
@@ -29,14 +30,14 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: ip_netbios_pxy.c,v 1.2 2008-09-19 02:15:13 laffer1 Exp $
+ * $Id$
  */
 
 #define	IPF_NETBIOS_PROXY
 
-int ippr_netbios_init __P((void));
-void ippr_netbios_fini __P((void));
-int ippr_netbios_out __P((fr_info_t *, ap_session_t *, nat_t *));
+void ipf_p_netbios_main_load __P((void));
+void ipf_p_netbios_main_unload __P((void));
+int ipf_p_netbios_out __P((void *, fr_info_t *, ap_session_t *, nat_t *));
 
 static	frentry_t	netbiosfr;
 
@@ -45,7 +46,8 @@
 /*
  * Initialize local structures.
  */
-int ippr_netbios_init()
+void
+ipf_p_netbios_main_load()
 {
 	bzero((char *)&netbiosfr, sizeof(netbiosfr));
 	netbiosfr.fr_ref = 1;
@@ -52,12 +54,11 @@
 	netbiosfr.fr_flags = FR_INQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE;
 	MUTEX_INIT(&netbiosfr.fr_lock, "NETBIOS proxy rule lock");
 	netbios_proxy_init = 1;
-
-	return 0;
 }
 
 
-void ippr_netbios_fini()
+void
+ipf_p_netbios_main_unload()
 {
 	if (netbios_proxy_init == 1) {
 		MUTEX_DESTROY(&netbiosfr.fr_lock);
@@ -66,10 +67,12 @@
 }
 
 
-int ippr_netbios_out(fin, aps, nat)
-fr_info_t *fin;
-ap_session_t *aps;
-nat_t *nat;
+int
+ipf_p_netbios_out(arg, fin, aps, nat)
+	void *arg;
+	fr_info_t *fin;
+	ap_session_t *aps;
+	nat_t *nat;
 {
 	char dgmbuf[6];
 	int off, dlen;

Modified: trunk/sys/contrib/ipfilter/netinet/ip_pool.c
===================================================================
--- trunk/sys/contrib/ipfilter/netinet/ip_pool.c	2018-05-28 18:55:30 UTC (rev 10138)
+++ trunk/sys/contrib/ipfilter/netinet/ip_pool.c	2018-05-28 18:56:30 UTC (rev 10139)
@@ -1,5 +1,6 @@
+/* $MidnightBSD$ */
 /*
- * Copyright (C) 1993-2001, 2003 by Darren Reed.
+ * Copyright (C) 2012 by Darren Reed.
  *
  * See the IPFILTER.LICENCE file for details on licencing.
  */
@@ -33,15 +34,10 @@
 # endif
 #endif
 #include <sys/time.h>
-#if !defined(linux)
-# include <sys/protosw.h>
-#endif
-#include <sys/socket.h>
-#if defined(_KERNEL) && (!defined(__SVR4) && !defined(__svr4__))
+#if defined(_KERNEL) && !defined(SOLARIS2)
 # include <sys/mbuf.h>
 #endif
 #if defined(__SVR4) || defined(__svr4__)
-# include <sys/filio.h>
 # include <sys/byteorder.h>
 # ifdef _KERNEL
 #  include <sys/dditypes.h>
@@ -53,71 +49,93 @@
 # include <sys/malloc.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
+#include <sys/socket.h>
 #include <net/if.h>
 #include <netinet/in.h>
+#if !defined(_KERNEL)
+# include "ipf.h"
+#endif
 
 #include "netinet/ip_compat.h"
 #include "netinet/ip_fil.h"
 #include "netinet/ip_pool.h"
+#include "netinet/radix_ipf.h"
 
-#if defined(IPFILTER_LOOKUP) && defined(_KERNEL) && \
-      ((BSD >= 198911) && !defined(__osf__) && \
-      !defined(__hpux) && !defined(__sgi))
-static int rn_freenode __P((struct radix_node *, void *));
-#endif
-
 /* END OF INCLUDES */
 
 #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 1.4 2013-01-08 01:31:40 laffer1 Exp $";
+static const char rcsid[] = "@(#)$Id$";
 #endif
 
-#ifdef IPFILTER_LOOKUP
+typedef struct ipf_pool_softc_s {
+	void		*ipf_radix;
+	ip_pool_t	*ipf_pool_list[LOOKUP_POOL_SZ];
+	ipf_pool_stat_t	ipf_pool_stats;
+	ip_pool_node_t	*ipf_node_explist;
+} ipf_pool_softc_t;
 
-# 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)	;
-#  define RADIX_NODE_HEAD_UNLOCK(x)	;
-# endif
 
-static void ip_pool_clearnodes __P((ip_pool_t *));
-static void *ip_pool_exists __P((int, char *));
+static void ipf_pool_clearnodes __P((ipf_main_softc_t *, ipf_pool_softc_t *,
+				     ip_pool_t *));
+static int ipf_pool_create __P((ipf_main_softc_t *, ipf_pool_softc_t *, iplookupop_t *));
+static int ipf_pool_deref __P((ipf_main_softc_t *, void *, void *));
+static int ipf_pool_destroy __P((ipf_main_softc_t *, ipf_pool_softc_t *, int, char *));
+static void *ipf_pool_exists __P((ipf_pool_softc_t *, int, char *));
+static void *ipf_pool_find __P((void *, int, char *));
+static ip_pool_node_t *ipf_pool_findeq __P((ipf_pool_softc_t *, ip_pool_t *,
+					    addrfamily_t *, addrfamily_t *));
+static void ipf_pool_free __P((ipf_main_softc_t *, ipf_pool_softc_t *,
+			       ip_pool_t *));
+static int ipf_pool_insert_node __P((ipf_main_softc_t *, ipf_pool_softc_t *,
+				     ip_pool_t *, struct ip_pool_node *));
+static int ipf_pool_iter_deref __P((ipf_main_softc_t *, void *, int, int, void *));
+static int ipf_pool_iter_next __P((ipf_main_softc_t *,  void *, ipftoken_t *,
+				   ipflookupiter_t *));
+static size_t ipf_pool_flush __P((ipf_main_softc_t *, void *, iplookupflush_t *));
+static int ipf_pool_node_add __P((ipf_main_softc_t *, void *, iplookupop_t *,
+				  int));
+static int ipf_pool_node_del __P((ipf_main_softc_t *, void *, iplookupop_t *,
+				  int));
+static void ipf_pool_node_deref __P((ipf_pool_softc_t *, ip_pool_node_t *));
+static int ipf_pool_remove_node __P((ipf_main_softc_t *, ipf_pool_softc_t *,
+				     ip_pool_t *, ip_pool_node_t *));
+static int ipf_pool_search __P((ipf_main_softc_t *, void *, int,
+				void *, u_int));
+static void *ipf_pool_soft_create __P((ipf_main_softc_t *));
+static void ipf_pool_soft_destroy __P((ipf_main_softc_t *, void *));
+static void ipf_pool_soft_fini __P((ipf_main_softc_t *, void *));
+static int ipf_pool_soft_init __P((ipf_main_softc_t *, void *));
+static int ipf_pool_stats_get __P((ipf_main_softc_t *, void *, iplookupop_t *));
+static int ipf_pool_table_add __P((ipf_main_softc_t *, void *, iplookupop_t *));
+static int ipf_pool_table_del __P((ipf_main_softc_t *, void *, iplookupop_t *));
+static void *ipf_pool_select_add_ref __P((void *, int, char *));
+static void ipf_pool_expire __P((ipf_main_softc_t *, void *));
 
-ip_pool_stat_t ipoolstat;
-ipfrwlock_t ip_poolrw;
+ipf_lookup_t ipf_pool_backend = {
+	IPLT_POOL,
+	ipf_pool_soft_create,
+	ipf_pool_soft_destroy,
+	ipf_pool_soft_init,
+	ipf_pool_soft_fini,
+	ipf_pool_search,
+	ipf_pool_flush,
+	ipf_pool_iter_deref,
+	ipf_pool_iter_next,
+	ipf_pool_node_add,
+	ipf_pool_node_del,
+	ipf_pool_stats_get,
+	ipf_pool_table_add,
+	ipf_pool_table_del,
+	ipf_pool_deref,
+	ipf_pool_find,
+	ipf_pool_select_add_ref,
+	NULL,
+	ipf_pool_expire,
+	NULL
+};
 
-/*
- * Binary tree routines from Sedgewick and enhanced to do ranges of addresses.
- * NOTE: Insertion *MUST* be from greatest range to least for it to work!
- * These should be replaced, eventually, by something else - most notably a
- * interval searching method.  The important feature is to be able to find
- * the best match.
- *
- * So why not use a radix tree for this?  As the first line implies, it
- * has been written to work with a _range_ of addresses.  A range is not
- * necessarily a match with any given netmask so what we end up dealing
- * with is an interval tree.  Implementations of these are hard to find
- * and the one herein is far from bug free.
- *
- * Sigh, in the end I became convinced that the bugs the code contained did
- * not make it worthwhile not using radix trees.  For now the radix tree from
- * 4.4 BSD is used, but this is not viewed as a long term solution.
- */
-ip_pool_t *ip_pool_list[IPL_LOGSIZE] = { NULL, NULL, NULL, NULL,
-					 NULL, NULL, NULL, NULL };
 
-
 #ifdef TEST_POOL
 void treeprint __P((ip_pool_t *));
 
@@ -126,96 +144,98 @@
 	int argc;
 	char *argv[];
 {
+	ip_pool_node_t node;
 	addrfamily_t a, b;
 	iplookupop_t op;
 	ip_pool_t *ipo;
 	i6addr_t ip;
 
-	RWLOCK_INIT(&ip_poolrw, "poolrw");
-	ip_pool_init();
+	RWLOCK_INIT(softc->ipf_poolrw, "poolrw");
+	ipf_pool_init();
 
-	bzero((char *)&a, sizeof(a));
-	bzero((char *)&b, sizeof(b));
 	bzero((char *)&ip, sizeof(ip));
 	bzero((char *)&op, sizeof(op));
+	bzero((char *)&node, sizeof(node));
 	strcpy(op.iplo_name, "0");
 
-	if (ip_pool_create(&op) == 0)
-		ipo = ip_pool_exists(0, "0");
+	if (ipf_pool_create(&op) == 0)
+		ipo = ipf_pool_exists(0, "0");
 
-	a.adf_addr.in4.s_addr = 0x0a010203;
-	b.adf_addr.in4.s_addr = 0xffffffff;
-	ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
-	ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
+	node.ipn_addr.adf_family = AF_INET;
 
-	a.adf_addr.in4.s_addr = 0x0a000000;
-	b.adf_addr.in4.s_addr = 0xff000000;
-	ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 0);
-	ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 0);
+	node.ipn_addr.adf_addr.in4.s_addr = 0x0a010203;
+	node.ipn_mask.adf_addr.in4.s_addr = 0xffffffff;
+	node.ipn_info = 1;
+	ipf_pool_insert_node(ipo, &node);
 
-	a.adf_addr.in4.s_addr = 0x0a010100;
-	b.adf_addr.in4.s_addr = 0xffffff00;
-	ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
-	ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
+	node.ipn_addr.adf_addr.in4.s_addr = 0x0a000000;
+	node.ipn_mask.adf_addr.in4.s_addr = 0xff000000;
+	node.ipn_info = 0;
+	ipf_pool_insert_node(ipo, &node);
 
-	a.adf_addr.in4.s_addr = 0x0a010200;
-	b.adf_addr.in4.s_addr = 0xffffff00;
-	ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 0);
-	ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 0);
+	node.ipn_addr.adf_addr.in4.s_addr = 0x0a010100;
+	node.ipn_mask.adf_addr.in4.s_addr = 0xffffff00;
+	node.ipn_info = 1;
+	ipf_pool_insert_node(ipo, &node);
 
-	a.adf_addr.in4.s_addr = 0x0a010000;
-	b.adf_addr.in4.s_addr = 0xffff0000;
-	ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
-	ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
+	node.ipn_addr.adf_addr.in4.s_addr = 0x0a010200;
+	node.ipn_mask.adf_addr.in4.s_addr = 0xffffff00;
+	node.ipn_info = 0;
+	ipf_pool_insert_node(ipo, &node);
 
-	a.adf_addr.in4.s_addr = 0x0a01020f;
-	b.adf_addr.in4.s_addr = 0xffffffff;
-	ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
-	ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
+	node.ipn_addr.adf_addr.in4.s_addr = 0x0a010000;
+	node.ipn_mask.adf_addr.in4.s_addr = 0xffff0000;
+	node.ipn_info = 1;
+	ipf_pool_insert_node(ipo, &node);
+
+	node.ipn_addr.adf_addr.in4.s_addr = 0x0a01020f;
+	node.ipn_mask.adf_addr.in4.s_addr = 0xffffffff;
+	node.ipn_info = 1;
+	ipf_pool_insert_node(ipo, &node);
 #ifdef	DEBUG_POOL
-treeprint(ipo);
+	treeprint(ipo);
 #endif
 	ip.in4.s_addr = 0x0a00aabb;
 	printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
-		ip_pool_search(ipo, 4, &ip));
+		ipf_pool_search(ipo, 4, &ip, 1));
 
 	ip.in4.s_addr = 0x0a000001;
 	printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
-		ip_pool_search(ipo, 4, &ip));
+		ipf_pool_search(ipo, 4, &ip, 1));
 
 	ip.in4.s_addr = 0x0a000101;
 	printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
-		ip_pool_search(ipo, 4, &ip));
+		ipf_pool_search(ipo, 4, &ip, 1));
 
 	ip.in4.s_addr = 0x0a010001;
 	printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
-		ip_pool_search(ipo, 4, &ip));
+		ipf_pool_search(ipo, 4, &ip, 1));
 
 	ip.in4.s_addr = 0x0a010101;
 	printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
-		ip_pool_search(ipo, 4, &ip));
+		ipf_pool_search(ipo, 4, &ip, 1));
 
 	ip.in4.s_addr = 0x0a010201;
 	printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
-		ip_pool_search(ipo, 4, &ip));
+		ipf_pool_search(ipo, 4, &ip, 1));
 
 	ip.in4.s_addr = 0x0a010203;
 	printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
-		ip_pool_search(ipo, 4, &ip));
+		ipf_pool_search(ipo, 4, &ip, 1));
 
 	ip.in4.s_addr = 0x0a01020f;
 	printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
-		ip_pool_search(ipo, 4, &ip));
+		ipf_pool_search(ipo, 4, &ip, 1));
 
 	ip.in4.s_addr = 0x0b00aabb;
 	printf("search(%#x) = %d (-1)\n", ip.in4.s_addr,
-		ip_pool_search(ipo, 4, &ip));
+		ipf_pool_search(ipo, 4, &ip, 1));
 
 #ifdef	DEBUG_POOL
-treeprint(ipo);
+	treeprint(ipo);
 #endif
 
-	ip_pool_fini();
+	ipf_pool_fini();
 
 	return 0;
 }
@@ -223,7 +243,7 @@
 
 void
 treeprint(ipo)
-ip_pool_t *ipo;
+	ip_pool_t *ipo;
 {
 	ip_pool_node_t *c;
 
@@ -237,123 +257,445 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    ip_pool_init                                                */
+/* Function:    ipf_pool_soft_create                                        */
+/* Returns:     void *   - NULL = failure, else pointer to local context    */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*                                                                          */
+/* Initialise the routing table data structures where required.             */
+/* ------------------------------------------------------------------------ */
+static void *
+ipf_pool_soft_create(softc)
+	ipf_main_softc_t *softc;
+{
+	ipf_pool_softc_t *softp;
+
+	KMALLOC(softp, ipf_pool_softc_t *);
+	if (softp == NULL) {
+		IPFERROR(70032);
+		return NULL;
+	}
+
+	bzero((char *)softp, sizeof(*softp));
+
+	softp->ipf_radix = ipf_rx_create();
+	if (softp->ipf_radix == NULL) {
+		IPFERROR(70033);
+		KFREE(softp);
+		return NULL;
+	}
+
+	return softp;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_pool_soft_init                                          */
 /* Returns:     int     - 0 = success, else error                           */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              arg(I)   - pointer to local context to use                  */
 /*                                                                          */
 /* Initialise the routing table data structures where required.             */
 /* ------------------------------------------------------------------------ */
-int ip_pool_init()
+static int
+ipf_pool_soft_init(softc, arg)
+	ipf_main_softc_t *softc;
+	void *arg;
 {
+	ipf_pool_softc_t *softp = arg;
 
-	bzero((char *)&ipoolstat, sizeof(ipoolstat));
+	ipf_rx_init(softp->ipf_radix);
 
-#if (!defined(_KERNEL) || (BSD < 199306))
-	rn_init();
-#endif
 	return 0;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    ip_pool_fini                                                */
-/* Returns:     int     - 0 = success, else error                           */
+/* Function:    ipf_pool_soft_fini                                          */
+/* Returns:     Nil                                                         */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              arg(I)   - pointer to local context to use                  */
 /* Locks:       WRITE(ipf_global)                                           */
 /*                                                                          */
 /* Clean up all the pool data structures allocated and call the cleanup     */
-/* function for the radix tree that supports the pools. ip_pool_destroy() is*/
+/* function for the radix tree that supports the pools. ipf_pool_destroy is */
 /* used to delete the pools one by one to ensure they're properly freed up. */
 /* ------------------------------------------------------------------------ */
-void ip_pool_fini()
+static void
+ipf_pool_soft_fini(softc, arg)
+	ipf_main_softc_t *softc;
+	void *arg;
 {
+	ipf_pool_softc_t *softp = arg;
 	ip_pool_t *p, *q;
 	int i;
 
-	for (i = 0; i <= IPL_LOGMAX; i++) {
-		for (q = ip_pool_list[i]; (p = q) != NULL; ) {
+	softc = arg;
+
+	for (i = -1; i <= IPL_LOGMAX; i++) {
+		for (q = softp->ipf_pool_list[i + 1]; (p = q) != NULL; ) {
 			q = p->ipo_next;
-			(void) ip_pool_destroy(i, p->ipo_name);
+			(void) ipf_pool_destroy(softc, arg, i, p->ipo_name);
 		}
 	}
+}
 
-#if (!defined(_KERNEL) || (BSD < 199306))
-	rn_fini();
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_pool_soft_destroy                                       */
+/* Returns:     Nil                                                         */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              arg(I)   - pointer to local context to use                  */
+/*                                                                          */
+/* Clean up the pool by free'ing the radix tree associated with it and free */
+/* up the pool context too.                                                 */
+/* ------------------------------------------------------------------------ */
+static void
+ipf_pool_soft_destroy(softc, arg)
+	ipf_main_softc_t *softc;
+	void *arg;
+{
+	ipf_pool_softc_t *softp = arg;
+
+	ipf_rx_destroy(softp->ipf_radix);
+
+	KFREE(softp);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:   ipf_pool_node_add                                            */
+/* Returns:    int - 0 = success, else error                                */
+/* Parameters: softc(I) - pointer to soft context main structure            */
+/*             arg(I)   - pointer to local context to use                   */
+/*             op(I) - pointer to lookup operatin data                      */
+/*                                                                          */
+/* When adding a new node, a check is made to ensure that the address/mask  */
+/* pair supplied has been appropriately prepared by applying the mask to    */
+/* the address prior to calling for the pair to be added.                   */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_pool_node_add(softc, arg, op, uid)
+	ipf_main_softc_t *softc;
+	void *arg;
+	iplookupop_t *op;
+	int uid;
+{
+	ip_pool_node_t node, *m;
+	ip_pool_t *p;
+	int err;
+
+	if (op->iplo_size != sizeof(node)) {
+		IPFERROR(70014);
+		return EINVAL;
+	}
+
+	err = COPYIN(op->iplo_struct, &node, sizeof(node));
+	if (err != 0) {
+		IPFERROR(70015);
+		return EFAULT;
+	}
+
+	p = ipf_pool_find(arg, op->iplo_unit, op->iplo_name);
+	if (p == NULL) {
+		IPFERROR(70017);
+		return ESRCH;
+	}
+
+	if (node.ipn_addr.adf_family == AF_INET) {
+		if (node.ipn_addr.adf_len != offsetof(addrfamily_t, adf_addr) +
+					     sizeof(struct in_addr)) {
+			IPFERROR(70028);
+			return EINVAL;
+		}
+	}
+#ifdef USE_INET6
+	else if (node.ipn_addr.adf_family == AF_INET6) {
+		if (node.ipn_addr.adf_len != offsetof(addrfamily_t, adf_addr) +
+					     sizeof(struct in6_addr)) {
+			IPFERROR(70034);
+			return EINVAL;
+		}
+	}
 #endif
+	if (node.ipn_mask.adf_len != node.ipn_addr.adf_len) {
+		IPFERROR(70029);
+		return EINVAL;
+	}
+
+	/*
+	 * Check that the address/mask pair works.
+	 */
+	if (node.ipn_addr.adf_family == AF_INET) {
+		if ((node.ipn_addr.adf_addr.in4.s_addr &
+		     node.ipn_mask.adf_addr.in4.s_addr) !=
+		    node.ipn_addr.adf_addr.in4.s_addr) {
+			IPFERROR(70035);
+			return EINVAL;
+		}
+	}
+#ifdef USE_INET6
+	else if (node.ipn_addr.adf_family == AF_INET6) {
+		if (IP6_MASKNEQ(&node.ipn_addr.adf_addr.in6,
+				&node.ipn_mask.adf_addr.in6,
+				&node.ipn_addr.adf_addr.in6)) {
+			IPFERROR(70036);
+			return EINVAL;
+		}
+	}
+#endif
+
+	/*
+	 * add an entry to a pool - return an error if it already
+	 * exists remove an entry from a pool - if it exists
+	 * - in both cases, the pool *must* exist!
+	 */
+	m = ipf_pool_findeq(arg, p, &node.ipn_addr, &node.ipn_mask);
+	if (m != NULL) {
+		IPFERROR(70018);
+		return EEXIST;
+	}
+	err = ipf_pool_insert_node(softc, arg, p, &node);
+
+	return err;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    ip_pool_statistics                                          */
-/* Returns:     int     - 0 = success, else error                           */
-/* Parameters:  op(I)   - pointer to lookup operation arguments             */
+/* Function:   ipf_pool_node_del                                            */
+/* Returns:    int - 0 = success, else error                                */
+/* Parameters: softc(I) - pointer to soft context main structure            */
+/*             arg(I)   - pointer to local context to use                   */
+/*             op(I)    - pointer to lookup operatin data                   */
 /*                                                                          */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_pool_node_del(softc, arg, op, uid)
+	ipf_main_softc_t *softc;
+	void *arg;
+	iplookupop_t *op;
+	int uid;
+{
+	ip_pool_node_t node, *m;
+	ip_pool_t *p;
+	int err;
+
+
+	if (op->iplo_size != sizeof(node)) {
+		IPFERROR(70019);
+		return EINVAL;
+	}
+	node.ipn_uid = uid;
+
+	err = COPYIN(op->iplo_struct, &node, sizeof(node));
+	if (err != 0) {
+		IPFERROR(70020);
+		return EFAULT;
+	}
+
+	if (node.ipn_addr.adf_family == AF_INET) {
+		if (node.ipn_addr.adf_len != offsetof(addrfamily_t, adf_addr) +
+					     sizeof(struct in_addr)) {
+			IPFERROR(70030);
+			return EINVAL;
+		}
+	}
+#ifdef USE_INET6
+	else if (node.ipn_addr.adf_family == AF_INET6) {
+		if (node.ipn_addr.adf_len != offsetof(addrfamily_t, adf_addr) +
+					     sizeof(struct in6_addr)) {
+			IPFERROR(70037);
+			return EINVAL;
+		}
+	}
+#endif
+	if (node.ipn_mask.adf_len != node.ipn_addr.adf_len) {
+		IPFERROR(70031);
+		return EINVAL;
+	}
+
+	p = ipf_pool_find(arg, op->iplo_unit, op->iplo_name);
+	if (p == NULL) {
+		IPFERROR(70021);
+		return ESRCH;
+	}
+
+	m = ipf_pool_findeq(arg, p, &node.ipn_addr, &node.ipn_mask);
+	if (m == NULL) {
+		IPFERROR(70022);
+		return ENOENT;
+	}
+
+	if ((uid != 0) && (uid != m->ipn_uid)) {
+		IPFERROR(70024);
+		return EACCES;
+	}
+
+	err = ipf_pool_remove_node(softc, arg, p, m);
+
+	return err;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:   ipf_pool_table_add                                           */
+/* Returns:    int - 0 = success, else error                                */
+/* Parameters: softc(I) - pointer to soft context main structure            */
+/*             arg(I)   - pointer to local context to use                   */
+/*             op(I)    - pointer to lookup operatin data                   */
+/*                                                                          */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_pool_table_add(softc, arg, op)
+	ipf_main_softc_t *softc;
+	void *arg;
+	iplookupop_t *op;
+{
+	int err;
+
+	if (((op->iplo_arg & LOOKUP_ANON) == 0) &&
+	    (ipf_pool_find(arg, op->iplo_unit, op->iplo_name) != NULL)) {
+		IPFERROR(70023);
+		err = EEXIST;
+	} else {
+		err = ipf_pool_create(softc, arg, op);
+	}
+
+	return err;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:   ipf_pool_table_del                                           */
+/* Returns:    int - 0 = success, else error                                */
+/* Parameters: softc(I) - pointer to soft context main structure            */
+/*             arg(I)   - pointer to local context to use                   */
+/*             op(I)    - pointer to lookup operatin data                   */
+/*                                                                          */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_pool_table_del(softc, arg, op)
+	ipf_main_softc_t *softc;
+	void *arg;
+	iplookupop_t *op;
+{
+	return ipf_pool_destroy(softc, arg, op->iplo_unit, op->iplo_name);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_pool_statistics                                         */
+/* Returns:     int      - 0 = success, else error                          */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              arg(I)   - pointer to local context to use                  */
+/*              op(I)    - pointer to lookup operatin data                  */
+/*                                                                          */
 /* Copy the current statistics out into user space, collecting pool list    */
 /* pointers as appropriate for later use.                                   */
 /* ------------------------------------------------------------------------ */
-int ip_pool_statistics(op)
-iplookupop_t *op;
+static int
+ipf_pool_stats_get(softc, arg, op)
+	ipf_main_softc_t *softc;
+	void *arg;
+	iplookupop_t *op;
 {
-	ip_pool_stat_t stats;
+	ipf_pool_softc_t *softp = arg;
+	ipf_pool_stat_t stats;
 	int unit, i, err = 0;
 
-	if (op->iplo_size != sizeof(ipoolstat))
+	if (op->iplo_size != sizeof(ipf_pool_stat_t)) {
+		IPFERROR(70001);
 		return EINVAL;
+	}
 
-	bcopy((char *)&ipoolstat, (char *)&stats, sizeof(stats));
+	bcopy((char *)&softp->ipf_pool_stats, (char *)&stats, sizeof(stats));
 	unit = op->iplo_unit;
 	if (unit == IPL_LOGALL) {
-		for (i = 0; i < IPL_LOGSIZE; i++)
-			stats.ipls_list[i] = ip_pool_list[i];
-	} else if (unit >= 0 && unit < IPL_LOGSIZE) {
+		for (i = 0; i <= LOOKUP_POOL_MAX; i++)
+			stats.ipls_list[i] = softp->ipf_pool_list[i];
+	} else if (unit >= 0 && unit <= IPL_LOGMAX) {
+		unit++;						/* -1 => 0 */
 		if (op->iplo_name[0] != '\0')
-			stats.ipls_list[unit] = ip_pool_exists(unit,
-							       op->iplo_name);
+			stats.ipls_list[unit] = ipf_pool_exists(softp, unit - 1,
+								op->iplo_name);
 		else
-			stats.ipls_list[unit] = ip_pool_list[unit];
-	} else
+			stats.ipls_list[unit] = softp->ipf_pool_list[unit];
+	} else {
+		IPFERROR(70025);
 		err = EINVAL;
-	if (err == 0)
+	}
+	if (err == 0) {
 		err = COPYOUT(&stats, op->iplo_struct, sizeof(stats));
-	return err;
+		if (err != 0) {
+			IPFERROR(70026);
+			return EFAULT;
+		}
+	}
+	return 0;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    ip_pool_exists                                              */
-/* Returns:     int     - 0 = success, else error                           */
-/* Parameters:  ipo(I)  - pointer to the pool getting the new node.         */
+/* Function:    ipf_pool_exists                                             */
+/* Returns:     int      - 0 = success, else error                          */
+/* Parameters:  softp(I) - pointer to soft context pool information         */
+/*              unit(I)  - ipfilter device to which we are working on       */
+/*              name(I)  - name of the pool                                 */
 /*                                                                          */
 /* Find a matching pool inside the collection of pools for a particular     */
 /* device, indicated by the unit number.                                    */
 /* ------------------------------------------------------------------------ */
-static void *ip_pool_exists(unit, name)
-int unit;
-char *name;
+static void *
+ipf_pool_exists(softp, unit, name)
+	ipf_pool_softc_t *softp;
+	int unit;
+	char *name;
 {
 	ip_pool_t *p;
+	int i;
 
-	for (p = ip_pool_list[unit]; p != NULL; p = p->ipo_next)
-		if (strncmp(p->ipo_name, name, sizeof(p->ipo_name)) == 0)
-			break;
+	if (unit == IPL_LOGALL) {
+		for (i = 0; i <= LOOKUP_POOL_MAX; i++) {
+			for (p = softp->ipf_pool_list[i]; p != NULL;
+			     p = p->ipo_next) {
+				if (strncmp(p->ipo_name, name,
+					    sizeof(p->ipo_name)) == 0)
+					break;
+			}
+			if (p != NULL)
+				break;
+		}
+	} else {
+		for (p = softp->ipf_pool_list[unit + 1]; p != NULL;
+		     p = p->ipo_next)
+			if (strncmp(p->ipo_name, name,
+				    sizeof(p->ipo_name)) == 0)
+				break;
+	}
 	return p;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    ip_pool_find                                                */
-/* Returns:     int     - 0 = success, else error                           */
-/* Parameters:  ipo(I)  - pointer to the pool getting the new node.         */
+/* Function:    ipf_pool_find                                               */
+/* Returns:     int    - 0 = success, else error                            */
+/* Parameters:  arg(I)  - pointer to local context to use                   */
+/*              unit(I) - ipfilter device to which we are working on        */
+/*              name(I)  - name of the pool                                 */
 /*                                                                          */
 /* 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;
+static void *
+ipf_pool_find(arg, unit, name)
+	void *arg;
+	int unit;
+	char *name;
 {
+	ipf_pool_softc_t *softp = arg;
 	ip_pool_t *p;
 
-	p = ip_pool_exists(unit, name);
+	p = ipf_pool_exists(softp, unit, name);
 	if ((p != NULL) && (p->ipo_flags & IPOOL_DELETE))
 		return NULL;
 
@@ -362,45 +704,75 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    ip_pool_findeq                                              */
+/* Function:    ipf_pool_select_add_ref                                     */
+/* Returns:     int - 0 = success, else error                               */
+/* Parameters:  arg(I)  - pointer to local context to use                   */
+/*              unit(I) - ipfilter device to which we are working on        */
+/*              name(I)  - name of the pool                                 */
+/*                                                                          */
+/* ------------------------------------------------------------------------ */
+static void *
+ipf_pool_select_add_ref(arg, unit, name)
+	void *arg;
+	int unit;
+	char *name;
+{
+	ip_pool_t *p;
+
+	p = ipf_pool_find(arg, -1, name);
+	if (p == NULL)
+		p = ipf_pool_find(arg, unit, name);
+	if (p != NULL) {
+		ATOMIC_INC32(p->ipo_ref);
+	}
+	return p;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_pool_findeq                                             */
 /* Returns:     int     - 0 = success, else error                           */
-/* Parameters:  ipo(I)  - pointer to the pool getting the new node.         */
-/*              addr(I) - pointer to address information to delete          */
-/*              mask(I) -                                                   */
+/* Parameters:  softp(I) - pointer to soft context pool information         */
+/*              ipo(I)  - pointer to the pool getting the new node.         */
+/*              addr(I) - pointer to address information to match on        */
+/*              mask(I) - pointer to the address mask to match              */
 /*                                                                          */
 /* Searches for an exact match of an entry in the pool.                     */
 /* ------------------------------------------------------------------------ */
-ip_pool_node_t *ip_pool_findeq(ipo, addr, mask)
-ip_pool_t *ipo;
-addrfamily_t *addr, *mask;
+extern void printhostmask __P((int, u_32_t *, u_32_t *));
+static ip_pool_node_t *
+ipf_pool_findeq(softp, ipo, addr, mask)
+	ipf_pool_softc_t *softp;
+	ip_pool_t *ipo;
+	addrfamily_t *addr, *mask;
 {
-	struct radix_node *n;
-	SPL_INT(s);
+	ipf_rdx_node_t *n;
 
-	SPL_NET(s);
-	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);
-	SPL_X(s);
+	n = ipo->ipo_head->lookup(ipo->ipo_head, addr, mask);
 	return (ip_pool_node_t *)n;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    ip_pool_search                                              */
+/* Function:    ipf_pool_search                                             */
 /* Returns:     int     - 0 == +ve match, -1 == error, 1 == -ve/no match    */
-/* Parameters:  tptr(I)    - pointer to the pool to search                  */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              tptr(I)    - pointer to the pool to search                  */
 /*              version(I) - IP protocol version (4 or 6)                   */
 /*              dptr(I)    - pointer to address information                 */
+/*              bytes(I)   - length of packet                               */
 /*                                                                          */
 /* Search the pool for a given address and return a search result.          */
 /* ------------------------------------------------------------------------ */
-int ip_pool_search(tptr, ipversion, dptr)
-void *tptr;
-int ipversion;
-void *dptr;
+static int
+ipf_pool_search(softc, tptr, ipversion, dptr, bytes)
+	ipf_main_softc_t *softc;
+	void *tptr;
+	int ipversion;
+	void *dptr;
+	u_int bytes;
 {
-	struct radix_node *rn;
+	ipf_rdx_node_t *rn;
 	ip_pool_node_t *m;
 	i6addr_t *addr;
 	addrfamily_t v;
@@ -415,75 +787,126 @@
 	m = NULL;
 	addr = (i6addr_t *)dptr;
 	bzero(&v, sizeof(v));
-	v.adf_len = offsetof(addrfamily_t, adf_addr);
 
 	if (ipversion == 4) {
-		v.adf_len += sizeof(addr->in4);
+		v.adf_family = AF_INET;
+		v.adf_len = offsetof(addrfamily_t, adf_addr) +
+			    sizeof(struct in_addr);
 		v.adf_addr.in4 = addr->in4;
 #ifdef USE_INET6
 	} else if (ipversion == 6) {
-		v.adf_len += sizeof(addr->in6);
+		v.adf_family = AF_INET6;
+		v.adf_len = offsetof(addrfamily_t, adf_addr) +
+			    sizeof(struct in6_addr);
 		v.adf_addr.in6 = addr->in6;
 #endif
 	} else
 		return -1;
 
-	READ_ENTER(&ip_poolrw);
+	READ_ENTER(&softc->ipf_poolrw);
 
-	RADIX_NODE_HEAD_LOCK(ipo->ipo_head);
-	rn = ipo->ipo_head->rnh_matchaddr(&v, ipo->ipo_head);
-	RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head);
+	rn = ipo->ipo_head->matchaddr(ipo->ipo_head, &v);
 
-	if ((rn != NULL) && ((rn->rn_flags & RNF_ROOT) == 0)) {
+	if ((rn != NULL) && (rn->root == 0)) {
 		m = (ip_pool_node_t *)rn;
 		ipo->ipo_hits++;
+		m->ipn_bytes += bytes;
 		m->ipn_hits++;
 		rv = m->ipn_info;
 	}
-	RWLOCK_EXIT(&ip_poolrw);
+	RWLOCK_EXIT(&softc->ipf_poolrw);
 	return rv;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    ip_pool_insert                                              */
-/* Returns:     int     - 0 = success, else error                           */
-/* Parameters:  ipo(I)  - pointer to the pool getting the new node.         */
-/*              addr(I) - address being added as a node                     */
-/*              mask(I) - netmask to with the node being added              */
-/*              info(I) - extra information to store in this node.          */
-/* Locks:       WRITE(ip_poolrw)                                            */
+/* Function:    ipf_pool_insert_node                                        */
+/* Returns:     int      - 0 = success, else error                          */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              softp(I) - pointer to soft context pool information         */
+/*              ipo(I)   - pointer to the pool getting the new node.        */
+/*              node(I)  - structure with address/mask to add               */
+/* Locks:       WRITE(ipf_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.                   */
 /* ------------------------------------------------------------------------ */
-int ip_pool_insert(ipo, addr, mask, info)
-ip_pool_t *ipo;
-i6addr_t *addr, *mask;
-int info;
+static int
+ipf_pool_insert_node(softc, softp, ipo, node)
+	ipf_main_softc_t *softc;
+	ipf_pool_softc_t *softp;
+	ip_pool_t *ipo;
+	struct ip_pool_node *node;
 {
-	struct radix_node *rn;
+	ipf_rdx_node_t *rn;
 	ip_pool_node_t *x;
 
+	if ((node->ipn_addr.adf_len > sizeof(*rn)) ||
+	    (node->ipn_addr.adf_len < 4)) {
+		IPFERROR(70003);
+		return EINVAL;
+	}
+
+	if ((node->ipn_mask.adf_len > sizeof(*rn)) ||
+	    (node->ipn_mask.adf_len < 4)) {
+		IPFERROR(70004);
+		return EINVAL;
+	}
+
 	KMALLOC(x, ip_pool_node_t *);
 	if (x == NULL) {
+		IPFERROR(70002);
 		return ENOMEM;
 	}
 
-	bzero(x, sizeof(*x));
+	*x = *node;
+	bzero((char *)x->ipn_nodes, sizeof(x->ipn_nodes));
+	x->ipn_owner = ipo;
+	x->ipn_hits = 0;
+	x->ipn_next = NULL;
+	x->ipn_pnext = NULL;
+	x->ipn_dnext = NULL;
+	x->ipn_pdnext = NULL;
 
-	x->ipn_info = info;
-	(void)strncpy(x->ipn_name, ipo->ipo_name, sizeof(x->ipn_name));
+	if (x->ipn_die != 0) {
+		/*
+		 * If the new node has a given expiration time, insert it
+		 * into the list of expiring nodes with the ones to be
+		 * removed first added to the front of the list. The
+		 * insertion is O(n) but it is kept sorted for quick scans
+		 * at expiration interval checks.
+		 */
+		ip_pool_node_t *n;
 
-	bcopy(addr, &x->ipn_addr.adf_addr, sizeof(*addr));
-	x->ipn_addr.adf_len = sizeof(x->ipn_addr);
-	bcopy(mask, &x->ipn_mask.adf_addr, sizeof(*mask));
-	x->ipn_mask.adf_len = sizeof(x->ipn_mask);
+		x->ipn_die = softc->ipf_ticks + IPF_TTLVAL(x->ipn_die);
+		for (n = softp->ipf_node_explist; n != NULL; n = n->ipn_dnext) {
+			if (x->ipn_die < n->ipn_die)
+				break;
+			if (n->ipn_dnext == NULL) {
+				/*
+				 * We've got to the last node and everything
+				 * wanted to be expired before this new node,
+				 * so we have to tack it on the end...
+				 */
+				n->ipn_dnext = x;
+				x->ipn_pdnext = &n->ipn_dnext;
+				n = NULL;
+				break;
+			}
+		}
 
-	RADIX_NODE_HEAD_LOCK(ipo->ipo_head);
-	rn = ipo->ipo_head->rnh_addaddr(&x->ipn_addr, &x->ipn_mask,
-					ipo->ipo_head, x->ipn_nodes);
-	RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head);
+		if (softp->ipf_node_explist == NULL) {
+			softp->ipf_node_explist = x;
+			x->ipn_pdnext = &softp->ipf_node_explist;
+		} else if (n != NULL) {
+			x->ipn_dnext = n;
+			x->ipn_pdnext = n->ipn_pdnext;
+			n->ipn_pdnext = &x->ipn_dnext;
+		}
+	}
+
+	rn = ipo->ipo_head->addaddr(ipo->ipo_head, &x->ipn_addr, &x->ipn_mask,
+				    x->ipn_nodes);
 #ifdef	DEBUG_POOL
 	printf("Added %p at %p\n", x, rn);
 #endif
@@ -490,17 +913,16 @@
 
 	if (rn == NULL) {
 		KFREE(x);
+		IPFERROR(70005);
 		return ENOMEM;
 	}
 
 	x->ipn_ref = 1;
-	x->ipn_next = ipo->ipo_list;
-	x->ipn_pnext = &ipo->ipo_list;
-	if (ipo->ipo_list != NULL)
-		ipo->ipo_list->ipn_pnext = &x->ipn_next;
-	ipo->ipo_list = x;
+	x->ipn_pnext = ipo->ipo_tail;
+	*ipo->ipo_tail = x;
+	ipo->ipo_tail = &x->ipn_next;
 
-	ipoolstat.ipls_nodes++;
+	softp->ipf_pool_stats.ipls_nodes++;
 
 	return 0;
 }
@@ -507,10 +929,12 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    ip_pool_create                                              */
-/* Returns:     int     - 0 = success, else error                           */
-/* Parameters:  op(I) - pointer to iplookup struct with call details        */
-/* Locks:       WRITE(ip_poolrw)                                            */
+/* Function:    ipf_pool_create                                             */
+/* Returns:     int      - 0 = success, else error                          */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              softp(I) - pointer to soft context pool information         */
+/*              op(I)    - pointer to iplookup struct with call details     */
+/* Locks:       WRITE(ipf_poolrw)                                           */
 /*                                                                          */
 /* Creates a new group according to the paramters passed in via the         */
 /* iplookupop structure.  Does not check to see if the group already exists */
@@ -522,8 +946,11 @@
 /* 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;
+static int
+ipf_pool_create(softc, softp, op)
+	ipf_main_softc_t *softc;
+	ipf_pool_softc_t *softp;
+	iplookupop_t *op;
 {
 	char name[FR_GROUPLEN];
 	int poolnum, unit;
@@ -532,10 +959,12 @@
 	unit = op->iplo_unit;
 
 	if ((op->iplo_arg & LOOKUP_ANON) == 0) {
-		h = ip_pool_exists(unit, op->iplo_name);
+		h = ipf_pool_exists(softp, unit, op->iplo_name);
 		if (h != NULL) {
-			if ((h->ipo_flags & IPOOL_DELETE) == 0)
+			if ((h->ipo_flags & IPOOL_DELETE) == 0) {
+				IPFERROR(70006);
 				return EEXIST;
+			}
 			h->ipo_flags &= ~IPOOL_DELETE;
 			return 0;
 		}
@@ -542,13 +971,15 @@
 	}
 
 	KMALLOC(h, ip_pool_t *);
-	if (h == NULL)
+	if (h == NULL) {
+		IPFERROR(70007);
 		return ENOMEM;
+	}
 	bzero(h, sizeof(*h));
 
-	if (rn_inithead((void **)&h->ipo_head,
-			offsetof(addrfamily_t, adf_addr) << 3) == 0) {
+	if (ipf_rx_inithead(softp->ipf_radix, &h->ipo_head) != 0) {
 		KFREE(h);
+		IPFERROR(70008);
 		return ENOMEM;
 	}
 
@@ -564,7 +995,7 @@
 		(void)sprintf(name, "%x", poolnum);
 #endif
 
-		for (p = ip_pool_list[unit]; p != NULL; ) {
+		for (p = softp->ipf_pool_list[unit + 1]; p != NULL; ) {
 			if (strncmp(name, p->ipo_name,
 				    sizeof(p->ipo_name)) == 0) {
 				poolnum++;
@@ -573,7 +1004,7 @@
 #else
 				(void)sprintf(name, "%x", poolnum);
 #endif
-				p = ip_pool_list[unit];
+				p = softp->ipf_pool_list[unit + 1];
 			} else
 				p = p->ipo_next;
 		}
@@ -584,16 +1015,18 @@
 		(void)strncpy(h->ipo_name, op->iplo_name, sizeof(h->ipo_name));
 	}
 
+	h->ipo_radix = softp->ipf_radix;
 	h->ipo_ref = 1;
 	h->ipo_list = NULL;
+	h->ipo_tail = &h->ipo_list;
 	h->ipo_unit = unit;
-	h->ipo_next = ip_pool_list[unit];
-	if (ip_pool_list[unit] != NULL)
-		ip_pool_list[unit]->ipo_pnext = &h->ipo_next;
-	h->ipo_pnext = &ip_pool_list[unit];
-	ip_pool_list[unit] = h;
+	h->ipo_next = softp->ipf_pool_list[unit + 1];
+	if (softp->ipf_pool_list[unit + 1] != NULL)
+		softp->ipf_pool_list[unit + 1]->ipo_pnext = &h->ipo_next;
+	h->ipo_pnext = &softp->ipf_pool_list[unit + 1];
+	softp->ipf_pool_list[unit + 1] = h;
 
-	ipoolstat.ipls_pools++;
+	softp->ipf_pool_stats.ipls_pools++;
 
 	return 0;
 }
@@ -600,105 +1033,126 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    ip_pool_remove                                              */
-/* Returns:     int    - 0 = success, else error                            */
-/* Parameters:  ipo(I) - pointer to the pool to remove the node from.       */
-/*              ipe(I) - address being deleted as a node                    */
-/* Locks:       WRITE(ip_poolrw)                                            */
+/* Function:    ipf_pool_remove_node                                        */
+/* Returns:     int      - 0 = success, else error                          */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              ipo(I)   - pointer to the pool to remove the node from.     */
+/*              ipe(I)   - address being deleted as a node                  */
+/* Locks:       WRITE(ipf_poolrw)                                           */
 /*                                                                          */
 /* Remove a node from the pool given by ipo.                                */
 /* ------------------------------------------------------------------------ */
-int ip_pool_remove(ipo, ipe)
-ip_pool_t *ipo;
-ip_pool_node_t *ipe;
+static int
+ipf_pool_remove_node(softc, softp, ipo, ipe)
+	ipf_main_softc_t *softc;
+	ipf_pool_softc_t *softp;
+	ip_pool_t *ipo;
+	ip_pool_node_t *ipe;
 {
+	void *ptr;
 
+	if (ipo->ipo_tail == &ipe->ipn_next)
+		ipo->ipo_tail = ipe->ipn_pnext;
+
 	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(&ipe->ipn_addr, &ipe->ipn_mask,
-				   ipo->ipo_head);
-	RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head);
+	if (ipe->ipn_pdnext != NULL)
+		*ipe->ipn_pdnext = ipe->ipn_dnext;
+	if (ipe->ipn_dnext != NULL)
+		ipe->ipn_dnext->ipn_pdnext = ipe->ipn_pdnext;
 
-	ip_pool_node_deref(ipe);
+	ptr = ipo->ipo_head->deladdr(ipo->ipo_head, &ipe->ipn_addr,
+				     &ipe->ipn_mask);
 
-	return 0;
+	if (ptr != NULL) {
+		ipf_pool_node_deref(softp, ipe);
+		return 0;
+	}
+	IPFERROR(70027);
+	return ESRCH;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    ip_pool_destroy                                             */
+/* Function:    ipf_pool_destroy                                            */
 /* Returns:     int    - 0 = success, else error                            */
-/* Parameters:  op(I)  -  information about the pool to remove              */
-/* Locks:       WRITE(ip_poolrw) or WRITE(ipf_global)                       */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              softp(I) - pointer to soft context pool information         */
+/*              unit(I)  - ipfilter device to which we are working on      */
+/*              name(I)  - name of the pool                                 */
+/* Locks:       WRITE(ipf_poolrw) or WRITE(ipf_global)                      */
 /*                                                                          */
 /* Search for a pool using paramters passed in and if it's not otherwise    */
 /* 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 ipfdetach() where ip_poolrw */
+/* NOTE: Because this function is called out of ipfdetach() where ipf_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.            */
+/* assertion that one of the two (ipf_poolrw,ipf_global) is held.           */
 /* ------------------------------------------------------------------------ */
-int ip_pool_destroy(unit, name)
-int unit;
-char *name;
+static int
+ipf_pool_destroy(softc, softp, unit, name)
+	ipf_main_softc_t *softc;
+	ipf_pool_softc_t *softp;
+	int unit;
+	char *name;
 {
 	ip_pool_t *ipo;
 
-	ipo = ip_pool_exists(unit, name);
-	if (ipo == NULL)
+	ipo = ipf_pool_exists(softp, unit, name);
+	if (ipo == NULL) {
+		IPFERROR(70009);
 		return ESRCH;
+	}
 
 	if (ipo->ipo_ref != 1) {
-		ip_pool_clearnodes(ipo);
+		ipf_pool_clearnodes(softc, softp, ipo);
 		ipo->ipo_flags |= IPOOL_DELETE;
 		return 0;
 	}
 
-	ip_pool_free(ipo);
+	ipf_pool_free(softc, softp, ipo);
 	return 0;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    ip_pool_flush                                               */
+/* Function:    ipf_pool_flush                                              */
 /* Returns:     int    - number of pools deleted                            */
-/* Parameters:  fp(I)  - which pool(s) to flush                             */
-/* Locks:       WRITE(ip_poolrw) or WRITE(ipf_global)                       */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              arg(I)   - pointer to local context to use                  */
+/*              fp(I)    - which pool(s) to flush                           */
+/* Locks:       WRITE(ipf_poolrw) or WRITE(ipf_global)                      */
 /*                                                                          */
 /* Free all pools associated with the device that matches the unit number   */
 /* passed in with operation.                                                */
 /*                                                                          */
-/* NOTE: Because this function is called out of ipfdetach() where ip_poolrw */
+/* NOTE: Because this function is called out of ipfdetach() where ipf_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.            */
+/* assertion that one of the two (ipf_poolrw,ipf_global) is held.           */
 /* ------------------------------------------------------------------------ */
-int ip_pool_flush(fp)
-iplookupflush_t *fp;
+static size_t
+ipf_pool_flush(softc, arg, fp)
+	ipf_main_softc_t *softc;
+	void *arg;
+	iplookupflush_t *fp;
 {
+	ipf_pool_softc_t *softp = arg;
 	int i, num = 0, unit, err;
 	ip_pool_t *p, *q;
-	iplookupop_t op;
 
 	unit = fp->iplf_unit;
-
-	for (i = 0; i <= IPL_LOGMAX; i++) {
+	for (i = -1; i <= IPL_LOGMAX; i++) {
 		if (unit != IPLT_ALL && i != unit)
 			continue;
-		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));
+		for (q = softp->ipf_pool_list[i + 1]; (p = q) != NULL; ) {
 			q = p->ipo_next;
-			err = ip_pool_destroy(op.iplo_unit, op.iplo_name);
+			err = ipf_pool_destroy(softc, softp, i, p->ipo_name);
 			if (err == 0)
 				num++;
-			else
-				break;
 		}
 	}
 	return num;
@@ -706,101 +1160,109 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    ip_pool_free                                                */
+/* Function:    ipf_pool_free                                               */
 /* Returns:     void                                                        */
-/* Parameters:  ipo(I) -  pointer to pool structure                         */
-/* Locks:       WRITE(ip_poolrw) or WRITE(ipf_global)                       */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              softp(I) - pointer to soft context pool information         */
+/*              ipo(I) - pointer to pool structure                          */
+/* Locks:       WRITE(ipf_poolrw) or WRITE(ipf_global)                      */
 /*                                                                          */
 /* Deletes the pool strucutre passed in from the list of pools and deletes  */
 /* all of the address information stored in it, including any tree data     */
 /* structures also allocated.                                               */
 /*                                                                          */
-/* NOTE: Because this function is called out of ipfdetach() where ip_poolrw */
+/* NOTE: Because this function is called out of ipfdetach() where ipf_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.            */
+/* assertion that one of the two (ipf_poolrw,ipf_global) is held.           */
 /* ------------------------------------------------------------------------ */
-void ip_pool_free(ipo)
-ip_pool_t *ipo;
+static void
+ipf_pool_free(softc, softp, ipo)
+	ipf_main_softc_t *softc;
+	ipf_pool_softc_t *softp;
+	ip_pool_t *ipo;
 {
 
-	ip_pool_clearnodes(ipo);
+	ipf_pool_clearnodes(softc, softp, 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);
+	ipf_rx_freehead(ipo->ipo_head);
 	KFREE(ipo);
 
-	ipoolstat.ipls_pools--;
+	softp->ipf_pool_stats.ipls_pools--;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    ip_pool_clearnodes                                          */
+/* Function:    ipf_pool_clearnodes                                         */
 /* Returns:     void                                                        */
-/* Parameters:  ipo(I) -  pointer to pool structure                         */
-/* Locks:       WRITE(ip_poolrw) or WRITE(ipf_global)                       */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              softp(I) - pointer to soft context pool information         */
+/*              ipo(I)   - pointer to pool structure                        */
+/* Locks:       WRITE(ipf_poolrw) or WRITE(ipf_global)                      */
 /*                                                                          */
 /* Deletes all nodes stored in a pool structure.                            */
 /* ------------------------------------------------------------------------ */
-static void ip_pool_clearnodes(ipo)
-ip_pool_t *ipo;
+static void
+ipf_pool_clearnodes(softc, softp, ipo)
+	ipf_main_softc_t *softc;
+	ipf_pool_softc_t *softp;
+	ip_pool_t *ipo;
 {
-	ip_pool_node_t *n;
+	ip_pool_node_t *n, **next;
 
-	RADIX_NODE_HEAD_LOCK(ipo->ipo_head);
-	while ((n = ipo->ipo_list) != NULL) {
-		ipo->ipo_head->rnh_deladdr(&n->ipn_addr, &n->ipn_mask,
-					   ipo->ipo_head);
+	for (next = &ipo->ipo_list; (n = *next) != NULL; )
+		ipf_pool_remove_node(softc, softp, ipo, n);
 
-		*n->ipn_pnext = n->ipn_next;
-		if (n->ipn_next)
-			n->ipn_next->ipn_pnext = n->ipn_pnext;
-
-		KFREE(n);
-
-		ipoolstat.ipls_nodes--;
-	}
-	RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head);
-
 	ipo->ipo_list = NULL;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    ip_pool_deref                                               */
+/* Function:    ipf_pool_deref                                              */
 /* Returns:     void                                                        */
-/* Parameters:  ipo(I) -  pointer to pool structure                         */
-/* Locks:       WRITE(ip_poolrw)                                            */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              arg(I)   - pointer to local context to use                  */
+/*              pool(I)  - pointer to pool structure                        */
+/* Locks:       WRITE(ipf_poolrw)                                           */
 /*                                                                          */
 /* Drop the number of known references to this pool structure by one and if */
 /* we arrive at zero known references, free it.                             */
 /* ------------------------------------------------------------------------ */
-void ip_pool_deref(ipo)
-ip_pool_t *ipo;
+static int
+ipf_pool_deref(softc, arg, pool)
+	ipf_main_softc_t *softc;
+	void *arg, *pool;
 {
+	ip_pool_t *ipo = pool;
 
 	ipo->ipo_ref--;
 
 	if (ipo->ipo_ref == 0)
-		ip_pool_free(ipo);
+		ipf_pool_free(softc, arg, ipo);
 
 	else if ((ipo->ipo_ref == 1) && (ipo->ipo_flags & IPOOL_DELETE))
-		ip_pool_destroy(ipo->ipo_unit, ipo->ipo_name);
+		ipf_pool_destroy(softc, arg, ipo->ipo_unit, ipo->ipo_name);
+
+	return 0;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    ip_pool_node_deref                                          */
+/* Function:    ipf_pool_node_deref                                         */
 /* Returns:     void                                                        */
-/* Parameters:  ipn(I) - pointer to pool structure                          */
-/* Locks:       WRITE(ip_poolrw)                                            */
+/* Parameters:  softp(I) - pointer to soft context pool information         */
+/*              ipn(I)   - pointer to pool structure                        */
+/* Locks:       WRITE(ipf_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;
+static void
+ipf_pool_node_deref(softp, ipn)
+	ipf_pool_softc_t *softp;
+	ip_pool_node_t *ipn;
 {
 
 	ipn->ipn_ref--;
@@ -807,24 +1269,31 @@
 
 	if (ipn->ipn_ref == 0) {
 		KFREE(ipn);
-		ipoolstat.ipls_nodes--;
+		softp->ipf_pool_stats.ipls_nodes--;
 	}
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    ip_pool_getnext                                             */
+/* Function:    ipf_pool_iter_next                                          */
 /* Returns:     void                                                        */
-/* Parameters:  token(I) - pointer to pool structure                        */
-/* Parameters:  ilp(IO)   - pointer to pool iterating structure             */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              arg(I)   - pointer to local context to use                  */
+/*              token(I) - pointer to pool structure                        */
+/*              ilp(IO)  - pointer to pool iterating structure              */
 /*                                                                          */
 /* ------------------------------------------------------------------------ */
-int ip_pool_getnext(token, ilp)
-ipftoken_t *token;
-ipflookupiter_t *ilp;
+static int
+ipf_pool_iter_next(softc, arg, token, ilp)
+	ipf_main_softc_t *softc;
+	void *arg;
+	ipftoken_t *token;
+	ipflookupiter_t *ilp;
 {
+	ipf_pool_softc_t *softp = arg;
 	ip_pool_node_t *node, zn, *nextnode;
 	ip_pool_t *ipo, zp, *nextipo;
+	void *pnext;
 	int err;
 
 	err = 0;
@@ -833,7 +1302,7 @@
 	ipo = NULL;
 	nextipo = NULL;
 
-	READ_ENTER(&ip_poolrw);
+	READ_ENTER(&softc->ipf_poolrw);
 
 	switch (ilp->ili_otype)
 	{
@@ -840,13 +1309,13 @@
 	case IPFLOOKUPITER_LIST :
 		ipo = token->ipt_data;
 		if (ipo == NULL) {
-			nextipo = ip_pool_list[(int)ilp->ili_unit];
+			nextipo = softp->ipf_pool_list[(int)ilp->ili_unit + 1];
 		} else {
 			nextipo = ipo->ipo_next;
 		}
 
 		if (nextipo != NULL) {
-			ATOMIC_INC(nextipo->ipo_ref);
+			ATOMIC_INC32(nextipo->ipo_ref);
 			token->ipt_data = nextipo;
 		} else {
 			bzero((char *)&zp, sizeof(zp));
@@ -853,15 +1322,18 @@
 			nextipo = &zp;
 			token->ipt_data = NULL;
 		}
+		pnext = nextipo->ipo_next;
 		break;
 
 	case IPFLOOKUPITER_NODE :
 		node = token->ipt_data;
 		if (node == NULL) {
-			ipo = ip_pool_exists(ilp->ili_unit, ilp->ili_name);
-			if (ipo == NULL)
+			ipo = ipf_pool_exists(arg, ilp->ili_unit,
+					      ilp->ili_name);
+			if (ipo == NULL) {
+				IPFERROR(70010);
 				err = ESRCH;
-			else {
+			} else {
 				nextnode = ipo->ipo_list;
 				ipo = NULL;
 			}
@@ -870,7 +1342,7 @@
 		}
 
 		if (nextnode != NULL) {
-			ATOMIC_INC(nextnode->ipn_ref);
+			ATOMIC_INC32(nextnode->ipn_ref);
 			token->ipt_data = nextnode;
 		} else {
 			bzero((char *)&zn, sizeof(zn));
@@ -877,14 +1349,17 @@
 			nextnode = &zn;
 			token->ipt_data = NULL;
 		}
+		pnext = nextnode->ipn_next;
 		break;
+
 	default :
+		IPFERROR(70011);
+		pnext = NULL;
 		err = EINVAL;
 		break;
 	}
 
-	RWLOCK_EXIT(&ip_poolrw);
-
+	RWLOCK_EXIT(&softc->ipf_poolrw);
 	if (err != 0)
 		return err;
 
@@ -891,27 +1366,33 @@
 	switch (ilp->ili_otype)
 	{
 	case IPFLOOKUPITER_LIST :
+		err = COPYOUT(nextipo, ilp->ili_data, sizeof(*nextipo));
+		if (err != 0)  {
+			IPFERROR(70012);
+			err = EFAULT;
+		}
 		if (ipo != NULL) {
-			WRITE_ENTER(&ip_poolrw);
-			ip_pool_deref(ipo);
-			RWLOCK_EXIT(&ip_poolrw);
+			WRITE_ENTER(&softc->ipf_poolrw);
+			ipf_pool_deref(softc, softp, ipo);
+			RWLOCK_EXIT(&softc->ipf_poolrw);
 		}
-		err = COPYOUT(nextipo, ilp->ili_data, sizeof(*nextipo));
-		if (err != 0)
-			err = EFAULT;
 		break;
 
 	case IPFLOOKUPITER_NODE :
+		err = COPYOUT(nextnode, ilp->ili_data, sizeof(*nextnode));
+		if (err != 0) {
+			IPFERROR(70013);
+			err = EFAULT;
+		}
 		if (node != NULL) {
-			WRITE_ENTER(&ip_poolrw);
-			ip_pool_node_deref(node);
-			RWLOCK_EXIT(&ip_poolrw);
+			WRITE_ENTER(&softc->ipf_poolrw);
+			ipf_pool_node_deref(softp, node);
+			RWLOCK_EXIT(&softc->ipf_poolrw);
 		}
-		err = COPYOUT(nextnode, ilp->ili_data, sizeof(*nextnode));
-		if (err != 0)
-			err = EFAULT;
 		break;
 	}
+	if (pnext == NULL)
+		ipf_token_mark_complete(token);
 
 	return err;
 }
@@ -918,75 +1399,92 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    ip_pool_iterderef                                           */
+/* Function:    ipf_pool_iterderef                                          */
 /* Returns:     void                                                        */
-/* Parameters:  ipn(I) - pointer to pool structure                          */
-/* Locks:       WRITE(ip_poolrw)                                            */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              arg(I)   - pointer to local context to use                  */
+/*              unit(I)  - ipfilter device to which we are working on       */
+/* Locks:       WRITE(ipf_poolrw)                                           */
 /*                                                                          */
 /* ------------------------------------------------------------------------ */
-void ip_pool_iterderef(otype, unit, data)
-u_int otype;
-int unit;
-void *data;
+static int
+ipf_pool_iter_deref(softc, arg, otype, unit, data)
+	ipf_main_softc_t *softc;
+	void *arg;
+	int otype;
+	int unit;
+	void *data;
 {
+	ipf_pool_softc_t *softp = arg;
 
 	if (data == NULL)
-		return;
+		return EINVAL;
 
 	if (unit < 0 || unit > IPL_LOGMAX)
-		return;
+		return EINVAL;
 
 	switch (otype)
 	{
 	case IPFLOOKUPITER_LIST :
-		WRITE_ENTER(&ip_poolrw);
-		ip_pool_deref((ip_pool_t *)data);
-		RWLOCK_EXIT(&ip_poolrw);
+		ipf_pool_deref(softc, softp, (ip_pool_t *)data);
 		break;
 
 	case IPFLOOKUPITER_NODE :
-		WRITE_ENTER(&ip_poolrw);
-		ip_pool_node_deref((ip_pool_node_t *)data);
-		RWLOCK_EXIT(&ip_poolrw);
+		ipf_pool_node_deref(softp, (ip_pool_node_t *)data);
 		break;
 	default :
 		break;
 	}
+
+	return 0;
 }
 
 
-# if defined(_KERNEL) && ((BSD >= 198911) && !defined(__osf__) && \
-      !defined(__hpux) && !defined(__sgi))
-static int
-rn_freenode(struct radix_node *n, void *p)
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_pool_expire                                             */
+/* Returns:     Nil                                                         */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              arg(I)   - pointer to local context to use                  */
+/*                                                                          */
+/* At present this function exists just to support temporary addition of    */
+/* nodes to the address pool.                                               */
+/* ------------------------------------------------------------------------ */
+static void
+ipf_pool_expire(softc, arg)
+	ipf_main_softc_t *softc;
+	void *arg;
 {
-	struct radix_node_head *rnh = p;
-	struct radix_node *d;
+	ipf_pool_softc_t *softp = arg;
+	ip_pool_node_t *n;
 
-	d = rnh->rnh_deladdr(n->rn_key, NULL, rnh);
-	if (d != NULL) {
-		FreeS(d, max_keylen + 2 * sizeof (*d));
+	while ((n = softp->ipf_node_explist) != NULL) {
+		/*
+		 * Because the list is kept sorted on insertion, the fist
+		 * one that dies in the future means no more work to do.
+		 */
+		if (n->ipn_die > softc->ipf_ticks)
+			break;
+		ipf_pool_remove_node(softc, softp, n->ipn_owner, n);
 	}
-	return 0;
 }
 
 
+
+
+#ifndef _KERNEL
 void
-rn_freehead(rnh)
-      struct radix_node_head *rnh;
+ipf_pool_dump(softc, arg)
+	ipf_main_softc_t *softc;
+	void *arg;
 {
+	ipf_pool_softc_t *softp = arg;
+	ip_pool_t *ipl;
+	int i;
 
-	RADIX_NODE_HEAD_LOCK(rnh);
-	(*rnh->rnh_walktree)(rnh, rn_freenode, rnh);
-
-	rnh->rnh_addaddr = NULL;
-	rnh->rnh_deladdr = NULL;
-	rnh->rnh_matchaddr = NULL;
-	rnh->rnh_lookup = NULL;
-	rnh->rnh_walktree = NULL;
-	RADIX_NODE_HEAD_UNLOCK(rnh);
-
-	Free(rnh);
+	printf("List of configured pools\n");
+	for (i = 0; i <= LOOKUP_POOL_MAX; i++)
+		for (ipl = softp->ipf_pool_list[i]; ipl != NULL;
+		     ipl = ipl->ipo_next)
+			printpool(ipl, bcopywrap, NULL, opts, NULL);
 }
-# endif
-#endif /* IPFILTER_LOOKUP */
+#endif

Modified: trunk/sys/contrib/ipfilter/netinet/ip_pool.h
===================================================================
--- trunk/sys/contrib/ipfilter/netinet/ip_pool.h	2018-05-28 18:55:30 UTC (rev 10138)
+++ trunk/sys/contrib/ipfilter/netinet/ip_pool.h	2018-05-28 18:56:30 UTC (rev 10139)
@@ -1,44 +1,35 @@
+/* $MidnightBSD$ */
 /*
- * Copyright (C) 1993-2001, 2003 by Darren Reed.
+ * Copyright (C) 2012 by Darren Reed.
  *
  * See the IPFILTER.LICENCE file for details on licencing.
  *
- * $Id: ip_pool.h,v 1.2 2008-09-19 02:15:13 laffer1 Exp $
+ * $Id$
  */
 
 #ifndef	__IP_POOL_H__
 #define	__IP_POOL_H__
 
-#if defined(_KERNEL) && !defined(__osf__) && !defined(__hpux) && \
-    !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) || defined(sun)
-#  include "radix_ipf_local.h"
-#  define radix_mask ipf_radix_mask
-#  define radix_node ipf_radix_node
-#  define radix_node_head ipf_radix_node_head
-# else
-#  include "radix_ipf.h"
-# endif
-#endif
 #include "netinet/ip_lookup.h"
+#include "radix_ipf.h"
 
 #define	IP_POOL_NOMATCH		0
 #define	IP_POOL_POSITIVE	1
 
 typedef	struct ip_pool_node {
-	struct	radix_node	ipn_nodes[2];
+	ipf_rdx_node_t		ipn_nodes[2];
 	addrfamily_t		ipn_addr;
 	addrfamily_t		ipn_mask;
+	int			ipn_uid;
 	int			ipn_info;
 	int			ipn_ref;
-char			ipn_name[FR_GROUPLEN];
-u_long			ipn_hits;
+	char			ipn_name[FR_GROUPLEN];
+	U_QUAD_T		ipn_hits;
+	U_QUAD_T		ipn_bytes;
+	u_long			ipn_die;
 	struct ip_pool_node	*ipn_next, **ipn_pnext;
+	struct ip_pool_node	*ipn_dnext, **ipn_pdnext;
+	struct ip_pool_s	*ipn_owner;
 } ip_pool_node_t;
 
 
@@ -45,13 +36,16 @@
 typedef	struct ip_pool_s {
 	struct ip_pool_s	*ipo_next;
 	struct ip_pool_s	**ipo_pnext;
-	struct radix_node_head	*ipo_head;
-	ip_pool_node_t	*ipo_list;
-	u_long		ipo_hits;
-	int		ipo_unit;
-	int		ipo_flags;
-	int		ipo_ref;
-	char		ipo_name[FR_GROUPLEN];
+	ipf_rdx_head_t		*ipo_head;
+	ip_pool_node_t		*ipo_list;
+	ip_pool_node_t		**ipo_tail;
+	ip_pool_node_t		*ipo_nextaddr;
+	void			*ipo_radix;
+	u_long			ipo_hits;
+	int			ipo_unit;
+	int			ipo_flags;
+	int			ipo_ref;
+	char			ipo_name[FR_GROUPLEN];
 } ip_pool_t;
 
 #define	IPOOL_DELETE	0x01
@@ -58,33 +52,17 @@
 #define	IPOOL_ANON	0x02
 
 
-typedef	struct	ip_pool_stat	{
-	u_long		ipls_pools;
-	u_long		ipls_tables;
-	u_long		ipls_nodes;
-	ip_pool_t	*ipls_list[IPL_LOGSIZE];
-} ip_pool_stat_t;
+typedef	struct	ipf_pool_stat	{
+	u_long			ipls_pools;
+	u_long			ipls_tables;
+	u_long			ipls_nodes;
+	ip_pool_t		*ipls_list[LOOKUP_POOL_SZ];
+} ipf_pool_stat_t;
 
+extern	ipf_lookup_t	ipf_pool_backend;
 
-extern	ip_pool_stat_t	ipoolstat;
-extern	ip_pool_t	*ip_pool_list[IPL_LOGSIZE];
+#ifndef _KERNEL
+extern	void	ipf_pool_dump __P((ipf_main_softc_t *, void *));
+#endif
 
-extern	int	ip_pool_search __P((void *, int, void *));
-extern	int	ip_pool_init __P((void));
-extern	void	ip_pool_fini __P((void));
-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((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__ */

Modified: trunk/sys/contrib/ipfilter/netinet/ip_pptp_pxy.c
===================================================================
--- trunk/sys/contrib/ipfilter/netinet/ip_pptp_pxy.c	2018-05-28 18:55:30 UTC (rev 10138)
+++ trunk/sys/contrib/ipfilter/netinet/ip_pptp_pxy.c	2018-05-28 18:56:30 UTC (rev 10139)
@@ -1,18 +1,43 @@
+/* $MidnightBSD$ */
 /*
- * Copyright (C) 2002-2003 by Darren Reed
+ * Copyright (C) 2012 by Darren Reed.
  *
  * Simple PPTP transparent proxy for in-kernel use.  For use with the NAT
  * code.
  *
- * $Id: ip_pptp_pxy.c,v 1.2 2008-09-19 02:15:13 laffer1 Exp $
+ * $Id$
  *
  */
 #define	IPF_PPTP_PROXY
 
+
+
+/*
+ * PPTP proxy
+ */
+typedef struct pptp_side {
+	u_32_t		pptps_nexthdr;
+	u_32_t		pptps_next;
+	int		pptps_state;
+	int		pptps_gothdr;
+	int		pptps_len;
+	int		pptps_bytes;
+	char		*pptps_wptr;
+	char		pptps_buffer[512];
+} pptp_side_t;
+
+typedef struct pptp_pxy {
+	nat_t		*pptp_nat;
+	struct ipstate	*pptp_state;
+	u_short		pptp_call[2];
+	pptp_side_t	pptp_side[2];
+	ipnat_t		*pptp_rule;
+} pptp_pxy_t;
+
 typedef	struct pptp_hdr {
-	u_short	pptph_len;
-	u_short	pptph_type;
-	u_32_t	pptph_cookie;
+	u_short		pptph_len;
+	u_short		pptph_type;
+	u_32_t		pptph_cookie;
 } pptp_hdr_t;
 
 #define	PPTP_MSGTYPE_CTL	1
@@ -33,41 +58,41 @@
 #define	PPTP_MTCTL_LINKINFO	15
 
 
-int ippr_pptp_init __P((void));
-void ippr_pptp_fini __P((void));
-int ippr_pptp_new __P((fr_info_t *, ap_session_t *, nat_t *));
-void ippr_pptp_del __P((ap_session_t *));
-int ippr_pptp_inout __P((fr_info_t *, ap_session_t *, nat_t *));
-void ippr_pptp_donatstate __P((fr_info_t *, nat_t *, pptp_pxy_t *));
-int ippr_pptp_message __P((fr_info_t *, nat_t *, pptp_pxy_t *, pptp_side_t *));
-int ippr_pptp_nextmessage __P((fr_info_t *, nat_t *, pptp_pxy_t *, int));
-int ippr_pptp_mctl __P((fr_info_t *, nat_t *, pptp_pxy_t *, pptp_side_t *));
+void ipf_p_pptp_main_load __P((void));
+void ipf_p_pptp_main_unload __P((void));
+int ipf_p_pptp_new __P((void *, fr_info_t *, ap_session_t *, nat_t *));
+void ipf_p_pptp_del __P((ipf_main_softc_t *, ap_session_t *));
+int ipf_p_pptp_inout __P((void *, fr_info_t *, ap_session_t *, nat_t *));
+void ipf_p_pptp_donatstate __P((fr_info_t *, nat_t *, pptp_pxy_t *));
+int ipf_p_pptp_message __P((fr_info_t *, nat_t *, pptp_pxy_t *, pptp_side_t *));
+int ipf_p_pptp_nextmessage __P((fr_info_t *, nat_t *, pptp_pxy_t *, int));
+int ipf_p_pptp_mctl __P((fr_info_t *, nat_t *, pptp_pxy_t *, pptp_side_t *));
 
 static	frentry_t	pptpfr;
 
-int	pptp_proxy_init = 0;
-int	ippr_pptp_debug = 0;
-int	ippr_pptp_gretimeout = IPF_TTLVAL(120);	/* 2 minutes */
+static	int	pptp_proxy_init = 0;
+static	int	ipf_p_pptp_debug = 0;
+static	int	ipf_p_pptp_gretimeout = IPF_TTLVAL(120);	/* 2 minutes */
 
 
 /*
  * PPTP application proxy initialization.
  */
-int ippr_pptp_init()
+void
+ipf_p_pptp_main_load()
 {
 	bzero((char *)&pptpfr, sizeof(pptpfr));
 	pptpfr.fr_ref = 1;
-	pptpfr.fr_age[0] = ippr_pptp_gretimeout;
-	pptpfr.fr_age[1] = ippr_pptp_gretimeout;
+	pptpfr.fr_age[0] = ipf_p_pptp_gretimeout;
+	pptpfr.fr_age[1] = ipf_p_pptp_gretimeout;
 	pptpfr.fr_flags = FR_OUTQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE;
 	MUTEX_INIT(&pptpfr.fr_lock, "PPTP proxy rule lock");
 	pptp_proxy_init = 1;
-
-	return 0;
 }
 
 
-void ippr_pptp_fini()
+void
+ipf_p_pptp_main_unload()
 {
 	if (pptp_proxy_init == 1) {
 		MUTEX_DESTROY(&pptpfr.fr_lock);
@@ -82,65 +107,84 @@
  * 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;
-ap_session_t *aps;
-nat_t *nat;
+int
+ipf_p_pptp_new(arg, fin, aps, nat)
+	void *arg;
+	fr_info_t *fin;
+	ap_session_t *aps;
+	nat_t *nat;
 {
 	pptp_pxy_t *pptp;
 	ipnat_t *ipn;
+	ipnat_t *np;
+	int size;
 	ip_t *ip;
 
+	if (fin->fin_v != 4)
+		return -1;
+
 	ip = fin->fin_ip;
+	np = nat->nat_ptr;
+	size = np->in_size;
 
-	if (nat_outlookup(fin, 0, IPPROTO_GRE, nat->nat_inip,
+	if (ipf_nat_outlookup(fin, 0, IPPROTO_GRE, nat->nat_osrcip,
 			  ip->ip_dst) != NULL) {
-		if (ippr_pptp_debug > 0)
-			printf("ippr_pptp_new: GRE session %s\n",
-			       "already exists");
+		if (ipf_p_pptp_debug > 0)
+			printf("ipf_p_pptp_new: GRE session already exists\n");
 		return -1;
 	}
 
-	aps->aps_psiz = sizeof(*pptp);
-	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 %s\n",
-			       "failed");
+	KMALLOC(pptp, pptp_pxy_t *);
+	if (pptp == NULL) {
+		if (ipf_p_pptp_debug > 0)
+			printf("ipf_p_pptp_new: malloc for aps_data failed\n");
 		return -1;
 	}
+	KMALLOCS(ipn, ipnat_t *, size);
+	if (ipn == NULL) {
+		KFREE(pptp);
+		return -1;
+	}
 
+	aps->aps_data = pptp;
+	aps->aps_psiz = sizeof(*pptp);
+	bzero((char *)pptp, sizeof(*pptp));
+	bzero((char *)ipn, size);
+	pptp->pptp_rule = ipn;
+
 	/*
 	 * Create NAT rule against which the tunnel/transport mapping is
 	 * created.  This is required because the current NAT rule does not
 	 * describe GRE but TCP instead.
 	 */
-	pptp = aps->aps_data;
-	bzero((char *)pptp, sizeof(*pptp));
-	ipn = &pptp->pptp_rule;
+	ipn->in_size = size;
 	ipn->in_ifps[0] = fin->fin_ifp;
 	ipn->in_apr = NULL;
 	ipn->in_use = 1;
 	ipn->in_hits = 1;
 	ipn->in_ippip = 1;
-	if (nat->nat_dir == NAT_OUTBOUND) {
-		ipn->in_nip = ntohl(nat->nat_outip.s_addr);
-		ipn->in_outip = fin->fin_saddr;
-		ipn->in_redir = NAT_MAP;
-	} else if (nat->nat_dir == NAT_INBOUND) {
-		ipn->in_nip = 0;
-		ipn->in_outip = nat->nat_outip.s_addr;
-		ipn->in_redir = NAT_REDIRECT;
-	}
-	ipn->in_inip = nat->nat_inip.s_addr;
-	ipn->in_inmsk = 0xffffffff;
-	ipn->in_outmsk = 0xffffffff;
-	ipn->in_srcip = fin->fin_saddr;
-	ipn->in_srcmsk = 0xffffffff;
-	bcopy(nat->nat_ptr->in_ifnames[0], ipn->in_ifnames[0],
-	      sizeof(ipn->in_ifnames[0]));
-	ipn->in_p = IPPROTO_GRE;
+	ipn->in_snip = ntohl(nat->nat_nsrcaddr);
+	ipn->in_nsrcaddr = fin->fin_saddr;
+	ipn->in_dnip = ntohl(nat->nat_ndstaddr);
+	ipn->in_ndstaddr = nat->nat_ndstaddr;
+	ipn->in_redir = np->in_redir;
+	ipn->in_osrcaddr = nat->nat_osrcaddr;
+	ipn->in_odstaddr = nat->nat_odstaddr;
+	ipn->in_osrcmsk = 0xffffffff;
+	ipn->in_nsrcmsk = 0xffffffff;
+	ipn->in_odstmsk = 0xffffffff;
+	ipn->in_ndstmsk = 0xffffffff;
+	ipn->in_flags = (np->in_flags | IPN_PROXYRULE);
+	MUTEX_INIT(&ipn->in_lock, "pptp proxy NAT rule");
 
+	ipn->in_namelen = np->in_namelen;
+	bcopy(np->in_names, ipn->in_ifnames, ipn->in_namelen);
+	ipn->in_ifnames[0] = np->in_ifnames[0];
+	ipn->in_ifnames[1] = np->in_ifnames[1];
+
+	ipn->in_pr[0] = IPPROTO_GRE;
+	ipn->in_pr[1] = IPPROTO_GRE;
+
 	pptp->pptp_side[0].pptps_wptr = pptp->pptp_side[0].pptps_buffer;
 	pptp->pptp_side[1].pptps_wptr = pptp->pptp_side[1].pptps_buffer;
 	return 0;
@@ -147,11 +191,13 @@
 }
 
 
-void ippr_pptp_donatstate(fin, nat, pptp)
-fr_info_t *fin;
-nat_t *nat;
-pptp_pxy_t *pptp;
+void
+ipf_p_pptp_donatstate(fin, nat, pptp)
+	fr_info_t *fin;
+	nat_t *nat;
+	pptp_pxy_t *pptp;
 {
+	ipf_main_softc_t *softc = fin->fin_main_soft;
 	fr_info_t fi;
 	grehdr_t gre;
 	nat_t *nat2;
@@ -165,8 +211,6 @@
 	if ((nat2 == NULL) || (pptp->pptp_state == NULL)) {
 		bcopy((char *)fin, (char *)&fi, sizeof(fi));
 		bzero((char *)&gre, sizeof(gre));
-		fi.fin_state = NULL;
-		fi.fin_nat = NULL;
 		fi.fin_fi.fi_p = IPPROTO_GRE;
 		fi.fin_fr = &pptpfr;
 		if ((nat->nat_dir == NAT_OUTBOUND && fin->fin_out) ||
@@ -183,13 +227,9 @@
 		fi.fin_flx |= FI_IGNORE;
 		fi.fin_dp = &gre;
 		gre.gr_flags = htons(1 << 13);
-		if (fin->fin_out && nat->nat_dir == NAT_INBOUND) {
-			fi.fin_fi.fi_saddr = fin->fin_fi.fi_daddr;
-			fi.fin_fi.fi_daddr = nat->nat_outip.s_addr;
-		} else if (!fin->fin_out && nat->nat_dir == NAT_OUTBOUND) {
-			fi.fin_fi.fi_saddr = nat->nat_inip.s_addr;
-			fi.fin_fi.fi_daddr = fin->fin_fi.fi_saddr;
-		}
+
+		fi.fin_fi.fi_saddr = nat->nat_osrcaddr;
+		fi.fin_fi.fi_daddr = nat->nat_odstaddr;
 	}
 
 	/*
@@ -196,34 +236,38 @@
 	 * Update NAT timeout/create NAT if missing.
 	 */
 	if (nat2 != NULL)
-		fr_queueback(&nat2->nat_tqe);
+		ipf_queueback(softc->ipf_ticks, &nat2->nat_tqe);
 	else {
-		nat2 = nat_new(&fi, &pptp->pptp_rule, &pptp->pptp_nat,
-			       NAT_SLAVE, nat->nat_dir);
-		pptp->pptp_nat = nat2;
+#ifdef USE_MUTEXES
+		ipf_nat_softc_t *softn = softc->ipf_nat_soft;
+#endif
+
+		MUTEX_ENTER(&softn->ipf_nat_new);
+		nat2 = ipf_nat_add(&fi, pptp->pptp_rule, &pptp->pptp_nat,
+				   NAT_SLAVE, nat->nat_dir);
+		MUTEX_EXIT(&softn->ipf_nat_new);
 		if (nat2 != NULL) {
-			(void) nat_proto(&fi, nat2, 0);
-			nat_update(&fi, nat2, nat2->nat_ptr);
+			(void) ipf_nat_proto(&fi, nat2, 0);
+			MUTEX_ENTER(&nat2->nat_lock);
+			ipf_nat_update(&fi, nat2);
+			MUTEX_EXIT(&nat2->nat_lock);
 		}
 	}
 
-	READ_ENTER(&ipf_state);
+	READ_ENTER(&softc->ipf_state);
 	if (pptp->pptp_state != NULL) {
-		fr_queueback(&pptp->pptp_state->is_sti);
-		RWLOCK_EXIT(&ipf_state);
+		ipf_queueback(softc->ipf_ticks, &pptp->pptp_state->is_sti);
+		RWLOCK_EXIT(&softc->ipf_state);
 	} else {
-		RWLOCK_EXIT(&ipf_state);
+		RWLOCK_EXIT(&softc->ipf_state);
 		if (nat2 != NULL) {
 			if (nat->nat_dir == NAT_INBOUND)
-				fi.fin_fi.fi_daddr = nat2->nat_inip.s_addr;
+				fi.fin_fi.fi_daddr = nat2->nat_ndstaddr;
 			else
-				fi.fin_fi.fi_saddr = nat2->nat_inip.s_addr;
+				fi.fin_fi.fi_saddr = nat2->nat_osrcaddr;
 		}
 		fi.fin_ifp = NULL;
-		pptp->pptp_state = fr_addstate(&fi, &pptp->pptp_state,
-					       0);
-		if (fi.fin_state != NULL)
-			fr_statederef((ipstate_t **)&fi.fin_state);
+		(void) ipf_state_add(softc, &fi, &pptp->pptp_state, 0);
 	}
 	ip->ip_p = p;
 	return;
@@ -235,13 +279,14 @@
  * build it up completely (fits in our buffer) then pass it off to the message
  * parsing function.
  */
-int ippr_pptp_nextmessage(fin, nat, pptp, rev)
-fr_info_t *fin;
-nat_t *nat;
-pptp_pxy_t *pptp;
-int rev;
+int
+ipf_p_pptp_nextmessage(fin, nat, pptp, rev)
+	fr_info_t *fin;
+	nat_t *nat;
+	pptp_pxy_t *pptp;
+	int rev;
 {
-	static const char *funcname = "ippr_pptp_nextmessage";
+	static const char *funcname = "ipf_p_pptp_nextmessage";
 	pptp_side_t *pptps;
 	u_32_t start, end;
 	pptp_hdr_t *hdr;
@@ -271,7 +316,7 @@
 		return 0;
 
 	if (pptps->pptps_next != start) {
-		if (ippr_pptp_debug > 5)
+		if (ipf_p_pptp_debug > 5)
 			printf("%s: next (%x) != start (%x)\n", funcname,
 				pptps->pptps_next, start);
 		return -1;
@@ -296,7 +341,7 @@
 			if (pptps->pptps_bytes == 8) {
 				pptps->pptps_next += 8;
 				if (ntohl(hdr->pptph_cookie) != 0x1a2b3c4d) {
-					if (ippr_pptp_debug > 1)
+					if (ipf_p_pptp_debug > 1)
 						printf("%s: bad cookie (%x)\n",
 						       funcname,
 						       hdr->pptph_cookie);
@@ -320,7 +365,7 @@
 			 * bad data packet, anyway.
 			 */
 			if (len > sizeof(pptps->pptps_buffer)) {
-				if (ippr_pptp_debug > 3)
+				if (ipf_p_pptp_debug > 3)
 					printf("%s: message too big (%d)\n",
 					       funcname, len);
 				pptps->pptps_next = pptps->pptps_nexthdr;
@@ -341,7 +386,7 @@
 		if (pptps->pptps_len > pptps->pptps_bytes)
 			break;
 
-		ippr_pptp_message(fin, nat, pptp, pptps);
+		ipf_p_pptp_message(fin, nat, pptp, pptps);
 		pptps->pptps_wptr = pptps->pptps_buffer;
 		pptps->pptps_gothdr = 0;
 		pptps->pptps_bytes = 0;
@@ -359,11 +404,12 @@
 /*
  * handle a complete PPTP message
  */
-int ippr_pptp_message(fin, nat, pptp, pptps)
-fr_info_t *fin;
-nat_t *nat;
-pptp_pxy_t *pptp;
-pptp_side_t *pptps;
+int
+ipf_p_pptp_message(fin, nat, pptp, pptps)
+	fr_info_t *fin;
+	nat_t *nat;
+	pptp_pxy_t *pptp;
+	pptp_side_t *pptps;
 {
 	pptp_hdr_t *hdr = (pptp_hdr_t *)pptps->pptps_buffer;
 
@@ -370,7 +416,7 @@
 	switch (ntohs(hdr->pptph_type))
 	{
 	case PPTP_MSGTYPE_CTL :
-		ippr_pptp_mctl(fin, nat, pptp, pptps);
+		ipf_p_pptp_mctl(fin, nat, pptp, pptps);
 		break;
 
 	default :
@@ -383,11 +429,12 @@
 /*
  * handle a complete PPTP control message
  */
-int ippr_pptp_mctl(fin, nat, pptp, pptps)
-fr_info_t *fin;
-nat_t *nat;
-pptp_pxy_t *pptp;
-pptp_side_t *pptps;
+int
+ipf_p_pptp_mctl(fin, nat, pptp, pptps)
+	fr_info_t *fin;
+	nat_t *nat;
+	pptp_pxy_t *pptp;
+	pptp_side_t *pptps;
 {
 	u_short *buffer = (u_short *)(pptps->pptps_buffer);
 	pptp_side_t *pptpo;
@@ -432,7 +479,7 @@
 			pptps->pptps_state = PPTP_MTCTL_OUTREP;
 			pptp->pptp_call[0] = buffer[7];
 			pptp->pptp_call[1] = buffer[6];
-			ippr_pptp_donatstate(fin, nat, pptp);
+			ipf_p_pptp_donatstate(fin, nat, pptp);
 		}
 		break;
 	case PPTP_MTCTL_INREQ :
@@ -443,7 +490,7 @@
 			pptps->pptps_state = PPTP_MTCTL_INREP;
 			pptp->pptp_call[0] = buffer[7];
 			pptp->pptp_call[1] = buffer[6];
-			ippr_pptp_donatstate(fin, nat, pptp);
+			ipf_p_pptp_donatstate(fin, nat, pptp);
 		}
 		break;
 	case PPTP_MTCTL_INCONNECT :
@@ -471,10 +518,12 @@
  * For outgoing PPTP packets.  refresh timeouts for NAT & state entries, if
  * we can.  If they have disappeared, recreate them.
  */
-int ippr_pptp_inout(fin, aps, nat)
-fr_info_t *fin;
-ap_session_t *aps;
-nat_t *nat;
+int
+ipf_p_pptp_inout(arg, fin, aps, nat)
+	void *arg;
+	fr_info_t *fin;
+	ap_session_t *aps;
+	nat_t *nat;
 {
 	pptp_pxy_t *pptp;
 	tcphdr_t *tcp;
@@ -495,7 +544,7 @@
 		pptp->pptp_side[rev].pptps_next = ntohl(tcp->th_seq) + 1;
 		pptp->pptp_side[rev].pptps_nexthdr = ntohl(tcp->th_seq) + 1;
 	}
-	return ippr_pptp_nextmessage(fin, nat, (pptp_pxy_t *)aps->aps_data,
+	return ipf_p_pptp_nextmessage(fin, nat, (pptp_pxy_t *)aps->aps_data,
 				     rev);
 }
 
@@ -503,8 +552,10 @@
 /*
  * clean up after ourselves.
  */
-void ippr_pptp_del(aps)
-ap_session_t *aps;
+void
+ipf_p_pptp_del(softc, aps)
+	ipf_main_softc_t *softc;
+	ap_session_t *aps;
 {
 	pptp_pxy_t *pptp;
 
@@ -516,15 +567,15 @@
 		 * *_del() is on a callback from aps_free(), from nat_delete()
 		 */
 
-		READ_ENTER(&ipf_state);
+		READ_ENTER(&softc->ipf_state);
 		if (pptp->pptp_state != NULL) {
-			pptp->pptp_state->is_die = fr_ticks + 1;
-			pptp->pptp_state->is_me = NULL;
-			fr_queuefront(&pptp->pptp_state->is_sti);
+			ipf_state_setpending(softc, pptp->pptp_state);
 		}
-		RWLOCK_EXIT(&ipf_state);
+		RWLOCK_EXIT(&softc->ipf_state);
 
-		pptp->pptp_state = NULL;
-		pptp->pptp_nat = NULL;
+		if (pptp->pptp_nat != NULL)
+			ipf_nat_setpending(softc, pptp->pptp_nat);
+		pptp->pptp_rule->in_flags |= IPN_DELETE;
+		ipf_nat_rule_deref(softc, &pptp->pptp_rule);
 	}
 }

Modified: trunk/sys/contrib/ipfilter/netinet/ip_proxy.c
===================================================================
--- trunk/sys/contrib/ipfilter/netinet/ip_proxy.c	2018-05-28 18:55:30 UTC (rev 10138)
+++ trunk/sys/contrib/ipfilter/netinet/ip_proxy.c	2018-05-28 18:56:30 UTC (rev 10139)
@@ -1,7 +1,8 @@
-/*	$FreeBSD$	*/
+/* $MidnightBSD$ */
+/*	$FreeBSD: stable/10/sys/contrib/ipfilter/netinet/ip_proxy.c 255332 2013-09-06 23:11:19Z cy $	*/
 
 /*
- * Copyright (C) 1997-2003 by Darren Reed.
+ * Copyright (C) 2012 by Darren Reed.
  *
  * See the IPFILTER.LICENCE file for details on licencing.
  */
@@ -49,9 +50,6 @@
 #if defined(_KERNEL) && (__FreeBSD_version >= 220000)
 # include <sys/filio.h>
 # include <sys/fcntl.h>
-# if (__FreeBSD_version >= 300000) && !defined(IPFILTER_LKM)
-#  include "opt_ipfilter.h"
-# endif
 #else
 # include <sys/ioctl.h>
 #endif
@@ -63,7 +61,7 @@
 # include <sys/stream.h>
 # include <sys/kmem.h>
 #endif
-#if __FreeBSD__ > 2
+#if __FreeBSD_version >= 300000
 # include <sys/queue.h>
 #endif
 #include <net/if.h>
@@ -70,7 +68,6 @@
 #ifdef sun
 # include <net/af.h>
 #endif
-#include <net/route.h>
 #include <netinet/in.h>
 #include <netinet/in_systm.h>
 #include <netinet/ip.h>
@@ -90,9 +87,12 @@
 # include <sys/malloc.h>
 #endif
 
+/* END OF INCLUDES */
+
 #include "netinet/ip_ftp_pxy.c"
+#include "netinet/ip_tftp_pxy.c"
 #include "netinet/ip_rcmd_pxy.c"
-# include "netinet/ip_pptp_pxy.c"
+#include "netinet/ip_pptp_pxy.c"
 #if defined(_KERNEL)
 # include "netinet/ip_irc_pxy.c"
 # include "netinet/ip_raudio_pxy.c"
@@ -101,93 +101,474 @@
 #include "netinet/ip_ipsec_pxy.c"
 #include "netinet/ip_rpcb_pxy.c"
 
-/* END OF INCLUDES */
-
 #if !defined(lint)
-static const char rcsid[] = "@(#)$Id: ip_proxy.c,v 1.4 2013-01-08 01:31:40 laffer1 Exp $";
+static const char rcsid[] = "@(#)$Id$";
 #endif
 
-static int appr_fixseqack __P((fr_info_t *, ip_t *, ap_session_t *, int ));
-
 #define	AP_SESS_SIZE	53
 
-#if defined(_KERNEL)
-int		ipf_proxy_debug = 0;
-#else
-int		ipf_proxy_debug = 2;
-#endif
-ap_session_t	*ap_sess_tab[AP_SESS_SIZE];
-ap_session_t	*ap_sess_list = NULL;
-aproxy_t	*ap_proxylist = NULL;
-aproxy_t	ap_proxies[] = {
+static int ipf_proxy_fixseqack __P((fr_info_t *, ip_t *, ap_session_t *, int ));
+static aproxy_t *ipf_proxy_create_clone __P((ipf_main_softc_t *, aproxy_t *));
+
+typedef struct ipf_proxy_softc_s {
+	int		ips_proxy_debug;
+	int		ips_proxy_session_size;
+	ap_session_t	**ips_sess_tab;
+	ap_session_t	*ips_sess_list;
+	aproxy_t	*ips_proxies;
+	int		ips_init_run;
+	ipftuneable_t	*ipf_proxy_tune;
+} ipf_proxy_softc_t;
+
+static ipftuneable_t ipf_proxy_tuneables[] = {
+	{ { (void *)offsetof(ipf_proxy_softc_t, ips_proxy_debug) },
+		"proxy_debug",	0,	0x1f,
+		stsizeof(ipf_proxy_softc_t, ips_proxy_debug),
+		0,	NULL,	NULL },
+	{ { NULL },		NULL,			0,	0,
+		0,
+		0,	NULL,	NULL}
+};
+
+static	aproxy_t	*ap_proxylist = NULL;
+static	aproxy_t	ips_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, NULL },
+	{ NULL, NULL, "ftp", (char)IPPROTO_TCP, 0, 0, 0,
+	  ipf_p_ftp_main_load, ipf_p_ftp_main_unload,
+	  ipf_p_ftp_soft_create, ipf_p_ftp_soft_destroy,
+	  NULL, NULL,
+	  ipf_p_ftp_new, ipf_p_ftp_del, ipf_p_ftp_in, ipf_p_ftp_out, NULL,
+	  NULL, NULL, NULL, NULL },
 #endif
+#ifdef	IPF_TFTP_PROXY
+	{ NULL, NULL, "tftp", (char)IPPROTO_UDP, 0, 0, 0,
+	  ipf_p_tftp_main_load, ipf_p_tftp_main_unload,
+	  ipf_p_tftp_soft_create, ipf_p_tftp_soft_destroy,
+	  NULL, NULL,
+	  ipf_p_tftp_new, ipf_p_tftp_del,
+	  ipf_p_tftp_in, ipf_p_tftp_out, NULL,
+	  NULL, NULL, NULL, NULL },
+#endif
 #ifdef	IPF_IRC_PROXY
-	{ NULL, "irc", (char)IPPROTO_TCP, 0, 0, ippr_irc_init, ippr_irc_fini,
-	  ippr_irc_new, NULL, NULL, ippr_irc_out, NULL, NULL },
+	{ NULL, NULL, "irc", (char)IPPROTO_TCP, 0, 0, 0,
+	  ipf_p_irc_main_load, ipf_p_irc_main_unload,
+	  NULL, NULL,
+	  NULL, NULL,
+	  ipf_p_irc_new, NULL, NULL, ipf_p_irc_out, NULL,
+	  NULL, NULL, NULL, NULL },
 #endif
 #ifdef	IPF_RCMD_PROXY
-	{ NULL, "rcmd", (char)IPPROTO_TCP, 0, 0, ippr_rcmd_init, ippr_rcmd_fini,
-	  ippr_rcmd_new, NULL, ippr_rcmd_in, ippr_rcmd_out, NULL, NULL },
+	{ NULL, NULL, "rcmd", (char)IPPROTO_TCP, 0, 0, 0,
+	  ipf_p_rcmd_main_load, ipf_p_rcmd_main_unload,
+	  NULL, NULL,
+	  NULL, NULL,
+	  ipf_p_rcmd_new, ipf_p_rcmd_del,
+	  ipf_p_rcmd_in, ipf_p_rcmd_out, NULL,
+	  NULL, NULL, NULL, NULL },
 #endif
 #ifdef	IPF_RAUDIO_PROXY
-	{ NULL, "raudio", (char)IPPROTO_TCP, 0, 0, ippr_raudio_init, ippr_raudio_fini,
-	  ippr_raudio_new, NULL, ippr_raudio_in, ippr_raudio_out, NULL, NULL },
+	{ NULL, NULL, "raudio", (char)IPPROTO_TCP, 0, 0, 0,
+	  ipf_p_raudio_main_load, ipf_p_raudio_main_unload,
+	  NULL, NULL,
+	  NULL, NULL,
+	  ipf_p_raudio_new, NULL, ipf_p_raudio_in, ipf_p_raudio_out, NULL,
+	  NULL, NULL, NULL, NULL },
 #endif
 #ifdef	IPF_MSNRPC_PROXY
-	{ NULL, "msnrpc", (char)IPPROTO_TCP, 0, 0, ippr_msnrpc_init, ippr_msnrpc_fini,
-	  ippr_msnrpc_new, NULL, ippr_msnrpc_in, ippr_msnrpc_out, NULL, NULL },
+	{ NULL, NULL, "msnrpc", (char)IPPROTO_TCP, 0, 0, 0,
+	  ipf_p_msnrpc_init, ipf_p_msnrpc_fini,
+	  NULL, NULL,
+	  NULL, NULL,
+	  ipf_p_msnrpc_new, NULL, ipf_p_msnrpc_in, ipf_p_msnrpc_out, NULL,
+	  NULL, NULL, NULL, NULL },
 #endif
 #ifdef	IPF_NETBIOS_PROXY
-	{ NULL, "netbios", (char)IPPROTO_UDP, 0, 0, ippr_netbios_init, ippr_netbios_fini,
-	  NULL, NULL, NULL, ippr_netbios_out, NULL, NULL },
+	{ NULL, NULL, "netbios", (char)IPPROTO_UDP, 0, 0, 0,
+	  ipf_p_netbios_main_load, ipf_p_netbios_main_unload,
+	  NULL, NULL,
+	  NULL, NULL,
+	  NULL, NULL, NULL, ipf_p_netbios_out, NULL,
+	  NULL, NULL, NULL, NULL },
 #endif
 #ifdef	IPF_IPSEC_PROXY
-	{ NULL, "ipsec", (char)IPPROTO_UDP, 0, 0,
-	  ippr_ipsec_init, ippr_ipsec_fini, ippr_ipsec_new, ippr_ipsec_del,
-	  ippr_ipsec_inout, ippr_ipsec_inout, ippr_ipsec_match, NULL },
+	{ NULL, NULL, "ipsec", (char)IPPROTO_UDP, 0, 0, 0,
+	  NULL, NULL,
+	  ipf_p_ipsec_soft_create, ipf_p_ipsec_soft_destroy,
+	  ipf_p_ipsec_soft_init, ipf_p_ipsec_soft_fini,
+	  ipf_p_ipsec_new, ipf_p_ipsec_del,
+	  ipf_p_ipsec_inout, ipf_p_ipsec_inout, ipf_p_ipsec_match,
+	  NULL, NULL, NULL, NULL },
 #endif
+#ifdef	IPF_DNS_PROXY
+	{ NULL, NULL, "dns", (char)IPPROTO_UDP, 0, 0, 0,
+	  NULL, NULL,
+	  ipf_p_dns_soft_create, ipf_p_dns_soft_destroy,
+	  NULL, NULL,
+	  ipf_p_dns_new, ipf_p_ipsec_del,
+	  ipf_p_dns_inout, ipf_p_dns_inout, ipf_p_dns_match,
+	  ipf_p_dns_ctl, NULL, NULL, NULL },
+#endif
 #ifdef	IPF_PPTP_PROXY
-	{ NULL, "pptp", (char)IPPROTO_TCP, 0, 0,
-	  ippr_pptp_init, ippr_pptp_fini, ippr_pptp_new, ippr_pptp_del,
-	  ippr_pptp_inout, ippr_pptp_inout, NULL, NULL },
+	{ NULL, NULL, "pptp", (char)IPPROTO_TCP, 0, 0, 0,
+	  ipf_p_pptp_main_load, ipf_p_pptp_main_unload,
+	  NULL, NULL,
+	  NULL, NULL,
+	  ipf_p_pptp_new, ipf_p_pptp_del,
+	  ipf_p_pptp_inout, ipf_p_pptp_inout, NULL,
+	  NULL, NULL, NULL, NULL },
 #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, NULL },
-	{ NULL, "h245", (char)IPPROTO_TCP, 0, 0, NULL, NULL,
-	  ippr_h245_new, NULL, NULL, ippr_h245_out, NULL, NULL },
-#endif
 #ifdef	IPF_RPCB_PROXY
-# if 0
-	{ NULL, "rpcbt", (char)IPPROTO_TCP, 0, 0,
-	  ippr_rpcb_init, ippr_rpcb_fini, ippr_rpcb_new, ippr_rpcb_del,
-	  ippr_rpcb_in, ippr_rpcb_out, NULL, NULL },
+# ifndef _KERNEL
+	{ NULL, NULL, "rpcbt", (char)IPPROTO_TCP, 0, 0, 0,
+	  NULL, NULL,
+	  NULL, NULL,
+	  NULL, NULL,
+	  ipf_p_rpcb_new, ipf_p_rpcb_del,
+	  ipf_p_rpcb_in, ipf_p_rpcb_out, NULL,
+	  NULL, NULL, NULL, NULL },
 # endif
-	{ NULL, "rpcbu", (char)IPPROTO_UDP, 0, 0,
-	  ippr_rpcb_init, ippr_rpcb_fini, ippr_rpcb_new, ippr_rpcb_del,
-	  ippr_rpcb_in, ippr_rpcb_out, NULL, NULL },
+	{ NULL, NULL, "rpcbu", (char)IPPROTO_UDP, 0, 0, 0,
+	  ipf_p_rpcb_main_load, ipf_p_rpcb_main_unload,
+	  NULL, NULL,
+	  NULL, NULL,
+	  ipf_p_rpcb_new, ipf_p_rpcb_del,
+	  ipf_p_rpcb_in, ipf_p_rpcb_out, NULL,
+	  NULL, NULL, NULL, NULL },
 #endif
-	{ NULL, "", '\0', 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }
+	{ NULL, NULL, "", '\0', 0, 0, 0,
+	  NULL, NULL,
+	  NULL, NULL,
+	  NULL, NULL,
+	  NULL, NULL,
+	  NULL, NULL, NULL,
+	  NULL, NULL, NULL, NULL }
 };
 
-/*
- * Dynamically add a new kernel proxy.  Ensure that it is unique in the
- * collection compiled in and dynamically added.
- */
-int appr_add(ap)
-aproxy_t *ap;
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_proxy_main_load                                         */
+/* Returns:     int    - 0 == success, else failure.                        */
+/* Parameters:  Nil                                                         */
+/*                                                                          */
+/* Initialise hook for kernel application proxies.                          */
+/* Call the initialise routine for all the compiled in kernel proxies.      */
+/* ------------------------------------------------------------------------ */
+int
+ipf_proxy_main_load()
 {
+	aproxy_t *ap;
+
+	for (ap = ips_proxies; ap->apr_p; ap++) {
+		if (ap->apr_load != NULL)
+			(*ap->apr_load)();
+	}
+	return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_proxy_main_unload                                       */
+/* Returns:     int - 0 == success, else failure.                           */
+/* Parameters:  Nil                                                         */
+/*                                                                          */
+/* Unload hook for kernel application proxies.                              */
+/* Call the finialise routine for all the compiled in kernel proxies.       */
+/* ------------------------------------------------------------------------ */
+int
+ipf_proxy_main_unload()
+{
+	aproxy_t *ap;
+
+	for (ap = ips_proxies; ap->apr_p; ap++)
+		if (ap->apr_unload != NULL)
+			(*ap->apr_unload)();
+	for (ap = ap_proxylist; ap; ap = ap->apr_next)
+		if (ap->apr_unload != NULL)
+			(*ap->apr_unload)();
+
+	return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_proxy_soft_create                                       */
+/* Returns:     void *   -                                                  */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*                                                                          */
+/* Build the structure to hold all of the run time data to support proxies. */
+/* ------------------------------------------------------------------------ */
+void *
+ipf_proxy_soft_create(softc)
+	ipf_main_softc_t *softc;
+{
+	ipf_proxy_softc_t *softp;
+	aproxy_t *last;
+	aproxy_t *apn;
+	aproxy_t *ap;
+
+	KMALLOC(softp, ipf_proxy_softc_t *);
+	if (softp == NULL)
+		return softp;
+
+	bzero((char *)softp, sizeof(*softp));
+
+#if defined(_KERNEL)
+	softp->ips_proxy_debug = 0;
+#else
+	softp->ips_proxy_debug = 2;
+#endif
+	softp->ips_proxy_session_size = AP_SESS_SIZE;
+
+	softp->ipf_proxy_tune = ipf_tune_array_copy(softp,
+						    sizeof(ipf_proxy_tuneables),
+						    ipf_proxy_tuneables);
+	if (softp->ipf_proxy_tune == NULL) {
+		ipf_proxy_soft_destroy(softc, softp);
+		return NULL;
+	}
+	if (ipf_tune_array_link(softc, softp->ipf_proxy_tune) == -1) {
+		ipf_proxy_soft_destroy(softc, softp);
+		return NULL;
+	}
+
+	last = NULL;
+	for (ap = ips_proxies; ap->apr_p; ap++) {
+		apn = ipf_proxy_create_clone(softc, ap);
+		if (apn == NULL)
+			goto failed;
+		if (last != NULL)
+			last->apr_next = apn;
+		else
+			softp->ips_proxies = apn;
+		last = apn;
+	}
+	for (ap = ips_proxies; ap != NULL; ap = ap->apr_next) {
+		apn = ipf_proxy_create_clone(softc, ap);
+		if (apn == NULL)
+			goto failed;
+		if (last != NULL)
+			last->apr_next = apn;
+		else
+			softp->ips_proxies = apn;
+		last = apn;
+	}
+
+	return softp;
+failed:
+	ipf_proxy_soft_destroy(softc, softp);
+	return NULL;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_proxy_soft_create                                       */
+/* Returns:     void *   -                                                  */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              orig(I)  - pointer to proxy definition to copy              */
+/*                                                                          */
+/* This function clones a proxy definition given by orig and returns a      */
+/* a pointer to that copy.                                                  */
+/* ------------------------------------------------------------------------ */
+static aproxy_t *
+ipf_proxy_create_clone(softc, orig)
+	ipf_main_softc_t *softc;
+	aproxy_t *orig;
+{
+	aproxy_t *apn;
+
+	KMALLOC(apn, aproxy_t *);
+	if (apn == NULL)
+		return NULL;
+
+	bcopy((char *)orig, (char *)apn, sizeof(*apn));
+	apn->apr_next = NULL;
+	apn->apr_soft = NULL;
+
+	if (apn->apr_create != NULL) {
+		apn->apr_soft = (*apn->apr_create)(softc);
+		if (apn->apr_soft == NULL) {
+			KFREE(apn);
+			return NULL;
+		}
+	}
+
+	apn->apr_parent = orig;
+	orig->apr_clones++;
+
+	return apn;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_proxy_soft_create                                       */
+/* Returns:     int      - 0 == success, else failure.                      */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              arg(I)   - pointer to proxy contect data                    */
+/*                                                                          */
+/* Initialise the proxy context and walk through each of the proxies and    */
+/* call its initialisation function. This allows for proxies to do any      */
+/* local setup prior to actual use.                                         */
+/* ------------------------------------------------------------------------ */
+int
+ipf_proxy_soft_init(softc, arg)
+	ipf_main_softc_t *softc;
+	void *arg;
+{
+	ipf_proxy_softc_t *softp;
+	aproxy_t *ap;
+	u_int size;
+	int err;
+
+	softp = arg;
+	size = softp->ips_proxy_session_size * sizeof(ap_session_t *);
+
+	KMALLOCS(softp->ips_sess_tab, ap_session_t **, size);
+
+	if (softp->ips_sess_tab == NULL)
+		return -1;
+
+	bzero(softp->ips_sess_tab, size);
+
+	for (ap = softp->ips_proxies; ap != NULL; ap = ap->apr_next) {
+		if (ap->apr_init != NULL) {
+			err = (*ap->apr_init)(softc, ap->apr_soft);
+			if (err != 0)
+				return -2;
+		}
+	}
+	softp->ips_init_run = 1;
+
+	return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_proxy_soft_create                                       */
+/* Returns:     int      - 0 == success, else failure.                      */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              arg(I)   - pointer to proxy contect data                    */
+/*                                                                          */
+/* This function should always succeed. It is responsible for ensuring that */
+/* the proxy context can be safely called when ipf_proxy_soft_destroy is    */
+/* called and suring all of the proxies have similarly been instructed.     */
+/* ------------------------------------------------------------------------ */
+int
+ipf_proxy_soft_fini(softc, arg)
+	ipf_main_softc_t *softc;
+	void *arg;
+{
+	ipf_proxy_softc_t *softp = arg;
+	aproxy_t *ap;
+
+	for (ap = softp->ips_proxies; ap != NULL; ap = ap->apr_next) {
+		if (ap->apr_fini != NULL) {
+			(*ap->apr_fini)(softc, ap->apr_soft);
+		}
+	}
+
+	if (softp->ips_sess_tab != NULL) {
+		KFREES(softp->ips_sess_tab,
+		       softp->ips_proxy_session_size * sizeof(ap_session_t *));
+		softp->ips_sess_tab = NULL;
+	}
+	softp->ips_init_run = 0;
+
+	return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_proxy_soft_destroy                                      */
+/* Returns:     Nil                                                         */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              arg(I)   - pointer to proxy contect data                    */
+/*                                                                          */
+/* Free up all of the local data structures allocated during creation.      */
+/* ------------------------------------------------------------------------ */
+void
+ipf_proxy_soft_destroy(softc, arg)
+	ipf_main_softc_t *softc;
+	void *arg;
+{
+	ipf_proxy_softc_t *softp = arg;
+	aproxy_t *ap;
+
+	while ((ap = softp->ips_proxies) != NULL) {
+		softp->ips_proxies = ap->apr_next;
+		if (ap->apr_destroy != NULL)
+			(*ap->apr_destroy)(softc, ap->apr_soft);
+		ap->apr_parent->apr_clones--;
+		KFREE(ap);
+	}
+
+	if (softp->ipf_proxy_tune != NULL) {
+                ipf_tune_array_unlink(softc, softp->ipf_proxy_tune);
+                KFREES(softp->ipf_proxy_tune, sizeof(ipf_proxy_tuneables));
+                softp->ipf_proxy_tune = NULL;
+	}
+
+	KFREE(softp);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_proxy_flush                                             */
+/* Returns:     Nil                                                         */
+/* Parameters:  arg(I)   - pointer to proxy contect data                    */
+/*              how(I)   - indicates the type of flush operation            */
+/*                                                                          */
+/* Walk through all of the proxies and pass on the flush command as either  */
+/* a flush or a clear.                                                      */
+/* ------------------------------------------------------------------------ */
+void
+ipf_proxy_flush(arg, how)
+	void *arg;
+	int how;
+{
+	ipf_proxy_softc_t *softp = arg;
+	aproxy_t *ap;
+
+	switch (how)
+	{
+	case 0 :
+		for (ap = softp->ips_proxies; ap; ap = ap->apr_next)
+			if (ap->apr_flush != NULL)
+				(*ap->apr_flush)(ap, how);
+		break;
+	case 1 :
+		for (ap = softp->ips_proxies; ap; ap = ap->apr_next)
+			if (ap->apr_clear != NULL)
+				(*ap->apr_clear)(ap);
+		break;
+	default :
+		break;
+	}
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_proxy_add                                               */
+/* Returns:     int   - 0 == success, else failure.                         */
+/* Parameters:  ap(I) - pointer to proxy structure                          */
+/*                                                                          */
+/* Dynamically add a new kernel proxy.  Ensure that it is unique in the     */
+/* collection compiled in and dynamically added.                            */
+/* ------------------------------------------------------------------------ */
+int
+ipf_proxy_add(arg, ap)
+	void *arg;
+	aproxy_t *ap;
+{
+	ipf_proxy_softc_t *softp = arg;
+
 	aproxy_t *a;
 
-	for (a = ap_proxies; a->apr_p; a++)
+	for (a = ips_proxies; a->apr_p; a++)
 		if ((a->apr_p == ap->apr_p) &&
 		    !strncmp(a->apr_label, ap->apr_label,
 			     sizeof(ap->apr_label))) {
-			if (ipf_proxy_debug > 1)
-				printf("appr_add: %s/%d already present (B)\n",
+			if (softp->ips_proxy_debug & 0x01)
+				printf("ipf_proxy_add: %s/%d present (B)\n",
 				       a->apr_label, a->apr_p);
 			return -1;
 		}
@@ -196,45 +577,57 @@
 		if ((a->apr_p == ap->apr_p) &&
 		    !strncmp(a->apr_label, ap->apr_label,
 			     sizeof(ap->apr_label))) {
-			if (ipf_proxy_debug > 1)
-				printf("appr_add: %s/%d already present (D)\n",
+			if (softp->ips_proxy_debug & 0x01)
+				printf("ipf_proxy_add: %s/%d present (D)\n",
 				       a->apr_label, a->apr_p);
 			return -1;
 		}
 	ap->apr_next = ap_proxylist;
 	ap_proxylist = ap;
-	if (ap->apr_init != NULL)
-		return (*ap->apr_init)();
+	if (ap->apr_load != NULL)
+		(*ap->apr_load)();
 	return 0;
 }
 
 
-/*
- * Check to see if the proxy this control request has come through for
- * exists, and if it does and it has a control function then invoke that
- * control function.
- */
-int appr_ctl(ctl)
-ap_ctl_t *ctl;
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_proxy_ctl                                               */
+/* Returns:     int    - 0 == success, else error                           */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              arg(I)   - pointer to proxy context                         */
+/*              ctl(I)   - pointer to proxy control structure               */
+/*                                                                          */
+/* Check to see if the proxy this control request has come through for      */
+/* exists, and if it does and it has a control function then invoke that    */
+/* control function.                                                        */
+/* ------------------------------------------------------------------------ */
+int
+ipf_proxy_ctl(softc, arg, ctl)
+	ipf_main_softc_t *softc;
+	void *arg;
+	ap_ctl_t *ctl;
 {
+	ipf_proxy_softc_t *softp = arg;
 	aproxy_t *a;
 	int error;
 
-	a = appr_lookup(ctl->apc_p, ctl->apc_label);
+	a = ipf_proxy_lookup(arg, ctl->apc_p, ctl->apc_label);
 	if (a == NULL) {
-		if (ipf_proxy_debug > 1)
-			printf("appr_ctl: can't find %s/%d\n",
+		if (softp->ips_proxy_debug & 0x01)
+			printf("ipf_proxy_ctl: can't find %s/%d\n",
 				ctl->apc_label, ctl->apc_p);
+		IPFERROR(80001);
 		error = ESRCH;
 	} else if (a->apr_ctl == NULL) {
-		if (ipf_proxy_debug > 1)
-			printf("appr_ctl: no ctl function for %s/%d\n",
+		if (softp->ips_proxy_debug & 0x01)
+			printf("ipf_proxy_ctl: no ctl function for %s/%d\n",
 				ctl->apc_label, ctl->apc_p);
+		IPFERROR(80002);
 		error = ENXIO;
 	} else {
-		error = (*a->apr_ctl)(a, ctl);
-		if ((error != 0) && (ipf_proxy_debug > 1))
-			printf("appr_ctl: %s/%d ctl error %d\n",
+		error = (*a->apr_ctl)(softc, a->apr_soft, ctl);
+		if ((error != 0) && (softp->ips_proxy_debug & 0x02))
+			printf("ipf_proxy_ctl: %s/%d ctl error %d\n",
 				a->apr_label, a->apr_p, error);
 	}
 	return error;
@@ -241,44 +634,56 @@
 }
 
 
-/*
- * Delete a proxy that has been added dynamically from those available.
- * If it is in use, return 1 (do not destroy NOW), not in use 0 or -1
- * if it cannot be matched.
- */
-int appr_del(ap)
-aproxy_t *ap;
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_proxy_del                                               */
+/* Returns:     int   - 0 == success, else failure.                         */
+/* Parameters:  ap(I) - pointer to proxy structure                          */
+/*                                                                          */
+/* Delete a proxy that has been added dynamically from those available.     */
+/* If it is in use, return 1 (do not destroy NOW), not in use 0 or -1       */
+/* if it cannot be matched.                                                 */
+/* ------------------------------------------------------------------------ */
+int
+ipf_proxy_del(ap)
+	aproxy_t *ap;
 {
 	aproxy_t *a, **app;
 
-	for (app = &ap_proxylist; ((a = *app) != NULL); app = &a->apr_next)
+	for (app = &ap_proxylist; ((a = *app) != NULL); app = &a->apr_next) {
 		if (a == ap) {
 			a->apr_flags |= APR_DELETE;
-			*app = a->apr_next;
-			if (ap->apr_ref != 0) {
-				if (ipf_proxy_debug > 2)
-					printf("appr_del: orphaning %s/%d\n",
-						ap->apr_label, ap->apr_p);
-				return 1;
+			if (ap->apr_ref == 0 && ap->apr_clones == 0) {
+				*app = a->apr_next;
+				return 0;
 			}
-			return 0;
+			return 1;
 		}
-	if (ipf_proxy_debug > 1)
-		printf("appr_del: proxy %lx not found\n", (u_long)ap);
+	}
+
 	return -1;
 }
 
 
-/*
- * Return 1 if the packet is a good match against a proxy, else 0.
- */
-int appr_ok(fin, tcp, nat)
-fr_info_t *fin;
-tcphdr_t *tcp;
-ipnat_t *nat;
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_proxy_ok                                                */
+/* Returns:     int    - 1 == good match else not.                          */
+/* Parameters:  fin(I) - pointer to packet information                      */
+/*              tcp(I) - pointer to TCP/UDP header                          */
+/*              nat(I) - pointer to current NAT session                     */
+/*                                                                          */
+/* This function extends the NAT matching to ensure that a packet that has  */
+/* arrived matches the proxy information attached to the NAT rule. Notably, */
+/* if the proxy is scheduled to be deleted then packets will not match the  */
+/* rule even if the rule is still active.                                   */
+/* ------------------------------------------------------------------------ */
+int
+ipf_proxy_ok(fin, tcp, np)
+	fr_info_t *fin;
+	tcphdr_t *tcp;
+	ipnat_t *np;
 {
-	aproxy_t *apr = nat->in_apr;
-	u_short dport = nat->in_dport;
+	aproxy_t *apr = np->in_apr;
+	u_short dport = np->in_odport;
 
 	if ((apr == NULL) || (apr->apr_flags & APR_DELETE) ||
 	    (fin->fin_p != apr->apr_p))
@@ -289,14 +694,26 @@
 }
 
 
-int appr_ioctl(data, cmd, mode, ctx)
-caddr_t data;
-ioctlcmd_t cmd;
-int mode;
-void *ctx;
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_proxy_ioctl                                             */
+/* Returns:     int    - 0 == success, else error                           */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              data(I)  - pointer to ioctl data                            */
+/*              cmd(I)   - ioctl command                                    */
+/*              mode(I)  - mode bits for device                             */
+/*              ctx(I)   - pointer to context information                   */
+/*                                                                          */
+/* ------------------------------------------------------------------------ */
+int
+ipf_proxy_ioctl(softc, data, cmd, mode, ctx)
+	ipf_main_softc_t *softc;
+	caddr_t data;
+	ioctlcmd_t cmd;
+	int mode;
+	void *ctx;
 {
 	ap_ctl_t ctl;
-	u_char *ptr;
+	caddr_t ptr;
 	int error;
 
 	mode = mode;	/* LINT */
@@ -304,17 +721,19 @@
 	switch (cmd)
 	{
 	case SIOCPROXY :
-		error = BCOPYIN(data, &ctl, sizeof(ctl));
-		if (error != 0)
-			return EFAULT;
+		error = ipf_inobj(softc, data, NULL, &ctl, IPFOBJ_PROXYCTL);
+		if (error != 0) {
+			return error;
+		}
 		ptr = NULL;
 
 		if (ctl.apc_dsize > 0) {
-			KMALLOCS(ptr, u_char *, ctl.apc_dsize);
-			if (ptr == NULL)
+			KMALLOCS(ptr, caddr_t, ctl.apc_dsize);
+			if (ptr == NULL) {
+				IPFERROR(80003);
 				error = ENOMEM;
-			else {
-				error = copyinptr(ctl.apc_data, ptr,
+			} else {
+				error = copyinptr(softc, ctl.apc_data, ptr,
 						  ctl.apc_dsize);
 				if (error == 0)
 					ctl.apc_data = ptr;
@@ -325,14 +744,16 @@
 		}
 
 		if (error == 0)
-			error = appr_ctl(&ctl);
+			error = ipf_proxy_ctl(softc, softc->ipf_proxy_soft,
+					      &ctl);
 
-		if (ptr != NULL) {
+		if ((error != 0) && (ptr != NULL)) {
 			KFREES(ptr, ctl.apc_dsize);
 		}
 		break;
 
 	default :
+		IPFERROR(80004);
 		error = EINVAL;
 	}
 	return error;
@@ -339,27 +760,37 @@
 }
 
 
-/*
- * If a proxy has a match function, call that to do extended packet
- * matching.
- */
-int appr_match(fin, nat)
-fr_info_t *fin;
-nat_t *nat;
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_proxy_match                                             */
+/* Returns:     int    - 0 == success, else error                           */
+/* Parameters:  fin(I) - pointer to packet information                      */
+/*              nat(I) - pointer to current NAT session                     */
+/*                                                                          */
+/* If a proxy has a match function, call that to do extended packet         */
+/* matching. Whilst other parts of the NAT code are rather lenient when it  */
+/* comes to the quality of the packet that it will transform, the proxy     */
+/* matching is not because they need to work with data, not just headers.   */
+/* ------------------------------------------------------------------------ */
+int
+ipf_proxy_match(fin, nat)
+	fr_info_t *fin;
+	nat_t *nat;
 {
+	ipf_main_softc_t *softc = fin->fin_main_soft;
+	ipf_proxy_softc_t *softp = softc->ipf_proxy_soft;
 	aproxy_t *apr;
 	ipnat_t *ipn;
 	int result;
 
 	ipn = nat->nat_ptr;
-	if (ipf_proxy_debug > 8)
-		printf("appr_match(%lx,%lx) aps %lx ptr %lx\n",
+	if (softp->ips_proxy_debug & 0x04)
+		printf("ipf_proxy_match(%lx,%lx) aps %lx ptr %lx\n",
 			(u_long)fin, (u_long)nat, (u_long)nat->nat_aps,
 			(u_long)ipn);
 
 	if ((fin->fin_flx & (FI_SHORT|FI_BAD)) != 0) {
-		if (ipf_proxy_debug > 0)
-			printf("appr_match: flx 0x%x (BAD|SHORT)\n",
+		if (softp->ips_proxy_debug & 0x08)
+			printf("ipf_proxy_match: flx 0x%x (BAD|SHORT)\n",
 				fin->fin_flx);
 		return -1;
 	}
@@ -366,8 +797,8 @@
 
 	apr = ipn->in_apr;
 	if ((apr == NULL) || (apr->apr_flags & APR_DELETE)) {
-		if (ipf_proxy_debug > 0)
-			printf("appr_match:apr %lx apr_flags 0x%x\n",
+		if (softp->ips_proxy_debug & 0x08)
+			printf("ipf_proxy_match:apr %lx apr_flags 0x%x\n",
 				(u_long)apr, apr ? apr->apr_flags : 0);
 		return -1;
 	}
@@ -375,8 +806,8 @@
 	if (apr->apr_match != NULL) {
 		result = (*apr->apr_match)(fin, nat->nat_aps, nat);
 		if (result != 0) {
-			if (ipf_proxy_debug > 4)
-				printf("appr_match: result %d\n", result);
+			if (softp->ips_proxy_debug & 0x08)
+				printf("ipf_proxy_match: result %d\n", result);
 			return -1;
 		}
 	}
@@ -384,24 +815,32 @@
 }
 
 
-/*
- * Allocate a new application proxy structure and fill it in with the
- * relevant details.  call the init function once complete, prior to
- * returning.
- */
-int appr_new(fin, nat)
-fr_info_t *fin;
-nat_t *nat;
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_proxy_new                                               */
+/* Returns:     int    - 0 == success, else error                           */
+/* Parameters:  fin(I) - pointer to packet information                      */
+/*              nat(I) - pointer to current NAT session                     */
+/*                                                                          */
+/* Allocate a new application proxy structure and fill it in with the       */
+/* relevant details.  call the init function once complete, prior to        */
+/* returning.                                                               */
+/* ------------------------------------------------------------------------ */
+int
+ipf_proxy_new(fin, nat)
+	fr_info_t *fin;
+	nat_t *nat;
 {
+	ipf_main_softc_t *softc = fin->fin_main_soft;
+	ipf_proxy_softc_t *softp = softc->ipf_proxy_soft;
 	register ap_session_t *aps;
 	aproxy_t *apr;
 
-	if (ipf_proxy_debug > 8)
-		printf("appr_new(%lx,%lx) \n", (u_long)fin, (u_long)nat);
+	if (softp->ips_proxy_debug & 0x04)
+		printf("ipf_proxy_new(%lx,%lx) \n", (u_long)fin, (u_long)nat);
 
 	if ((nat->nat_ptr == NULL) || (nat->nat_aps != NULL)) {
-		if (ipf_proxy_debug > 0)
-			printf("appr_new: nat_ptr %lx nat_aps %lx\n",
+		if (softp->ips_proxy_debug & 0x08)
+			printf("ipf_proxy_new: nat_ptr %lx nat_aps %lx\n",
 				(u_long)nat->nat_ptr, (u_long)nat->nat_aps);
 		return -1;
 	}
@@ -410,8 +849,8 @@
 
 	if ((apr->apr_flags & APR_DELETE) ||
 	    (fin->fin_p != apr->apr_p)) {
-		if (ipf_proxy_debug > 2)
-			printf("appr_new: apr_flags 0x%x p %d/%d\n",
+		if (softp->ips_proxy_debug & 0x08)
+			printf("ipf_proxy_new: apr_flags 0x%x p %d/%d\n",
 				apr->apr_flags, fin->fin_p, apr->apr_p);
 		return -1;
 	}
@@ -418,31 +857,30 @@
 
 	KMALLOC(aps, ap_session_t *);
 	if (!aps) {
-		if (ipf_proxy_debug > 0)
-			printf("appr_new: malloc failed (%lu)\n",
+		if (softp->ips_proxy_debug & 0x08)
+			printf("ipf_proxy_new: malloc failed (%lu)\n",
 				(u_long)sizeof(ap_session_t));
 		return -1;
 	}
 
 	bzero((char *)aps, sizeof(*aps));
-	aps->aps_p = fin->fin_p;
 	aps->aps_data = NULL;
 	aps->aps_apr = apr;
 	aps->aps_psiz = 0;
 	if (apr->apr_new != NULL)
-		if ((*apr->apr_new)(fin, aps, nat) == -1) {
+		if ((*apr->apr_new)(apr->apr_soft, fin, aps, nat) == -1) {
 			if ((aps->aps_data != NULL) && (aps->aps_psiz != 0)) {
 				KFREES(aps->aps_data, aps->aps_psiz);
 			}
 			KFREE(aps);
-			if (ipf_proxy_debug > 2)
-				printf("appr_new: new(%lx) failed\n",
+			if (softp->ips_proxy_debug & 0x08)
+				printf("ipf_proxy_new: new(%lx) failed\n",
 					(u_long)apr->apr_new);
 			return -1;
 		}
 	aps->aps_nat = nat;
-	aps->aps_next = ap_sess_list;
-	ap_sess_list = aps;
+	aps->aps_next = softp->ips_sess_list;
+	softp->ips_sess_list = aps;
 	nat->nat_aps = aps;
 
 	return 0;
@@ -449,26 +887,33 @@
 }
 
 
-/*
- * Check to see if a packet should be passed through an active proxy routine
- * if one has been setup for it.  We don't need to check the checksum here if
- * IPFILTER_CKSUM is defined because if it is, a failed check causes FI_BAD
- * to be set.
- */
-int appr_check(fin, nat)
-fr_info_t *fin;
-nat_t *nat;
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_proxy_check                                             */
+/* Returns:     int - -1 == error, 0 == success                             */
+/* Parameters:  fin(I) - pointer to packet information                      */
+/*              nat(I) - pointer to current NAT session                     */
+/*                                                                          */
+/* Check to see if a packet should be passed through an active proxy        */
+/* routine if one has been setup for it.  We don't need to check the        */
+/* checksum here if IPFILTER_CKSUM is defined because if it is, a failed    */
+/* check causes FI_BAD to be set.                                           */
+/* ------------------------------------------------------------------------ */
+int
+ipf_proxy_check(fin, nat)
+	fr_info_t *fin;
+	nat_t *nat;
 {
-#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6)
-# if defined(ICK_VALID)
+	ipf_main_softc_t *softc = fin->fin_main_soft;
+	ipf_proxy_softc_t *softp = softc->ipf_proxy_soft;
+#if SOLARIS && defined(_KERNEL) && defined(ICK_VALID)
 	mb_t *m;
-# endif
-	int dosum = 1;
 #endif
 	tcphdr_t *tcp = NULL;
 	udphdr_t *udp = NULL;
 	ap_session_t *aps;
 	aproxy_t *apr;
+	short adjlen;
+	int dosum;
 	ip_t *ip;
 	short rv;
 	int err;
@@ -477,24 +922,25 @@
 #endif
 
 	if (fin->fin_flx & FI_BAD) {
-		if (ipf_proxy_debug > 0)
-			printf("appr_check: flx 0x%x (BAD)\n", fin->fin_flx);
+		if (softp->ips_proxy_debug & 0x08)
+			printf("ipf_proxy_check: flx 0x%x (BAD)\n",
+			       fin->fin_flx);
 		return -1;
 	}
 
 #ifndef IPFILTER_CKSUM
-	if ((fin->fin_out == 0) && (fr_checkl4sum(fin) == -1)) {
-		if (ipf_proxy_debug > 0)
-			printf("appr_check: l4 checksum failure %d\n",
+	if ((fin->fin_out == 0) && (ipf_checkl4sum(fin) == -1)) {
+		if (softp->ips_proxy_debug & 0x08)
+			printf("ipf_proxy_check: l4 checksum failure %d\n",
 				fin->fin_p);
 		if (fin->fin_p == IPPROTO_TCP)
-			frstats[fin->fin_out].fr_tcpbad++;
+			softc->ipf_stats[fin->fin_out].fr_tcpbad++;
 		return -1;
 	}
 #endif
 
 	aps = nat->nat_aps;
-	if ((aps != NULL) && (aps->aps_p == fin->fin_p)) {
+	if (aps != NULL) {
 		/*
 		 * If there is data in this packet to be proxied then try and
 		 * get it all into the one buffer, else drop it.
@@ -501,31 +947,29 @@
 		 */
 #if defined(MENTAT) || defined(HAVE_M_PULLDOWN)
 		if ((fin->fin_dlen > 0) && !(fin->fin_flx & FI_COALESCE))
-			if (fr_coalesce(fin) == -1) {
-				if (ipf_proxy_debug > 0)
-					printf("appr_check: fr_coalesce failed %x\n", fin->fin_flx);
+			if (ipf_coalesce(fin) == -1) {
+				if (softp->ips_proxy_debug & 0x08)
+					printf("ipf_proxy_check: %s %x\n",
+					       "coalesce failed", fin->fin_flx);
 				return -1;
 			}
 #endif
 		ip = fin->fin_ip;
+		if (fin->fin_cksum > FI_CK_SUMOK)
+			dosum = 0;
+		else
+			dosum = 1;
 
 		switch (fin->fin_p)
 		{
 		case IPPROTO_TCP :
 			tcp = (tcphdr_t *)fin->fin_dp;
-
-#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) && defined(ICK_VALID)
+#if SOLARIS && defined(_KERNEL) && defined(ICK_VALID)
 			m = fin->fin_qfm;
 			if (dohwcksum && (m->b_ick_flag == ICK_VALID))
 				dosum = 0;
 #endif
-			/*
-			 * Don't bother the proxy with these...or in fact,
-			 * should we free up proxy stuff when seen?
-			 */
-			if ((fin->fin_tcpf & TH_RST) != 0)
-				break;
-			/*FALLTHROUGH*/
+			break;
 		case IPPROTO_UDP :
 			udp = (udphdr_t *)fin->fin_dp;
 			break;
@@ -537,22 +981,24 @@
 		err = 0;
 		if (fin->fin_out != 0) {
 			if (apr->apr_outpkt != NULL)
-				err = (*apr->apr_outpkt)(fin, aps, nat);
+				err = (*apr->apr_outpkt)(apr->apr_soft, fin,
+							 aps, nat);
 		} else {
 			if (apr->apr_inpkt != NULL)
-				err = (*apr->apr_inpkt)(fin, aps, nat);
+				err = (*apr->apr_inpkt)(apr->apr_soft, fin,
+							aps, nat);
 		}
 
 		rv = APR_EXIT(err);
-		if (((ipf_proxy_debug > 0) && (rv != 0)) ||
-		    (ipf_proxy_debug > 8))
-			printf("appr_check: out %d err %x rv %d\n",
+		if (((softp->ips_proxy_debug & 0x08) && (rv != 0)) ||
+		    (softp->ips_proxy_debug & 0x04))
+			printf("ipf_proxy_check: out %d err %x rv %d\n",
 				fin->fin_out, err, rv);
 		if (rv == 1)
 			return -1;
 
 		if (rv == 2) {
-			appr_free(apr);
+			ipf_proxy_deref(apr);
 			nat->nat_aps = NULL;
 			return -1;
 		}
@@ -562,16 +1008,17 @@
 		 * so we need to recalculate the header checksums for the
 		 * packet.
 		 */
+		adjlen = APR_INC(err);
 #if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi)
-		if (err != 0) {
-			short adjlen = err & 0xffff;
-
-			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);
-		}
+		s1 = LONG_SUM(fin->fin_plen - adjlen);
+		s2 = LONG_SUM(fin->fin_plen);
+		CALC_SUMD(s1, s2, sd);
+		if ((err != 0) && (fin->fin_cksum < FI_CK_L4PART) &&
+		    fin->fin_v == 4)
+			ipf_fix_outcksum(0, &ip->ip_sum, sd, 0);
 #endif
+		if (fin->fin_flx & FI_DOCKSUM)
+			dosum = 1;
 
 		/*
 		 * For TCP packets, we may need to adjust the sequence and
@@ -583,28 +1030,24 @@
 		 * changed or not.
 		 */
 		if (tcp != NULL) {
-			err = appr_fixseqack(fin, ip, aps, APR_INC(err));
-#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6)
-			if (dosum)
-				tcp->th_sum = fr_cksum(fin->fin_qfm, ip,
-						       IPPROTO_TCP, tcp,
-						       fin->fin_plen);
-#else
-			tcp->th_sum = fr_cksum(fin->fin_m, ip,
-					       IPPROTO_TCP, tcp,
-					       fin->fin_plen);
-#endif
+			err = ipf_proxy_fixseqack(fin, ip, aps, adjlen);
+			if (fin->fin_cksum == FI_CK_L4PART) {
+				u_short sum = ntohs(tcp->th_sum);
+				sum += adjlen;
+				tcp->th_sum = htons(sum);
+			} else if (fin->fin_cksum < FI_CK_L4PART) {
+				tcp->th_sum = fr_cksum(fin, ip,
+						       IPPROTO_TCP, tcp);
+			}
 		} 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,
-						       fin->fin_plen);
-#else
-			udp->uh_sum = fr_cksum(fin->fin_m, ip,
-					       IPPROTO_UDP, udp,
-					       fin->fin_plen);
-#endif
+			if (fin->fin_cksum == FI_CK_L4PART) {
+				u_short sum = ntohs(udp->uh_sum);
+				sum += adjlen;
+				udp->uh_sum = htons(sum);
+			} else if (dosum) {
+				udp->uh_sum = fr_cksum(fin, ip,
+						       IPPROTO_UDP, udp);
+			}
 		}
 		aps->aps_bytes += fin->fin_plen;
 		aps->aps_pkts++;
@@ -614,19 +1057,28 @@
 }
 
 
-/*
- * Search for an proxy by the protocol it is being used with and its name.
- */
-aproxy_t *appr_lookup(pr, name)
-u_int pr;
-char *name;
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_proxy_lookup                                            */
+/* Returns:     int - -1 == error, 0 == success                             */
+/* Parameters:  arg(I)  - pointer to proxy context information              */
+/*              pr(I)   - protocol number for proxy                         */
+/*              name(I) - proxy name                                        */
+/*                                                                          */
+/* Search for an proxy by the protocol it is being used with and its name.  */
+/* ------------------------------------------------------------------------ */
+aproxy_t *
+ipf_proxy_lookup(arg, pr, name)
+	void *arg;
+	u_int pr;
+	char *name;
 {
+	ipf_proxy_softc_t *softp = arg;
 	aproxy_t *ap;
 
-	if (ipf_proxy_debug > 8)
-		printf("appr_lookup(%d,%s)\n", pr, name);
+	if (softp->ips_proxy_debug & 0x04)
+		printf("ipf_proxy_lookup(%d,%s)\n", pr, name);
 
-	for (ap = ap_proxies; ap->apr_p; ap++)
+	for (ap = softp->ips_proxies; ap != NULL; ap = ap->apr_next)
 		if ((ap->apr_p == pr) &&
 		    !strncmp(name, ap->apr_label, sizeof(ap->apr_label))) {
 			ap->apr_ref++;
@@ -633,28 +1085,43 @@
 			return ap;
 		}
 
-	for (ap = ap_proxylist; ap; ap = ap->apr_next)
-		if ((ap->apr_p == pr) &&
-		    !strncmp(name, ap->apr_label, sizeof(ap->apr_label))) {
-			ap->apr_ref++;
-			return ap;
-		}
-	if (ipf_proxy_debug > 2)
-		printf("appr_lookup: failed for %d/%s\n", pr, name);
+	if (softp->ips_proxy_debug & 0x08)
+		printf("ipf_proxy_lookup: failed for %d/%s\n", pr, name);
 	return NULL;
 }
 
 
-void appr_free(ap)
-aproxy_t *ap;
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_proxy_deref                                             */
+/* Returns:     Nil                                                         */
+/* Parameters:  ap(I) - pointer to proxy structure                          */
+/*                                                                          */
+/* Drop the reference counter associated with the proxy.                    */
+/* ------------------------------------------------------------------------ */
+void
+ipf_proxy_deref(ap)
+	aproxy_t *ap;
 {
 	ap->apr_ref--;
 }
 
 
-void aps_free(aps)
-ap_session_t *aps;
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_proxy_free                                              */
+/* Returns:     Nil                                                         */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              aps(I)   - pointer to current proxy session                 */
+/* Locks Held:  ipf_nat_new, ipf_nat(W)                                     */
+/*                                                                          */
+/* Free up proxy session information allocated to be used with a NAT        */
+/* session.                                                                 */
+/* ------------------------------------------------------------------------ */
+void
+ipf_proxy_free(softc, aps)
+	ipf_main_softc_t *softc;
+	ap_session_t *aps;
 {
+	ipf_proxy_softc_t *softp = softc->ipf_proxy_soft;
 	ap_session_t *a, **ap;
 	aproxy_t *apr;
 
@@ -661,7 +1128,7 @@
 	if (!aps)
 		return;
 
-	for (ap = &ap_sess_list; ((a = *ap) != NULL); ap = &a->aps_next)
+	for (ap = &softp->ips_sess_list; ((a = *ap) != NULL); ap = &a->aps_next)
 		if (a == aps) {
 			*ap = a->aps_next;
 			break;
@@ -669,7 +1136,7 @@
 
 	apr = aps->aps_apr;
 	if ((apr != NULL) && (apr->apr_del != NULL))
-		(*apr->apr_del)(aps);
+		(*apr->apr_del)(softc, aps);
 
 	if ((aps->aps_data != NULL) && (aps->aps_psiz != 0))
 		KFREES(aps->aps_data, aps->aps_psiz);
@@ -677,15 +1144,28 @@
 }
 
 
-/*
- * returns 2 if ack or seq number in TCP header is changed, returns 0 otherwise
- */
-static int appr_fixseqack(fin, ip, aps, inc)
-fr_info_t *fin;
-ip_t *ip;
-ap_session_t *aps;
-int inc;
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_proxy_fixseqack                                         */
+/* Returns:     int    - 2 if TCP ack/seq is changed, else 0                */
+/* Parameters:  fin(I) - pointer to packet information                      */
+/*              ip(I)  - pointer to IP header                               */
+/*              nat(I) - pointer to current NAT session                     */
+/*              inc(I) - delta to apply to TCP sequence numbering           */
+/*                                                                          */
+/* Adjust the TCP sequence/acknowledge numbers in the TCP header based on   */
+/* whether or not the new header is past the point at which an adjustment   */
+/* occurred. This might happen because of (say) an FTP string being changed */
+/* and the new string being a different length to the old.                  */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_proxy_fixseqack(fin, ip, aps, inc)
+	fr_info_t *fin;
+	ip_t *ip;
+	ap_session_t *aps;
+	int inc;
 {
+	ipf_main_softc_t *softc = fin->fin_main_soft;
+	ipf_proxy_softc_t *softp = softc->ipf_proxy_soft;
 	int sel, ch = 0, out, nlen;
 	u_32_t seq1, seq2;
 	tcphdr_t *tcp;
@@ -694,10 +1174,10 @@
 	tcp = (tcphdr_t *)fin->fin_dp;
 	out = fin->fin_out;
 	/*
-	 * fin->fin_plen has already been adjusted by 'inc'.
+	 * ip_len has already been adjusted by 'inc'.
 	 */
-	nlen = fin->fin_plen;
-	nlen -= (IP_HL(ip) << 2) + (TCP_OFF(tcp) << 2);
+	nlen = fin->fin_dlen;
+	nlen -= (TCP_OFF(tcp) << 2);
 
 	inc2 = inc;
 	inc = (int)inc2;
@@ -709,7 +1189,7 @@
 		/* switch to other set ? */
 		if ((aps->aps_seqmin[!sel] > aps->aps_seqmin[sel]) &&
 		    (seq1 > aps->aps_seqmin[!sel])) {
-			if (ipf_proxy_debug > 7)
+			if (softp->ips_proxy_debug & 0x10)
 				printf("proxy out switch set seq %d -> %d %x > %x\n",
 					sel, !sel, seq1,
 					aps->aps_seqmin[!sel]);
@@ -729,7 +1209,7 @@
 		if (inc && (seq1 > aps->aps_seqmin[!sel])) {
 			aps->aps_seqmin[sel] = seq1 + nlen - 1;
 			aps->aps_seqoff[sel] = aps->aps_seqoff[sel] + inc;
-			if (ipf_proxy_debug > 7)
+			if (softp->ips_proxy_debug & 0x10)
 				printf("proxy seq set %d at %x to %d + %d\n",
 					sel, aps->aps_seqmin[sel],
 					aps->aps_seqoff[sel], inc);
@@ -743,7 +1223,7 @@
 		/* switch to other set ? */
 		if ((aps->aps_ackmin[!sel] > aps->aps_ackmin[sel]) &&
 		    (seq1 > aps->aps_ackmin[!sel])) {
-			if (ipf_proxy_debug > 7)
+			if (softp->ips_proxy_debug & 0x10)
 				printf("proxy out switch set ack %d -> %d %x > %x\n",
 					sel, !sel, seq1,
 					aps->aps_ackmin[!sel]);
@@ -762,7 +1242,7 @@
 		/* switch to other set ? */
 		if ((aps->aps_ackmin[!sel] > aps->aps_ackmin[sel]) &&
 		    (seq1 > aps->aps_ackmin[!sel])) {
-			if (ipf_proxy_debug > 7)
+			if (softp->ips_proxy_debug & 0x10)
 				printf("proxy in switch set ack %d -> %d %x > %x\n",
 					sel, !sel, seq1, aps->aps_ackmin[!sel]);
 			sel = aps->aps_sel[out] = !sel;
@@ -782,7 +1262,7 @@
 			aps->aps_ackmin[!sel] = seq1 + nlen - 1;
 			aps->aps_ackoff[!sel] = aps->aps_ackoff[sel] + inc;
 
-			if (ipf_proxy_debug > 7)
+			if (softp->ips_proxy_debug & 0x10)
 				printf("proxy ack set %d at %x to %d + %d\n",
 					!sel, aps->aps_seqmin[!sel],
 					aps->aps_seqoff[sel], inc);
@@ -796,7 +1276,7 @@
 		/* switch to other set ? */
 		if ((aps->aps_seqmin[!sel] > aps->aps_seqmin[sel]) &&
 		    (seq1 > aps->aps_seqmin[!sel])) {
-			if (ipf_proxy_debug > 7)
+			if (softp->ips_proxy_debug & 0x10)
 				printf("proxy in switch set seq %d -> %d %x > %x\n",
 					sel, !sel, seq1, aps->aps_seqmin[!sel]);
 			sel = aps->aps_sel[1 - out] = !sel;
@@ -803,7 +1283,7 @@
 		}
 
 		if (aps->aps_seqoff[sel] != 0) {
-			if (ipf_proxy_debug > 7)
+			if (softp->ips_proxy_debug & 0x10)
 				printf("sel %d seqoff %d seq1 %x seqmin %x\n",
 					sel, aps->aps_seqoff[sel], seq1,
 					aps->aps_seqmin[sel]);
@@ -815,45 +1295,175 @@
 		}
 	}
 
-	if (ipf_proxy_debug > 8)
-		printf("appr_fixseqack: seq %x ack %x\n",
+	if (softp->ips_proxy_debug & 0x10)
+		printf("ipf_proxy_fixseqack: seq %u ack %u\n",
 			(u_32_t)ntohl(tcp->th_seq), (u_32_t)ntohl(tcp->th_ack));
 	return ch ? 2 : 0;
 }
 
 
-/*
- * Initialise hook for kernel application proxies.
- * Call the initialise routine for all the compiled in kernel proxies.
- */
-int appr_init()
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_proxy_rule_rev                                          */
+/* Returns:     ipnat_t * - NULL = failure, else pointer to new rule        */
+/* Parameters:  nat(I) - pointer to NAT session to create rule from         */
+/*                                                                          */
+/* This function creates a NAT rule that is based upon the reverse packet   */
+/* flow associated with this NAT session. Thus if this NAT session was      */
+/* created with a map rule then this function will create a rdr rule.       */ 
+/* Only address fields and network interfaces are assigned in this function */
+/* and the address fields are formed such that an exact is required. If the */
+/* original rule had a netmask, that is not replicated here not is it       */
+/* desired. The ultimate goal here is to create a NAT rule to support a NAT */
+/* session being created that does not have a user configured rule. The     */
+/* classic example is supporting the FTP proxy, where a data channel needs  */
+/* to be setup, based on the addresses used for the control connection. In  */
+/* that case, this function is used to handle creating NAT rules to support */
+/* data connections with the PORT and EPRT commands.                        */
+/* ------------------------------------------------------------------------ */ 
+ipnat_t *
+ipf_proxy_rule_rev(nat)
+	nat_t *nat;
 {
-	aproxy_t *ap;
-	int err = 0;
+	ipnat_t *old;
+	ipnat_t *ipn;
+	int size;
 
-	for (ap = ap_proxies; ap->apr_p; ap++) {
-		if (ap->apr_init != NULL) {
-			err = (*ap->apr_init)();
-			if (err != 0)
-				break;
+	old = nat->nat_ptr;
+	size = old->in_size;
+
+	KMALLOCS(ipn, ipnat_t *, size);
+	if (ipn == NULL)
+		return NULL;
+
+	bzero((char *)ipn, size);
+
+	ipn->in_use = 1;
+	ipn->in_hits = 1;
+	ipn->in_ippip = 1;
+	ipn->in_apr = NULL;
+	ipn->in_size = size;
+	ipn->in_pr[0] = old->in_pr[1];
+	ipn->in_pr[1] = old->in_pr[0];
+	ipn->in_v[0] = old->in_v[1];
+	ipn->in_v[1] = old->in_v[0];
+	ipn->in_ifps[0] = old->in_ifps[1];
+	ipn->in_ifps[1] = old->in_ifps[0];
+	ipn->in_flags = (old->in_flags | IPN_PROXYRULE);
+
+	ipn->in_nsrcip6 = nat->nat_odst6;
+	ipn->in_osrcip6 = nat->nat_ndst6;
+
+	if ((old->in_redir & NAT_REDIRECT) != 0) {
+		ipn->in_redir = NAT_MAP;
+		if (ipn->in_v[0] == 4) {
+			ipn->in_snip = ntohl(nat->nat_odstaddr);
+			ipn->in_dnip = ntohl(nat->nat_nsrcaddr);
+		} else {
+#ifdef USE_INET6
+			ipn->in_snip6 = nat->nat_odst6;
+			ipn->in_dnip6 = nat->nat_nsrc6;
+#endif
 		}
+		ipn->in_ndstip6 = nat->nat_nsrc6;
+		ipn->in_odstip6 = nat->nat_osrc6;
+	} else {
+		ipn->in_redir = NAT_REDIRECT;
+		if (ipn->in_v[0] == 4) {
+			ipn->in_snip = ntohl(nat->nat_odstaddr);
+			ipn->in_dnip = ntohl(nat->nat_osrcaddr);
+		} else {
+#ifdef USE_INET6
+			ipn->in_snip6 = nat->nat_odst6;
+			ipn->in_dnip6 = nat->nat_osrc6;
+#endif
+		}
+		ipn->in_ndstip6 = nat->nat_osrc6;
+		ipn->in_odstip6 = nat->nat_nsrc6;
 	}
-	return err;
+
+	IP6_SETONES(&ipn->in_osrcmsk6);
+	IP6_SETONES(&ipn->in_nsrcmsk6);
+	IP6_SETONES(&ipn->in_odstmsk6);
+	IP6_SETONES(&ipn->in_ndstmsk6);
+
+	ipn->in_namelen = old->in_namelen;
+	ipn->in_ifnames[0] = old->in_ifnames[1];
+	ipn->in_ifnames[1] = old->in_ifnames[0];
+	bcopy(old->in_names, ipn->in_names, ipn->in_namelen);
+	MUTEX_INIT(&ipn->in_lock, "ipnat rev rule lock");
+
+	return ipn;
 }
 
 
-/*
- * Unload hook for kernel application proxies.
- * Call the finialise routine for all the compiled in kernel proxies.
- */
-void appr_unload()
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_proxy_rule_fwd                                          */
+/* Returns:     ipnat_t * - NULL = failure, else pointer to new rule        */
+/* Parameters:  nat(I) - pointer to NAT session to create rule from         */
+/*                                                                          */
+/* The purpose and rationale of this function is much the same as the above */
+/* function, ipf_proxy_rule_rev, except that a rule is created that matches */
+/* the same direction as that of the existing NAT session. Thus if this NAT */ 
+/* session was created with a map rule then this function will also create  */
+/* a data structure to represent a map rule. Whereas ipf_proxy_rule_rev is  */
+/* used to support PORT/EPRT, this function supports PASV/EPSV.             */
+/* ------------------------------------------------------------------------ */ 
+ipnat_t *
+ipf_proxy_rule_fwd(nat)
+	nat_t *nat;
 {
-	aproxy_t *ap;
+	ipnat_t *old;
+	ipnat_t *ipn;
+	int size;
 
-	for (ap = ap_proxies; ap->apr_p; ap++)
-		if (ap->apr_fini != NULL)
-			(*ap->apr_fini)();
-	for (ap = ap_proxylist; ap; ap = ap->apr_next)
-		if (ap->apr_fini != NULL)
-			(*ap->apr_fini)();
+	old = nat->nat_ptr;
+	size = old->in_size;
+
+	KMALLOCS(ipn, ipnat_t *, size);
+	if (ipn == NULL)
+		return NULL;
+
+	bzero((char *)ipn, size);
+
+	ipn->in_use = 1;
+	ipn->in_hits = 1;
+	ipn->in_ippip = 1;
+	ipn->in_apr = NULL;
+	ipn->in_size = size;
+	ipn->in_pr[0] = old->in_pr[0];
+	ipn->in_pr[1] = old->in_pr[1];
+	ipn->in_v[0] = old->in_v[0];
+	ipn->in_v[1] = old->in_v[1];
+	ipn->in_ifps[0] = nat->nat_ifps[0];
+	ipn->in_ifps[1] = nat->nat_ifps[1];
+	ipn->in_flags = (old->in_flags | IPN_PROXYRULE);
+
+	ipn->in_nsrcip6 = nat->nat_nsrc6;
+	ipn->in_osrcip6 = nat->nat_osrc6;
+	ipn->in_ndstip6 = nat->nat_ndst6;
+	ipn->in_odstip6 = nat->nat_odst6;
+	ipn->in_redir = old->in_redir;
+
+	if (ipn->in_v[0] == 4) {
+		ipn->in_snip = ntohl(nat->nat_nsrcaddr);
+		ipn->in_dnip = ntohl(nat->nat_ndstaddr);
+	} else {
+#ifdef USE_INET6
+		ipn->in_snip6 = nat->nat_nsrc6;
+		ipn->in_dnip6 = nat->nat_ndst6;
+#endif
+	}
+
+	IP6_SETONES(&ipn->in_osrcmsk6);
+	IP6_SETONES(&ipn->in_nsrcmsk6);
+	IP6_SETONES(&ipn->in_odstmsk6);
+	IP6_SETONES(&ipn->in_ndstmsk6);
+
+	ipn->in_namelen = old->in_namelen;
+	ipn->in_ifnames[0] = old->in_ifnames[0];
+	ipn->in_ifnames[1] = old->in_ifnames[1];
+	bcopy(old->in_names, ipn->in_names, ipn->in_namelen);
+	MUTEX_INIT(&ipn->in_lock, "ipnat fwd rule lock");
+
+	return ipn;
 }

Modified: trunk/sys/contrib/ipfilter/netinet/ip_proxy.h
===================================================================
--- trunk/sys/contrib/ipfilter/netinet/ip_proxy.h	2018-05-28 18:55:30 UTC (rev 10138)
+++ trunk/sys/contrib/ipfilter/netinet/ip_proxy.h	2018-05-28 18:56:30 UTC (rev 10139)
@@ -1,11 +1,12 @@
-/*	$FreeBSD$	*/
+/* $MidnightBSD$ */
+/*	$FreeBSD: stable/10/sys/contrib/ipfilter/netinet/ip_proxy.h 305138 2016-08-31 18:00:41Z dim $	*/
 
 /*
- * Copyright (C) 1997-2001 by Darren Reed.
+ * Copyright (C) 2012 by Darren Reed.
  *
  * See the IPFILTER.LICENCE file for details on licencing.
  *
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/contrib/ipfilter/netinet/ip_proxy.h 305138 2016-08-31 18:00:41Z dim $
  * Id: ip_proxy.h,v 2.31.2.2 2005/03/12 19:33:48 darrenr Exp
  */
 
@@ -12,8 +13,12 @@
 #ifndef	__IP_PROXY_H__
 #define	__IP_PROXY_H__
 
-#ifndef SOLARIS
-#define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4)))
+#ifndef	SOLARIS
+# if defined(sun) && (defined(__svr4__) || defined(__SVR4))
+#  define	SOLARIS		1
+# else
+#  define	SOLARIS		0
+# endif
 #endif
 
 #if defined(__STDC__) || defined(__GNUC__) || defined(_AIX51)
@@ -53,14 +58,11 @@
 		struct	ap_tcp	apu_tcp;
 		struct	ap_udp	apu_udp;
 	} aps_un;
-	u_int	aps_flags;
 	U_QUAD_T aps_bytes;	/* bytes sent */
 	U_QUAD_T aps_pkts;	/* packets sent */
 	void	*aps_nat;	/* pointer back to nat struct */
 	void	*aps_data;	/* private data */
-	int	aps_p;		/* protocol */
 	int	aps_psiz;	/* size of private data */
-	struct	ap_session	*aps_hnext;
 	struct	ap_session	*aps_next;
 } ap_session_t;
 
@@ -76,6 +78,7 @@
 
 typedef	struct	ap_control {
 	char	apc_label[APR_LABELLEN];
+	char	apc_config[APR_LABELLEN];
 	u_char	apc_p;
 	/*
 	 * The following fields are upto the proxy's apr_ctl routine to deal
@@ -93,21 +96,36 @@
 	size_t	apc_dsize;
 } ap_ctl_t;
 
+#define	APC_CMD_ADD	0
+#define	APC_CMD_DEL	1
 
+
 typedef	struct	aproxy	{
 	struct	aproxy	*apr_next;
+	struct	aproxy	*apr_parent;
 	char	apr_label[APR_LABELLEN];	/* Proxy label # */
-	u_char	apr_p;		/* protocol */
-	int	apr_ref;	/* +1 per rule referencing it */
+	u_char	apr_p;				/* protocol */
 	int	apr_flags;
-	int	(* apr_init) __P((void));
-	void	(* apr_fini) __P((void));
-	int	(* apr_new) __P((fr_info_t *, ap_session_t *, struct nat *));
-	void	(* apr_del) __P((ap_session_t *));
-	int	(* apr_inpkt) __P((fr_info_t *, ap_session_t *, struct nat *));
-	int	(* apr_outpkt) __P((fr_info_t *, ap_session_t *, struct nat *));
+	int	apr_ref;
+	int	apr_clones;
+	void	(* apr_load) __P((void));
+	void	(* apr_unload) __P((void));
+	void	*(* apr_create) __P((ipf_main_softc_t *));
+	void	(* apr_destroy) __P((ipf_main_softc_t *, void *));
+	int	(* apr_init) __P((ipf_main_softc_t *, void *));
+	void	(* apr_fini) __P((ipf_main_softc_t *, void *));
+	int	(* apr_new) __P((void *, fr_info_t *, ap_session_t *,
+				 struct nat *));
+	void	(* apr_del) __P((ipf_main_softc_t *, ap_session_t *));
+	int	(* apr_inpkt) __P((void *, fr_info_t *, ap_session_t *,
+				   struct nat *));
+	int	(* apr_outpkt) __P((void *, fr_info_t *, ap_session_t *,
+				    struct nat *));
 	int	(* apr_match) __P((fr_info_t *, ap_session_t *, struct nat *));
-	int	(* apr_ctl) __P((struct aproxy *, struct ap_control *));
+	int	(* apr_ctl) __P((ipf_main_softc_t *, void *, ap_ctl_t *));
+	int	(* apr_clear) __P((struct aproxy *));
+	int	(* apr_flush) __P((struct aproxy *, int));
+	void	*apr_soft;
 } aproxy_t;
 
 #define	APR_DELETE	1
@@ -116,42 +134,37 @@
 #define	APR_EXIT(x)	(((x) >> 16) & 0xffff)
 #define	APR_INC(x)	((x) & 0xffff)
 
+
+#ifdef _KERNEL
 /*
  * Generic #define's to cover missing things in the kernel
  */
-#ifndef isdigit
-#define isdigit(x)	((x) >= '0' && (x) <= '9')
-#endif
-#ifndef isupper
-#define isupper(x)	(((unsigned)(x) >= 'A') && ((unsigned)(x) <= 'Z'))
-#endif
-#ifndef islower
-#define islower(x)	(((unsigned)(x) >= 'a') && ((unsigned)(x) <= 'z'))
-#endif
-#ifndef isalpha
-#define isalpha(x)	(isupper(x) || islower(x))
-#endif
-#ifndef toupper
-#define toupper(x)	(isupper(x) ? (x) : (x) - 'a' + 'A')
-#endif
-#ifndef isspace
-#define isspace(x)	(((x) == ' ') || ((x) == '\r') || ((x) == '\n') || \
+# ifndef isdigit
+#  define isdigit(x)	((x) >= '0' && (x) <= '9')
+# endif
+# ifndef isupper
+#  define isupper(x)	(((unsigned)(x) >= 'A') && ((unsigned)(x) <= 'Z'))
+# endif
+# ifndef islower
+#  define islower(x)	(((unsigned)(x) >= 'a') && ((unsigned)(x) <= 'z'))
+# endif
+# ifndef isalpha
+#  define isalpha(x)	(isupper(x) || islower(x))
+# endif
+# ifndef toupper
+#  define toupper(x)	(isupper(x) ? (x) : (x) - 'a' + 'A')
+# endif
+# ifndef isspace
+#  define isspace(x)	(((x) == ' ') || ((x) == '\r') || ((x) == '\n') || \
 			 ((x) == '\t') || ((x) == '\b'))
-#endif
+# endif
+#endif /* _KERNEL */
 
 /*
- * This is the scratch buffer size used to hold strings from the TCP stream
- * that we may want to parse.  It's an arbitrary size, really, but it must
- * be at least as large as IPF_FTPBUFSZ.
- */ 
-#define	FTP_BUFSZ	120
-
-/*
- * This buffer, however, doesn't need to be nearly so big.  It just needs to
- * be able to squeeze in the largest command it needs to rewrite, Which ones
- * does it rewrite? EPRT, PORT, 227 replies.
+ * For the ftp proxy.
  */
-#define	IPF_FTPBUFSZ	80	/* This *MUST* be >= 53! */
+#define	FTP_BUFSZ	160
+#define	IPF_FTPBUFSZ	160
 
 typedef struct  ftpside {
 	char	*ftps_rptr;
@@ -159,8 +172,9 @@
 	void	*ftps_ifp;
 	u_32_t	ftps_seq[2];
 	u_32_t	ftps_len;
-	int	ftps_junk;	/* 2 = no cr/lf yet, 1 = cannot parse */
+	int	ftps_junk;
 	int	ftps_cmds;
+	int	ftps_cmd;
 	char	ftps_buf[FTP_BUFSZ];
 } ftpside_t;
 
@@ -167,11 +181,28 @@
 typedef struct  ftpinfo {
 	int 	  	ftp_passok;
 	int		ftp_incok;
+	void		*ftp_pendstate;
+	nat_t		*ftp_pendnat;
 	ftpside_t	ftp_side[2];
 } ftpinfo_t;
 
 
 /*
+ * IPsec proxy
+ */
+typedef u_32_t		ipsec_cookie_t[2];
+
+typedef struct ipsec_pxy {
+	ipsec_cookie_t	ipsc_icookie;
+	ipsec_cookie_t	ipsc_rcookie;
+	int		ipsc_rckset;
+	nat_t		*ipsc_nat;
+	struct ipstate	*ipsc_state;
+	ipnat_t		*ipsc_rule;
+} ipsec_pxy_t;
+
+
+/*
  * For the irc proxy.
  */
 typedef	struct	ircinfo {
@@ -187,6 +218,16 @@
 
 
 /*
+ * For the DNS "proxy"
+ */
+typedef struct dnsinfo {
+        ipfmutex_t	dnsi_lock;
+	u_short		dnsi_id;
+	char		dnsi_buffer[512];
+} dnsinfo_t;
+
+
+/*
  * Real audio proxy structure and #defines
  */
 typedef	struct	raudio_s {
@@ -231,43 +272,6 @@
 
 
 /*
- * IPSec proxy
- */
-typedef	u_32_t	ipsec_cookie_t[2];
-
-typedef struct ipsec_pxy {
-	ipsec_cookie_t	ipsc_icookie;
-	ipsec_cookie_t	ipsc_rcookie;
-	int		ipsc_rckset;
-	ipnat_t		ipsc_rule;
-	nat_t		*ipsc_nat;
-	struct ipstate	*ipsc_state;
-} ipsec_pxy_t;
-
-/*
- * PPTP proxy
- */
-typedef	struct pptp_side {
-	u_32_t		pptps_nexthdr;
-	u_32_t		pptps_next;
-	int		pptps_state;
-	int		pptps_gothdr;
-	int		pptps_len;
-	int		pptps_bytes;
-	char		*pptps_wptr;
-	char		pptps_buffer[512];
-} pptp_side_t;
-
-typedef	struct pptp_pxy {
-	ipnat_t		pptp_rule;
-	nat_t		*pptp_nat;
-	struct ipstate	*pptp_state;
-	u_short		pptp_call[2];
-	pptp_side_t	pptp_side[2];
-} pptp_pxy_t;
-
-
-/*
  * Sun RPCBIND proxy
  */
 #define RPCB_MAXMSG	888
@@ -439,24 +443,26 @@
  */
 #define XDRALIGN(x)	((((x) % 4) != 0) ? ((((x) + 3) / 4) * 4) : (x))
 
-extern	ap_session_t	*ap_sess_tab[AP_SESS_SIZE];
-extern	ap_session_t	*ap_sess_list;
-extern	aproxy_t	ap_proxies[];
-extern	int		ippr_ftp_pasvonly;
-extern	int		ipf_proxy_debug;
+extern	int	ipf_proxy_add __P((void *, aproxy_t *));
+extern	int	ipf_proxy_check __P((fr_info_t *, struct nat *));
+extern	int	ipf_proxy_ctl __P((ipf_main_softc_t *, void *, ap_ctl_t *));
+extern	int	ipf_proxy_del __P((aproxy_t *));
+extern	void	ipf_proxy_deref __P((aproxy_t *));
+extern	void	ipf_proxy_flush __P((void *, int));
+extern	int	ipf_proxy_init __P((void));
+extern	int	ipf_proxy_ioctl __P((ipf_main_softc_t *, caddr_t, ioctlcmd_t, int, void *));
+extern	aproxy_t	*ipf_proxy_lookup __P((void *, u_int, char *));
+extern	int	ipf_proxy_match __P((fr_info_t *, struct nat *));
+extern	int	ipf_proxy_new __P((fr_info_t *, struct nat *));
+extern	int	ipf_proxy_ok __P((fr_info_t *, tcphdr_t *, struct ipnat *));
+extern	void	ipf_proxy_free __P((ipf_main_softc_t *, ap_session_t *));
+extern	int	ipf_proxy_main_load __P((void));
+extern	int	ipf_proxy_main_unload __P((void));
+extern	ipnat_t	*ipf_proxy_rule_fwd __P((nat_t *));
+extern	ipnat_t	*ipf_proxy_rule_rev __P((nat_t *));
+extern	void	*ipf_proxy_soft_create __P((ipf_main_softc_t *));
+extern	void	ipf_proxy_soft_destroy __P((ipf_main_softc_t *, void *));
+extern	int	ipf_proxy_soft_init __P((ipf_main_softc_t *, void *));
+extern	int	ipf_proxy_soft_fini __P((ipf_main_softc_t *, void *));
 
-extern	int	appr_add __P((aproxy_t *));
-extern	int	appr_ctl __P((ap_ctl_t *));
-extern	int	appr_del __P((aproxy_t *));
-extern	int	appr_init __P((void));
-extern	void	appr_unload __P((void));
-extern	int	appr_ok __P((fr_info_t *, tcphdr_t *, struct ipnat *));
-extern	int	appr_match __P((fr_info_t *, struct nat *));
-extern	void	appr_free __P((aproxy_t *));
-extern	void	aps_free __P((ap_session_t *));
-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, void *));
-
 #endif /* __IP_PROXY_H__ */

Modified: trunk/sys/contrib/ipfilter/netinet/ip_raudio_pxy.c
===================================================================
--- trunk/sys/contrib/ipfilter/netinet/ip_raudio_pxy.c	2018-05-28 18:55:30 UTC (rev 10138)
+++ trunk/sys/contrib/ipfilter/netinet/ip_raudio_pxy.c	2018-05-28 18:56:30 UTC (rev 10139)
@@ -1,22 +1,22 @@
-/*	$FreeBSD$	*/
+/* $MidnightBSD$ */
+/*	$FreeBSD: stable/10/sys/contrib/ipfilter/netinet/ip_raudio_pxy.c 259073 2013-12-07 18:23:29Z peter $	*/
 
 /*
- * $FreeBSD$
- * Copyright (C) 1998-2003 by Darren Reed
+ * Copyright (C) 2012 by Darren Reed.
  *
  * See the IPFILTER.LICENCE file for details on licencing.
  *
- * $Id: ip_raudio_pxy.c,v 1.4 2013-01-08 01:31:40 laffer1 Exp $
+ * $Id: ip_raudio_pxy.c,v 1.40.2.4 2006/07/14 06:12:17 darrenr Exp $
  */
 
 #define	IPF_RAUDIO_PROXY
 
 
-int ippr_raudio_init __P((void));
-void ippr_raudio_fini __P((void));
-int ippr_raudio_new __P((fr_info_t *, ap_session_t *, nat_t *));
-int ippr_raudio_in __P((fr_info_t *, ap_session_t *, nat_t *));
-int ippr_raudio_out __P((fr_info_t *, ap_session_t *, nat_t *));
+void ipf_p_raudio_main_load __P((void));
+void ipf_p_raudio_main_unload __P((void));
+int ipf_p_raudio_new __P((void *, fr_info_t *, ap_session_t *, nat_t *));
+int ipf_p_raudio_in __P((void *, fr_info_t *, ap_session_t *, nat_t *));
+int ipf_p_raudio_out __P((void *, fr_info_t *, ap_session_t *, nat_t *));
 
 static	frentry_t	raudiofr;
 
@@ -26,7 +26,8 @@
 /*
  * Real Audio application proxy initialization.
  */
-int ippr_raudio_init()
+void
+ipf_p_raudio_main_load()
 {
 	bzero((char *)&raudiofr, sizeof(raudiofr));
 	raudiofr.fr_ref = 1;
@@ -33,12 +34,11 @@
 	raudiofr.fr_flags = FR_INQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE;
 	MUTEX_INIT(&raudiofr.fr_lock, "Real Audio proxy rule lock");
 	raudio_proxy_init = 1;
-
-	return 0;
 }
 
 
-void ippr_raudio_fini()
+void
+ipf_p_raudio_main_unload()
 {
 	if (raudio_proxy_init == 1) {
 		MUTEX_DESTROY(&raudiofr.fr_lock);
@@ -50,20 +50,24 @@
 /*
  * Setup for a new proxy to handle Real Audio.
  */
-int ippr_raudio_new(fin, aps, nat)
-fr_info_t *fin;
-ap_session_t *aps;
-nat_t *nat;
+int
+ipf_p_raudio_new(arg, fin, aps, nat)
+	void *arg;
+	fr_info_t *fin;
+	ap_session_t *aps;
+	nat_t *nat;
 {
 	raudio_t *rap;
 
+	nat = nat;	/* LINT */
+
+	if (fin->fin_v != 4)
+		return -1;
+
 	KMALLOCS(aps->aps_data, void *, sizeof(raudio_t));
 	if (aps->aps_data == NULL)
 		return -1;
 
-	fin = fin;	/* LINT */
-	nat = nat;	/* LINT */
-
 	bzero(aps->aps_data, sizeof(raudio_t));
 	rap = aps->aps_data;
 	aps->aps_psiz = sizeof(raudio_t);
@@ -73,10 +77,12 @@
 
 
 
-int ippr_raudio_out(fin, aps, nat)
-fr_info_t *fin;
-ap_session_t *aps;
-nat_t *nat;
+int
+ipf_p_raudio_out(arg, fin, aps, nat)
+	void *arg;
+	fr_info_t *fin;
+	ap_session_t *aps;
+	nat_t *nat;
 {
 	raudio_t *rap = aps->aps_data;
 	unsigned char membuf[512 + 1], *s;
@@ -179,14 +185,18 @@
 }
 
 
-int ippr_raudio_in(fin, aps, nat)
-fr_info_t *fin;
-ap_session_t *aps;
-nat_t *nat;
+int
+ipf_p_raudio_in(arg, fin, aps, nat)
+	void *arg;
+	fr_info_t *fin;
+	ap_session_t *aps;
+	nat_t *nat;
 {
 	unsigned char membuf[IPF_MAXPORTLEN + 1], *s;
 	tcphdr_t *tcp, tcph, *tcp2 = &tcph;
 	raudio_t *rap = aps->aps_data;
+	ipf_main_softc_t *softc;
+	ipf_nat_softc_t *softn;
 	struct in_addr swa, swb;
 	int off, dlen, slen;
 	int a1, a2, a3, a4;
@@ -198,6 +208,8 @@
 	ip_t *ip;
 	mb_t *m;
 
+	softc = fin->fin_main_soft;
+	softn = softc->ipf_nat_soft;
 	/*
 	 * Wait until we've seen the end of the start messages and even then
 	 * only proceed further if we're using UDP.  If they want to use TCP
@@ -272,14 +284,12 @@
 	swb = ip->ip_dst;
 
 	ip->ip_p = IPPROTO_UDP;
-	ip->ip_src = nat->nat_inip;
-	ip->ip_dst = nat->nat_oip;
+	ip->ip_src = nat->nat_ndstip;
+	ip->ip_dst = nat->nat_odstip;
 
 	bcopy((char *)fin, (char *)&fi, sizeof(fi));
 	bzero((char *)tcp2, sizeof(*tcp2));
 	TCP_OFF_A(tcp2, 5);
-	fi.fin_state = NULL;
-	fi.fin_nat = NULL;
 	fi.fin_flx |= FI_IGNORE;
 	fi.fin_dp = (char *)tcp2;
 	fi.fin_fr = &raudiofr;
@@ -287,7 +297,7 @@
 	fi.fin_plen = fi.fin_hlen + sizeof(*tcp2);
 	tcp2->th_win = htons(8192);
 	slen = ip->ip_len;
-	ip->ip_len = fin->fin_hlen + sizeof(*tcp);
+	ip->ip_len = htons(fin->fin_hlen + sizeof(*tcp));
 
 	if (((rap->rap_mode & RAP_M_UDP_ROBUST) == RAP_M_UDP_ROBUST) &&
 	    (rap->rap_srport != 0)) {
@@ -298,16 +308,19 @@
 		fi.fin_data[0] = dp;
 		fi.fin_data[1] = sp;
 		fi.fin_out = 0;
-		nat2 = nat_new(&fi, nat->nat_ptr, NULL,
+		MUTEX_ENTER(&softn->ipf_nat_new);
+		nat2 = ipf_nat_add(&fi, nat->nat_ptr, NULL,
 			       NAT_SLAVE|IPN_UDP | (sp ? 0 : SI_W_SPORT),
 			       NAT_OUTBOUND);
+		MUTEX_EXIT(&softn->ipf_nat_new);
 		if (nat2 != NULL) {
-			(void) nat_proto(&fi, nat2, IPN_UDP);
-			nat_update(&fi, nat2, nat2->nat_ptr);
+			(void) ipf_nat_proto(&fi, nat2, IPN_UDP);
+			MUTEX_ENTER(&nat2->nat_lock);
+			ipf_nat_update(&fi, nat2);
+			MUTEX_EXIT(&nat2->nat_lock);
 
-			(void) fr_addstate(&fi, NULL, (sp ? 0 : SI_W_SPORT));
-			if (fi.fin_state != NULL)
-				fr_statederef((ipstate_t **)&fi.fin_state);
+			(void) ipf_state_add(softc, &fi, NULL,
+					     (sp ? 0 : SI_W_SPORT));
 		}
 	}
 
@@ -318,16 +331,18 @@
 		fi.fin_data[0] = sp;
 		fi.fin_data[1] = 0;
 		fi.fin_out = 1;
-		nat2 = nat_new(&fi, nat->nat_ptr, NULL,
+		MUTEX_ENTER(&softn->ipf_nat_new);
+		nat2 = ipf_nat_add(&fi, nat->nat_ptr, NULL,
 			       NAT_SLAVE|IPN_UDP|SI_W_DPORT,
 			       NAT_OUTBOUND);
+		MUTEX_EXIT(&softn->ipf_nat_new);
 		if (nat2 != NULL) {
-			(void) nat_proto(&fi, nat2, IPN_UDP);
-			nat_update(&fi, nat2, nat2->nat_ptr);
+			(void) ipf_nat_proto(&fi, nat2, IPN_UDP);
+			MUTEX_ENTER(&nat2->nat_lock);
+			ipf_nat_update(&fi, nat2);
+			MUTEX_EXIT(&nat2->nat_lock);
 
-			(void) fr_addstate(&fi, NULL, SI_W_DPORT);
-			if (fi.fin_state != NULL)
-				fr_statederef((ipstate_t **)&fi.fin_state);
+			(void) ipf_state_add(softc, &fi, NULL, SI_W_DPORT);
 		}
 	}
 

Modified: trunk/sys/contrib/ipfilter/netinet/ip_rcmd_pxy.c
===================================================================
--- trunk/sys/contrib/ipfilter/netinet/ip_rcmd_pxy.c	2018-05-28 18:55:30 UTC (rev 10138)
+++ trunk/sys/contrib/ipfilter/netinet/ip_rcmd_pxy.c	2018-05-28 18:56:30 UTC (rev 10139)
@@ -1,37 +1,48 @@
-/*	$FreeBSD$	*/
+/* $MidnightBSD$ */
+/*	$FreeBSD: stable/10/sys/contrib/ipfilter/netinet/ip_rcmd_pxy.c 256199 2013-10-09 17:07:50Z dim $	*/
 
 /*
- * Copyright (C) 1998-2003 by Darren Reed
+ * Copyright (C) 2012 by Darren Reed.
  *
  * See the IPFILTER.LICENCE file for details on licencing.
  *
- * $Id: ip_rcmd_pxy.c,v 1.4 2013-01-08 01:31:40 laffer1 Exp $
+ * $Id$
  *
  * Simple RCMD transparent proxy for in-kernel use.  For use with the NAT
  * code.
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/contrib/ipfilter/netinet/ip_rcmd_pxy.c 256199 2013-10-09 17:07:50Z dim $
  */
 
 #define	IPF_RCMD_PROXY
 
+typedef struct rcmdinfo {
+	u_32_t	rcmd_port;	/* Port number seen */
+	u_32_t	rcmd_portseq;	/* Sequence number where port is first seen */
+	ipnat_t	*rcmd_rule;	/* Template rule for back connection */
+} rcmdinfo_t;
 
-int ippr_rcmd_init __P((void));
-void ippr_rcmd_fini __P((void));
-int ippr_rcmd_new __P((fr_info_t *, ap_session_t *, nat_t *));
-int ippr_rcmd_out __P((fr_info_t *, ap_session_t *, nat_t *));
-int ippr_rcmd_in __P((fr_info_t *, ap_session_t *, nat_t *));
+void ipf_p_rcmd_main_load __P((void));
+void ipf_p_rcmd_main_unload __P((void));
+
+int ipf_p_rcmd_init __P((void));
+void ipf_p_rcmd_fini __P((void));
+void ipf_p_rcmd_del __P((ipf_main_softc_t *, ap_session_t *));
+int ipf_p_rcmd_new __P((void *, fr_info_t *, ap_session_t *, nat_t *));
+int ipf_p_rcmd_out __P((void *, fr_info_t *, ap_session_t *, nat_t *));
+int ipf_p_rcmd_in __P((void *, fr_info_t *, ap_session_t *, nat_t *));
 u_short ipf_rcmd_atoi __P((char *));
-int ippr_rcmd_portmsg __P((fr_info_t *, ap_session_t *, nat_t *));
+int ipf_p_rcmd_portmsg __P((fr_info_t *, ap_session_t *, nat_t *));
 
 static	frentry_t	rcmdfr;
 
-int	rcmd_proxy_init = 0;
+static	int		rcmd_proxy_init = 0;
 
 
 /*
  * RCMD application proxy initialization.
  */
-int ippr_rcmd_init()
+void
+ipf_p_rcmd_main_load()
 {
 	bzero((char *)&rcmdfr, sizeof(rcmdfr));
 	rcmdfr.fr_ref = 1;
@@ -38,12 +49,11 @@
 	rcmdfr.fr_flags = FR_INQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE;
 	MUTEX_INIT(&rcmdfr.fr_lock, "RCMD proxy rule lock");
 	rcmd_proxy_init = 1;
-
-	return 0;
 }
 
 
-void ippr_rcmd_fini()
+void
+ipf_p_rcmd_main_unload()
 {
 	if (rcmd_proxy_init == 1) {
 		MUTEX_DESTROY(&rcmdfr.fr_lock);
@@ -55,36 +65,70 @@
 /*
  * Setup for a new RCMD proxy.
  */
-int ippr_rcmd_new(fin, aps, nat)
-fr_info_t *fin;
-ap_session_t *aps;
-nat_t *nat;
+int
+ipf_p_rcmd_new(arg, fin, aps, nat)
+	void *arg;
+	fr_info_t *fin;
+	ap_session_t *aps;
+	nat_t *nat;
 {
 	tcphdr_t *tcp = (tcphdr_t *)fin->fin_dp;
+	rcmdinfo_t *rc;
+	ipnat_t *ipn;
+	ipnat_t *np;
+	int size;
 
 	fin = fin;	/* LINT */
-	nat = nat;	/* LINT */
 
-	aps->aps_psiz = sizeof(u_32_t);
-	KMALLOCS(aps->aps_data, u_32_t *, sizeof(u_32_t));
-	if (aps->aps_data == NULL) {
+	np = nat->nat_ptr;
+	size = np->in_size;
+	KMALLOC(rc, rcmdinfo_t *);
+	if (rc == NULL) {
 #ifdef IP_RCMD_PROXY_DEBUG
-		printf("ippr_rcmd_new:KMALLOCS(%d) failed\n", sizeof(u_32_t));
+		printf("ipf_p_rcmd_new:KMALLOCS(%d) failed\n", sizeof(*rc));
 #endif
 		return -1;
 	}
-	*(u_32_t *)aps->aps_data = 0;
 	aps->aps_sport = tcp->th_sport;
 	aps->aps_dport = tcp->th_dport;
+
+	ipn = ipf_proxy_rule_rev(nat);
+	if (ipn == NULL) {
+		KFREE(rc);
+		return -1;
+	}
+
+	aps->aps_data = rc;
+	aps->aps_psiz = sizeof(*rc);
+	bzero((char *)rc, sizeof(*rc));
+
+	rc->rcmd_rule = ipn;
+
 	return 0;
 }
 
 
+void
+ipf_p_rcmd_del(softc, aps)
+	ipf_main_softc_t *softc;
+	ap_session_t *aps;
+{
+	rcmdinfo_t *rci;
+
+	rci = aps->aps_data;
+	if (rci != NULL) {
+		rci->rcmd_rule->in_flags |= IPN_DELETE;
+		ipf_nat_rule_deref(softc, &rci->rcmd_rule);
+	}
+}
+
+
 /*
  * ipf_rcmd_atoi - implement a simple version of atoi
  */
-u_short ipf_rcmd_atoi(ptr)
-char *ptr;
+u_short
+ipf_rcmd_atoi(ptr)
+	char *ptr;
 {
 	register char *s = ptr, c;
 	register u_short i = 0;
@@ -97,44 +141,50 @@
 }
 
 
-int ippr_rcmd_portmsg(fin, aps, nat)
-fr_info_t *fin;
-ap_session_t *aps;
-nat_t *nat;
+int
+ipf_p_rcmd_portmsg(fin, aps, nat)
+	fr_info_t *fin;
+	ap_session_t *aps;
+	nat_t *nat;
 {
 	tcphdr_t *tcp, tcph, *tcp2 = &tcph;
-	struct in_addr swip, swip2;
-	int off, dlen, nflags;
+	int off, dlen, nflags, direction;
+	ipf_main_softc_t *softc;
+	ipf_nat_softc_t *softn;
 	char portbuf[8], *s;
+	rcmdinfo_t *rc;
 	fr_info_t fi;
 	u_short sp;
 	nat_t *nat2;
+#ifdef USE_INET6
+	ip6_t *ip6;
+#endif
+	int tcpsz;
+	int slen = 0; /* silence gcc */
 	ip_t *ip;
 	mb_t *m;
 
 	tcp = (tcphdr_t *)fin->fin_dp;
 
-	if (tcp->th_flags & TH_SYN) {
-		*(u_32_t *)aps->aps_data = htonl(ntohl(tcp->th_seq) + 1);
-		return 0;
-	}
-
-	if ((*(u_32_t *)aps->aps_data != 0) &&
-	    (tcp->th_seq != *(u_32_t *)aps->aps_data))
-		return 0;
-
 	m = fin->fin_m;
 	ip = fin->fin_ip;
-	off = (char *)tcp - (char *)ip + (TCP_OFF(tcp) << 2) + fin->fin_ipoff;
+	tcpsz = TCP_OFF(tcp) << 2;
+#ifdef USE_INET6
+	ip6 = (ip6_t *)fin->fin_ip;
+#endif
+	softc = fin->fin_main_soft;
+	softn = softc->ipf_nat_soft;
+	off = (char *)tcp - (char *)ip + tcpsz + fin->fin_ipoff;
 
-#ifdef __sgi
-	dlen = fin->fin_plen - off;
-#else
-	dlen = MSGDSIZE(m) - off;
-#endif
+	dlen = fin->fin_dlen - tcpsz;
 	if (dlen <= 0)
 		return 0;
 
+	rc = (rcmdinfo_t *)aps->aps_data;
+	if ((rc->rcmd_portseq != 0) &&
+	    (tcp->th_seq != rc->rcmd_portseq))
+		return 0;
+
 	bzero(portbuf, sizeof(portbuf));
 	COPYDATA(m, off, MIN(sizeof(portbuf), dlen), portbuf);
 
@@ -143,97 +193,161 @@
 	sp = ipf_rcmd_atoi(s);
 	if (sp == 0) {
 #ifdef IP_RCMD_PROXY_DEBUG
-		printf("ippr_rcmd_portmsg:sp == 0 dlen %d [%s]\n",
+		printf("ipf_p_rcmd_portmsg:sp == 0 dlen %d [%s]\n",
 		       dlen, portbuf);
 #endif
 		return 0;
 	}
 
+	if (rc->rcmd_port != 0 && sp != rc->rcmd_port) {
+#ifdef IP_RCMD_PROXY_DEBUG
+		printf("ipf_p_rcmd_portmsg:sp(%d) != rcmd_port(%d)\n",
+		       sp, rc->rcmd_port);
+#endif
+		return 0;
+	}
+
+	rc->rcmd_port = sp;
+	rc->rcmd_portseq = tcp->th_seq;
+
 	/*
-	 * Add skeleton NAT entry for connection which will come back the
-	 * other way.
+	 * Initialise the packet info structure so we can search the NAT
+	 * table to see if there already is soemthing present that matches
+	 * up with what we want to add.
 	 */
 	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;
-	if (nat->nat_dir == NAT_OUTBOUND)
-		nat2 = nat_outlookup(&fi, NAT_SEARCH|IPN_TCP, nat->nat_p,
-				     nat->nat_inip, nat->nat_oip);
-	else
-		nat2 = nat_inlookup(&fi, NAT_SEARCH|IPN_TCP, nat->nat_p,
-				    nat->nat_inip, nat->nat_oip);
-	if (nat2 == NULL) {
-		int slen;
+	fi.fin_data[0] = 0;
+	fi.fin_data[1] = sp;
+	fi.fin_src6 = nat->nat_ndst6;
+	fi.fin_dst6 = nat->nat_nsrc6;
 
-		slen = ip->ip_len;
-		ip->ip_len = fin->fin_hlen + sizeof(*tcp);
-		bzero((char *)tcp2, sizeof(*tcp2));
-		tcp2->th_win = htons(8192);
-		tcp2->th_sport = htons(sp);
-		tcp2->th_dport = 0; /* XXX - don't specify remote port */
-		TCP_OFF_A(tcp2, 5);
-		tcp2->th_flags = TH_SYN;
-		fi.fin_dp = (char *)tcp2;
-		fi.fin_fr = &rcmdfr;
-		fi.fin_dlen = sizeof(*tcp2);
-		fi.fin_plen = fi.fin_hlen + sizeof(*tcp2);
-		fi.fin_flx &= FI_LOWTTL|FI_FRAG|FI_TCPUDP|FI_OPTIONS|FI_IGNORE;
-		nflags = NAT_SLAVE|IPN_TCP|SI_W_DPORT;
-
-		swip = ip->ip_src;
-		swip2 = ip->ip_dst;
-
+	if (nat->nat_v[0] == 6) {
+#ifdef USE_INET6
 		if (nat->nat_dir == NAT_OUTBOUND) {
-			fi.fin_fi.fi_saddr = nat->nat_inip.s_addr;
-			ip->ip_src = nat->nat_inip;
+			nat2 = ipf_nat6_outlookup(&fi, NAT_SEARCH|IPN_TCP,
+						  nat->nat_pr[1],
+						  &nat->nat_osrc6.in6,
+						  &nat->nat_odst6.in6);
 		} else {
-			fi.fin_fi.fi_saddr = nat->nat_oip.s_addr;
-			ip->ip_src = nat->nat_oip;
-			nflags |= NAT_NOTRULEPORT;
+			nat2 = ipf_nat6_inlookup(&fi, NAT_SEARCH|IPN_TCP,
+						 nat->nat_pr[0],
+						 &nat->nat_osrc6.in6,
+						 &nat->nat_odst6.in6);
 		}
+#else
+		nat2 = (void *)-1;
+#endif
+	} else {
+		if (nat->nat_dir == NAT_OUTBOUND) {
+			nat2 = ipf_nat_outlookup(&fi, NAT_SEARCH|IPN_TCP,
+						 nat->nat_pr[1],
+						 nat->nat_osrcip,
+						 nat->nat_odstip);
+		} else {
+			nat2 = ipf_nat_inlookup(&fi, NAT_SEARCH|IPN_TCP,
+						nat->nat_pr[0],
+						nat->nat_osrcip,
+						nat->nat_odstip);
+		}
+	}
+	if (nat2 != NULL)
+		return APR_ERR(1);
 
-		nat2 = nat_new(&fi, nat->nat_ptr, NULL, nflags, nat->nat_dir);
+	/*
+	 * Add skeleton NAT entry for connection which will come
+	 * back the other way.
+	 */
 
-		if (nat2 != NULL) {
-			(void) nat_proto(&fi, nat2, IPN_TCP);
-			nat_update(&fi, nat2, nat2->nat_ptr);
-			fi.fin_ifp = NULL;
-			if (nat->nat_dir == NAT_INBOUND) {
-				fi.fin_fi.fi_daddr = nat->nat_inip.s_addr;
-				ip->ip_dst = nat->nat_inip;
-			}
-			(void) fr_addstate(&fi, NULL, SI_W_DPORT);
-			if (fi.fin_state != NULL)
-				fr_statederef((ipstate_t **)&fi.fin_state);
-		}
+	if (nat->nat_v[0] == 6) {
+#ifdef USE_INET6
+		slen = ip6->ip6_plen;
+		ip6->ip6_plen = htons(sizeof(*tcp));
+#endif
+	} else {
+		slen = ip->ip_len;
+		ip->ip_len = htons(fin->fin_hlen + sizeof(*tcp));
+	}
+
+	/*
+	 * Fill out the fake TCP header with a few fields that ipfilter
+	 * considers to be important.
+	 */
+	bzero((char *)tcp2, sizeof(*tcp2));
+	tcp2->th_win = htons(8192);
+	TCP_OFF_A(tcp2, 5);
+	tcp2->th_flags = TH_SYN;
+
+	fi.fin_dp = (char *)tcp2;
+	fi.fin_fr = &rcmdfr;
+	fi.fin_dlen = sizeof(*tcp2);
+	fi.fin_plen = fi.fin_hlen + sizeof(*tcp2);
+	fi.fin_flx &= FI_LOWTTL|FI_FRAG|FI_TCPUDP|FI_OPTIONS|FI_IGNORE;
+
+	if (nat->nat_dir == NAT_OUTBOUND) {
+		fi.fin_out = 0;
+		direction = NAT_INBOUND;
+	} else {
+		fi.fin_out = 1;
+		direction = NAT_OUTBOUND;
+	}
+	nflags = SI_W_SPORT|NAT_SLAVE|IPN_TCP;
+
+	MUTEX_ENTER(&softn->ipf_nat_new);
+	if (fin->fin_v == 4)
+		nat2 = ipf_nat_add(&fi, rc->rcmd_rule, NULL, nflags,
+				   direction);
+#ifdef USE_INET6
+	else
+		nat2 = ipf_nat6_add(&fi, rc->rcmd_rule, NULL, nflags,
+				    direction);
+#endif
+	MUTEX_EXIT(&softn->ipf_nat_new);
+
+	if (nat2 != NULL) {
+		(void) ipf_nat_proto(&fi, nat2, IPN_TCP);
+		MUTEX_ENTER(&nat2->nat_lock);
+		ipf_nat_update(&fi, nat2);
+		MUTEX_EXIT(&nat2->nat_lock);
+		fi.fin_ifp = NULL;
+		if (nat2->nat_dir == NAT_INBOUND)
+			fi.fin_dst6 = nat->nat_osrc6;
+		(void) ipf_state_add(softc, &fi, NULL, SI_W_SPORT);
+	}
+	if (nat->nat_v[0] == 6) {
+#ifdef USE_INET6
+		ip6->ip6_plen = slen;
+#endif
+	} else {
 		ip->ip_len = slen;
-		ip->ip_src = swip;
-		ip->ip_dst = swip2;
 	}
+	if (nat2 == NULL)
+		return APR_ERR(1);
 	return 0;
 }
 
 
-int ippr_rcmd_out(fin, aps, nat)
-fr_info_t *fin;
-ap_session_t *aps;
-nat_t *nat;
+int
+ipf_p_rcmd_out(arg, fin, aps, nat)
+	void *arg;
+	fr_info_t *fin;
+	ap_session_t *aps;
+	nat_t *nat;
 {
 	if (nat->nat_dir == NAT_OUTBOUND)
-		return ippr_rcmd_portmsg(fin, aps, nat);
+		return ipf_p_rcmd_portmsg(fin, aps, nat);
 	return 0;
 }
 
 
-int ippr_rcmd_in(fin, aps, nat)
-fr_info_t *fin;
-ap_session_t *aps;
-nat_t *nat;
+int
+ipf_p_rcmd_in(arg, fin, aps, nat)
+	void *arg;
+	fr_info_t *fin;
+	ap_session_t *aps;
+	nat_t *nat;
 {
 	if (nat->nat_dir == NAT_INBOUND)
-		return ippr_rcmd_portmsg(fin, aps, nat);
+		return ipf_p_rcmd_portmsg(fin, aps, nat);
 	return 0;
 }

Modified: trunk/sys/contrib/ipfilter/netinet/ip_rpcb_pxy.c
===================================================================
--- trunk/sys/contrib/ipfilter/netinet/ip_rpcb_pxy.c	2018-05-28 18:55:30 UTC (rev 10138)
+++ trunk/sys/contrib/ipfilter/netinet/ip_rpcb_pxy.c	2018-05-28 18:56:30 UTC (rev 10139)
@@ -1,5 +1,6 @@
+/* $MidnightBSD$ */
 /*
- * Copyright (C) 2002-2003 by Ryan Beasley <ryanb at goddamnbastard.org>
+ * Copyright (C) 2002-2012 by Ryan Beasley <ryanb at goddamnbastard.org>
  *
  * See the IPFILTER.LICENCE file for details on licencing.
  */
@@ -37,44 +38,43 @@
  *   o The enclosed hack of STREAMS support is pretty sick and most likely
  *     broken.
  *
- *	$Id: ip_rpcb_pxy.c,v 1.2 2008-09-19 02:15:13 laffer1 Exp $
+ *	$Id$
  */
-
 #define	IPF_RPCB_PROXY
 
 /*
  * Function prototypes
  */
-int	ippr_rpcb_init __P((void));
-void	ippr_rpcb_fini __P((void));
-int	ippr_rpcb_new __P((fr_info_t *, ap_session_t *, nat_t *));
-void	ippr_rpcb_del __P((ap_session_t *));
-int	ippr_rpcb_in __P((fr_info_t *, ap_session_t *, nat_t *));
-int	ippr_rpcb_out __P((fr_info_t *, ap_session_t *, nat_t *));
+void	ipf_p_rpcb_main_load __P((void));
+void	ipf_p_rpcb_main_unload __P((void));
+int	ipf_p_rpcb_new __P((void *, fr_info_t *, ap_session_t *, nat_t *));
+void	ipf_p_rpcb_del __P((ipf_main_softc_t *, ap_session_t *));
+int	ipf_p_rpcb_in __P((void *, fr_info_t *, ap_session_t *, nat_t *));
+int	ipf_p_rpcb_out __P((void *, fr_info_t *, ap_session_t *, nat_t *));
 
-static void	ippr_rpcb_flush __P((rpcb_session_t *));
-static int	ippr_rpcb_decodereq __P((fr_info_t *, nat_t *,
+static void	ipf_p_rpcb_flush __P((rpcb_session_t *));
+static int	ipf_p_rpcb_decodereq __P((fr_info_t *, nat_t *,
 	rpcb_session_t *, rpc_msg_t *));
-static int	ippr_rpcb_skipauth __P((rpc_msg_t *, xdr_auth_t *, u_32_t **));
-static int	ippr_rpcb_insert __P((rpcb_session_t *, rpcb_xact_t *));
-static int	ippr_rpcb_xdrrpcb __P((rpc_msg_t *, u_32_t *, rpcb_args_t *));
-static int	ippr_rpcb_getuaddr __P((rpc_msg_t *, xdr_uaddr_t *,
+static int	ipf_p_rpcb_skipauth __P((rpc_msg_t *, xdr_auth_t *, u_32_t **));
+static int	ipf_p_rpcb_insert __P((rpcb_session_t *, rpcb_xact_t *));
+static int	ipf_p_rpcb_xdrrpcb __P((rpc_msg_t *, u_32_t *, rpcb_args_t *));
+static int	ipf_p_rpcb_getuaddr __P((rpc_msg_t *, xdr_uaddr_t *,
 	u_32_t **));
-static u_int	ippr_rpcb_atoi __P((char *));
-static int	ippr_rpcb_modreq __P((fr_info_t *, nat_t *, rpc_msg_t *,
+static u_int	ipf_p_rpcb_atoi __P((char *));
+static int	ipf_p_rpcb_modreq __P((fr_info_t *, nat_t *, rpc_msg_t *,
 	mb_t *, u_int));
-static int	ippr_rpcb_decoderep __P((fr_info_t *, nat_t *,
+static int	ipf_p_rpcb_decoderep __P((fr_info_t *, nat_t *,
 	rpcb_session_t *, rpc_msg_t *, rpcb_xact_t **));
-static rpcb_xact_t *	ippr_rpcb_lookup __P((rpcb_session_t *, u_32_t));
-static void	ippr_rpcb_deref __P((rpcb_session_t *, rpcb_xact_t *));
-static int	ippr_rpcb_getproto __P((rpc_msg_t *, xdr_proto_t *,
+static rpcb_xact_t *	ipf_p_rpcb_lookup __P((rpcb_session_t *, u_32_t));
+static void	ipf_p_rpcb_deref __P((rpcb_session_t *, rpcb_xact_t *));
+static int	ipf_p_rpcb_getproto __P((rpc_msg_t *, xdr_proto_t *,
 	u_32_t **));
-static int	ippr_rpcb_getnat __P((fr_info_t *, nat_t *, u_int, u_int));
-static int	ippr_rpcb_modv3 __P((fr_info_t *, nat_t *, rpc_msg_t *,
+static int	ipf_p_rpcb_getnat __P((fr_info_t *, nat_t *, u_int, u_int));
+static int	ipf_p_rpcb_modv3 __P((fr_info_t *, nat_t *, rpc_msg_t *,
 	mb_t *, u_int));
-static int	ippr_rpcb_modv4 __P((fr_info_t *, nat_t *, rpc_msg_t *,
+static int	ipf_p_rpcb_modv4 __P((fr_info_t *, nat_t *, rpc_msg_t *,
 	mb_t *, u_int));
-static void     ippr_rpcb_fixlen __P((fr_info_t *, int));
+static void     ipf_p_rpcb_fixlen __P((fr_info_t *, int));
 
 /*
  * Global variables
@@ -84,7 +84,7 @@
 static	int	rpcbcnt;	/* Upper bound of allocated RPCB sessions. */
 				/* XXX rpcbcnt still requires locking. */
 
-int	rpcb_proxy_init = 0;
+static	int	rpcb_proxy_init = 0;
 
 
 /*
@@ -98,15 +98,15 @@
  * Public subroutines
  */
 
-/* --------------------------------------------------------------------	*/
-/* Function:	ippr_rpcb_init						*/
-/* Returns:	int - 0 == success					*/
-/* Parameters:	(void)							*/
-/*									*/
-/* Initialize the filter rule entry and session limiter.		*/
-/* --------------------------------------------------------------------	*/
-int
-ippr_rpcb_init()
+/* -------------------------------------------------------------------- */
+/* Function:    ipf_p_rpcb_main_load                                    */
+/* Returns:     void                                                    */
+/* Parameters:  (void)                                                  */
+/*                                                                      */
+/* Initialize the filter rule entry and session limiter.                */
+/* -------------------------------------------------------------------- */
+void
+ipf_p_rpcb_main_load()
 {
 	rpcbcnt = 0;
 
@@ -115,19 +115,17 @@
 	rpcbfr.fr_flags = FR_PASS|FR_QUICK|FR_KEEPSTATE;
 	MUTEX_INIT(&rpcbfr.fr_lock, "ipf Sun RPCB proxy rule lock");
 	rpcb_proxy_init = 1;
-
-	return(0);
 }
 
-/* --------------------------------------------------------------------	*/
-/* Function:	ippr_rpcb_fini						*/
-/* Returns:	void							*/
-/* Parameters:	(void)							*/
-/*									*/
-/* Destroy rpcbfr's mutex to avoid a lock leak.				*/
-/* --------------------------------------------------------------------	*/
+/* -------------------------------------------------------------------- */
+/* Function:    ipf_p_rpcb_main_unload                                  */
+/* Returns:     void                                                    */
+/* Parameters:  (void)                                                  */
+/*                                                                      */
+/* Destroy rpcbfr's mutex to avoid a lock leak.                         */
+/* -------------------------------------------------------------------- */
 void
-ippr_rpcb_fini()
+ipf_p_rpcb_main_unload()
 {
 	if (rpcb_proxy_init == 1) {
 		MUTEX_DESTROY(&rpcbfr.fr_lock);
@@ -136,7 +134,7 @@
 }
 
 /* --------------------------------------------------------------------	*/
-/* Function:	ippr_rpcb_new						*/
+/* Function:	ipf_p_rpcb_new						*/
 /* Returns:	int - -1 == failure, 0 == success			*/
 /* Parameters:	fin(I)	- pointer to packet information			*/
 /*		aps(I)	- pointer to proxy session structure		*/
@@ -145,7 +143,8 @@
 /* Allocate resources for per-session proxy structures.			*/
 /* --------------------------------------------------------------------	*/
 int
-ippr_rpcb_new(fin, aps, nat)
+ipf_p_rpcb_new(arg, fin, aps, nat)
+	void *arg;
 	fr_info_t *fin;
 	ap_session_t *aps;
 	nat_t *nat;
@@ -152,9 +151,11 @@
 {
 	rpcb_session_t *rs;
 
-	fin = fin;	/* LINT */
 	nat = nat;	/* LINT */
 
+	if (fin->fin_v != 4)
+		return -1;
+
 	KMALLOC(rs, rpcb_session_t *);
 	if (rs == NULL)
 		return(-1);
@@ -168,7 +169,7 @@
 }
 
 /* --------------------------------------------------------------------	*/
-/* Function:	ippr_rpcb_del						*/
+/* Function:	ipf_p_rpcb_del						*/
 /* Returns:	void							*/
 /* Parameters:	aps(I)	- pointer to proxy session structure		*/
 /*									*/
@@ -175,7 +176,8 @@
 /* Free up a session's list of RPCB requests.				*/
 /* --------------------------------------------------------------------	*/
 void
-ippr_rpcb_del(aps)
+ipf_p_rpcb_del(softc, aps)
+	ipf_main_softc_t *softc;
 	ap_session_t *aps;
 {
 	rpcb_session_t *rs;
@@ -182,13 +184,13 @@
 	rs = (rpcb_session_t *)aps->aps_data;
 
 	MUTEX_ENTER(&rs->rs_rxlock);
-	ippr_rpcb_flush(rs);
+	ipf_p_rpcb_flush(rs);
 	MUTEX_EXIT(&rs->rs_rxlock);
 	MUTEX_DESTROY(&rs->rs_rxlock);
 }
 
 /* --------------------------------------------------------------------	*/
-/* Function:	ippr_rpcb_in						*/
+/* Function:	ipf_p_rpcb_in						*/
 /* Returns:	int - APR_ERR(1) == drop the packet, 			*/
 /*		      APR_ERR(2) == kill the proxy session,		*/
 /*		      else change in packet length (in bytes)		*/
@@ -201,7 +203,8 @@
 /* for decoding.  Also pass packet off for a rewrite if necessary.	*/
 /* --------------------------------------------------------------------	*/
 int
-ippr_rpcb_in(fin, aps, nat)
+ipf_p_rpcb_in(arg, fin, aps, nat)
+	void *arg;
 	fr_info_t *fin;
 	ap_session_t *aps;
 	nat_t *nat;
@@ -235,7 +238,7 @@
 	rm->rm_buflen = dlen;
 
 	/* Send off to decode request. */
-	rv = ippr_rpcb_decodereq(fin, nat, rs, rm);
+	rv = ipf_p_rpcb_decodereq(fin, nat, rs, rm);
 
 	switch(rv)
 	{
@@ -246,11 +249,11 @@
 	case 0:
 		break;
 	case 1:
-		rv = ippr_rpcb_modreq(fin, nat, rm, m, off);
+		rv = ipf_p_rpcb_modreq(fin, nat, rm, m, off);
 		break;
 	default:
 		/*CONSTANTCONDITION*/
-		IPF_PANIC(1, ("illegal rv %d (ippr_rpcb_req)", rv));
+		IPF_PANIC(1, ("illegal rv %d (ipf_p_rpcb_req)", rv));
 	}
 
 	return(rv);
@@ -257,7 +260,7 @@
 }
 
 /* --------------------------------------------------------------------	*/
-/* Function:	ippr_rpcb_out						*/
+/* Function:	ipf_p_rpcb_out						*/
 /* Returns:	int - APR_ERR(1) == drop the packet, 			*/
 /*		      APR_ERR(2) == kill the proxy session,		*/
 /*		      else change in packet length (in bytes)		*/
@@ -272,7 +275,8 @@
 /* allow direct communication between RPC client and server.		*/
 /* --------------------------------------------------------------------	*/
 int
-ippr_rpcb_out(fin, aps, nat)
+ipf_p_rpcb_out(arg, fin, aps, nat)
+	void *arg;
 	fr_info_t *fin;
 	ap_session_t *aps;
 	nat_t *nat;
@@ -311,7 +315,7 @@
 	rx = NULL;		/* XXX gcc */
 
 	/* Send off to decode reply. */
-	rv = ippr_rpcb_decoderep(fin, nat, rs, rm, &rx);
+	rv = ipf_p_rpcb_decoderep(fin, nat, rs, rm, &rx);
 
 	switch(rv)
 	{
@@ -318,7 +322,7 @@
 	case -1: /* Bad packet */
                 if (rx != NULL) {
                         MUTEX_ENTER(&rs->rs_rxlock);
-                        ippr_rpcb_deref(rs, rx);
+                        ipf_p_rpcb_deref(rs, rx);
                         MUTEX_EXIT(&rs->rs_rxlock);
                 }
 		return(APR_ERR(1));
@@ -334,16 +338,16 @@
 		 * same.  (i.e., this box is either a router or rpcbind
 		 * only listens on loopback.)
 		 */
-		if (nat->nat_inip.s_addr != nat->nat_outip.s_addr) {
+		if (nat->nat_odstaddr != nat->nat_ndstaddr) {
 			if (rx->rx_type == RPCB_RES_STRING)
-				diff = ippr_rpcb_modv3(fin, nat, rm, m, off);
+				diff = ipf_p_rpcb_modv3(fin, nat, rm, m, off);
 			else if (rx->rx_type == RPCB_RES_LIST)
-				diff = ippr_rpcb_modv4(fin, nat, rm, m, off);
+				diff = ipf_p_rpcb_modv4(fin, nat, rm, m, off);
 		}
 		break;
 	default:
 		/*CONSTANTCONDITION*/
-		IPF_PANIC(1, ("illegal rv %d (ippr_rpcb_decoderep)", rv));
+		IPF_PANIC(1, ("illegal rv %d (ipf_p_rpcb_decoderep)", rv));
 	}
 
 	if (rx != NULL) {
@@ -354,8 +358,8 @@
                  * finished with rx, and the other signals that we've
                  * processed its reply.
                  */
-                ippr_rpcb_deref(rs, rx);
-                ippr_rpcb_deref(rs, rx);
+                ipf_p_rpcb_deref(rs, rx);
+                ipf_p_rpcb_deref(rs, rx);
                 MUTEX_EXIT(&rs->rs_rxlock);
 	}
 
@@ -367,7 +371,7 @@
  */
 
 /* --------------------------------------------------------------------	*/
-/* Function:	ippr_rpcb_flush						*/
+/* Function:	ipf_p_rpcb_flush						*/
 /* Returns:	void							*/
 /* Parameters:	rs(I)	- pointer to RPCB session structure		*/
 /*									*/
@@ -374,7 +378,7 @@
 /* Simply flushes the list of outstanding transactions, if any.		*/
 /* --------------------------------------------------------------------	*/
 static void
-ippr_rpcb_flush(rs)
+ipf_p_rpcb_flush(rs)
 	rpcb_session_t *rs;
 {
 	rpcb_xact_t *r1, *r2;
@@ -391,7 +395,7 @@
 }
 
 /* --------------------------------------------------------------------	*/
-/* Function:	ippr_rpcb_decodereq					*/
+/* Function:	ipf_p_rpcb_decodereq					*/
 /* Returns:	int - -1 == bad request or critical failure,		*/
 /*		       0 == request successfully decoded,		*/
 /*		       1 == request successfully decoded; requires	*/
@@ -408,7 +412,7 @@
 /* is enough room in rs_buf for the basic RPC message "preamble".	*/
 /* --------------------------------------------------------------------	*/
 static int
-ippr_rpcb_decodereq(fin, nat, rs, rm)
+ipf_p_rpcb_decodereq(fin, nat, rs, rm)
 	fr_info_t *fin;
 	nat_t *nat;
 	rpcb_session_t *rs;
@@ -440,9 +444,9 @@
 	rc->rc_proc = p++;
 
 	/* Bypass RPC authentication stuff. */
-	if (ippr_rpcb_skipauth(rm, &rc->rc_authcred, &p) != 0)
+	if (ipf_p_rpcb_skipauth(rm, &rc->rc_authcred, &p) != 0)
 		return(-1);
-	if (ippr_rpcb_skipauth(rm, &rc->rc_authverf, &p) != 0)
+	if (ipf_p_rpcb_skipauth(rm, &rc->rc_authverf, &p) != 0)
 		return(-1);
 
 	/* Compare RPCB version and procedure numbers. */
@@ -488,17 +492,17 @@
 		ra = &rc->rc_rpcbargs;
 
 		/* Decode the 'struct rpcb' request. */
-		if (ippr_rpcb_xdrrpcb(rm, p, ra) != 0)
+		if (ipf_p_rpcb_xdrrpcb(rm, p, ra) != 0)
 			return(-1);
 
 		/* Are the target address & port valid? */
-		if ((ra->ra_maddr.xu_ip != nat->nat_outip.s_addr) ||
-		    (ra->ra_maddr.xu_port != nat->nat_outport))
+		if ((ra->ra_maddr.xu_ip != nat->nat_ndstaddr) ||
+		    (ra->ra_maddr.xu_port != nat->nat_ndport))
 		    	return(-1);
 
 		/* Do we need to rewrite this packet? */
-		if ((nat->nat_outip.s_addr != nat->nat_inip.s_addr) ||
-		    (nat->nat_outport != nat->nat_inport))
+		if ((nat->nat_ndstaddr != nat->nat_odstaddr) ||
+		    (nat->nat_ndport != nat->nat_odport))
 		    	mod = 1;
 		break;
 	default:
@@ -506,7 +510,7 @@
 	}
 
         MUTEX_ENTER(&rs->rs_rxlock);
-	if (ippr_rpcb_insert(rs, &rx) != 0) {
+	if (ipf_p_rpcb_insert(rs, &rx) != 0) {
                 MUTEX_EXIT(&rs->rs_rxlock);
 		return(-1);
 	}
@@ -516,7 +520,7 @@
 }
 
 /* --------------------------------------------------------------------	*/
-/* Function:	ippr_rpcb_skipauth					*/
+/* Function:	ipf_p_rpcb_skipauth					*/
 /* Returns:	int -- -1 == illegal auth parameters (lengths)		*/
 /*			0 == valid parameters, pointer advanced		*/
 /* Parameters:	rm(I)	- pointer to RPC message structure		*/
@@ -527,7 +531,7 @@
 /* it.									*/
 /* --------------------------------------------------------------------	*/
 static int
-ippr_rpcb_skipauth(rm, auth, buf)
+ipf_p_rpcb_skipauth(rm, auth, buf)
 	rpc_msg_t *rm;
 	xdr_auth_t *auth;
 	u_32_t **buf;
@@ -559,7 +563,7 @@
 }
 
 /* --------------------------------------------------------------------	*/
-/* Function:	ippr_rpcb_insert					*/
+/* Function:	ipf_p_rpcb_insert					*/
 /* Returns:	int -- -1 == list insertion failed,			*/
 /*			0 == item successfully added			*/
 /* Parameters:	rs(I)	- pointer to RPCB session structure		*/
@@ -566,13 +570,13 @@
 /*		rx(I)	- pointer to RPCB transaction structure		*/
 /* --------------------------------------------------------------------	*/
 static int
-ippr_rpcb_insert(rs, rx)
+ipf_p_rpcb_insert(rs, rx)
 	rpcb_session_t *rs;
 	rpcb_xact_t *rx;
 {
 	rpcb_xact_t *rxp;
 
-	rxp = ippr_rpcb_lookup(rs, rx->rx_xid);
+	rxp = ipf_p_rpcb_lookup(rs, rx->rx_xid);
 	if (rxp != NULL) {
                 ++rxp->rx_ref;
 		return(0);
@@ -602,7 +606,7 @@
 }
 
 /* --------------------------------------------------------------------	*/
-/* Function:	ippr_rpcb_xdrrpcb					*/
+/* Function:	ipf_p_rpcb_xdrrpcb					*/
 /* Returns:	int -- -1 == failure to properly decode the request	*/
 /*			0 == rpcb successfully decoded			*/
 /* Parameters:	rs(I)	- pointer to RPCB session structure		*/
@@ -613,7 +617,7 @@
 /* within only the context of TCP/UDP over IP networks.			*/
 /* --------------------------------------------------------------------	*/
 static int
-ippr_rpcb_xdrrpcb(rm, p, ra)
+ipf_p_rpcb_xdrrpcb(rm, p, ra)
 	rpc_msg_t *rm;
 	u_32_t *p;
 	rpcb_args_t *ra;
@@ -625,11 +629,11 @@
 	p += 2;
 
 	/* Decode r_netid.  Must be "tcp" or "udp". */
-	if (ippr_rpcb_getproto(rm, &ra->ra_netid, &p) != 0)
+	if (ipf_p_rpcb_getproto(rm, &ra->ra_netid, &p) != 0)
 		return(-1);
 
 	/* Decode r_maddr. */
-	if (ippr_rpcb_getuaddr(rm, &ra->ra_maddr, &p) != 0)
+	if (ipf_p_rpcb_getuaddr(rm, &ra->ra_maddr, &p) != 0)
 		return(-1);
 
 	/* Advance to r_owner and make sure it's empty. */
@@ -640,7 +644,7 @@
 }
 
 /* --------------------------------------------------------------------	*/
-/* Function:	ippr_rpcb_getuaddr					*/
+/* Function:	ipf_p_rpcb_getuaddr					*/
 /* Returns:	int -- -1 == illegal string,				*/
 /*			0 == string parsed; contents recorded		*/
 /* Parameters:	rm(I)	- pointer to RPC message structure		*/
@@ -650,7 +654,7 @@
 /* Decode the IP address / port at p and record them in xu.		*/
 /* --------------------------------------------------------------------	*/
 static int
-ippr_rpcb_getuaddr(rm, xu, p)
+ipf_p_rpcb_getuaddr(rm, xu, p)
 	rpc_msg_t *rm;
 	xdr_uaddr_t *xu;
 	u_32_t **p;
@@ -699,7 +703,7 @@
 
 			/* Check for ASCII byte. */
 			*c = '\0';
-			t = ippr_rpcb_atoi(b);
+			t = ipf_p_rpcb_atoi(b);
 			if (t > 255)
 				return(-1);
 
@@ -721,7 +725,7 @@
 		return(-1);
 
 	/* Handle the last byte (port low byte) */
-	t = ippr_rpcb_atoi(b);
+	t = ipf_p_rpcb_atoi(b);
 	if (t > 255)
 		return(-1);
 	pp[d - 4] = t & 0xff;
@@ -730,7 +734,7 @@
 }
 
 /* --------------------------------------------------------------------	*/
-/* Function:	ippr_rpcb_atoi (XXX should be generic for all proxies)	*/
+/* Function:	ipf_p_rpcb_atoi (XXX should be generic for all proxies)	*/
 /* Returns:	int -- integer representation of supplied string	*/
 /* Parameters:	ptr(I)	- input string					*/
 /*									*/
@@ -737,7 +741,7 @@
 /* Simple version of atoi(3) ripped from ip_rcmd_pxy.c.			*/
 /* --------------------------------------------------------------------	*/
 static u_int
-ippr_rpcb_atoi(ptr)
+ipf_p_rpcb_atoi(ptr)
 	char *ptr;
 {
 	register char *s = ptr, c;
@@ -751,7 +755,7 @@
 }
 
 /* --------------------------------------------------------------------	*/
-/* Function:	ippr_rpcb_modreq					*/
+/* Function:	ipf_p_rpcb_modreq					*/
 /* Returns:	int -- change in datagram length			*/
 /*			APR_ERR(2) - critical failure			*/
 /* Parameters:	fin(I)	- pointer to packet information			*/
@@ -764,7 +768,7 @@
 /* with the latter.  (This is exclusive to protocol versions 3 & 4).	*/
 /* --------------------------------------------------------------------	*/
 static int
-ippr_rpcb_modreq(fin, nat, rm, m, off)
+ipf_p_rpcb_modreq(fin, nat, rm, m, off)
 	fr_info_t *fin;
 	nat_t *nat;
 	rpc_msg_t *rm;
@@ -779,8 +783,8 @@
 	int diff;
 
 	ra = &rm->rm_call.rc_rpcbargs;
-	i = (char *)&nat->nat_inip.s_addr;
-	p = (char *)&nat->nat_inport;
+	i = (char *)&nat->nat_odstaddr;
+	p = (char *)&nat->nat_odport;
 
 	/* Form new string. */
 	bzero(uaddr, sizeof(uaddr)); /* Just in case we need padding. */
@@ -821,9 +825,9 @@
 	if (diff != 0) {
 		udp = fin->fin_dp;
 		udp->uh_ulen = htons(ntohs(udp->uh_ulen) + diff);
-		fin->fin_ip->ip_len += diff;
+		fin->fin_plen += diff;
+		fin->fin_ip->ip_len = htons(fin->fin_plen);
 		fin->fin_dlen += diff;
-		fin->fin_plen += diff;
 		/* XXX Storage lengths. */
 	}
 
@@ -831,7 +835,7 @@
 }
 
 /* --------------------------------------------------------------------	*/
-/* Function:	ippr_rpcb_decoderep					*/
+/* Function:	ipf_p_rpcb_decoderep					*/
 /* Returns:	int - -1 == bad request or critical failure,		*/
 /*		       0 == valid, negative reply			*/
 /*		       1 == vaddlid, positive reply; needs no changes	*/
@@ -851,7 +855,7 @@
 /* is enough room in rs_buf for the basic RPC message "preamble".	*/
 /* --------------------------------------------------------------------	*/
 static int
-ippr_rpcb_decoderep(fin, nat, rs, rm, rxp)
+ipf_p_rpcb_decoderep(fin, nat, rs, rm, rxp)
 	fr_info_t *fin;
 	nat_t *nat;
 	rpcb_session_t *rs;
@@ -875,7 +879,7 @@
 
 	/* Lookup XID */
         MUTEX_ENTER(&rs->rs_rxlock);
-	if ((rx = ippr_rpcb_lookup(rs, xdr)) == NULL) {
+	if ((rx = ipf_p_rpcb_lookup(rs, xdr)) == NULL) {
                 MUTEX_EXIT(&rs->rs_rxlock);
 		return(-1);
         }
@@ -900,7 +904,7 @@
 	}
 
 	/* Bypass RPC authentication stuff. */
-	if (ippr_rpcb_skipauth(rm, &rr->rr_authverf, &p) != 0)
+	if (ipf_p_rpcb_skipauth(rm, &rr->rr_authverf, &p) != 0)
 		return(-1);
 
 	/* Test accept status */
@@ -916,20 +920,20 @@
 		/* There must be only one 4 byte argument. */
 		if (!RPCB_BUF_EQ(rm, p, 4))
 			return(-1);
-		
+
 		rr->rr_v2 = p;
 		xdr = B(rr->rr_v2);
-		
+
 		/* Reply w/ a 0 port indicates service isn't registered */
 		if (xdr == 0)
 			return(0);
-		
+
 		/* Is the value sane? */
 		if (xdr > 65535)
 			return(-1);
 
 		/* Create NAT & state table entries. */
-		if (ippr_rpcb_getnat(fin, nat, rx->rx_proto, (u_int)xdr) != 0)
+		if (ipf_p_rpcb_getnat(fin, nat, rx->rx_proto, (u_int)xdr) != 0)
 			return(-1);
 		break;
 	case RPCB_RES_STRING:
@@ -947,15 +951,15 @@
 			return(0);
 
 		/* Decode the target IP address / port. */
-		if (ippr_rpcb_getuaddr(rm, &rr->rr_v3, &p) != 0)
+		if (ipf_p_rpcb_getuaddr(rm, &rr->rr_v3, &p) != 0)
 			return(-1);
 
 		/* Validate the IP address and port contained. */
-		if (nat->nat_inip.s_addr != rr->rr_v3.xu_ip)
+		if (nat->nat_odstaddr != rr->rr_v3.xu_ip)
 			return(-1);
 
 		/* Create NAT & state table entries. */
-		if (ippr_rpcb_getnat(fin, nat, rx->rx_proto,
+		if (ipf_p_rpcb_getnat(fin, nat, rx->rx_proto,
 				     (u_int)rr->rr_v3.xu_port) != 0)
 			return(-1);
 		break;
@@ -980,9 +984,9 @@
 
 		for(;;) {
 			re = &rl->rl_entries[rl->rl_cnt];
-			if (ippr_rpcb_getuaddr(rm, &re->re_maddr, &p) != 0)
+			if (ipf_p_rpcb_getuaddr(rm, &re->re_maddr, &p) != 0)
 				return(-1);
-			if (ippr_rpcb_getproto(rm, &re->re_netid, &p) != 0)
+			if (ipf_p_rpcb_getproto(rm, &re->re_netid, &p) != 0)
 				return(-1);
 			/* re_semantics & re_pfamily length */
 			if (!RPCB_BUF_GEQ(rm, p, 12))
@@ -992,7 +996,7 @@
 			if ((xdr != 4) || strncmp((char *)p, "inet", 4))
 				return(-1);
 			p++;
-			if (ippr_rpcb_getproto(rm, &re->re_proto, &p) != 0)
+			if (ipf_p_rpcb_getproto(rm, &re->re_proto, &p) != 0)
 				return(-1);
 			if (!RPCB_BUF_GEQ(rm, p, 4))
 				return(-1);
@@ -1011,7 +1015,7 @@
 
 		for(rl->rl_cnt = 0; rl->rl_cnt < cnt; rl->rl_cnt++) {
 			re = &rl->rl_entries[rl->rl_cnt];
-			rv = ippr_rpcb_getnat(fin, nat,
+			rv = ipf_p_rpcb_getnat(fin, nat,
 			                      re->re_proto.xp_proto,
 				              (u_int)re->re_maddr.xu_port);
 			if (rv != 0)
@@ -1027,7 +1031,7 @@
 }
 
 /* --------------------------------------------------------------------	*/
-/* Function:	ippr_rpcb_lookup					*/
+/* Function:	ipf_p_rpcb_lookup					*/
 /* Returns:	rpcb_xact_t * 	- NULL == no matching record,		*/
 /*				  else pointer to relevant entry	*/
 /* Parameters:	rs(I)	- pointer to RPCB session			*/
@@ -1034,7 +1038,7 @@
 /*		xid(I)	- XID to look for				*/
 /* --------------------------------------------------------------------	*/
 static rpcb_xact_t *
-ippr_rpcb_lookup(rs, xid)
+ipf_p_rpcb_lookup(rs, xid)
 	rpcb_session_t *rs;
 	u_32_t xid;
 {
@@ -1051,7 +1055,7 @@
 }
 
 /* --------------------------------------------------------------------	*/
-/* Function:	ippr_rpcb_deref					        */
+/* Function:	ipf_p_rpcb_deref					        */
 /* Returns:	(void)							*/
 /* Parameters:	rs(I)	- pointer to RPCB session			*/
 /*		rx(I)	- pointer to RPC transaction struct to remove	*/
@@ -1062,7 +1066,7 @@
 /* Free the RPCB transaction record rx from the chain of entries.	*/
 /* --------------------------------------------------------------------	*/
 static void
-ippr_rpcb_deref(rs, rx)
+ipf_p_rpcb_deref(rs, rx)
 	rpcb_session_t *rs;
 	rpcb_xact_t *rx;
 {
@@ -1085,7 +1089,7 @@
 }
 
 /* --------------------------------------------------------------------	*/
-/* Function:	ippr_rpcb_getproto					*/
+/* Function:	ipf_p_rpcb_getproto					*/
 /* Returns:	int - -1 == illegal protocol/netid,			*/
 /*		       0 == legal protocol/netid			*/
 /* Parameters:	rm(I)	- pointer to RPC message structure		*/
@@ -1095,7 +1099,7 @@
 /* Decode netid/proto stored at p and record its numeric value.	 	*/
 /* --------------------------------------------------------------------	*/
 static int
-ippr_rpcb_getproto(rm, xp, p)
+ipf_p_rpcb_getproto(rm, xp, p)
 	rpc_msg_t *rm;
 	xdr_proto_t *xp;
 	u_32_t **p;
@@ -1122,7 +1126,7 @@
 	else {
 		return(-1);
 	}
-	
+
 	/* Advance past the string. */
 	(*p)++;
 
@@ -1130,7 +1134,7 @@
 }
 
 /* --------------------------------------------------------------------	*/
-/* Function:	ippr_rpcb_getnat					*/
+/* Function:	ipf_p_rpcb_getnat					*/
 /* Returns:	int -- -1 == failed to create table entries,		*/
 /*			0 == success					*/
 /* Parameters:	fin(I)	- pointer to packet information			*/
@@ -1142,12 +1146,13 @@
 /* attempt between RPC client and server.				*/
 /* --------------------------------------------------------------------	*/
 static int
-ippr_rpcb_getnat(fin, nat, proto, port)
+ipf_p_rpcb_getnat(fin, nat, proto, port)
 	fr_info_t *fin;
 	nat_t *nat;
 	u_int proto;
 	u_int port;
 {
+	ipf_main_softc_t *softc = fin->fin_main_soft;
 	ipnat_t *ipn, ipnat;
 	tcphdr_t tcp;
 	ipstate_t *is;
@@ -1159,15 +1164,13 @@
 
 	/* 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;
 	fi.fin_p = proto;
 	fi.fin_sport = 0;
 	fi.fin_dport = port & 0xffff;
 	fi.fin_flx |= FI_IGNORE;
+	fi.fin_saddr = nat->nat_osrcaddr;
+	fi.fin_daddr = nat->nat_odstaddr;
 
 	bzero((char *)&tcp, sizeof(tcp));
 	tcp.th_dport = htons(port);
@@ -1195,18 +1198,18 @@
 	 * If successful, fr_stlookup returns with ipf_state locked.  We have
 	 * no use for this lock, so simply unlock it if necessary.
 	 */
-	is = fr_stlookup(&fi, &tcp, NULL);
+	is = ipf_state_lookup(&fi, &tcp, NULL);
 	if (is != NULL) {
-		RWLOCK_EXIT(&ipf_state);
+		RWLOCK_EXIT(&softc->ipf_state);
 	}
 
-	RWLOCK_EXIT(&ipf_nat);
+	RWLOCK_EXIT(&softc->ipf_nat);
 
-	WRITE_ENTER(&ipf_nat);
-	natl = nat_inlookup(&fi, nflags, proto, fi.fin_src, fi.fin_dst);
+	WRITE_ENTER(&softc->ipf_nat);
+	natl = ipf_nat_inlookup(&fi, nflags, proto, fi.fin_src, fi.fin_dst);
 
 	if ((natl != NULL) && (is != NULL)) {
-		MUTEX_DOWNGRADE(&ipf_nat);
+		MUTEX_DOWNGRADE(&softc->ipf_nat);
 		return(0);
 	}
 
@@ -1220,6 +1223,10 @@
 	nflags &= ~NAT_SEARCH;
 
 	if (natl == NULL) {
+#ifdef USE_MUTEXES
+		ipf_nat_softc_t *softn = softc->ipf_nat_soft;
+#endif
+
 		/* XXX Since we're just copying the original ipn contents
 		 * back, would we be better off just sending a pointer to
 		 * the 'temp' copy off to nat_new instead?
@@ -1228,10 +1235,11 @@
 		bcopy((char *)ipn, (char *)&ipnat, sizeof(ipnat));
 		ipn->in_flags = nflags & IPN_TCPUDP;
 		ipn->in_apr = NULL;
-		ipn->in_p = proto;
-		ipn->in_pmin = htons(fi.fin_dport);
-		ipn->in_pmax = htons(fi.fin_dport);
-		ipn->in_pnext = htons(fi.fin_dport);
+		ipn->in_pr[0] = proto;
+		ipn->in_pr[1] = proto;
+		ipn->in_dpmin = fi.fin_dport;
+		ipn->in_dpmax = fi.fin_dport;
+		ipn->in_dpnext = fi.fin_dport;
 		ipn->in_space = 1;
 		ipn->in_ippip = 1;
 		if (ipn->in_flags & IPN_FILTER) {
@@ -1238,36 +1246,40 @@
 			ipn->in_scmp = 0;
 			ipn->in_dcmp = 0;
 		}
-		*ipn->in_plabel = '\0';
+		ipn->in_plabel = -1;
 
 		/* Create NAT entry.  return NULL if this fails. */
-		natl = nat_new(&fi, ipn, NULL, nflags|SI_CLONE|NAT_SLAVE,
+		MUTEX_ENTER(&softn->ipf_nat_new);
+		natl = ipf_nat_add(&fi, ipn, NULL, nflags|SI_CLONE|NAT_SLAVE,
 			       NAT_INBOUND);
+		MUTEX_EXIT(&softn->ipf_nat_new);
 
 		bcopy((char *)&ipnat, (char *)ipn, sizeof(ipnat));
 
 		if (natl == NULL) {
-			MUTEX_DOWNGRADE(&ipf_nat);
+			MUTEX_DOWNGRADE(&softc->ipf_nat);
 			return(-1);
 		}
 
+		natl->nat_ptr = ipn;
+		fi.fin_saddr = natl->nat_nsrcaddr;
+		fi.fin_daddr = natl->nat_ndstaddr;
 		ipn->in_use++;
-		(void) nat_proto(&fi, natl, nflags);
-		nat_update(&fi, natl, natl->nat_ptr);
+		(void) ipf_nat_proto(&fi, natl, nflags);
+		MUTEX_ENTER(&natl->nat_lock);
+		ipf_nat_update(&fi, natl);
+		MUTEX_EXIT(&natl->nat_lock);
 	}
-	MUTEX_DOWNGRADE(&ipf_nat);
+	MUTEX_DOWNGRADE(&softc->ipf_nat);
 
 	if (is == NULL) {
 		/* Create state entry.  Return NULL if this fails. */
-		fi.fin_dst = nat->nat_inip;
-		fi.fin_nat = (void *)natl;
 		fi.fin_flx |= FI_NATED;
 		fi.fin_flx &= ~FI_STATE;
 		nflags &= NAT_TCPUDP;
 		nflags |= SI_W_SPORT|SI_CLONE;
 
-		is = fr_addstate(&fi, NULL, nflags);
-		if (is == NULL) {
+		if (ipf_state_add(softc, &fi, NULL, nflags) != 0) {
 			/*
 			 * XXX nat_delete is private to ip_nat.c.  Should
 			 * check w/ Darren about this one.
@@ -1276,8 +1288,6 @@
 			 */
 			return(-1);
 		}
-		if (fi.fin_state != NULL)
-			fr_statederef((ipstate_t **)&fi.fin_state);
 	}
 
 	return(0);
@@ -1284,7 +1294,7 @@
 }
 
 /* --------------------------------------------------------------------	*/
-/* Function:	ippr_rpcb_modv3						*/
+/* Function:	ipf_p_rpcb_modv3						*/
 /* Returns:	int -- change in packet length				*/
 /* Parameters:	fin(I)	- pointer to packet information			*/
 /*		nat(I)	- pointer to NAT session			*/
@@ -1296,7 +1306,7 @@
 /* lengths as necessary.						*/
 /* --------------------------------------------------------------------	*/
 static int
-ippr_rpcb_modv3(fin, nat, rm, m, off)
+ipf_p_rpcb_modv3(fin, nat, rm, m, off)
 	fr_info_t *fin;
 	nat_t *nat;
 	rpc_msg_t *rm;
@@ -1310,7 +1320,7 @@
 	int diff;
 
 	rr = &rm->rm_resp;
-	i = (char *)&nat->nat_outip.s_addr;
+	i = (char *)&nat->nat_ndstaddr;
 	p = (char *)&rr->rr_v3.xu_port;
 
 	/* Form new string. */
@@ -1336,7 +1346,7 @@
 
 	/* Write new string. */
 	COPYBACK(m, off, xlen, uaddr);
-	
+
 	/* Determine difference in data lengths. */
 	diff = xlen - XDRALIGN(B(rr->rr_v3.xu_xslen));
 
@@ -1345,13 +1355,13 @@
 	 * adjustments.
 	 */
 	if (diff != 0)
-		ippr_rpcb_fixlen(fin, diff);
+		ipf_p_rpcb_fixlen(fin, diff);
 
 	return(diff);
 }
 
 /* --------------------------------------------------------------------	*/
-/* Function:	ippr_rpcb_modv4						*/
+/* Function:	ipf_p_rpcb_modv4						*/
 /* Returns:	int -- change in packet length				*/
 /* Parameters:	fin(I)	- pointer to packet information			*/
 /*		nat(I)	- pointer to NAT session			*/
@@ -1362,7 +1372,7 @@
 /* Write new rpcb_entry list, adjusting	lengths as necessary.		*/
 /* --------------------------------------------------------------------	*/
 static int
-ippr_rpcb_modv4(fin, nat, rm, m, off)
+ipf_p_rpcb_modv4(fin, nat, rm, m, off)
 	fr_info_t *fin;
 	nat_t *nat;
 	rpc_msg_t *rm;
@@ -1381,7 +1391,7 @@
 	rr = &rm->rm_resp;
 	rl = &rr->rr_v4;
 
-	i = (char *)&nat->nat_outip.s_addr;
+	i = (char *)&nat->nat_ndstaddr;
 
 	/* Determine mbuf offset to write to. */
 	re = &rl->rl_entries[0];
@@ -1432,7 +1442,7 @@
 	 * adjustments.
 	 */
 	if (diff != 0)
-		ippr_rpcb_fixlen(fin, diff);
+		ipf_p_rpcb_fixlen(fin, diff);
 
 	return(diff);
 }
@@ -1439,7 +1449,7 @@
 
 
 /* --------------------------------------------------------------------	*/
-/* Function:    ippr_rpcb_fixlen                                        */
+/* Function:    ipf_p_rpcb_fixlen                                        */
 /* Returns:     (void)                                                  */
 /* Parameters:  fin(I)  - pointer to packet information                 */
 /*              len(I)  - change in packet length                       */
@@ -1448,7 +1458,7 @@
 /* header fields.                                                       */
 /* --------------------------------------------------------------------	*/
 static void
-ippr_rpcb_fixlen(fin, len)
+ipf_p_rpcb_fixlen(fin, len)
         fr_info_t *fin;
         int len;
 {
@@ -1456,9 +1466,9 @@
 
         udp = fin->fin_dp;
         udp->uh_ulen = htons(ntohs(udp->uh_ulen) + len);
-        fin->fin_ip->ip_len += len;
+        fin->fin_plen += len;
+        fin->fin_ip->ip_len = htons(fin->fin_plen);
         fin->fin_dlen += len;
-        fin->fin_plen += len;
 }
 
 #undef B

Modified: trunk/sys/contrib/ipfilter/netinet/ip_rules.c
===================================================================
--- trunk/sys/contrib/ipfilter/netinet/ip_rules.c	2018-05-28 18:55:30 UTC (rev 10138)
+++ trunk/sys/contrib/ipfilter/netinet/ip_rules.c	2018-05-28 18:56:30 UTC (rev 10139)
@@ -1,7 +1,8 @@
-/*	$FreeBSD$	*/
+/* $MidnightBSD$ */
+/*	$FreeBSD: stable/10/sys/contrib/ipfilter/netinet/ip_rules.c 255332 2013-09-06 23:11:19Z cy $	*/
 
 /*
-* Copyright (C) 1993-2000 by Darren Reed.
+* Copyright (C) 2012 by Darren Reed.
 *
 * Redistribution and use in source and binary forms are permitted
 * provided that this notice is preserved and due credit is given
@@ -8,12 +9,23 @@
 * to the original author and the contributors.
 */
 
+#include <sys/param.h>
 #include <sys/types.h>
 #include <sys/time.h>
 #include <sys/socket.h>
-#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__sgi)
-# include <sys/systm.h>
+#if defined(__FreeBSD_version) && (__FreeBSD_version >= 40000)
+# if defined(_KERNEL)
+#  include <sys/libkern.h>
+# else
+#  include <sys/unistd.h>
+# endif
 #endif
+#if defined(__NetBSD_Version__) && (__NetBSD_Version__ >= 399000000)
+#else
+# if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__sgi)
+#  include <sys/systm.h>
+# endif
+#endif
 #include <sys/errno.h>
 #include <sys/param.h>
 #if !defined(__SVR4) && !defined(__svr4__) && !defined(__hpux)
@@ -40,12 +52,15 @@
 
 #ifdef IPFILTER_COMPILED
 
+extern ipf_main_softc_t ipfmain;
+
+
 static u_long in_rule__0[] = {
-0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xffffffff, 0, 0, 0, 0, 0, 0, 0x1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x80000000, 0x8002, 0, 0, 0, 0xffff, 0, 0, 0x4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+0, 0, 0, 0, 0, 0, 0, 0x8070d88, 0, 0, 0, 0xffffffff, 0, 0, 0, 0, 0, 0, 0, 0xffffffff, 0x1b0, 0x1, 0, 0, 0, 0x2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x40000000, 0x8002, 0, 0, 0, 0xffff, 0, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xffffffff, 0, 0, 0, 0, 0, 0, 0, 0, 0xffffffff, 0, 0, 0, 0, 0, 0, 0, 0, 0xffffffff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xffffffff, 0, 0, 0, 0
 };
 
 static u_long out_rule__0[] = {
-0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xffffffff, 0, 0, 0, 0, 0, 0, 0x1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x80000000, 0x4002, 0, 0, 0, 0xffff, 0, 0, 0x4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+0, 0, 0, 0, 0, 0, 0, 0x8070d88, 0, 0, 0, 0xffffffff, 0, 0, 0, 0, 0, 0, 0, 0xffffffff, 0x1b0, 0x1, 0, 0, 0, 0x3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x40000000, 0x4002, 0, 0, 0, 0xffff, 0, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xffffffff, 0, 0, 0, 0, 0, 0, 0, 0, 0xffffffff, 0, 0, 0, 0, 0, 0, 0, 0, 0xffffffff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xffffffff, 0, 0, 0, 0
 };
 
 frentry_t *ipf_rules_in_[1] = {
@@ -52,6 +67,17 @@
 	(frentry_t *)&in_rule__0
 };
 
+/* XXX	This file (ip_rules.c) is not part of the ipfilter tarball, it is
+   XXX	generated by the ipfilter build process. Unfortunately the build
+   XXX  process did not generate the following lines so they are added
+   XXX	by hand here. This is a bit of a hack but it works for now. Future
+   XXX  imports/merges of ipfilter may generate this so the following will
+   XXX	need to be removed following some future merge.
+   XXX	*/
+frentry_t *ipf_rules_out_[1] = {
+	(frentry_t *)&out_rule__0
+};
+
 frentry_t *ipfrule_match_in_(fin, passp)
 fr_info_t *fin;
 u_32_t *passp;
@@ -62,10 +88,6 @@
 	return fr;
 }
 
-frentry_t *ipf_rules_out_[1] = {
-	(frentry_t *)&out_rule__0
-};
-
 frentry_t *ipfrule_match_out_(fin, passp)
 fr_info_t *fin;
 u_32_t *passp;
@@ -87,9 +109,14 @@
 		fp = ipf_rules_out_[i];
 		fp->fr_next = NULL;
 		for (j = i + 1; j < max; j++)
-			if (strncmp(fp->fr_group,
+			if (strncmp(fp->fr_names + fp->fr_group,
+				    ipf_rules_out_[j]->fr_names +
 				    ipf_rules_out_[j]->fr_group,
 				    FR_GROUPLEN) == 0) {
+				if (ipf_rules_out_[j] != NULL)
+					ipf_rules_out_[j]->fr_pnext =
+					    &fp->fr_next;
+				fp->fr_pnext = &ipf_rules_out_[j];
 				fp->fr_next = ipf_rules_out_[j];
 				break;
 			}
@@ -97,13 +124,14 @@
 
 	fp = &ipfrule_out_;
 	bzero((char *)fp, sizeof(*fp));
-	fp->fr_type = FR_T_CALLFUNC|FR_T_BUILTIN;
+	fp->fr_type = FR_T_CALLFUNC_BUILTIN;
 	fp->fr_flags = FR_OUTQUE|FR_NOMATCH;
 	fp->fr_data = (void *)ipf_rules_out_[0];
 	fp->fr_dsize = sizeof(ipf_rules_out_[0]);
-	fp->fr_v = 4;
+	fp->fr_family = AF_INET;
 	fp->fr_func = (ipfunc_t)ipfrule_match_out_;
-	err = frrequest(IPL_LOGIPF, SIOCADDFR, (caddr_t)fp, fr_active, 0);
+	err = frrequest(&ipfmain, IPL_LOGIPF, SIOCADDFR, (caddr_t)fp,
+			ipfmain.ipf_active, 0);
 	return err;
 }
 
@@ -129,8 +157,9 @@
 		}
 	}
 	if (err == 0)
-		err = frrequest(IPL_LOGIPF, SIOCDELFR,
-				(caddr_t)&ipfrule_out_, fr_active, 0);
+		err = frrequest(&ipfmain, IPL_LOGIPF, SIOCDELFR,
+				(caddr_t)&ipfrule_out_,
+				ipfmain.ipf_active, 0);
 	if (err)
 		return err;
 
@@ -149,9 +178,14 @@
 		fp = ipf_rules_in_[i];
 		fp->fr_next = NULL;
 		for (j = i + 1; j < max; j++)
-			if (strncmp(fp->fr_group,
+			if (strncmp(fp->fr_names + fp->fr_group,
+				    ipf_rules_in_[j]->fr_names +
 				    ipf_rules_in_[j]->fr_group,
 				    FR_GROUPLEN) == 0) {
+				if (ipf_rules_in_[j] != NULL)
+					ipf_rules_in_[j]->fr_pnext =
+					    &fp->fr_next;
+				fp->fr_pnext = &ipf_rules_in_[j];
 				fp->fr_next = ipf_rules_in_[j];
 				break;
 			}
@@ -159,13 +193,14 @@
 
 	fp = &ipfrule_in_;
 	bzero((char *)fp, sizeof(*fp));
-	fp->fr_type = FR_T_CALLFUNC|FR_T_BUILTIN;
+	fp->fr_type = FR_T_CALLFUNC_BUILTIN;
 	fp->fr_flags = FR_INQUE|FR_NOMATCH;
 	fp->fr_data = (void *)ipf_rules_in_[0];
 	fp->fr_dsize = sizeof(ipf_rules_in_[0]);
-	fp->fr_v = 4;
+	fp->fr_family = AF_INET;
 	fp->fr_func = (ipfunc_t)ipfrule_match_in_;
-	err = frrequest(IPL_LOGIPF, SIOCADDFR, (caddr_t)fp, fr_active, 0);
+	err = frrequest(&ipfmain, IPL_LOGIPF, SIOCADDFR, (caddr_t)fp,
+			ipfmain.ipf_active, 0);
 	return err;
 }
 
@@ -191,8 +226,9 @@
 		}
 	}
 	if (err == 0)
-		err = frrequest(IPL_LOGIPF, SIOCDELFR,
-				(caddr_t)&ipfrule_in_, fr_active, 0);
+		err = frrequest(&ipfmain, IPL_LOGIPF, SIOCDELFR,
+				(caddr_t)&ipfrule_in_,
+				ipfmain.ipf_active, 0);
 	if (err)
 		return err;
 

Modified: trunk/sys/contrib/ipfilter/netinet/ip_rules.h
===================================================================
--- trunk/sys/contrib/ipfilter/netinet/ip_rules.h	2018-05-28 18:55:30 UTC (rev 10138)
+++ trunk/sys/contrib/ipfilter/netinet/ip_rules.h	2018-05-28 18:56:30 UTC (rev 10139)
@@ -1,4 +1,5 @@
-/*	$FreeBSD$	*/
+/* $MidnightBSD$ */
+/*	$FreeBSD: stable/10/sys/contrib/ipfilter/netinet/ip_rules.h 145517 2005-04-25 18:15:41Z darrenr $	*/
 
 extern int ipfrule_add __P((void));
 extern int ipfrule_remove __P((void));

Modified: trunk/sys/contrib/ipfilter/netinet/ip_scan.c
===================================================================
--- trunk/sys/contrib/ipfilter/netinet/ip_scan.c	2018-05-28 18:55:30 UTC (rev 10138)
+++ trunk/sys/contrib/ipfilter/netinet/ip_scan.c	2018-05-28 18:56:30 UTC (rev 10139)
@@ -1,5 +1,6 @@
+/* $MidnightBSD$ */
 /*
- * Copyright (C) 1995-2001 by Darren Reed.
+ * Copyright (C) 2012 by Darren Reed.
  *
  * See the IPFILTER.LICENCE file for details on licencing.
  */
@@ -58,17 +59,17 @@
 
 #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 1.4 2013-01-08 01:31:40 laffer1 Exp $";
+static const char rcsid[] = "@(#)$Id$";
 #endif
 
 #ifdef	IPFILTER_SCAN	/* endif at bottom of file */
 
 
-ipscan_t	*ipsc_list = NULL,
-		*ipsc_tail = NULL;
-ipscanstat_t	ipsc_stat;
+ipscan_t	*ipf_scan_list = NULL,
+		*ipf_scan_tail = NULL;
+ipscanstat_t	ipf_scan_stat;
 # ifdef USE_MUTEXES
-ipfrwlock_t	ipsc_rwlock;
+ipfrwlock_t	ipf_scan_rwlock;
 # endif
 
 # ifndef isalpha
@@ -77,42 +78,47 @@
 # endif
 
 
-int ipsc_add __P((caddr_t));
-int ipsc_delete __P((caddr_t));
-struct ipscan *ipsc_lookup __P((char *));
-int ipsc_matchstr __P((sinfo_t *, char *, int));
-int ipsc_matchisc __P((ipscan_t *, ipstate_t *, int, int, int *));
-int ipsc_match __P((ipstate_t *));
+int ipf_scan_add __P((caddr_t));
+int ipf_scan_remove __P((caddr_t));
+struct ipscan *ipf_scan_lookup __P((char *));
+int ipf_scan_matchstr __P((sinfo_t *, char *, int));
+int ipf_scan_matchisc __P((ipscan_t *, ipstate_t *, int, int, int *));
+int ipf_scan_match __P((ipstate_t *));
 
-static int	ipsc_inited = 0;
+static int	ipf_scan_inited = 0;
 
 
-int ipsc_init()
+int
+ipf_scan_init()
 {
-	RWLOCK_INIT(&ipsc_rwlock, "ip scan rwlock");
-	ipsc_inited = 1;
+	RWLOCK_INIT(&ipf_scan_rwlock, "ip scan rwlock");
+	ipf_scan_inited = 1;
 	return 0;
 }
 
 
-void fr_scanunload()
+void
+ipf_scan_unload(ipf_main_softc_t *arg)
 {
-	if (ipsc_inited == 1) {
-		RW_DESTROY(&ipsc_rwlock);
-		ipsc_inited = 0;
+	if (ipf_scan_inited == 1) {
+		RW_DESTROY(&ipf_scan_rwlock);
+		ipf_scan_inited = 0;
 	}
 }
 
 
-int ipsc_add(data)
-caddr_t data;
+int
+ipf_scan_add(data)
+	caddr_t data;
 {
 	ipscan_t *i, *isc;
 	int err;
 
 	KMALLOC(isc, ipscan_t *);
-	if (!isc)
+	if (!isc) {
+		ipf_interror = 90001;
 		return ENOMEM;
+	}
 
 	err = copyinptr(data, isc, sizeof(*isc));
 	if (err) {
@@ -120,23 +126,24 @@
 		return err;
 	}
 
-	WRITE_ENTER(&ipsc_rwlock);
+	WRITE_ENTER(&ipf_scan_rwlock);
 
-	i = ipsc_lookup(isc->ipsc_tag);
-	if (i) {
-		RWLOCK_EXIT(&ipsc_rwlock);
+	i = ipf_scan_lookup(isc->ipsc_tag);
+	if (i != NULL) {
+		RWLOCK_EXIT(&ipf_scan_rwlock);
 		KFREE(isc);
+		ipf_interror = 90002;
 		return EEXIST;
 	}
 
-	if (ipsc_tail) {
-		ipsc_tail->ipsc_next = isc;
-		isc->ipsc_pnext = &ipsc_tail->ipsc_next;
-		ipsc_tail = isc;
+	if (ipf_scan_tail) {
+		ipf_scan_tail->ipsc_next = isc;
+		isc->ipsc_pnext = &ipf_scan_tail->ipsc_next;
+		ipf_scan_tail = isc;
 	} else {
-		ipsc_list = isc;
-		ipsc_tail = isc;
-		isc->ipsc_pnext = &ipsc_list;
+		ipf_scan_list = isc;
+		ipf_scan_tail = isc;
+		isc->ipsc_pnext = &ipf_scan_list;
 	}
 	isc->ipsc_next = NULL;
 
@@ -145,14 +152,15 @@
 	isc->ipsc_sref = 0;
 	isc->ipsc_active = 0;
 
-	ipsc_stat.iscs_entries++;
-	RWLOCK_EXIT(&ipsc_rwlock);
+	ipf_scan_stat.iscs_entries++;
+	RWLOCK_EXIT(&ipf_scan_rwlock);
 	return 0;
 }
 
 
-int ipsc_delete(data)
-caddr_t data;
+int
+ipf_scan_remove(data)
+	caddr_t data;
 {
 	ipscan_t isc, *i;
 	int err;
@@ -161,14 +169,15 @@
 	if (err)
 		return err;
 
-	WRITE_ENTER(&ipsc_rwlock);
+	WRITE_ENTER(&ipf_scan_rwlock);
 
-	i = ipsc_lookup(isc.ipsc_tag);
+	i = ipf_scan_lookup(isc.ipsc_tag);
 	if (i == NULL)
 		err = ENOENT;
 	else {
 		if (i->ipsc_fref) {
-			RWLOCK_EXIT(&ipsc_rwlock);
+			RWLOCK_EXIT(&ipf_scan_rwlock);
+			ipf_interror = 90003;
 			return EBUSY;
 		}
 
@@ -176,26 +185,27 @@
 		if (i->ipsc_next)
 			i->ipsc_next->ipsc_pnext = i->ipsc_pnext;
 		else {
-			if (i->ipsc_pnext == &ipsc_list)
-				ipsc_tail = NULL;
+			if (i->ipsc_pnext == &ipf_scan_list)
+				ipf_scan_tail = NULL;
 			else
-				ipsc_tail = *(*i->ipsc_pnext)->ipsc_pnext;
+				ipf_scan_tail = *(*i->ipsc_pnext)->ipsc_pnext;
 		}
 
-		ipsc_stat.iscs_entries--;
+		ipf_scan_stat.iscs_entries--;
 		KFREE(i);
 	}
-	RWLOCK_EXIT(&ipsc_rwlock);
+	RWLOCK_EXIT(&ipf_scan_rwlock);
 	return err;
 }
 
 
-struct ipscan *ipsc_lookup(tag)
-char *tag;
+struct ipscan *
+ipf_scan_lookup(tag)
+	char *tag;
 {
 	ipscan_t *i;
 
-	for (i = ipsc_list; i; i = i->ipsc_next)
+	for (i = ipf_scan_list; i; i = i->ipsc_next)
 		if (!strcmp(i->ipsc_tag, tag))
 			return i;
 	return NULL;
@@ -202,20 +212,23 @@
 }
 
 
-int ipsc_attachfr(fr)
-struct frentry *fr;
+int
+ipf_scan_attachfr(fr)
+	struct frentry *fr;
 {
 	ipscan_t *i;
 
-	if (fr->fr_isctag[0]) {
-		READ_ENTER(&ipsc_rwlock);
-		i = ipsc_lookup(fr->fr_isctag);
+	if (fr->fr_isctag != -1) {
+		READ_ENTER(&ipf_scan_rwlock);
+		i = ipf_scan_lookup(fr->fr_isctag + fr->fr_names);
 		if (i != NULL) {
 			ATOMIC_INC32(i->ipsc_fref);
 		}
-		RWLOCK_EXIT(&ipsc_rwlock);
-		if (i == NULL)
+		RWLOCK_EXIT(&ipf_scan_rwlock);
+		if (i == NULL) {
+			ipf_interror = 90004;
 			return ENOENT;
+		}
 		fr->fr_isc = i;
 	}
 	return 0;
@@ -222,15 +235,16 @@
 }
 
 
-int ipsc_attachis(is)
-struct ipstate *is;
+int
+ipf_scan_attachis(is)
+	struct ipstate *is;
 {
 	frentry_t *fr;
 	ipscan_t *i;
 
-	READ_ENTER(&ipsc_rwlock);
+	READ_ENTER(&ipf_scan_rwlock);
 	fr = is->is_rule;
-	if (fr) {
+	if (fr != NULL) {
 		i = fr->fr_isc;
 		if ((i != NULL) && (i != (ipscan_t *)-1)) {
 			is->is_isc = i;
@@ -245,13 +259,14 @@
 				is->is_flags |= IS_SC_MATCHS;
 		}
 	}
-	RWLOCK_EXIT(&ipsc_rwlock);
+	RWLOCK_EXIT(&ipf_scan_rwlock);
 	return 0;
 }
 
 
-int ipsc_detachfr(fr)
-struct frentry *fr;
+int
+ipf_scan_detachfr(fr)
+	struct frentry *fr;
 {
 	ipscan_t *i;
 
@@ -263,18 +278,19 @@
 }
 
 
-int ipsc_detachis(is)
-struct ipstate *is;
+int
+ipf_scan_detachis(is)
+	struct ipstate *is;
 {
 	ipscan_t *i;
 
-	READ_ENTER(&ipsc_rwlock);
+	READ_ENTER(&ipf_scan_rwlock);
 	if ((i = is->is_isc) && (i != (ipscan_t *)-1)) {
 		ATOMIC_DEC32(i->ipsc_sref);
 		is->is_isc = NULL;
 		is->is_flags &= ~(IS_SC_CLIENT|IS_SC_SERVER);
 	}
-	RWLOCK_EXIT(&ipsc_rwlock);
+	RWLOCK_EXIT(&ipf_scan_rwlock);
 	return 0;
 }
 
@@ -282,10 +298,11 @@
 /*
  * 'string' compare for scanning
  */
-int ipsc_matchstr(sp, str, n)
-sinfo_t *sp;
-char *str;
-int n;
+int
+ipf_scan_matchstr(sp, str, n)
+	sinfo_t *sp;
+	char *str;
+	int n;
 {
 	char *s, *t, *up;
 	int i = n;
@@ -316,10 +333,11 @@
  * Returns 3 if both server and client match, 2 if just server,
  * 1 if just client
  */
-int ipsc_matchisc(isc, is, cl, sl, maxm)
-ipscan_t *isc;
-ipstate_t *is;
-int cl, sl, maxm[2];
+int
+ipf_scan_matchisc(isc, is, cl, sl, maxm)
+	ipscan_t *isc;
+	ipstate_t *is;
+	int cl, sl, maxm[2];
 {
 	int i, j, k, n, ret = 0, flags;
 
@@ -348,7 +366,8 @@
 		i = 0;
 		n = MIN(cl, isc->ipsc_clen);
 		if ((n > 0) && (!maxm || (n >= maxm[1]))) {
-			if (!ipsc_matchstr(&isc->ipsc_cl, is->is_sbuf[0], n)) {
+			if (!ipf_scan_matchstr(&isc->ipsc_cl,
+					       is->is_sbuf[0], n)) {
 				i++;
 				ret |= 1;
 				if (n > j)
@@ -364,7 +383,8 @@
 		i = 0;
 		n = MIN(cl, isc->ipsc_slen);
 		if ((n > 0) && (!maxm || (n >= maxm[1]))) {
-			if (!ipsc_matchstr(&isc->ipsc_sl, is->is_sbuf[1], n)) {
+			if (!ipf_scan_matchstr(&isc->ipsc_sl,
+					       is->is_sbuf[1], n)) {
 				i++;
 				ret |= 2;
 				if (n > k)
@@ -381,8 +401,9 @@
 }
 
 
-int ipsc_match(is)
-ipstate_t *is;
+int
+ipf_scan_match(is)
+	ipstate_t *is;
 {
 	int i, j, k, n, cl, sl, maxm[2];
 	ipscan_t *isc, *lm;
@@ -399,7 +420,7 @@
 		/*
 		 * Known object to scan for.
 		 */
-		i = ipsc_matchisc(isc, is, cl, sl, NULL);
+		i = ipf_scan_matchisc(isc, is, cl, sl, NULL);
 		if (i & 1) {
 			is->is_flags |= IS_SC_MATCHC;
 			is->is_flags &= ~IS_SC_CLIENT;
@@ -415,8 +436,8 @@
 		lm = NULL;
 		maxm[0] = 0;
 		maxm[1] = 0;
-		for (k = 0, isc = ipsc_list; isc; isc = isc->ipsc_next) {
-			i = ipsc_matchisc(isc, is, cl, sl, maxm);
+		for (k = 0, isc = ipf_scan_list; isc; isc = isc->ipsc_next) {
+			i = ipf_scan_matchisc(isc, is, cl, sl, maxm);
 			if (i) {
 				/*
 				 * We only want to remember the best match
@@ -475,7 +496,7 @@
 	j = ISC_A_NONE;
 	if ((is->is_flags & IS_SC_MATCHALL) == IS_SC_MATCHALL) {
 		j = isc->ipsc_action;
-		ipsc_stat.iscs_acted++;
+		ipf_scan_stat.iscs_acted++;
 	} else if ((is->is_isc != NULL) &&
 		   ((is->is_flags & IS_SC_MATCHALL) != IS_SC_MATCHALL) &&
 		   !(is->is_flags & (IS_SC_CLIENT|IS_SC_SERVER))) {
@@ -483,7 +504,7 @@
 		 * Matching failed...
 		 */
 		j = isc->ipsc_else;
-		ipsc_stat.iscs_else++;
+		ipf_scan_stat.iscs_else++;
 	}
 
 	switch (j)
@@ -508,9 +529,10 @@
 /*
  * check if a packet matches what we're scanning for
  */
-int ipsc_packet(fin, is)
-fr_info_t *fin;
-ipstate_t *is;
+int
+ipf_scan_packet(fin, is)
+	fr_info_t *fin;
+	ipstate_t *is;
 {
 	int i, j, rv, dlen, off, thoff;
 	u_32_t seq, s0;
@@ -552,7 +574,7 @@
 	if (j == 0)
 		return 1;
 
-	(void) ipsc_match(is);
+	(void) ipf_scan_match(is);
 #if 0
 	/*
 	 * There is the potential here for plain text passwords to get
@@ -567,11 +589,12 @@
 }
 
 
-int fr_scan_ioctl(data, cmd, mode, uid, ctx)
-caddr_t data;
-ioctlcmd_t cmd;
-int mode, uid;
-void *ctx;
+int
+ipf_scan_ioctl(data, cmd, mode, uid, ctx)
+	caddr_t data;
+	ioctlcmd_t cmd;
+	int mode, uid;
+	void *ctx;
 {
 	ipscanstat_t ipscs;
 	int err = 0;
@@ -579,17 +602,19 @@
 	switch (cmd)
 	{
 	case SIOCADSCA :
-		err = ipsc_add(data);
+		err = ipf_scan_add(data);
 		break;
 	case SIOCRMSCA :
-		err = ipsc_delete(data);
+		err = ipf_scan_remove(data);
 		break;
 	case SIOCGSCST :
-		bcopy((char *)&ipsc_stat, (char *)&ipscs, sizeof(ipscs));
-		ipscs.iscs_list = ipsc_list;
+		bcopy((char *)&ipf_scan_stat, (char *)&ipscs, sizeof(ipscs));
+		ipscs.iscs_list = ipf_scan_list;
 		err = BCOPYOUT(&ipscs, data, sizeof(ipscs));
-		if (err != 0)
+		if (err != 0) {
+			ipf_interror = 90005;
 			err = EFAULT;
+		}
 		break;
 	default :
 		err = EINVAL;

Modified: trunk/sys/contrib/ipfilter/netinet/ip_scan.h
===================================================================
--- trunk/sys/contrib/ipfilter/netinet/ip_scan.h	2018-05-28 18:55:30 UTC (rev 10138)
+++ trunk/sys/contrib/ipfilter/netinet/ip_scan.h	2018-05-28 18:56:30 UTC (rev 10139)
@@ -1,10 +1,11 @@
+/* $MidnightBSD$ */
 /*
- * Copyright (C) 1993-2001 by Darren Reed.
+ * Copyright (C) 2012 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 1.2 2008-09-19 02:15:13 laffer1 Exp $
+ * $Id$
  */
 
 #ifndef __IP_SCAN_H__
@@ -94,13 +95,13 @@
 } ipscanstat_t;
 
 
-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 *));
-extern	int ipsc_detachis __P((struct ipstate *));
-extern	int ipsc_detachfr __P((struct frentry *));
-extern	int ipsc_packet __P((struct fr_info *, struct ipstate *));
-extern	void fr_scanunload __P((void));
+extern	int ipf_scan_ioctl __P((ipf_main_softc_t *, caddr_t, ioctlcmd_t, int, int, void *));
+extern	int ipf_scan_init __P((void));
+extern	int ipf_scan_attachis __P((struct ipstate *));
+extern	int ipf_scan_attachfr __P((struct frentry *));
+extern	int ipf_scan_detachis __P((struct ipstate *));
+extern	int ipf_scan_detachfr __P((struct frentry *));
+extern	int ipf_scan_packet __P((struct fr_info *, struct ipstate *));
+extern	void ipf_scan_unload __P((ipf_main_softc_t *));
 
 #endif /* __IP_SCAN_H__ */

Modified: trunk/sys/contrib/ipfilter/netinet/ip_state.c
===================================================================
--- trunk/sys/contrib/ipfilter/netinet/ip_state.c	2018-05-28 18:55:30 UTC (rev 10138)
+++ trunk/sys/contrib/ipfilter/netinet/ip_state.c	2018-05-28 18:56:30 UTC (rev 10139)
@@ -1,9 +1,14 @@
-/*	$FreeBSD$	*/
+/* $MidnightBSD$ */
+/*	$FreeBSD: stable/10/sys/contrib/ipfilter/netinet/ip_state.c 328274 2018-01-23 04:01:48Z cy $ */
 
 /*
- * Copyright (C) 1995-2003 by Darren Reed.
+ * Copyright (C) 2012 by Darren Reed.
  *
  * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * Copyright 2008 Sun Microsystems.
+ *
+ * $Id$
  */
 #if defined(KERNEL) || defined(_KERNEL)
 # undef KERNEL
@@ -15,14 +20,6 @@
 #include <sys/types.h>
 #include <sys/param.h>
 #include <sys/file.h>
-#if defined(__NetBSD__) && (NetBSD >= 199905) && !defined(IPFILTER_LKM) && \
-    defined(_KERNEL)
-# 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)
 #include "opt_inet6.h"
@@ -41,9 +38,6 @@
 #if defined(_KERNEL) && (__FreeBSD_version >= 220000)
 # include <sys/filio.h>
 # include <sys/fcntl.h>
-# if (__FreeBSD_version >= 300000) && !defined(IPFILTER_LKM)
-#  include "opt_ipfilter.h"
-# endif
 #else
 # include <sys/ioctl.h>
 #endif
@@ -72,36 +66,31 @@
 #ifdef sun
 # include <net/af.h>
 #endif
-#include <net/route.h>
 #include <netinet/in.h>
 #include <netinet/in_systm.h>
 #include <netinet/ip.h>
 #include <netinet/tcp.h>
-#if !defined(linux)
-# include <netinet/ip_var.h>
-#endif
 #if !defined(__hpux) && !defined(linux)
 # include <netinet/tcp_fsm.h>
 #endif
 #include <netinet/udp.h>
 #include <netinet/ip_icmp.h>
+#if !defined(_KERNEL)
+# include "ipf.h"
+#endif
 #include "netinet/ip_compat.h"
-#include <netinet/tcpip.h>
 #include "netinet/ip_fil.h"
 #include "netinet/ip_nat.h"
 #include "netinet/ip_frag.h"
 #include "netinet/ip_state.h"
 #include "netinet/ip_proxy.h"
-#ifdef	IPFILTER_SYNC
+#include "netinet/ip_lookup.h"
+#include "netinet/ip_dstlist.h"
 #include "netinet/ip_sync.h"
-#endif
-#ifdef	IPFILTER_SCAN
-#include "netinet/ip_scan.h"
-#endif
 #ifdef	USE_INET6
 #include <netinet/icmp6.h>
 #endif
-#if (__FreeBSD_version >= 300000)
+#if FREEBSD_GE_REV(300000)
 # include <sys/malloc.h>
 # if defined(_KERNEL) && !defined(IPFILTER_LKM)
 #  include <sys/libkern.h>
@@ -113,342 +102,511 @@
 
 #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 1.5 2013-01-08 01:31:40 laffer1 Exp $";
+static const char rcsid[] = "@(#)$Id$";
 #endif
 
-static	ipstate_t **ips_table = NULL;
-static	u_long	*ips_seed = NULL;
-static	int	ips_num = 0;
-static	u_long ips_last_force_flush = 0;
-ips_stat_t ips_stats;
 
+static ipftuneable_t ipf_state_tuneables[] = {
+	{ { (void *)offsetof(ipf_state_softc_t, ipf_state_max) },
+		"state_max",		1,	0x7fffffff,
+		stsizeof(ipf_state_softc_t, ipf_state_max),
+		0,			NULL,	NULL },
+	{ { (void *)offsetof(ipf_state_softc_t, ipf_state_size) },
+		"state_size",		1,	0x7fffffff,
+		stsizeof(ipf_state_softc_t, ipf_state_size),
+		0,			NULL,	ipf_state_rehash },
+	{ { (void *)offsetof(ipf_state_softc_t, ipf_state_lock) },
+		"state_lock",		0,	1,
+		stsizeof(ipf_state_softc_t, ipf_state_lock),
+		IPFT_RDONLY,		NULL,	NULL },
+	{ { (void *)offsetof(ipf_state_softc_t, ipf_state_maxbucket) },
+		"state_maxbucket",	1,	0x7fffffff,
+		stsizeof(ipf_state_softc_t, ipf_state_maxbucket),
+		0,			NULL,	NULL },
+	{ { (void *)offsetof(ipf_state_softc_t, ipf_state_logging) },
+		"state_logging",0,	1,
+		stsizeof(ipf_state_softc_t, ipf_state_logging),
+		0,			NULL,	NULL },
+	{ { (void *)offsetof(ipf_state_softc_t, ipf_state_wm_high) },
+		"state_wm_high",2,	100,
+		stsizeof(ipf_state_softc_t, ipf_state_wm_high),
+		0,			NULL,	NULL },
+	{ { (void *)offsetof(ipf_state_softc_t, ipf_state_wm_low) },
+		"state_wm_low",	1,	99,
+		stsizeof(ipf_state_softc_t, ipf_state_wm_low),
+		0,			NULL,	NULL },
+	{ { (void *)offsetof(ipf_state_softc_t, ipf_state_wm_freq) },
+		"state_wm_freq",2,	999999,
+		stsizeof(ipf_state_softc_t, ipf_state_wm_freq),
+		0,			NULL,	NULL },
+	{ { NULL },
+		NULL,			0,	0,
+		0,
+		0,	NULL, NULL }
+};
+
+#define	SINCL(x)	ATOMIC_INCL(softs->x)
+#define	SBUMP(x)	(softs->x)++
+#define	SBUMPD(x, y)	do { (softs->x.y)++; DT(y); } while (0)
+#define	SBUMPDX(x, y, z)do { (softs->x.y)++; DT(z); } while (0)
+
 #ifdef	USE_INET6
-static ipstate_t *fr_checkicmp6matchingstate __P((fr_info_t *));
+static ipstate_t *ipf_checkicmp6matchingstate __P((fr_info_t *));
 #endif
-static ipstate_t *fr_matchsrcdst __P((fr_info_t *, ipstate_t *, i6addr_t *,
+static int ipf_allowstateicmp __P((fr_info_t *, ipstate_t *, i6addr_t *));
+static ipstate_t *ipf_matchsrcdst __P((fr_info_t *, ipstate_t *, i6addr_t *,
 				      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 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 *));
-static int fr_tcpoptions __P((fr_info_t *, tcphdr_t *, tcpdata_t *));
-static ipstate_t *fr_stclone __P((fr_info_t *, tcphdr_t *, ipstate_t *));
-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 *));
+static ipstate_t *ipf_checkicmpmatchingstate __P((fr_info_t *));
+static int ipf_state_flush_entry __P((ipf_main_softc_t *, void *));
+static ips_stat_t *ipf_state_stats __P((ipf_main_softc_t *));
+static int ipf_state_del __P((ipf_main_softc_t *, ipstate_t *, int));
+static int ipf_state_remove __P((ipf_main_softc_t *, caddr_t));
+static int ipf_state_match __P((ipstate_t *is1, ipstate_t *is2));
+static int ipf_state_matchaddresses __P((ipstate_t *is1, ipstate_t *is2));
+static int ipf_state_matchipv4addrs __P((ipstate_t *is1, ipstate_t *is2));
+static int ipf_state_matchipv6addrs __P((ipstate_t *is1, ipstate_t *is2));
+static int ipf_state_matchisps __P((ipstate_t *is1, ipstate_t *is2));
+static int ipf_state_matchports __P((udpinfo_t *is1, udpinfo_t *is2));
+static int ipf_state_matcharray __P((ipstate_t *, int *, u_long));
+static void ipf_ipsmove __P((ipf_state_softc_t *, ipstate_t *, u_int));
+static int ipf_state_tcp __P((ipf_main_softc_t *, ipf_state_softc_t *,
+			      fr_info_t *, tcphdr_t *, ipstate_t *));
+static int ipf_tcpoptions __P((ipf_state_softc_t *, fr_info_t *,
+			       tcphdr_t *, tcpdata_t *));
+static ipstate_t *ipf_state_clone __P((fr_info_t *, tcphdr_t *, ipstate_t *));
+static void ipf_fixinisn __P((fr_info_t *, ipstate_t *));
+static void ipf_fixoutisn __P((fr_info_t *, ipstate_t *));
+static void ipf_checknewisn __P((fr_info_t *, ipstate_t *));
+static int ipf_state_iter __P((ipf_main_softc_t *, ipftoken_t *,
+			       ipfgeniter_t *, ipfobj_t *));
+static int ipf_state_gettable __P((ipf_main_softc_t *, ipf_state_softc_t *,
+				   char *));
+static	int ipf_state_tcpinwindow __P((struct fr_info *, struct tcpdata *,
+				       struct tcpdata *, tcphdr_t *, int));
 
-int fr_stputent __P((caddr_t));
-int fr_stgetent __P((caddr_t));
+static int ipf_state_getent __P((ipf_main_softc_t *, ipf_state_softc_t *,
+				 caddr_t));
+static int ipf_state_putent __P((ipf_main_softc_t *, ipf_state_softc_t *,
+				 caddr_t));
 
 #define	ONE_DAY		IPF_TTLVAL(1 * 86400)	/* 1 day */
 #define	FIVE_DAYS	(5 * ONE_DAY)
-#define	DOUBLE_HASH(x)	(((x) + ips_seed[(x) % fr_statesize]) % fr_statesize)
+#define	DOUBLE_HASH(x)	(((x) + softs->ipf_state_seed[(x) % \
+			 softs->ipf_state_size]) % softs->ipf_state_size)
 
-u_long	fr_tcpidletimeout = FIVE_DAYS,
-	fr_tcpclosewait = IPF_TTLVAL(2 * TCP_MSL),
-	fr_tcplastack = IPF_TTLVAL(30),
-	fr_tcptimeout = IPF_TTLVAL(2 * TCP_MSL),
-	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),
-	fr_icmptimeout = IPF_TTLVAL(60),
-	fr_icmpacktimeout = IPF_TTLVAL(6),
-	fr_iptimeout = IPF_TTLVAL(60);
-int	fr_statemax = IPSTATE_MAX,
-	fr_statesize = IPSTATE_SIZE;
-int	fr_state_doflush = 0,
-	fr_state_lock = 0,
-	fr_state_maxbucket = 0,
-	fr_state_maxbucket_reset = 1,
-	fr_state_init = 0;
-ipftq_t	ips_tqtqb[IPF_TCP_NSTATES],
-	ips_udptq,
-	ips_udpacktq,
-	ips_iptq,
-	ips_icmptq,
-	ips_icmpacktq,
-	ips_deletetq,
-	*ips_utqe = NULL;
-#ifdef	IPFILTER_LOG
-int	ipstate_logging = 1;
-#else
-int	ipstate_logging = 0;
-#endif
-ipstate_t *ips_list = NULL;
 
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_state_main_load                                         */
+/* Returns:     int - 0 == success, -1 == failure                           */
+/* Parameters:  Nil                                                         */
+/*                                                                          */
+/* A null-op function that exists as a placeholder so that the flow in      */
+/* other functions is obvious.                                              */
+/* ------------------------------------------------------------------------ */
+int
+ipf_state_main_load()
+{
+	return 0;
+}
 
+
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_stateinit                                                */
+/* Function:    ipf_state_main_unload                                       */
 /* Returns:     int - 0 == success, -1 == failure                           */
 /* Parameters:  Nil                                                         */
 /*                                                                          */
-/* Initialise all the global variables used within the state code.          */
-/* This action also includes initiailising locks.                           */
+/* A null-op function that exists as a placeholder so that the flow in      */
+/* other functions is obvious.                                              */
 /* ------------------------------------------------------------------------ */
-int fr_stateinit()
+int
+ipf_state_main_unload()
 {
-#if defined(NEED_LOCAL_RAND) || !defined(_KERNEL)
-	struct timeval tv;
+	return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_state_soft_create                                       */
+/* Returns:     void *   - NULL = failure, else pointer to soft context     */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*                                                                          */
+/* Create a new state soft context structure and populate it with the list  */
+/* of tunables and other default settings.                                  */
+/* ------------------------------------------------------------------------ */
+void *
+ipf_state_soft_create(softc)
+	ipf_main_softc_t *softc;
+{
+	ipf_state_softc_t *softs;
+
+	KMALLOC(softs, ipf_state_softc_t *);
+	if (softs == NULL)
+		return NULL;
+
+	bzero((char *)softs, sizeof(*softs));
+
+	softs->ipf_state_tune = ipf_tune_array_copy(softs,
+						    sizeof(ipf_state_tuneables),
+						    ipf_state_tuneables);
+	if (softs->ipf_state_tune == NULL) {
+		ipf_state_soft_destroy(softc, softs);
+		return NULL;
+	}
+	if (ipf_tune_array_link(softc, softs->ipf_state_tune) == -1) {
+		ipf_state_soft_destroy(softc, softs);
+		return NULL;
+	}
+
+#ifdef	IPFILTER_LOG
+	softs->ipf_state_logging = 1;
+#else
+	softs->ipf_state_logging = 0;
 #endif
-	int i;
+	softs->ipf_state_size = IPSTATE_SIZE,
+	softs->ipf_state_maxbucket = 0;
+	softs->ipf_state_wm_freq = IPF_TTLVAL(10);
+	softs->ipf_state_max = IPSTATE_MAX;
+	softs->ipf_state_wm_last = 0;
+	softs->ipf_state_wm_high = 99;
+	softs->ipf_state_wm_low = 90;
+	softs->ipf_state_inited = 0;
+	softs->ipf_state_lock = 0;
+	softs->ipf_state_doflush = 0;
 
-	KMALLOCS(ips_table, ipstate_t **, fr_statesize * sizeof(ipstate_t *));
-	if (ips_table == NULL)
-		return -1;
-	bzero((char *)ips_table, fr_statesize * sizeof(ipstate_t *));
+	return softs;
+}
 
-	KMALLOCS(ips_seed, u_long *, fr_statesize * sizeof(*ips_seed));
-	if (ips_seed == NULL)
-		return -2;
-#if defined(NEED_LOCAL_RAND) || !defined(_KERNEL)
-	tv.tv_sec = 0;
-	GETKTIME(&tv);
-#endif
-	for (i = 0; i < fr_statesize; i++) {
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_state_soft_destroy                                      */
+/* Returns:     Nil                                                         */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              arg(I)   - pointer to local context to use                  */
+/*                                                                          */
+/* Undo only what we did in soft create: unlink and free the tunables and   */
+/* free the soft context structure itself.                                  */
+/* ------------------------------------------------------------------------ */
+void
+ipf_state_soft_destroy(softc, arg)
+	ipf_main_softc_t *softc;
+	void *arg;
+{
+	ipf_state_softc_t *softs = arg;
+
+	if (softs->ipf_state_tune != NULL) {
+		ipf_tune_array_unlink(softc, softs->ipf_state_tune);
+		KFREES(softs->ipf_state_tune, sizeof(ipf_state_tuneables));
+		softs->ipf_state_tune = NULL;
+	}
+
+	KFREE(softs);
+}
+
+static void *
+ipf_state_seed_alloc(u_int state_size, u_int state_max)
+{
+	u_int i;
+	u_long *state_seed;
+	KMALLOCS(state_seed, u_long *, state_size * sizeof(*state_seed));
+	if (state_seed == NULL)
+		return NULL;
+
+	for (i = 0; i < state_size; i++) {
 		/*
-		 * XXX - ips_seed[X] should be a random number of sorts.
+		 * XXX - ipf_state_seed[X] should be a random number of sorts.
 		 */
-#if !defined(NEED_LOCAL_RAND) && defined(_KERNEL)
-		ips_seed[i] = arc4random();
+#if  FREEBSD_GE_REV(400000)
+		state_seed[i] = arc4random();
 #else
-		ips_seed[i] = ((u_long)ips_seed + i) * fr_statesize;
-		ips_seed[i] += tv.tv_sec;
-		ips_seed[i] *= (u_long)ips_seed;
-		ips_seed[i] ^= 0x5a5aa5a5;
-		ips_seed[i] *= fr_statemax;
+		state_seed[i] = ((u_long)state_seed + i) * state_size;
+		state_seed[i] ^= 0xa5a55a5a;
+		state_seed[i] *= (u_long)state_seed;
+		state_seed[i] ^= 0x5a5aa5a5;
+		state_seed[i] *= state_max;
 #endif
 	}
-#if defined(NEED_LOCAL_RAND) && defined(_KERNEL)
-	ipf_rand_push(ips_seed, fr_statesize * sizeof(*ips_seed));
-#endif
+	return state_seed;
+}
 
-	/* fill icmp reply type table */
-	for (i = 0; i <= ICMP_MAXTYPE; i++)
-		icmpreplytype4[i] = -1;
-	icmpreplytype4[ICMP_ECHO] = ICMP_ECHOREPLY;
-	icmpreplytype4[ICMP_TSTAMP] = ICMP_TSTAMPREPLY;
-	icmpreplytype4[ICMP_IREQ] = ICMP_IREQREPLY;
-	icmpreplytype4[ICMP_MASKREQ] = ICMP_MASKREPLY;
-#ifdef	USE_INET6
-	/* fill icmp reply type table */
-	for (i = 0; i <= ICMP6_MAXTYPE; i++)
-		icmpreplytype6[i] = -1;
-	icmpreplytype6[ICMP6_ECHO_REQUEST] = ICMP6_ECHO_REPLY;
-	icmpreplytype6[ICMP6_MEMBERSHIP_QUERY] = ICMP6_MEMBERSHIP_REPORT;
-	icmpreplytype6[ICMP6_NI_QUERY] = ICMP6_NI_REPLY;
-	icmpreplytype6[ND_ROUTER_SOLICIT] = ND_ROUTER_ADVERT;
-	icmpreplytype6[ND_NEIGHBOR_SOLICIT] = ND_NEIGHBOR_ADVERT;
-#endif
 
-	KMALLOCS(ips_stats.iss_bucketlen, u_long *,
-		 fr_statesize * sizeof(u_long));
-	if (ips_stats.iss_bucketlen == NULL)
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_state_soft_init                                         */
+/* Returns:     int      - 0 == success, -1 == failure                      */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              arg(I)   - pointer to local context to use                  */
+/*                                                                          */
+/* Initialise the state soft context structure so it is ready for use.      */
+/* This involves:                                                           */
+/* - allocating a hash table and zero'ing it out                            */
+/* - building a secondary table of seeds for double hashing to make it more */
+/*   difficult to attempt to attack the hash table itself (for DoS)         */
+/* - initialise all of the timeout queues, including a table for TCP, some  */
+/*   pairs of query/response for UDP and other IP protocols (typically the  */
+/*   reply queue has a shorter timeout than the query)                      */
+/* ------------------------------------------------------------------------ */
+int
+ipf_state_soft_init(softc, arg)
+	ipf_main_softc_t *softc;
+	void *arg;
+{
+	ipf_state_softc_t *softs = arg;
+	int i;
+
+	KMALLOCS(softs->ipf_state_table,
+		 ipstate_t **, softs->ipf_state_size * sizeof(ipstate_t *));
+	if (softs->ipf_state_table == NULL)
 		return -1;
-	bzero((char *)ips_stats.iss_bucketlen, fr_statesize * sizeof(u_long));
 
-	if (fr_state_maxbucket == 0) {
-		for (i = fr_statesize; i > 0; i >>= 1)
-			fr_state_maxbucket++;
-		fr_state_maxbucket *= 2;
+	bzero((char *)softs->ipf_state_table,
+	      softs->ipf_state_size * sizeof(ipstate_t *));
+
+	softs->ipf_state_seed = ipf_state_seed_alloc(softs->ipf_state_size,
+	    softs->ipf_state_max);
+	if (softs->ipf_state_seed == NULL)
+		return -2;
+
+	KMALLOCS(softs->ipf_state_stats.iss_bucketlen, u_int *,
+		 softs->ipf_state_size * sizeof(u_int));
+	if (softs->ipf_state_stats.iss_bucketlen == NULL)
+		return -3;
+
+	bzero((char *)softs->ipf_state_stats.iss_bucketlen,
+	      softs->ipf_state_size * sizeof(u_int));
+
+	if (softs->ipf_state_maxbucket == 0) {
+		for (i = softs->ipf_state_size; i > 0; i >>= 1)
+			softs->ipf_state_maxbucket++;
+		softs->ipf_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;
-	ips_udptq.ifq_ref = 1;
-	ips_udptq.ifq_head = NULL;
-	ips_udptq.ifq_tail = &ips_udptq.ifq_head;
-	MUTEX_INIT(&ips_udptq.ifq_lock, "ipftq udp tab");
-	ips_udptq.ifq_next = &ips_udpacktq;
-	ips_udpacktq.ifq_ttl = (u_long)fr_udpacktimeout;
-	ips_udpacktq.ifq_ref = 1;
-	ips_udpacktq.ifq_head = NULL;
-	ips_udpacktq.ifq_tail = &ips_udpacktq.ifq_head;
-	MUTEX_INIT(&ips_udpacktq.ifq_lock, "ipftq udpack tab");
-	ips_udpacktq.ifq_next = &ips_icmptq;
-	ips_icmptq.ifq_ttl = (u_long)fr_icmptimeout;
-	ips_icmptq.ifq_ref = 1;
-	ips_icmptq.ifq_head = NULL;
-	ips_icmptq.ifq_tail = &ips_icmptq.ifq_head;
-	MUTEX_INIT(&ips_icmptq.ifq_lock, "ipftq icmp tab");
-	ips_icmptq.ifq_next = &ips_icmpacktq;
-	ips_icmpacktq.ifq_ttl = (u_long)fr_icmpacktimeout;
-	ips_icmpacktq.ifq_ref = 1;
-	ips_icmpacktq.ifq_head = NULL;
-	ips_icmpacktq.ifq_tail = &ips_icmpacktq.ifq_head;
-	MUTEX_INIT(&ips_icmpacktq.ifq_lock, "ipftq icmpack tab");
-	ips_icmpacktq.ifq_next = &ips_iptq;
-	ips_iptq.ifq_ttl = (u_long)fr_iptimeout;
-	ips_iptq.ifq_ref = 1;
-	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 = &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;
+	ipf_sttab_init(softc, softs->ipf_state_tcptq);
+	softs->ipf_state_stats.iss_tcptab = softs->ipf_state_tcptq;
+	softs->ipf_state_tcptq[IPF_TCP_NSTATES - 1].ifq_next =
+						&softs->ipf_state_udptq;
 
-	RWLOCK_INIT(&ipf_state, "ipf IP state rwlock");
-	MUTEX_INIT(&ipf_stinsert, "ipf state insert mutex");
-	fr_state_init = 1;
+	IPFTQ_INIT(&softs->ipf_state_udptq, softc->ipf_udptimeout,
+		   "ipftq udp tab");
+	softs->ipf_state_udptq.ifq_next = &softs->ipf_state_udpacktq;
 
-	ips_last_force_flush = fr_ticks;
+	IPFTQ_INIT(&softs->ipf_state_udpacktq, softc->ipf_udpacktimeout,
+		   "ipftq udpack tab");
+	softs->ipf_state_udpacktq.ifq_next = &softs->ipf_state_icmptq;
+
+	IPFTQ_INIT(&softs->ipf_state_icmptq, softc->ipf_icmptimeout,
+		   "ipftq icmp tab");
+	softs->ipf_state_icmptq.ifq_next = &softs->ipf_state_icmpacktq;
+
+	IPFTQ_INIT(&softs->ipf_state_icmpacktq, softc->ipf_icmpacktimeout,
+		  "ipftq icmpack tab");
+	softs->ipf_state_icmpacktq.ifq_next = &softs->ipf_state_iptq;
+
+	IPFTQ_INIT(&softs->ipf_state_iptq, softc->ipf_iptimeout,
+		   "ipftq iptimeout tab");
+	softs->ipf_state_iptq.ifq_next = &softs->ipf_state_pending;
+
+	IPFTQ_INIT(&softs->ipf_state_pending, IPF_HZ_DIVIDE, "ipftq pending");
+	softs->ipf_state_pending.ifq_next = &softs->ipf_state_deletetq;
+
+	IPFTQ_INIT(&softs->ipf_state_deletetq, 1, "ipftq delete");
+	softs->ipf_state_deletetq.ifq_next = NULL;
+
+	MUTEX_INIT(&softs->ipf_stinsert, "ipf state insert mutex");
+
+
+	softs->ipf_state_wm_last = softc->ipf_ticks;
+	softs->ipf_state_inited = 1;
+
 	return 0;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_stateunload                                              */
-/* Returns:     Nil                                                         */
-/* Parameters:  Nil                                                         */
+/* Function:    ipf_state_soft_fini                                         */
+/* Returns:     int      - 0 = success, -1 = failure                        */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              arg(I)   - pointer to local context to use                  */
 /*                                                                          */
 /* Release and destroy any resources acquired or initialised so that        */
 /* IPFilter can be unloaded or re-initialised.                              */
 /* ------------------------------------------------------------------------ */
-void fr_stateunload()
+int
+ipf_state_soft_fini(softc, arg)
+	ipf_main_softc_t *softc;
+	void *arg;
 {
+	ipf_state_softc_t *softs = arg;
 	ipftq_t *ifq, *ifqnext;
 	ipstate_t *is;
 
-	while ((is = ips_list) != NULL)
-		fr_delstate(is, ISL_UNLOAD);
+	while ((is = softs->ipf_state_list) != NULL)
+		ipf_state_del(softc, is, ISL_UNLOAD);
 
 	/*
 	 * Proxy timeout queues are not cleaned here because although they
-	 * exist on the state list, appr_unload is called after fr_stateunload
-	 * and the proxies actually are responsible for them being created.
-	 * Should the proxy timeouts have their own list?  There's no real
-	 * justification as this is the only complicationA
+	 * exist on the state list, appr_unload is called after
+	 * ipf_state_unload and the proxies actually are responsible for them
+	 * being created. Should the proxy timeouts have their own list?
+	 * There's no real justification as this is the only complication.
 	 */
-	for (ifq = ips_utqe; ifq != NULL; ifq = ifqnext) {
+	for (ifq = softs->ipf_state_usertq; ifq != NULL; ifq = ifqnext) {
 		ifqnext = ifq->ifq_next;
-		if (((ifq->ifq_flags & IFQF_PROXY) == 0) &&
-		    (fr_deletetimeoutqueue(ifq) == 0))
-			fr_freetimeoutqueue(ifq);
+
+		if (ipf_deletetimeoutqueue(ifq) == 0)
+			ipf_freetimeoutqueue(softc, ifq);
 	}
 
-	ips_stats.iss_inuse = 0;
-	ips_num = 0;
+	softs->ipf_state_stats.iss_inuse = 0;
+	softs->ipf_state_stats.iss_active = 0;
 
-	if (fr_state_init == 1) {
-		fr_sttab_destroy(ips_tqtqb);
-		MUTEX_DESTROY(&ips_udptq.ifq_lock);
-		MUTEX_DESTROY(&ips_icmptq.ifq_lock);
-		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 (softs->ipf_state_inited == 1) {
+		softs->ipf_state_inited = 0;
+		ipf_sttab_destroy(softs->ipf_state_tcptq);
+		MUTEX_DESTROY(&softs->ipf_state_udptq.ifq_lock);
+		MUTEX_DESTROY(&softs->ipf_state_icmptq.ifq_lock);
+		MUTEX_DESTROY(&softs->ipf_state_udpacktq.ifq_lock);
+		MUTEX_DESTROY(&softs->ipf_state_icmpacktq.ifq_lock);
+		MUTEX_DESTROY(&softs->ipf_state_iptq.ifq_lock);
+		MUTEX_DESTROY(&softs->ipf_state_deletetq.ifq_lock);
+		MUTEX_DESTROY(&softs->ipf_state_pending.ifq_lock);
+		MUTEX_DESTROY(&softs->ipf_stinsert);
 	}
 
-	if (ips_table != NULL) {
-		KFREES(ips_table, fr_statesize * sizeof(*ips_table));
-		ips_table = NULL;
+	if (softs->ipf_state_table != NULL) {
+		KFREES(softs->ipf_state_table,
+		       softs->ipf_state_size * sizeof(*softs->ipf_state_table));
+		softs->ipf_state_table = NULL;
 	}
 
-	if (ips_seed != NULL) {
-		KFREES(ips_seed, fr_statesize * sizeof(*ips_seed));
-		ips_seed = NULL;
+	if (softs->ipf_state_seed != NULL) {
+		KFREES(softs->ipf_state_seed,
+		       softs->ipf_state_size * sizeof(*softs->ipf_state_seed));
+		softs->ipf_state_seed = NULL;
 	}
 
-	if (ips_stats.iss_bucketlen != NULL) {
-		KFREES(ips_stats.iss_bucketlen, fr_statesize * sizeof(u_long));
-		ips_stats.iss_bucketlen = NULL;
+	if (softs->ipf_state_stats.iss_bucketlen != NULL) {
+		KFREES(softs->ipf_state_stats.iss_bucketlen,
+		       softs->ipf_state_size * sizeof(u_int));
+		softs->ipf_state_stats.iss_bucketlen = NULL;
 	}
 
-	if (fr_state_maxbucket_reset == 1)
-		fr_state_maxbucket = 0;
+	return 0;
+}
 
-	if (fr_state_init == 1) {
-		fr_state_init = 0;
-		RW_DESTROY(&ipf_state);
-		MUTEX_DESTROY(&ipf_stinsert);
-	}
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_state_setlock                                           */
+/* Returns:     Nil                                                         */
+/* Parameters:  arg(I) - pointer to local context to use                    */
+/*              tmp(I) - new value for lock                                 */
+/*                                                                          */
+/* Stub function that allows for external manipulation of ipf_state_lock    */
+/* ------------------------------------------------------------------------ */
+void
+ipf_state_setlock(arg, tmp)
+	void *arg;
+	int tmp;
+{
+	ipf_state_softc_t *softs = arg;
+
+	softs->ipf_state_lock = tmp;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_statetstats                                              */
+/* Function:    ipf_state_stats                                             */
 /* Returns:     ips_state_t* - pointer to state stats structure             */
-/* Parameters:  Nil                                                         */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
 /*                                                                          */
 /* Put all the current numbers and pointers into a single struct and return */
 /* a pointer to it.                                                         */
 /* ------------------------------------------------------------------------ */
-static ips_stat_t *fr_statetstats()
+static ips_stat_t *
+ipf_state_stats(softc)
+	ipf_main_softc_t *softc;
 {
-	ips_stats.iss_active = ips_num;
-	ips_stats.iss_statesize = fr_statesize;
-	ips_stats.iss_statemax = fr_statemax;
-	ips_stats.iss_table = ips_table;
-	ips_stats.iss_list = ips_list;
-	ips_stats.iss_ticks = fr_ticks;
-	return &ips_stats;
+	ipf_state_softc_t *softs = softc->ipf_state_soft;
+	ips_stat_t *issp = &softs->ipf_state_stats;
+
+	issp->iss_state_size = softs->ipf_state_size;
+	issp->iss_state_max = softs->ipf_state_max;
+	issp->iss_table = softs->ipf_state_table;
+	issp->iss_list = softs->ipf_state_list;
+	issp->iss_ticks = softc->ipf_ticks;
+
+#ifdef IPFILTER_LOGGING
+	issp->iss_log_ok = ipf_log_logok(softc, IPF_LOGSTATE);
+	issp->iss_log_fail = ipf_log_failures(softc, IPF_LOGSTATE);
+#else
+	issp->iss_log_ok = 0;
+	issp->iss_log_fail = 0;
+#endif
+	return issp;
 }
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_state_remove                                             */
+/* Function:    ipf_state_remove                                            */
 /* Returns:     int - 0 == success, != 0 == failure                         */
-/* Parameters:  data(I) - pointer to state structure to delete from table   */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              data(I)  - pointer to state structure to delete from table  */
 /*                                                                          */
 /* Search for a state structure that matches the one passed, according to   */
 /* the IP addresses and other protocol specific information.                */
 /* ------------------------------------------------------------------------ */
-static int fr_state_remove(data)
-caddr_t data;
+static int
+ipf_state_remove(softc, data)
+	ipf_main_softc_t *softc;
+	caddr_t data;
 {
+	ipf_state_softc_t *softs = softc->ipf_state_soft;
 	ipstate_t *sp, st;
 	int error;
 
 	sp = &st;
-	error = fr_inobj(data, &st, IPFOBJ_IPSTATE);
+	error = ipf_inobj(softc, data, NULL, &st, IPFOBJ_IPSTATE);
 	if (error)
 		return EFAULT;
 
-	WRITE_ENTER(&ipf_state);
-	for (sp = ips_list; sp; sp = sp->is_next)
+	WRITE_ENTER(&softc->ipf_state);
+	for (sp = softs->ipf_state_list; sp; sp = sp->is_next)
 		if ((sp->is_p == st.is_p) && (sp->is_v == st.is_v) &&
 		    !bcmp((caddr_t)&sp->is_src, (caddr_t)&st.is_src,
 			  sizeof(st.is_src)) &&
-		    !bcmp((caddr_t)&sp->is_dst, (caddr_t)&st.is_src,
+		    !bcmp((caddr_t)&sp->is_dst, (caddr_t)&st.is_dst,
 			  sizeof(st.is_dst)) &&
 		    !bcmp((caddr_t)&sp->is_ps, (caddr_t)&st.is_ps,
 			  sizeof(st.is_ps))) {
-			fr_delstate(sp, ISL_REMOVE);
-			RWLOCK_EXIT(&ipf_state);
+			ipf_state_del(softc, sp, ISL_REMOVE);
+			RWLOCK_EXIT(&softc->ipf_state);
 			return 0;
 		}
-	RWLOCK_EXIT(&ipf_state);
+	RWLOCK_EXIT(&softc->ipf_state);
+
+	IPFERROR(100001);
 	return ESRCH;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_state_ioctl                                              */
+/* Function:    ipf_state_ioctl                                             */
 /* Returns:     int - 0 == success, != 0 == failure                         */
-/* Parameters:  data(I) - pointer to ioctl data                             */
-/*              cmd(I)  - ioctl command integer                             */
-/*              mode(I) - file mode bits used with open                     */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              data(I)  - pointer to ioctl data                            */
+/*              cmd(I)   - ioctl command integer                            */
+/*              mode(I)  - file mode bits used with open                    */
+/*              uid(I)   - uid of process making the ioctl call             */
+/*              ctx(I)   - pointer specific to context of the call          */
 /*                                                                          */
 /* Processes an ioctl call made to operate on the IP Filter state device.   */
 /* ------------------------------------------------------------------------ */
-int fr_state_ioctl(data, cmd, mode, uid, ctx)
-caddr_t data;
-ioctlcmd_t cmd;
-int mode, uid;
-void *ctx;
+int
+ipf_state_ioctl(softc, data, cmd, mode, uid, ctx)
+	ipf_main_softc_t *softc;
+	caddr_t data;
+	ioctlcmd_t cmd;
+	int mode, uid;
+	void *ctx;
 {
+	ipf_state_softc_t *softs = softc->ipf_state_soft;
 	int arg, ret, error = 0;
 	SPL_INT(s);
 
@@ -458,7 +616,7 @@
 	 * Delete an entry from the state table.
 	 */
 	case SIOCDELST :
-		error = fr_state_remove(data);
+		error = ipf_state_remove(softc, data);
 		break;
 
 	/*
@@ -465,48 +623,68 @@
 	 * Flush the state table
 	 */
 	case SIOCIPFFL :
-		error = BCOPYIN(data, (char *)&arg, sizeof(arg));
+		error = BCOPYIN(data, &arg, sizeof(arg));
 		if (error != 0) {
+			IPFERROR(100002);
 			error = EFAULT;
+
 		} else {
-			WRITE_ENTER(&ipf_state);
-			ret = fr_state_flush(arg, 4);
-			RWLOCK_EXIT(&ipf_state);
-			error = BCOPYOUT((char *)&ret, data, sizeof(ret));
-			if (error != 0)
+			WRITE_ENTER(&softc->ipf_state);
+			ret = ipf_state_flush(softc, arg, 4);
+			RWLOCK_EXIT(&softc->ipf_state);
+
+			error = BCOPYOUT(&ret, data, sizeof(ret));
+			if (error != 0) {
+				IPFERROR(100003);
 				error = EFAULT;
+			}
 		}
 		break;
 
 #ifdef	USE_INET6
 	case SIOCIPFL6 :
-		error = BCOPYIN(data, (char *)&arg, sizeof(arg));
+		error = BCOPYIN(data, &arg, sizeof(arg));
 		if (error != 0) {
+			IPFERROR(100004);
 			error = EFAULT;
+
 		} else {
-			WRITE_ENTER(&ipf_state);
-			ret = fr_state_flush(arg, 6);
-			RWLOCK_EXIT(&ipf_state);
-			error = BCOPYOUT((char *)&ret, data, sizeof(ret));
-			if (error != 0)
+			WRITE_ENTER(&softc->ipf_state);
+			ret = ipf_state_flush(softc, arg, 6);
+			RWLOCK_EXIT(&softc->ipf_state);
+
+			error = BCOPYOUT(&ret, data, sizeof(ret));
+			if (error != 0) {
+				IPFERROR(100005);
 				error = EFAULT;
+			}
 		}
 		break;
 #endif
+
+	case SIOCMATCHFLUSH :
+		WRITE_ENTER(&softc->ipf_state);
+		error = ipf_state_matchflush(softc, data);
+		RWLOCK_EXIT(&softc->ipf_state);
+		break;
+
 #ifdef	IPFILTER_LOG
 	/*
 	 * Flush the state log.
 	 */
 	case SIOCIPFFB :
-		if (!(mode & FWRITE))
+		if (!(mode & FWRITE)) {
+			IPFERROR(100008);
 			error = EPERM;
-		else {
+		} else {
 			int tmp;
 
-			tmp = ipflog_clear(IPL_LOGSTATE);
-			error = BCOPYOUT((char *)&tmp, data, sizeof(tmp));
-			if (error != 0)
+			tmp = ipf_log_clear(softc, IPL_LOGSTATE);
+			error = BCOPYOUT(&tmp, data, sizeof(tmp));
+			if (error != 0) {
+				IPFERROR(100009);
 				error = EFAULT;
+			}
 		}
 		break;
 
@@ -514,13 +692,16 @@
 	 * Turn logging of state information on/off.
 	 */
 	case SIOCSETLG :
-		if (!(mode & FWRITE))
+		if (!(mode & FWRITE)) {
+			IPFERROR(100010);
 			error = EPERM;
-		else {
-			error = BCOPYIN((char *)data, (char *)&ipstate_logging,
-					sizeof(ipstate_logging));
-			if (error != 0)
+		} else {
+			error = BCOPYIN(data, &softs->ipf_state_logging,
+					sizeof(softs->ipf_state_logging));
+			if (error != 0) {
+				IPFERROR(100011);
 				error = EFAULT;
+			}
 		}
 		break;
 
@@ -528,10 +709,12 @@
 	 * Return the current state of logging.
 	 */
 	case SIOCGETLG :
-		error = BCOPYOUT((char *)&ipstate_logging, (char *)data,
-				 sizeof(ipstate_logging));
-		if (error != 0)
+		error = BCOPYOUT(&softs->ipf_state_logging, data,
+				 sizeof(softs->ipf_state_logging));
+		if (error != 0) {
+			IPFERROR(100012);
 			error = EFAULT;
+		}
 		break;
 
 	/*
@@ -538,10 +721,12 @@
 	 * Return the number of bytes currently waiting to be read.
 	 */
 	case FIONREAD :
-		arg = iplused[IPL_LOGSTATE];	/* returned in an int */
-		error = BCOPYOUT((char *)&arg, data, sizeof(arg));
-		if (error != 0)
+		arg = ipf_log_bytesused(softc, IPL_LOGSTATE);
+		error = BCOPYOUT(&arg, data, sizeof(arg));
+		if (error != 0) {
+			IPFERROR(100013);
 			error = EFAULT;
+		}
 		break;
 #endif
 
@@ -549,7 +734,8 @@
 	 * Get the current state statistics.
 	 */
 	case SIOCGETFS :
-		error = fr_outobj(data, fr_statetstats(), IPFOBJ_STATESTAT);
+		error = ipf_outobj(softc, data, ipf_state_stats(softc),
+				   IPFOBJ_STATESTAT);
 		break;
 
 	/*
@@ -558,9 +744,10 @@
 	 */
 	case SIOCSTLCK :
 		if (!(mode & FWRITE)) {
+			IPFERROR(100014);
 			error = EPERM;
 		} else {
-			error = fr_lock(data, &fr_state_lock);
+			error = ipf_lock(data, &softs->ipf_state_lock);
 		}
 		break;
 
@@ -568,11 +755,12 @@
 	 * Add an entry to the current state table.
 	 */
 	case SIOCSTPUT :
-		if (!fr_state_lock || !(mode &FWRITE)) {
+		if (!softs->ipf_state_lock || !(mode &FWRITE)) {
+			IPFERROR(100015);
 			error = EACCES;
 			break;
 		}
-		error = fr_stputent(data);
+		error = ipf_state_putent(softc, softs, data);
 		break;
 
 	/*
@@ -579,11 +767,12 @@
 	 * Get a state table entry.
 	 */
 	case SIOCSTGET :
-		if (!fr_state_lock) {
+		if (!softs->ipf_state_lock) {
+			IPFERROR(100016);
 			error = EACCES;
 			break;
 		}
-		error = fr_stgetent(data);
+		error = ipf_state_getent(softc, softs, data);
 		break;
 
 	/*
@@ -590,10 +779,12 @@
 	 * 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 = BCOPYOUT(softs->ipf_state_stats.iss_bucketlen, data,
+				 softs->ipf_state_size * sizeof(u_int));
+		if (error != 0) {
+			IPFERROR(100017);
 			error = EFAULT;
+		}
 		break;
 
 	case SIOCGENITER :
@@ -600,42 +791,50 @@
 	    {
 		ipftoken_t *token;
 		ipfgeniter_t iter;
+		ipfobj_t obj;
 
-		error = fr_inobj(data, &iter, IPFOBJ_GENITER);
+		error = ipf_inobj(softc, data, &obj, &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
+		token = ipf_token_find(softc, IPFGENITER_STATE, uid, ctx);
+		if (token != NULL) {
+			error = ipf_state_iter(softc, token, &iter, &obj);
+			WRITE_ENTER(&softc->ipf_tokens);
+			ipf_token_deref(softc, token);
+			RWLOCK_EXIT(&softc->ipf_tokens);
+		} else {
+			IPFERROR(100018);
 			error = ESRCH;
-		RWLOCK_EXIT(&ipf_tokens);
+		}
 		SPL_X(s);
 		break;
 	    }
 
 	case SIOCGTABL :
-		error = fr_stgettable(data);
+		error = ipf_state_gettable(softc, softs, data);
 		break;
 
 	case SIOCIPFDELTOK :
-		error = BCOPYIN(data, (char *)&arg, sizeof(arg));
+		error = BCOPYIN(data, &arg, sizeof(arg));
 		if (error != 0) {
+			IPFERROR(100019);
 			error = EFAULT;
 		} else {
 			SPL_SCHED(s);
-			error = ipf_deltoken(arg, uid, ctx);
+			error = ipf_token_del(softc, arg, uid, ctx);
 			SPL_X(s);
 		}
 		break;
 
 	case SIOCGTQTAB :
-		error = fr_outobj(data, ips_tqtqb, IPFOBJ_STATETQTAB);
+		error = ipf_outobj(softc, data, softs->ipf_state_tcptq,
+				   IPFOBJ_STATETQTAB);
 		break;
 
 	default :
+		IPFERROR(100020);
 		error = EINVAL;
 		break;
 	}
@@ -644,9 +843,11 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_stgetent                                                 */
+/* Function:    ipf_state_getent                                            */
 /* Returns:     int - 0 == success, != 0 == failure                         */
-/* Parameters:  data(I) - pointer to state structure to retrieve from table */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              softs(I) - pointer to state context structure               */
+/*              data(I)  - pointer to state structure to retrieve from table*/
 /*                                                                          */
 /* Copy out state information from the kernel to a user space process.  If  */
 /* there is a filter rule associated with the state entry, copy that out    */
@@ -654,25 +855,30 @@
 /* the struct passed in and if not null and not found in the list of current*/
 /* state entries, the retrieval fails.                                      */
 /* ------------------------------------------------------------------------ */
-int fr_stgetent(data)
-caddr_t data;
+static int
+ipf_state_getent(softc, softs, data)
+	ipf_main_softc_t *softc;
+	ipf_state_softc_t *softs;
+	caddr_t data;
 {
 	ipstate_t *is, *isn;
 	ipstate_save_t ips;
 	int error;
 
-	error = fr_inobj(data, &ips, IPFOBJ_STATESAVE);
-	if (error != 0)
-		return error;
+	error = ipf_inobj(softc, data, NULL, &ips, IPFOBJ_STATESAVE);
+	if (error)
+		return EFAULT;
 
-	READ_ENTER(&ipf_state);
+	READ_ENTER(&softc->ipf_state);
 	isn = ips.ips_next;
 	if (isn == NULL) {
-		isn = ips_list;
+		isn = softs->ipf_state_list;
 		if (isn == NULL) {
-			RWLOCK_EXIT(&ipf_state);
-			if (ips.ips_next == NULL)
+			if (ips.ips_next == NULL) {
+				RWLOCK_EXIT(&softc->ipf_state);
+				IPFERROR(100021);
 				return ENOENT;
+			}
 			return 0;
 		}
 	} else {
@@ -681,11 +887,12 @@
 		 * current list of entries.  Security precaution to prevent
 		 * copying of random kernel data.
 		 */
-		for (is = ips_list; is; is = is->is_next)
+		for (is = softs->ipf_state_list; is; is = is->is_next)
 			if (is == isn)
 				break;
-		if (is == NULL) {
-			RWLOCK_EXIT(&ipf_state);
+		if (!is) {
+			RWLOCK_EXIT(&softc->ipf_state);
+			IPFERROR(100022);
 			return ESRCH;
 		}
 	}
@@ -695,16 +902,18 @@
 	if (isn->is_rule != NULL)
 		bcopy((char *)isn->is_rule, (char *)&ips.ips_fr,
 		      sizeof(ips.ips_fr));
-	RWLOCK_EXIT(&ipf_state);
-	error = fr_outobj(data, &ips, IPFOBJ_STATESAVE);
+	RWLOCK_EXIT(&softc->ipf_state);
+	error = ipf_outobj(softc, data, &ips, IPFOBJ_STATESAVE);
 	return error;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_stputent                                                 */
+/* Function:    ipf_state_putent                                            */
 /* Returns:     int - 0 == success, != 0 == failure                         */
-/* Parameters:  data(I) - pointer to state information struct               */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              softs(I) - pointer to state context structure               */
+/*              data(I)  - pointer to state information struct              */
 /*                                                                          */
 /* This function implements the SIOCSTPUT ioctl: insert a state entry into  */
 /* the state table.  If the state info. includes a pointer to a filter rule */
@@ -711,8 +920,11 @@
 /* then also add in an orphaned rule (will not show up in any "ipfstat -io" */
 /* output.                                                                  */
 /* ------------------------------------------------------------------------ */
-int fr_stputent(data)
-caddr_t data;
+int
+ipf_state_putent(softc, softs, data)
+	ipf_main_softc_t *softc;
+	ipf_state_softc_t *softs;
+	caddr_t data;
 {
 	ipstate_t *is, *isn;
 	ipstate_save_t ips;
@@ -720,13 +932,15 @@
 	frentry_t *fr;
 	char *name;
 
-	error = fr_inobj(data, &ips, IPFOBJ_STATESAVE);
-	if (error)
-		return EFAULT;
+	error = ipf_inobj(softc, data, NULL, &ips, IPFOBJ_STATESAVE);
+	if (error != 0)
+		return error;
 
 	KMALLOC(isn, ipstate_t *);
-	if (isn == NULL)
+	if (isn == NULL) {
+		IPFERROR(100023);
 		return ENOMEM;
+	}
 
 	bcopy((char *)&ips.ips_is, (char *)isn, sizeof(*isn));
 	bzero((char *)isn, offsetof(struct ipstate, is_pkts));
@@ -742,11 +956,14 @@
 	fr = ips.ips_rule;
 
 	if (fr == NULL) {
-		READ_ENTER(&ipf_state);
-		fr_stinsert(isn, 0);
+		int inserr;
+
+		READ_ENTER(&softc->ipf_state);
+		inserr = ipf_state_insert(softc, isn, 0);
 		MUTEX_EXIT(&isn->is_lock);
-		RWLOCK_EXIT(&ipf_state);
-		return 0;
+		RWLOCK_EXIT(&softc->ipf_state);
+
+		return inserr;
 	}
 
 	if (isn->is_flags & SI_NEWFR) {
@@ -753,6 +970,7 @@
 		KMALLOC(fr, frentry_t *);
 		if (fr == NULL) {
 			KFREE(isn);
+			IPFERROR(100024);
 			return ENOMEM;
 		}
 		bcopy((char *)&ips.ips_fr, (char *)fr, sizeof(*fr));
@@ -766,10 +984,19 @@
 		 * Look up all the interface names in the rule.
 		 */
 		for (i = 0; i < 4; i++) {
-			name = fr->fr_ifnames[i];
-			fr->fr_ifas[i] = fr_resolvenic(name, fr->fr_v);
+			if (fr->fr_ifnames[i] == -1) {
+				fr->fr_ifas[i] = NULL;
+				continue;
+			}
+			name = fr->fr_names + fr->fr_ifnames[i];
+			fr->fr_ifas[i] = ipf_resolvenic(softc, name,
+							fr->fr_family);
+		}
+
+		for (i = 0; i < 4; i++) {
 			name = isn->is_ifname[i];
-			isn->is_ifp[i] = fr_resolvenic(name, isn->is_v);
+			isn->is_ifp[i] = ipf_resolvenic(softc, name,
+							isn->is_v);
 		}
 
 		fr->fr_ref = 0;
@@ -777,31 +1004,35 @@
 		fr->fr_data = NULL;
 		fr->fr_type = FR_T_NONE;
 
-		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);
+		(void) ipf_resolvedest(softc, fr->fr_names, &fr->fr_tifs[0],
+				fr->fr_family);
+		(void) ipf_resolvedest(softc, fr->fr_names, &fr->fr_tifs[1],
+				fr->fr_family);
+		(void) ipf_resolvedest(softc, fr->fr_names, &fr->fr_dif,
+				fr->fr_family);
 
 		/*
 		 * send a copy back to userland of what we ended up
 		 * to allow for verification.
 		 */
-		error = fr_outobj(data, &ips, IPFOBJ_STATESAVE);
-		if (error) {
+		error = ipf_outobj(softc, data, &ips, IPFOBJ_STATESAVE);
+		if (error != 0) {
 			KFREE(isn);
 			MUTEX_DESTROY(&fr->fr_lock);
 			KFREE(fr);
+			IPFERROR(100025);
 			return EFAULT;
 		}
-		READ_ENTER(&ipf_state);
-		fr_stinsert(isn, 0);
+		READ_ENTER(&softc->ipf_state);
+		error = ipf_state_insert(softc, isn, 0);
 		MUTEX_EXIT(&isn->is_lock);
-		RWLOCK_EXIT(&ipf_state);
+		RWLOCK_EXIT(&softc->ipf_state);
 
 	} else {
-		READ_ENTER(&ipf_state);
-		for (is = ips_list; is; is = is->is_next)
+		READ_ENTER(&softc->ipf_state);
+		for (is = softs->ipf_state_list; is; is = is->is_next)
 			if (is->is_rule == fr) {
-				fr_stinsert(isn, 0);
+				error = ipf_state_insert(softc, isn, 0);
 				MUTEX_EXIT(&isn->is_lock);
 				break;
 			}
@@ -810,46 +1041,46 @@
 			KFREE(isn);
 			isn = NULL;
 		}
-		RWLOCK_EXIT(&ipf_state);
+		RWLOCK_EXIT(&softc->ipf_state);
 
-		return (isn == NULL) ? ESRCH : 0;
+		if (isn == NULL) {
+			IPFERROR(100033);
+			error = ESRCH;
+		}
 	}
 
-	return 0;
+	return error;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:   fr_stinsert                                                  */
-/* Returns:    Nil                                                          */
-/* Parameters: is(I)  - pointer to state structure                          */
-/*             rev(I) - flag indicating forward/reverse direction of packet */
+/* Function:    ipf_state_insert                                            */
+/* Returns:     int    - 0 == success, -1 == failure                        */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/* Parameters:  is(I)    - pointer to state structure                       */
+/*              rev(I) - flag indicating direction of packet                */
 /*                                                                          */
 /* Inserts a state structure into the hash table (for lookups) and the list */
 /* of state entries (for enumeration).  Resolves all of the interface names */
 /* to pointers and adjusts running stats for the hash table as appropriate. */
 /*                                                                          */
+/* This function can fail if the filter rule has had a population policy of */
+/* IP addresses used with stateful filtering assigned to it.                */
+/*                                                                          */
 /* Locking: it is assumed that some kind of lock on ipf_state is held.      */
-/*          Exits with is_lock initialised and held.                        */
+/*          Exits with is_lock initialised and held - *EVEN IF ERROR*.      */
 /* ------------------------------------------------------------------------ */
-void fr_stinsert(is, rev)
-ipstate_t *is;
-int rev;
+int
+ipf_state_insert(softc, is, rev)
+	ipf_main_softc_t *softc;
+	ipstate_t *is;
+	int rev;
 {
+	ipf_state_softc_t *softs = softc->ipf_state_soft;
 	frentry_t *fr;
 	u_int hv;
 	int i;
 
-	MUTEX_INIT(&is->is_lock, "ipf state entry");
-
-	fr = is->is_rule;
-	if (fr != NULL) {
-		MUTEX_ENTER(&fr->fr_lock);
-		fr->fr_ref++;
-		fr->fr_statecnt++;
-		MUTEX_EXIT(&fr->fr_lock);
-	}
-
 	/*
 	 * Look up all the interface names in the state entry.
 	 */
@@ -856,14 +1087,16 @@
 	for (i = 0; i < 4; i++) {
 		if (is->is_ifp[i] != NULL)
 			continue;
-		is->is_ifp[i] = fr_resolvenic(is->is_ifname[i], is->is_v);
+		is->is_ifp[i] = ipf_resolvenic(softc, is->is_ifname[i],
+					       is->is_v);
 	}
 
 	/*
-	 * If we could trust is_hv, then the modulous would not be needed, but
-	 * when running with IPFILTER_SYNC, this stops bad values.
+	 * If we could trust is_hv, then the modulus would not be needed,
+	 * but when running with IPFILTER_SYNC, this stops bad values.
 	 */
-	hv = is->is_hv % fr_statesize;
+	hv = is->is_hv % softs->ipf_state_size;
+	/* TRACE is, hv */
 	is->is_hv = hv;
 
 	/*
@@ -871,37 +1104,265 @@
 	 * possible that once the insert is complete another packet might
 	 * come along, match the entry and want to update it.
 	 */
+	MUTEX_INIT(&is->is_lock, "ipf state entry");
 	MUTEX_ENTER(&is->is_lock);
-	MUTEX_ENTER(&ipf_stinsert);
+	MUTEX_ENTER(&softs->ipf_stinsert);
 
+	fr = is->is_rule;
+	if (fr != NULL) {
+		if ((fr->fr_srctrack.ht_max_nodes != 0) &&
+		    (ipf_ht_node_add(softc, &fr->fr_srctrack,
+				     is->is_family, &is->is_src) == -1)) {
+			SBUMPD(ipf_state_stats, iss_max_track);
+			MUTEX_EXIT(&softs->ipf_stinsert);
+			return -1;
+		}
+
+		MUTEX_ENTER(&fr->fr_lock);
+		fr->fr_ref++;
+		MUTEX_EXIT(&fr->fr_lock);
+		fr->fr_statecnt++;
+	}
+
+	if (is->is_flags & (SI_WILDP|SI_WILDA)) {
+		DT(iss_wild_plus_one);
+		SINCL(ipf_state_stats.iss_wild);
+	}
+
+	SBUMP(ipf_state_stats.iss_proto[is->is_p]);
+	SBUMP(ipf_state_stats.iss_active_proto[is->is_p]);
+
 	/*
 	 * add into list table.
 	 */
-	if (ips_list != NULL)
-		ips_list->is_pnext = &is->is_next;
-	is->is_pnext = &ips_list;
-	is->is_next = ips_list;
-	ips_list = is;
+	if (softs->ipf_state_list != NULL)
+		softs->ipf_state_list->is_pnext = &is->is_next;
+	is->is_pnext = &softs->ipf_state_list;
+	is->is_next = softs->ipf_state_list;
+	softs->ipf_state_list = is;
 
-	if (ips_table[hv] != NULL)
-		ips_table[hv]->is_phnext = &is->is_hnext;
+	if (softs->ipf_state_table[hv] != NULL)
+		softs->ipf_state_table[hv]->is_phnext = &is->is_hnext;
 	else
-		ips_stats.iss_inuse++;
-	is->is_phnext = ips_table + hv;
-	is->is_hnext = ips_table[hv];
-	ips_table[hv] = is;
-	ips_stats.iss_bucketlen[hv]++;
-	ips_num++;
-	MUTEX_EXIT(&ipf_stinsert);
+		softs->ipf_state_stats.iss_inuse++;
+	is->is_phnext = softs->ipf_state_table + hv;
+	is->is_hnext = softs->ipf_state_table[hv];
+	softs->ipf_state_table[hv] = is;
+	softs->ipf_state_stats.iss_bucketlen[hv]++;
+	softs->ipf_state_stats.iss_active++;
+	MUTEX_EXIT(&softs->ipf_stinsert);
 
-	fr_setstatequeue(is, rev);
+	ipf_state_setqueue(softc, is, rev);
+
+	return 0;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_addstate                                                 */
-/* Returns:     ipstate_t* - NULL == failure, else pointer to new state     */
-/* Parameters:  fin(I)    - pointer to packet information                   */
+/* Function:    ipf_state_matchipv4addrs                                    */
+/* Returns:     int - 2 addresses match (strong match), 1 reverse match,    */
+/*                    0 no match                                            */
+/* Parameters:  is1, is2 pointers to states we are checking                 */
+/*                                                                          */
+/* Function matches IPv4 addresses it returns strong match for ICMP proto   */
+/* even there is only reverse match                                         */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_state_matchipv4addrs(is1, is2)
+	ipstate_t *is1, *is2;
+{
+	int	rv;
+
+	if (is1->is_saddr == is2->is_saddr && is1->is_daddr == is2->is_daddr)
+		rv = 2;
+	else if (is1->is_saddr == is2->is_daddr &&
+	    is1->is_daddr == is2->is_saddr) {
+		/* force strong match for ICMP protocol */
+		rv = (is1->is_p == IPPROTO_ICMP) ? 2 : 1;
+	}
+	else
+		rv = 0;
+
+	return (rv);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_state_matchipv6addrs                                    */
+/* Returns:     int - 2 addresses match (strong match), 1 reverse match,    */
+/*                    0 no match                                            */
+/* Parameters:  is1, is2 pointers to states we are checking                 */
+/*                                                                          */
+/* Function matches IPv6 addresses it returns strong match for ICMP proto   */
+/* even there is only reverse match                                         */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_state_matchipv6addrs(is1, is2)
+	ipstate_t *is1, *is2;
+{
+	int	rv;
+
+	if (IP6_EQ(&is1->is_src, &is2->is_src) &&
+	    IP6_EQ(&is1->is_dst, &is2->is_dst))
+		rv = 2;
+	else if (IP6_EQ(&is1->is_src, &is2->is_dst) &&
+	    IP6_EQ(&is1->is_dst, &is2->is_src)) {
+		/* force strong match for ICMPv6 protocol */
+		rv = (is1->is_p == IPPROTO_ICMPV6) ? 2 : 1;
+	}
+	else
+		rv = 0;
+
+	return (rv);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_state_matchaddresses                                    */
+/* Returns:     int - 2 addresses match, 1 reverse match, zero no match     */
+/* Parameters:  is1, is2 pointers to states we are checking                 */
+/*                                                                          */
+/* function retruns true if two pairs of addresses belong to single         */
+/* connection. suppose there are two endpoints:                             */
+/*      endpoint1 1.1.1.1                                                   */
+/*      endpoint2 1.1.1.2                                                   */
+/*                                                                          */
+/* the state is established by packet flying from .1 to .2 so we see:       */
+/*      is1->src = 1.1.1.1                                                  */
+/*      is1->dst = 1.1.1.2                                                  */
+/* now endpoint 1.1.1.2 sends answer                                        */
+/* retreives is1 record created by first packat and compares it with is2    */
+/* temporal record, is2 is initialized as follows:                          */
+/*      is2->src = 1.1.1.2                                                  */
+/*      is2->dst = 1.1.1.1                                                  */
+/* in this case 1 will be returned                                          */
+/*                                                                          */
+/* the ipf_matchaddresses() assumes those two records to be same. of course */
+/* the ipf_matchaddresses() also assume records are same in case you pass   */
+/* identical arguments (i.e. ipf_matchaddress(is1, is1) would return 2      */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_state_matchaddresses(is1, is2)
+	ipstate_t *is1, *is2;
+{
+	int	rv;
+
+	if (is1->is_v == 4) {
+		rv = ipf_state_matchipv4addrs(is1, is2);
+	}
+	else {
+		rv = ipf_state_matchipv6addrs(is1, is2);
+	}
+
+	return (rv);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_matchports                                              */
+/* Returns:     int - 2 match, 1 rverse match, 0 no match                   */
+/* Parameters:  ppairs1, ppairs - src, dst ports we want to match           */
+/*                                                                          */
+/* performs the same match for isps members as for addresses                */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_state_matchports(ppairs1, ppairs2)
+	udpinfo_t *ppairs1, *ppairs2;
+{
+	int	rv;
+
+	if (ppairs1->us_sport == ppairs2->us_sport &&
+	    ppairs1->us_dport == ppairs2->us_dport)
+		rv = 2;
+	else if (ppairs1->us_sport == ppairs2->us_dport &&
+		    ppairs1->us_dport == ppairs2->us_sport)
+		rv = 1;
+	else
+		rv = 0;
+
+	return (rv);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_matchisps                                               */
+/* Returns:     int - nonzero if isps members match, 0 nomatch              */
+/* Parameters:  is1, is2 - states we want to match                          */
+/*                                                                          */
+/* performs the same match for isps members as for addresses                */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_state_matchisps(is1, is2)
+	ipstate_t *is1, *is2;
+{
+	int	rv;
+
+	if (is1->is_p == is2->is_p) {
+		switch (is1->is_p)
+		{
+		case IPPROTO_TCP :
+		case IPPROTO_UDP :
+		case IPPROTO_GRE :
+			/* greinfo_t can be also interprted as port pair */
+			rv = ipf_state_matchports(&is1->is_ps.is_us,
+						  &is2->is_ps.is_us);
+			break;
+
+		case IPPROTO_ICMP :
+		case IPPROTO_ICMPV6 :
+			/* force strong match for ICMP datagram. */
+			if (bcmp(&is1->is_ps, &is2->is_ps,
+				 sizeof(icmpinfo_t)) == 0)  {
+				rv = 2;
+			} else {
+				rv = 0;
+			}
+			break;
+
+		default:
+			rv = 0;
+		}
+	} else {
+		rv = 0;
+	}
+
+	return (rv);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_state_match                                             */
+/* Returns:     int - nonzero match, zero no match                          */
+/* Parameters:  is1, is2 - states we want to match                          */
+/*                                                                          */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_state_match(is1, is2)
+	ipstate_t *is1, *is2;
+{
+	int	rv;
+	int	amatch;
+	int	pomatch;
+
+	if (bcmp(&is1->is_pass, &is2->is_pass,
+		 offsetof(struct ipstate, is_authmsk) -
+		 offsetof(struct ipstate, is_pass)) == 0) {
+
+		pomatch = ipf_state_matchisps(is1, is2);
+		amatch = ipf_state_matchaddresses(is1, is2);
+		rv = (amatch != 0) && (amatch == pomatch);
+	} else {
+		rv = 0;
+	}
+
+	return (rv);
+}
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_state_add                                               */
+/* Returns:     ipstate_t - 0 = success                                     */
+/* Parameters:  softc(I)  - pointer to soft context main structure          */
+/*              fin(I)    - pointer to packet information                   */
 /*              stsave(O) - pointer to place to save pointer to created     */
 /*                          state structure.                                */
 /*              flags(I)  - flags to use when creating the structure        */
@@ -916,26 +1377,50 @@
 /*       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;
-ipstate_t **stsave;
-u_int flags;
+int
+ipf_state_add(softc, fin, stsave, flags)
+	ipf_main_softc_t *softc;
+	fr_info_t *fin;
+	ipstate_t **stsave;
+	u_int flags;
 {
+	ipf_state_softc_t *softs = softc->ipf_state_soft;
 	ipstate_t *is, ips;
 	struct icmp *ic;
 	u_int pass, hv;
 	frentry_t *fr;
 	tcphdr_t *tcp;
-	grehdr_t *gre;
+	frdest_t *fdp;
 	int out;
 
-	if (fr_state_lock ||
-	    (fin->fin_flx & (FI_SHORT|FI_STATE|FI_FRAGBODY|FI_BAD)))
-		return NULL;
+	/*
+	 * If a locally created packet is trying to egress but it
+	 * does not match because of this lock, it is likely that
+	 * the policy will block it and return network unreachable further
+	 * up the stack. To mitigate this error, EAGAIN is returned instead,
+	 * telling the IP stack to try sending this packet again later.
+	 */
+	if (softs->ipf_state_lock) {
+		SBUMPD(ipf_state_stats, iss_add_locked);
+		fin->fin_error = EAGAIN;
+		return -1;
+	}
 
-	if ((fin->fin_flx & FI_OOW) && !(fin->fin_tcpf & TH_SYN))
-		return NULL;
+	if (fin->fin_flx & (FI_SHORT|FI_STATE|FI_FRAGBODY|FI_BAD)) {
+		SBUMPD(ipf_state_stats, iss_add_bad);
+		return -1;
+	}
 
+	if ((fin->fin_flx & FI_OOW) && !(fin->fin_tcpf & TH_SYN)) {
+		SBUMPD(ipf_state_stats, iss_add_oow);
+		return -1;
+	}
+
+	if ((softs->ipf_state_stats.iss_active * 100 / softs->ipf_state_max) >
+	    softs->ipf_state_wm_high) {
+		softs->ipf_state_doflush = 1;
+	}
+
 	/*
 	 * 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
@@ -948,26 +1433,49 @@
 	 */
 	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 ((softs->ipf_state_stats.iss_active >=
+		     softs->ipf_state_max) && (fr->fr_statemax == 0)) {
+			SBUMPD(ipf_state_stats, iss_max);
+			return 1;
 		}
 		if ((fr->fr_statemax != 0) &&
 		    (fr->fr_statecnt >= fr->fr_statemax)) {
-			ATOMIC_INCL(ips_stats.iss_maxref);
-			return NULL;
+			SBUMPD(ipf_state_stats, iss_max_ref);
+			return 2;
 		}
 	}
 
-	pass = (fr == NULL) ? 0 : fr->fr_flags;
+	is = &ips;
+	if (fr == NULL) {
+		pass = softc->ipf_flags;
+		is->is_tag = FR_NOLOGTAG;
+	} else {
+		pass = fr->fr_flags;
+	}
 
 	ic = NULL;
 	tcp = NULL;
 	out = fin->fin_out;
-	is = &ips;
 	bzero((char *)is, sizeof(*is));
-	is->is_die = 1 + fr_ticks;
+	is->is_die = 1 + softc->ipf_ticks;
+	/*
+	 * We want to check everything that is a property of this packet,
+	 * but we don't (automatically) care about its fragment status as
+	 * this may change.
+	 */
+	is->is_pass = pass;
+	is->is_v = fin->fin_v;
+	is->is_sec = fin->fin_secmsk;
+	is->is_secmsk = 0xffff;
+	is->is_auth = fin->fin_auth;
+	is->is_authmsk = 0xffff;
+	is->is_family = fin->fin_family;
+	is->is_opt[0] = fin->fin_optmsk;
+	is->is_optmsk[0] = 0xffffffff;
+	if (is->is_v == 6) {
+		is->is_opt[0] &= ~0x8;
+		is->is_optmsk[0] &= ~0x8;
+	}
 
 	/*
 	 * Copy and calculate...
@@ -1008,13 +1516,8 @@
 #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;
-		}
+		flags |= SI_W_DADDR;
+		hv -= is->is_daddr;
 	}
 
 	switch (is->is_p)
@@ -1026,9 +1529,8 @@
 		switch (ic->icmp_type)
 		{
 		case ICMP6_ECHO_REQUEST :
-			is->is_icmp.ici_type = ic->icmp_type;
 			hv += (is->is_icmp.ici_id = ic->icmp_id);
-			break;
+			/*FALLTHROUGH*/
 		case ICMP6_MEMBERSHIP_QUERY :
 		case ND_ROUTER_SOLICIT :
 		case ND_NEIGHBOR_SOLICIT :
@@ -1036,9 +1538,9 @@
 			is->is_icmp.ici_type = ic->icmp_type;
 			break;
 		default :
-			return NULL;
+			SBUMPD(ipf_state_stats, iss_icmp6_notquery);
+			return -2;
 		}
-		ATOMIC_INCL(ips_stats.iss_icmp);
 		break;
 #endif
 	case IPPROTO_ICMP :
@@ -1054,11 +1556,12 @@
 			hv += (is->is_icmp.ici_id = ic->icmp_id);
 			break;
 		default :
-			return NULL;
+			SBUMPD(ipf_state_stats, iss_icmp_notquery);
+			return -3;
 		}
-		ATOMIC_INCL(ips_stats.iss_icmp);
 		break;
 
+#if 0
 	case IPPROTO_GRE :
 		gre = fin->fin_dp;
 
@@ -1069,12 +1572,18 @@
 			is->is_call[1] = fin->fin_data[1];
 		}
 		break;
+#endif
 
 	case IPPROTO_TCP :
 		tcp = fin->fin_dp;
 
-		if (tcp->th_flags & TH_RST)
-			return NULL;
+		if (tcp->th_flags & TH_RST) {
+			SBUMPD(ipf_state_stats, iss_tcp_rstadd);
+			return -4;
+		}
+
+		/* TRACE is, flags, hv */
+
 		/*
 		 * The endian of the ports doesn't matter, but the ack and
 		 * sequence numbers do as we do mathematics on them later.
@@ -1086,6 +1595,8 @@
 			hv += is->is_dport;
 		}
 
+		/* TRACE is, flags, hv */
+
 		/*
 		 * If this is a real packet then initialise fields in the
 		 * state information structure from the TCP header information.
@@ -1110,15 +1621,14 @@
 			if ((tcp->th_flags & ~(TH_FIN|TH_ACK|TH_ECNALL)) ==
 			    TH_SYN &&
 			    (TCP_OFF(tcp) > (sizeof(tcphdr_t) >> 2))) {
-				if (fr_tcpoptions(fin, tcp,
-					      &is->is_tcp.ts_data[0]) == -1) {
+				if (ipf_tcpoptions(softs, fin, tcp,
+					      &is->is_tcp.ts_data[0]) == -1)
 					fin->fin_flx |= FI_BAD;
-				}
 			}
 
 			if ((fin->fin_out != 0) && (pass & FR_NEWISN) != 0) {
-				fr_checknewisn(fin, is);
-				fr_fixoutisn(fin, is);
+				ipf_checknewisn(fin, is);
+				ipf_fixoutisn(fin, is);
 			}
 
 			if ((tcp->th_flags & TH_OPENING) == TH_SYN)
@@ -1132,11 +1642,10 @@
 		}
 
 		/*
-		 * If we're creating state for a starting connection, start the
-		 * timer on it as we'll never see an error if it fails to
-		 * connect.
+		 * If we're creating state for a starting connection, start
+		 * the timer on it as we'll never see an error if it fails
+		 * to connect.
 		 */
-		ATOMIC_INCL(ips_stats.iss_tcp);
 		break;
 
 	case IPPROTO_UDP :
@@ -1148,7 +1657,6 @@
 			hv += tcp->th_dport;
 			hv += tcp->th_sport;
 		}
-		ATOMIC_INCL(ips_stats.iss_udp);
 		break;
 
 	default :
@@ -1156,96 +1664,77 @@
 	}
 	hv = DOUBLE_HASH(hv);
 	is->is_hv = hv;
-	is->is_rule = fr;
-	is->is_flags = flags & IS_INHERITED;
 
 	/*
 	 * Look for identical state.
 	 */
-	for (is = ips_table[is->is_hv % fr_statesize]; is != NULL;
-	     is = is->is_hnext) {
-		if (bcmp(&ips.is_src, &is->is_src,
-			 offsetof(struct ipstate, is_ps) -
-			 offsetof(struct ipstate, is_src)) == 0)
+	for (is = softs->ipf_state_table[hv % softs->ipf_state_size];
+	     is != NULL; is = is->is_hnext) {
+		if (ipf_state_match(&ips, is) == 1)
 			break;
 	}
-	if (is != NULL)
-		return NULL;
+	if (is != NULL) {
+		SBUMPD(ipf_state_stats, iss_add_dup);
+		return 3;
+	}
 
-	if (ips_stats.iss_bucketlen[hv] >= fr_state_maxbucket) {
-		ATOMIC_INCL(ips_stats.iss_bucketfull);
-		return NULL;
+	if (softs->ipf_state_stats.iss_bucketlen[hv] >=
+	    softs->ipf_state_maxbucket) {
+		SBUMPD(ipf_state_stats, iss_bucket_full);
+		return 4;
 	}
+
+	/*
+	 * No existing state; create new
+	 */
 	KMALLOC(is, ipstate_t *);
 	if (is == NULL) {
-		ATOMIC_INCL(ips_stats.iss_nomem);
-		return NULL;
+		SBUMPD(ipf_state_stats, iss_nomem);
+		return 5;
 	}
 	bcopy((char *)&ips, (char *)is, sizeof(*is));
+	is->is_flags = flags & IS_INHERITED;
+	is->is_rulen = fin->fin_rule;
+	is->is_rule = fr;
+
 	/*
-	 * Do not do the modulous here, it is done in fr_stinsert().
+	 * Do not do the modulus here, it is done in ipf_state_insert().
 	 */
 	if (fr != NULL) {
-		(void) strncpy(is->is_group, fr->fr_group, FR_GROUPLEN);
+		ipftq_t *tq;
+
+		(void) strncpy(is->is_group, FR_NAME(fr, fr_group),
+			       FR_GROUPLEN);
 		if (fr->fr_age[0] != 0) {
-			is->is_tqehead[0] = fr_addtimeoutqueue(&ips_utqe,
-							       fr->fr_age[0]);
+			tq = ipf_addtimeoutqueue(softc,
+						 &softs->ipf_state_usertq,
+						 fr->fr_age[0]);
+			is->is_tqehead[0] = tq;
 			is->is_sti.tqe_flags |= TQE_RULEBASED;
 		}
 		if (fr->fr_age[1] != 0) {
-			is->is_tqehead[1] = fr_addtimeoutqueue(&ips_utqe,
-							       fr->fr_age[1]);
+			tq = ipf_addtimeoutqueue(softc,
+						 &softs->ipf_state_usertq,
+						 fr->fr_age[1]);
+			is->is_tqehead[1] = tq;
 			is->is_sti.tqe_flags |= TQE_RULEBASED;
 		}
 
 		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];
-		strncpy(is->is_ifname[((1 - out) << 1)], fr->fr_ifnames[2],
-			sizeof(fr->fr_ifnames[2]));
-
-		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;
-
-		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]);
-		}
 	}
 
 	/*
-	 * It may seem strange to set is_ref to 2, but fr_check() will call
-	 * fr_statederef() after calling fr_addstate() and the idea is to
-	 * have it exist at the end of fr_check() with is_ref == 1.
+	 * It may seem strange to set is_ref to 2, but if stsave is not NULL
+	 * then a copy of the pointer is being stored somewhere else and in
+	 * the end, it will expect to be able to do something with it.
 	 */
-	is->is_ref = 2;
-	is->is_pass = pass;
+	is->is_me = stsave;
+	if (stsave != NULL) {
+		*stsave = is;
+		is->is_ref = 2;
+	} else {
+		is->is_ref = 1;
+	}
 	is->is_pkts[0] = 0, is->is_bytes[0] = 0;
 	is->is_pkts[1] = 0, is->is_bytes[1] = 0;
 	is->is_pkts[2] = 0, is->is_bytes[2] = 0;
@@ -1252,11 +1741,15 @@
 	is->is_pkts[3] = 0, is->is_bytes[3] = 0;
 	if ((fin->fin_flx & FI_IGNORE) == 0) {
 		is->is_pkts[out] = 1;
+		fin->fin_pktnum = 1;
 		is->is_bytes[out] = fin->fin_plen;
 		is->is_flx[out][0] = fin->fin_flx & FI_CMP;
 		is->is_flx[out][0] &= ~FI_OOW;
 	}
 
+	if (pass & FR_STLOOSE)
+		is->is_flags |= IS_LOOSE;
+
 	if (pass & FR_STSTRICT)
 		is->is_flags |= IS_STRICT;
 
@@ -1263,38 +1756,86 @@
 	if (pass & FR_STATESYNC)
 		is->is_flags |= IS_STATESYNC;
 
+	if (pass & FR_LOGFIRST)
+		is->is_pass &= ~(FR_LOGFIRST|FR_LOG);
+
+	READ_ENTER(&softc->ipf_state);
+
+	if (ipf_state_insert(softc, is, fin->fin_rev) == -1) {
+		RWLOCK_EXIT(&softc->ipf_state);
+		/*
+		 * This is a bit more manual than it should be but
+		 * ipf_state_del cannot be called.
+		 */
+		MUTEX_EXIT(&is->is_lock);
+		MUTEX_DESTROY(&is->is_lock);
+		if (is->is_tqehead[0] != NULL) {
+			if (ipf_deletetimeoutqueue(is->is_tqehead[0]) == 0)
+				ipf_freetimeoutqueue(softc, is->is_tqehead[0]);
+			is->is_tqehead[0] = NULL;
+		}
+		if (is->is_tqehead[1] != NULL) {
+			if (ipf_deletetimeoutqueue(is->is_tqehead[1]) == 0)
+				ipf_freetimeoutqueue(softc, is->is_tqehead[1]);
+			is->is_tqehead[1] = NULL;
+		}
+		KFREE(is);
+		return -1;
+	}
+
 	/*
-	 * We want to check everything that is a property of this packet,
-	 * but we don't (automatically) care about it's fragment status as
-	 * this may change.
+	 * Filling in the interface name is after the insert so that an
+	 * event (such as add/delete) of an interface that is referenced
+	 * by this rule will see this state entry.
 	 */
-	is->is_v = fin->fin_v;
-	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;
-	is->is_authmsk = 0xffff;
-	if (flags & (SI_WILDP|SI_WILDA)) {
-		ATOMIC_INCL(ips_stats.iss_wild);
-	}
-	is->is_rulen = fin->fin_rule;
+	if (fr != NULL) {
+		/*
+		 * 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] != -1 &&
+		     fr->fr_names[fr->fr_ifnames[out << 1] + 0] == '-' &&
+		     fr->fr_names[fr->fr_ifnames[out << 1] + 1] == '\0')) {
+			is->is_ifp[out << 1] = fr->fr_ifas[0];
+			strncpy(is->is_ifname[out << 1],
+				fr->fr_names + fr->fr_ifnames[0],
+				sizeof(fr->fr_ifnames[0]));
+		} else {
+			is->is_ifp[out << 1] = fin->fin_ifp;
+			COPYIFNAME(fin->fin_v, fin->fin_ifp,
+				   is->is_ifname[out << 1]);
+		}
 
+		is->is_ifp[(out << 1) + 1] = fr->fr_ifas[1];
+		if (fr->fr_ifnames[1] != -1) {
+			strncpy(is->is_ifname[(out << 1) + 1],
+				fr->fr_names + fr->fr_ifnames[1],
+				sizeof(fr->fr_ifnames[1]));
+		}
 
-	if (pass & FR_LOGFIRST)
-		is->is_pass &= ~(FR_LOGFIRST|FR_LOG);
+		is->is_ifp[(1 - out) << 1] = fr->fr_ifas[2];
+		if (fr->fr_ifnames[2] != -1) {
+			strncpy(is->is_ifname[((1 - out) << 1)],
+				fr->fr_names + fr->fr_ifnames[2],
+				sizeof(fr->fr_ifnames[2]));
+		}
 
-	READ_ENTER(&ipf_state);
+		is->is_ifp[((1 - out) << 1) + 1] = fr->fr_ifas[3];
+		if (fr->fr_ifnames[3] != -1) {
+			strncpy(is->is_ifname[((1 - out) << 1) + 1],
+				fr->fr_names + fr->fr_ifnames[3],
+				sizeof(fr->fr_ifnames[3]));
+		}
+	} else {
+		if (fin->fin_ifp != NULL) {
+			is->is_ifp[out << 1] = fin->fin_ifp;
+			COPYIFNAME(fin->fin_v, fin->fin_ifp,
+				   is->is_ifname[out << 1]);
+		}
+	}
 
-	fr_stinsert(is, fin->fin_rev);
-
 	if (fin->fin_p == IPPROTO_TCP) {
 		/*
 		* If we're creating state for a starting connection, start the
@@ -1301,38 +1842,57 @@
 		* timer on it as we'll never see an error if it fails to
 		* connect.
 		*/
-		(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);
+		(void) ipf_tcp_age(&is->is_sti, fin, softs->ipf_state_tcptq,
+				   is->is_flags, 2);
 	}
-#ifdef	IPFILTER_SYNC
+	MUTEX_EXIT(&is->is_lock);
 	if ((is->is_flags & IS_STATESYNC) && ((is->is_flags & SI_CLONE) == 0))
-		is->is_sync = ipfsync_new(SMC_STATE, fin, is);
-#endif
-	if (ipstate_logging)
-		ipstate_log(is, ISL_NEW);
+		is->is_sync = ipf_sync_new(softc, SMC_STATE, fin, is);
+	if (softs->ipf_state_logging)
+		ipf_state_log(softc, is, ISL_NEW);
 
-	RWLOCK_EXIT(&ipf_state);
-	fin->fin_state = is;
-	fin->fin_rev = IP6_NEQ(&is->is_dst, &fin->fin_daddr);
+	RWLOCK_EXIT(&softc->ipf_state);
+
 	fin->fin_flx |= FI_STATE;
 	if (fin->fin_flx & FI_FRAG)
-		(void) fr_newfrag(fin, pass ^ FR_KEEPSTATE);
+		(void) ipf_frag_new(softc, fin, pass);
 
-	return is;
+	fdp = &fr->fr_tifs[0];
+	if (fdp->fd_type == FRD_DSTLIST) {
+		ipf_dstlist_select_node(fin, fdp->fd_ptr, NULL,
+					&is->is_tifs[0]);
+	} else {
+		bcopy(fdp, &is->is_tifs[0], sizeof(*fdp));
+	}
+
+	fdp = &fr->fr_tifs[1];
+	if (fdp->fd_type == FRD_DSTLIST) {
+		ipf_dstlist_select_node(fin, fdp->fd_ptr, NULL,
+					&is->is_tifs[1]);
+	} else {
+		bcopy(fdp, &is->is_tifs[1], sizeof(*fdp));
+	}
+	fin->fin_tif = &is->is_tifs[fin->fin_rev];
+
+	fdp = &fr->fr_dif;
+	if (fdp->fd_type == FRD_DSTLIST) {
+		ipf_dstlist_select_node(fin, fdp->fd_ptr, NULL,
+					&is->is_dif);
+	} else {
+		bcopy(fdp, &is->is_dif, sizeof(*fdp));
+	}
+	fin->fin_dif = &is->is_dif;
+
+	return 0;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_tcpoptions                                               */
+/* Function:    ipf_tcpoptions                                              */
 /* 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                      */
+/* Parameters:  softs(I) - pointer to state context structure               */
+/*              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      */
 /*                                                                          */
@@ -1339,10 +1899,12 @@
 /* Look after the TCP header for any options and deal with those that are   */
 /* present.  Record details about those that we recogise.                   */
 /* ------------------------------------------------------------------------ */
-static int fr_tcpoptions(fin, tcp, td)
-fr_info_t *fin;
-tcphdr_t *tcp;
-tcpdata_t *td;
+static int
+ipf_tcpoptions(softs, fin, tcp, td)
+	ipf_state_softc_t *softs;
+	fr_info_t *fin;
+	tcphdr_t *tcp;
+	tcpdata_t *td;
 {
 	int off, mlen, ol, i, len, retval;
 	char buf[64], *s, opt;
@@ -1349,8 +1911,10 @@
 	mb_t *m = NULL;
 
 	len = (TCP_OFF(tcp) << 2);
-	if (fin->fin_dlen < len)
+	if (fin->fin_dlen < len) {
+		SBUMPD(ipf_state_stats, iss_tcp_toosmall);
 		return 0;
+	}
 	len -= sizeof(*tcp);
 
 	off = fin->fin_plen - fin->fin_dlen + sizeof(*tcp) + fin->fin_ipoff;
@@ -1422,14 +1986,19 @@
 		len -= ol;
 		s += ol;
 	}
+	if (retval == -1) {
+		SBUMPD(ipf_state_stats, iss_tcp_badopt);
+	}
 	return retval;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_tcpstate                                                 */
+/* Function:    ipf_state_tcp                                               */
 /* Returns:     int - 1 == packet matches state entry, 0 == it does not     */
-/* Parameters:  fin(I)   - pointer to packet information                    */
+/* Parameters:  softc(I)  - pointer to soft context main structure          */
+/*              softs(I) - pointer to state context structure               */
+/*              fin(I)   - pointer to packet information                    */
 /*              tcp(I)   - pointer to TCP packet header                     */
 /*              is(I)  - pointer to master state structure                  */
 /*                                                                          */
@@ -1437,16 +2006,19 @@
 /* Change timeout depending on whether new packet is a SYN-ACK returning    */
 /* for a SYN or a RST or FIN which indicate time to close up shop.          */
 /* ------------------------------------------------------------------------ */
-static int fr_tcpstate(fin, tcp, is)
-fr_info_t *fin;
-tcphdr_t *tcp;
-ipstate_t *is;
+static int
+ipf_state_tcp(softc, softs, fin, tcp, is)
+	ipf_main_softc_t *softc;
+	ipf_state_softc_t *softs;
+	fr_info_t *fin;
+	tcphdr_t *tcp;
+	ipstate_t *is;
 {
-	int source, ret = 0, flags;
 	tcpdata_t  *fdata, *tdata;
+	int source, ret, flags;
 
 	source = !fin->fin_rev;
-	if (((is->is_flags & IS_TCPFSM) != 0) && (source == 1) && 
+	if (((is->is_flags & IS_TCPFSM) != 0) && (source == 1) &&
 	    (ntohs(is->is_sport) != fin->fin_data[0]))
 		source = 0;
 	fdata = &is->is_tcp.ts_data[!source];
@@ -1462,34 +2034,37 @@
 		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);
+			ipf_movequeue(softc->ipf_ticks, &is->is_sti,
+				      is->is_sti.tqe_ifq,
+				      &softs->ipf_state_deletetq);
 			MUTEX_EXIT(&is->is_lock);
+			DT1(iss_tcp_closing, ipstate_t *, is);
+			SBUMP(ipf_state_stats.iss_tcp_closing);
 			return 0;
 		}
 	}
 
-	ret = fr_tcpinwindow(fin, fdata, tdata, tcp, is->is_flags);
+	if (is->is_flags & IS_LOOSE)
+		ret = 1;
+	else
+		ret = ipf_state_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);
-			if (FR_ISBLOCK(is->is_pass)) {
-				MUTEX_EXIT(&is->is_lock);
-				return 1;
-			}
-		}
-#endif
-
 		/*
 		 * Nearing end of connection, start timeout.
 		 */
-		ret = fr_tcp_age(&is->is_sti, fin, ips_tqtqb, is->is_flags);
+		ret = ipf_tcp_age(&is->is_sti, fin, softs->ipf_state_tcptq,
+				  is->is_flags, ret);
 		if (ret == 0) {
 			MUTEX_EXIT(&is->is_lock);
+			DT2(iss_tcp_fsm, fr_info_t *, fin, ipstate_t *, is);
+			SBUMP(ipf_state_stats.iss_tcp_fsm);
 			return 0;
 		}
 
+		if (softs->ipf_state_logging > 4)
+			ipf_state_log(softc, is, ISL_STATECHANGE);
+
 		/*
 		 * set s0's as appropriate.  Use syn-ack packet as it
 		 * contains both pieces of required information.
@@ -1503,25 +2078,29 @@
 			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))) {
-				if (fr_tcpoptions(fin, tcp, fdata) == -1)
+				if (ipf_tcpoptions(softs, fin, tcp,
+						   fdata) == -1)
 					fin->fin_flx |= FI_BAD;
 			}
 			if ((fin->fin_out != 0) && (is->is_pass & FR_NEWISN))
-				fr_checknewisn(fin, is);
+				ipf_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, fdata) == -1)
+				if (ipf_tcpoptions(softs, fin, tcp,
+						   fdata) == -1)
 					fin->fin_flx |= FI_BAD;
 			}
 
 			if ((fin->fin_out != 0) && (is->is_pass & FR_NEWISN))
-				fr_checknewisn(fin, is);
+				ipf_checknewisn(fin, is);
 
 		}
 		ret = 1;
 	} else {
-		fin->fin_flx |= FI_OOW;
+		DT2(iss_tcp_oow, fr_info_t *, fin, ipstate_t *, is);
+		SBUMP(ipf_state_stats.iss_tcp_oow);
+		ret = 0;
 	}
 	MUTEX_EXIT(&is->is_lock);
 	return ret;
@@ -1529,7 +2108,7 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_checknewisn                                              */
+/* Function:    ipf_checknewisn                                             */
 /* Returns:     Nil                                                         */
 /* Parameters:  fin(I)   - pointer to packet information                    */
 /*              is(I)  - pointer to master state structure                  */
@@ -1540,9 +2119,10 @@
 /* NOTE: This does not actually change the sequence numbers, only gets new  */
 /* one ready.                                                               */
 /* ------------------------------------------------------------------------ */
-static void fr_checknewisn(fin, is)
-fr_info_t *fin;
-ipstate_t *is;
+static void
+ipf_checknewisn(fin, is)
+	fr_info_t *fin;
+	ipstate_t *is;
 {
 	u_32_t sumd, old, new;
 	tcphdr_t *tcp;
@@ -1554,7 +2134,7 @@
 	if (((i == 0) && !(is->is_flags & IS_ISNSYN)) ||
 	    ((i == 1) && !(is->is_flags & IS_ISNACK))) {
 		old = ntohl(tcp->th_seq);
-		new = fr_newisn(fin);
+		new = ipf_newisn(fin);
 		is->is_isninc[i] = new - old;
 		CALC_SUMD(old, new, sumd);
 		is->is_sumd[i] = (sumd & 0xffff) + (sumd >> 16);
@@ -1565,9 +2145,8 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_tcpinwindow                                              */
-/* Returns:     int - 1 == packet inside TCP "window", 0 == not inside,     */
-/*                    2 == packet seq number matches next expected          */
+/* Function:    ipf_state_tcpinwindow                                       */
+/* Returns:     int - 1 == packet inside TCP "window", 0 == not inside.     */
 /* Parameters:  fin(I)   - pointer to packet information                    */
 /*              fdata(I) - pointer to tcp state informatio (forward)        */
 /*              tdata(I) - pointer to tcp state informatio (reverse)        */
@@ -1577,12 +2156,15 @@
 /* within the TCP data window.  In a show of generosity, allow packets that */
 /* are within the window space behind the current sequence # as well.       */
 /* ------------------------------------------------------------------------ */
-int fr_tcpinwindow(fin, fdata, tdata, tcp, flags)
-fr_info_t *fin;
-tcpdata_t  *fdata, *tdata;
-tcphdr_t *tcp;
-int flags;
+static int
+ipf_state_tcpinwindow(fin, fdata, tdata, tcp, flags)
+	fr_info_t *fin;
+	tcpdata_t  *fdata, *tdata;
+	tcphdr_t *tcp;
+	int flags;
 {
+	ipf_main_softc_t *softc = fin->fin_main_soft;
+	ipf_state_softc_t *softs = softc->ipf_state_soft;
 	tcp_seq seq, ack, end;
 	int ackskew, tcpflags;
 	u_32_t win, maxwin;
@@ -1651,12 +2233,17 @@
 	/*
 	 * Strict sequencing only allows in-order delivery.
 	 */
-	if (seq != fdata->td_end) {
-		if ((flags & IS_STRICT) != 0) {
+	if ((flags & IS_STRICT) != 0) {
+		if (seq != fdata->td_end) {
+			DT2(iss_tcp_struct, tcpdata_t *, fdata, int, seq);
+			SBUMP(ipf_state_stats.iss_tcp_strict);
+			fin->fin_flx |= FI_OOW;
 			return 0;
 		}
 	}
 
+#define	SEQ_GE(a,b)	((int)((a) - (b)) >= 0)
+#define	SEQ_GT(a,b)	((int)((a) - (b)) > 0)
 	inseq = 0;
 	if ((SEQ_GE(fdata->td_maxend, end)) &&
 	    (SEQ_GE(seq, fdata->td_end - maxwin)) &&
@@ -1672,6 +2259,8 @@
 	} else if ((seq == fdata->td_maxend) && (ackskew == 0) &&
 	    (fdata->td_winflags & TCP_SACK_PERMIT) &&
 	    (tdata->td_winflags & TCP_SACK_PERMIT)) {
+		DT2(iss_sinsack, tcpdata_t *, fdata, int, seq);
+		SBUMP(ipf_state_stats.iss_winsack);
 		inseq = 1;
 	/*
 	 * Sometimes a TCP RST will be generated with only the ACK field
@@ -1693,7 +2282,7 @@
 			 * accepted, even if it appears out of sequence.
 			 */
 			inseq = 1;
-		} else 
+		} else
 #endif
 		if (!(fdata->td_winflags &
 			    (TCP_WSCALE_SEEN|TCP_WSCALE_FIRST))) {
@@ -1737,12 +2326,14 @@
 			tdata->td_maxend = ack + win;
 		return 1;
 	}
+	SBUMP(ipf_state_stats.iss_oow);
+	fin->fin_flx |= FI_OOW;
 	return 0;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_stclone                                                  */
+/* Function:    ipf_state_clone                                             */
 /* Returns:     ipstate_t* - NULL == cloning failed,                        */
 /*                           else pointer to new state structure            */
 /* Parameters:  fin(I) - pointer to packet information                      */
@@ -1751,27 +2342,40 @@
 /*                                                                          */
 /* Create a "duplcate" state table entry from the master.                   */
 /* ------------------------------------------------------------------------ */
-static ipstate_t *fr_stclone(fin, tcp, is)
-fr_info_t *fin;
-tcphdr_t *tcp;
-ipstate_t *is;
+static ipstate_t *
+ipf_state_clone(fin, tcp, is)
+	fr_info_t *fin;
+	tcphdr_t *tcp;
+	ipstate_t *is;
 {
+	ipf_main_softc_t *softc = fin->fin_main_soft;
+	ipf_state_softc_t *softs = softc->ipf_state_soft;
 	ipstate_t *clone;
 	u_32_t send;
 
-	if (ips_num == fr_statemax) {
-		ATOMIC_INCL(ips_stats.iss_max);
-		fr_state_doflush = 1;
+	if (softs->ipf_state_stats.iss_active == softs->ipf_state_max) {
+		SBUMPD(ipf_state_stats, iss_max);
+		softs->ipf_state_doflush = 1;
 		return NULL;
 	}
 	KMALLOC(clone, ipstate_t *);
-	if (clone == NULL)
+	if (clone == NULL) {
+		SBUMPD(ipf_state_stats, iss_clone_nomem);
 		return NULL;
+	}
 	bcopy((char *)is, (char *)clone, sizeof(*clone));
 
 	MUTEX_NUKE(&clone->is_lock);
+	/*
+	 * It has not yet been placed on any timeout queue, so make sure
+	 * all of that data is zero'd out.
+	 */
+	clone->is_sti.tqe_pnext = NULL;
+	clone->is_sti.tqe_next = NULL;
+	clone->is_sti.tqe_ifq = NULL;
+	clone->is_sti.tqe_parent = clone;
 
-	clone->is_die = ONE_DAY + fr_ticks;
+	clone->is_die = ONE_DAY + softc->ipf_ticks;
 	clone->is_state[0] = 0;
 	clone->is_state[1] = 0;
 	send = ntohl(tcp->th_seq) + fin->fin_dlen - (TCP_OFF(tcp) << 2) +
@@ -1798,49 +2402,61 @@
 
 	clone->is_flags &= ~SI_CLONE;
 	clone->is_flags |= SI_CLONED;
-	fr_stinsert(clone, fin->fin_rev);
-	clone->is_ref = 2;
+	if (ipf_state_insert(softc, clone, fin->fin_rev) == -1) {
+		KFREE(clone);
+		return NULL;
+	}
+
+	clone->is_ref = 1;
 	if (clone->is_p == IPPROTO_TCP) {
-		(void) fr_tcp_age(&clone->is_sti, fin, ips_tqtqb,
-				  clone->is_flags);
+		(void) ipf_tcp_age(&clone->is_sti, fin, softs->ipf_state_tcptq,
+				   clone->is_flags, 2);
 	}
 	MUTEX_EXIT(&clone->is_lock);
-#ifdef	IPFILTER_SCAN
-	(void) ipsc_attachis(is);
-#endif
-#ifdef	IPFILTER_SYNC
 	if (is->is_flags & IS_STATESYNC)
-		clone->is_sync = ipfsync_new(SMC_STATE, fin, clone);
-#endif
+		clone->is_sync = ipf_sync_new(softc, SMC_STATE, fin, clone);
+	DT2(iss_clone, ipstate_t *, is, ipstate_t *, clone);
+	SBUMP(ipf_state_stats.iss_cloned);
 	return clone;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_matchsrcdst                                              */
+/* Function:    ipf_matchsrcdst                                             */
 /* Returns:     Nil                                                         */
-/* Parameters:  fin(I) - pointer to packet information                      */
-/*              is(I)  - pointer to state structure                         */
-/*              src(I) - pointer to source address                          */
-/*              dst(I) - pointer to destination address                     */
-/*              tcp(I) - pointer to TCP/UDP header                          */
+/* Parameters:  fin(I)   - pointer to packet information                    */
+/*              is(I)    - pointer to state structure                       */
+/*              src(I)   - pointer to source address                        */
+/*              dst(I)   - pointer to destination address                   */
+/*              tcp(I)   - pointer to TCP/UDP header                        */
+/*              cmask(I) - mask of FI_* bits to check                       */
 /*                                                                          */
 /* Match a state table entry against an IP packet.  The logic below is that */
 /* ret gets set to one if the match succeeds, else remains 0.  If it is     */
 /* still 0 after the test. no match.                                        */
 /* ------------------------------------------------------------------------ */
-static ipstate_t *fr_matchsrcdst(fin, is, src, dst, tcp, cmask)
-fr_info_t *fin;
-ipstate_t *is;
-i6addr_t *src, *dst;
-tcphdr_t *tcp;
-u_32_t cmask;
+static ipstate_t *
+ipf_matchsrcdst(fin, is, src, dst, tcp, cmask)
+	fr_info_t *fin;
+	ipstate_t *is;
+	i6addr_t *src, *dst;
+	tcphdr_t *tcp;
+	u_32_t cmask;
 {
+	ipf_main_softc_t *softc = fin->fin_main_soft;
+	ipf_state_softc_t *softs = softc->ipf_state_soft;
 	int ret = 0, rev, out, flags, flx = 0, idx;
 	u_short sp, dp;
 	u_32_t cflx;
 	void *ifp;
 
+	/*
+	 * If a connection is about to be deleted, no packets
+	 * are allowed to match it.
+	 */
+	if (is->is_sti.tqe_ifq == &softs->ipf_state_deletetq)
+		return NULL;
+
 	rev = IP6_NEQ(&is->is_dst, dst);
 	ifp = fin->fin_ifp;
 	out = fin->fin_out;
@@ -1872,8 +2488,12 @@
 	     *is->is_ifname[idx] == '*')))
 		ret = 1;
 
-	if (ret == 0)
+	if (ret == 0) {
+		DT2(iss_lookup_badifp, fr_info_t *, fin, ipstate_t *, is);
+		SBUMP(ipf_state_stats.iss_lookup_badifp);
+		/* TRACE is, out, rev, idx */
 		return NULL;
+	}
 	ret = 0;
 
 	/*
@@ -1883,7 +2503,8 @@
 		if ((IP6_EQ(&is->is_dst, dst) || (flags & SI_W_DADDR)) &&
 		    (IP6_EQ(&is->is_src, src) || (flags & SI_W_SADDR))) {
 			if (tcp) {
-				if ((sp == is->is_sport || flags & SI_W_SPORT)&&
+				if ((sp == is->is_sport || flags & SI_W_SPORT)
+				    &&
 				    (dp == is->is_dport || flags & SI_W_DPORT))
 					ret = 1;
 			} else {
@@ -1894,7 +2515,8 @@
 		if ((IP6_EQ(&is->is_dst, src) || (flags & SI_W_DADDR)) &&
 		    (IP6_EQ(&is->is_src, dst) || (flags & SI_W_SADDR))) {
 			if (tcp) {
-				if ((dp == is->is_sport || flags & SI_W_SPORT)&&
+				if ((dp == is->is_sport || flags & SI_W_SPORT)
+				    &&
 				    (sp == is->is_dport || flags & SI_W_DPORT))
 					ret = 1;
 			} else {
@@ -1903,8 +2525,12 @@
 		}
 	}
 
-	if (ret == 0)
+	if (ret == 0) {
+		SBUMP(ipf_state_stats.iss_lookup_badport);
+		DT2(iss_lookup_badport, fr_info_t *, fin, ipstate_t *, is);
+		/* TRACE rev, is, sp, dp, src, dst */
 		return NULL;
+	}
 
 	/*
 	 * Whether or not this should be here, is questionable, but the aim
@@ -1925,24 +2551,10 @@
 
 		if ((flags & SI_W_SADDR) != 0) {
 			if (rev == 0) {
-#ifdef USE_INET6
-				if (is->is_v == 6 &&
-				    IN6_IS_ADDR_MULTICAST(&fi->fi_src.in6))
-					/*EMPTY*/;
-				else
-#endif
-				{
-					is->is_src = fi->fi_src;
-					is->is_flags &= ~SI_W_SADDR;
-				}
+				is->is_src = fi->fi_src;
+				is->is_flags &= ~SI_W_SADDR;
 			} else {
-#ifdef USE_INET6
-				if (is->is_v == 6 &&
-				    IN6_IS_ADDR_MULTICAST(&fi->fi_dst.in6))
-					/*EMPTY*/;
-				else
-#endif
-				{
+				if (!(fin->fin_flx & (FI_MULTICAST|FI_MBCAST))){
 					is->is_src = fi->fi_dst;
 					is->is_flags &= ~SI_W_SADDR;
 				}
@@ -1949,31 +2561,17 @@
 			}
 		} else if ((flags & SI_W_DADDR) != 0) {
 			if (rev == 0) {
-#ifdef USE_INET6
-				if (is->is_v == 6 &&
-				    IN6_IS_ADDR_MULTICAST(&fi->fi_dst.in6))
-					/*EMPTY*/;
-				else
-#endif
-				{
+				if (!(fin->fin_flx & (FI_MULTICAST|FI_MBCAST))){
 					is->is_dst = fi->fi_dst;
 					is->is_flags &= ~SI_W_DADDR;
 				}
 			} else {
-#ifdef USE_INET6
-				if (is->is_v == 6 &&
-				    IN6_IS_ADDR_MULTICAST(&fi->fi_src.in6))
-					/*EMPTY*/;
-				else
-#endif
-				{
-					is->is_dst = fi->fi_src;
-					is->is_flags &= ~SI_W_DADDR;
-				}
+				is->is_dst = fi->fi_src;
+				is->is_flags &= ~SI_W_DADDR;
 			}
 		}
 		if ((is->is_flags & (SI_WILDA|SI_WILDP)) == 0) {
-			ATOMIC_DECL(ips_stats.iss_wild);
+			ATOMIC_DECL(softs->ipf_state_stats.iss_wild);
 		}
 	}
 
@@ -1986,29 +2584,31 @@
 	if ((cflx && (flx != (cflx & cmask))) ||
 	    ((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))
+	    ((fin->fin_auth & is->is_authmsk) != is->is_auth)) {
+		SBUMPD(ipf_state_stats, iss_miss_mask);
 		return NULL;
+	}
 
+	if ((fin->fin_flx & FI_IGNORE) != 0) {
+		fin->fin_rev = rev;
+		return is;
+	}
+
 	/*
 	 * Only one of the source or destination port can be flagged as a
 	 * wildcard.  When filling it in, fill in a copy of the matched entry
 	 * if it has the cloning flag set.
 	 */
-	if ((fin->fin_flx & FI_IGNORE) != 0) {
-		fin->fin_rev = rev;
-		return is;
-	}
-
 	if ((flags & (SI_W_SPORT|SI_W_DPORT))) {
 		if ((flags & SI_CLONE) != 0) {
 			ipstate_t *clone;
 
-			clone = fr_stclone(fin, tcp, is);
+			clone = ipf_state_clone(fin, tcp, is);
 			if (clone == NULL)
 				return NULL;
 			is = clone;
 		} else {
-			ATOMIC_DECL(ips_stats.iss_wild);
+			ATOMIC_DECL(softs->ipf_state_stats.iss_wild);
 		}
 
 		if ((flags & SI_W_SPORT) != 0) {
@@ -2031,8 +2631,8 @@
 			is->is_maxdend = is->is_dend + 1;
 		}
 		is->is_flags &= ~(SI_W_SPORT|SI_W_DPORT);
-		if ((flags & SI_CLONED) && ipstate_logging)
-			ipstate_log(is, ISL_CLONE);
+		if ((flags & SI_CLONED) && softs->ipf_state_logging)
+			ipf_state_log(softc, is, ISL_CLONE);
 	}
 
 	ret = -1;
@@ -2039,10 +2639,13 @@
 
 	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;
+		if (rev == 1 && is->is_optmsk[1] == 0) {
+			is->is_opt[1] = fin->fin_optmsk;
+			is->is_optmsk[1] = 0xffffffff;
+			if (is->is_v == 6) {
+				is->is_opt[1] &= ~0x8;
+				is->is_optmsk[1] &= ~0x8;
+			}
 		}
 	}
 
@@ -2053,7 +2656,7 @@
 	if (is->is_ifp[idx] == NULL &&
 	    (*is->is_ifname[idx] == '\0' || *is->is_ifname[idx] == '*')) {
 		is->is_ifp[idx] = ifp;
-		COPYIFNAME(is->is_v, ifp, is->is_ifname[idx]);
+		COPYIFNAME(fin->fin_v, ifp, is->is_ifname[idx]);
 	}
 	fin->fin_rev = rev;
 	return is;
@@ -2061,7 +2664,7 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_checkicmpmatchingstate                                   */
+/* Function:    ipf_checkicmpmatchingstate                                  */
 /* Returns:     Nil                                                         */
 /* Parameters:  fin(I) - pointer to packet information                      */
 /*                                                                          */
@@ -2071,13 +2674,13 @@
 /* If we return NULL then no lock on ipf_state is held.                     */
 /* If we return non-null then a read-lock on ipf_state is held.             */
 /* ------------------------------------------------------------------------ */
-static ipstate_t *fr_checkicmpmatchingstate(fin)
-fr_info_t *fin;
+static ipstate_t *
+ipf_checkicmpmatchingstate(fin)
+	fr_info_t *fin;
 {
+	ipf_main_softc_t *softc = fin->fin_main_soft;
+	ipf_state_softc_t *softs = softc->ipf_state_soft;
 	ipstate_t *is, **isp;
-	u_short sport, dport;
-	u_char	pr;
-	int backward, i, oi;
 	i6addr_t dst, src;
 	struct icmp *ic;
 	u_short savelen;
@@ -2085,6 +2688,7 @@
 	fr_info_t ofin;
 	tcphdr_t *tcp;
 	int type, len;
+	u_char	pr;
 	ip_t *oip;
 	u_int hv;
 
@@ -2096,8 +2700,10 @@
 	 */
 	if ((fin->fin_v != 4) || (fin->fin_hlen != sizeof(ip_t)) ||
 	    (fin->fin_plen < ICMPERR_MINPKTLEN) ||
-	    !(fin->fin_flx & FI_ICMPERR))
+	    !(fin->fin_flx & FI_ICMPERR)) {
+		SBUMPD(ipf_state_stats, iss_icmp_bad);
 		return NULL;
+	}
 	ic = fin->fin_dp;
 	type = ic->icmp_type;
 
@@ -2106,15 +2712,20 @@
 	 * Check if the at least the old IP header (with options) and
 	 * 8 bytes of payload is present.
 	 */
-	if (fin->fin_plen < ICMPERR_MAXPKTLEN + ((IP_HL(oip) - 5) << 2))
+	if (fin->fin_plen < ICMPERR_MAXPKTLEN + ((IP_HL(oip) - 5) << 2)) {
+		SBUMPDX(ipf_state_stats, iss_icmp_short, iss_icmp_short_1);
 		return NULL;
+	}
 
 	/*
 	 * Sanity Checks.
 	 */
 	len = fin->fin_dlen - ICMPERR_ICMPHLEN;
-	if ((len <= 0) || ((IP_HL(oip) << 2) > len))
+	if ((len <= 0) || ((IP_HL(oip) << 2) > len)) {
+		DT2(iss_icmp_len, fr_info_t *, fin, struct ip*, oip);
+		SBUMPDX(ipf_state_stats, iss_icmp_short, iss_icmp_short_1);
 		return NULL;
+	}
 
 	/*
 	 * Is the buffer big enough for all of it ?  It's the size of the IP
@@ -2122,7 +2733,7 @@
 	 * may be too big to be in this buffer but not so big that it's
 	 * outside the ICMP packet, leading to TCP deref's causing problems.
 	 * This is possible because we don't know how big oip_hl is when we
-	 * do the pullup early in fr_check() and thus can't guarantee it is
+	 * do the pullup early in ipf_check() and thus can't guarantee it is
 	 * all here now.
 	 */
 #ifdef  _KERNEL
@@ -2131,14 +2742,19 @@
 
 	m = fin->fin_m;
 # if defined(MENTAT)
-	if ((char *)oip + len > (char *)m->b_wptr)
+	if ((char *)oip + len > (char *)m->b_wptr) {
+		SBUMPDX(ipf_state_stats, iss_icmp_short, iss_icmp_short_2);
 		return NULL;
+	}
 # else
-	if ((char *)oip + len > (char *)fin->fin_ip + m->m_len)
+	if ((char *)oip + len > (char *)fin->fin_ip + m->m_len) {
+		SBUMPDX(ipf_state_stats, iss_icmp_short, iss_icmp_short_3);
 		return NULL;
+	}
 # endif
 	}
 #endif
+
 	bcopy((char *)fin, (char *)&ofin, sizeof(*fin));
 
 	/*
@@ -2154,15 +2770,14 @@
 	 * matchsrcdst note that not all fields are encessary
 	 * but this is the cleanest way. Note further we fill
 	 * in fin_mp such that if someone uses it we'll get
-	 * a kernel panic. fr_matchsrcdst does not use this.
+	 * a kernel panic. ipf_matchsrcdst does not use this.
 	 *
 	 * watch out here, as ip is in host order and oip in network
 	 * order. Any change we make must be undone afterwards, like
-	 * oip->ip_off - it is still in network byte order so fix it.
+	 * oip->ip_len.
 	 */
 	savelen = oip->ip_len;
-	oip->ip_len = len;
-	oip->ip_off = ntohs(oip->ip_off);
+	oip->ip_len = htons(len);
 
 	ofin.fin_flx = FI_NOCKSUM;
 	ofin.fin_v = 4;
@@ -2169,11 +2784,18 @@
 	ofin.fin_ip = oip;
 	ofin.fin_m = NULL;	/* if dereferenced, panic XXX */
 	ofin.fin_mp = NULL;	/* if dereferenced, panic XXX */
-	(void) fr_makefrip(IP_HL(oip) << 2, oip, &ofin);
+	(void) ipf_makefrip(IP_HL(oip) << 2, oip, &ofin);
 	ofin.fin_ifp = fin->fin_ifp;
 	ofin.fin_out = !fin->fin_out;
+
+	hv = (pr = oip->ip_p);
+	src.in4 = oip->ip_src;
+	hv += src.in4.s_addr;
+	dst.in4 = oip->ip_dst;
+	hv += dst.in4.s_addr;
+
 	/*
-	 * Reset the short and bad flag here because in fr_matchsrcdst()
+	 * Reset the short and bad flag here because in ipf_matchsrcdst()
 	 * the flags for the current packet (fin_flx) are compared against
 	 * those for the existing session.
 	 */
@@ -2180,11 +2802,10 @@
 	ofin.fin_flx &= ~(FI_BAD|FI_SHORT);
 
 	/*
-	 * Put old values of ip_len and ip_off back as we don't know
-	 * if we have to forward the packet (or process it again.
+	 * Put old values of ip_len back as we don't know
+	 * if we have to forward the packet or process it again.
 	 */
 	oip->ip_len = savelen;
-	oip->ip_off = htons(oip->ip_off);
 
 	switch (oip->ip_p)
 	{
@@ -2196,75 +2817,52 @@
 		 * XXX theoretically ICMP_ECHOREP and the other reply's are
 		 * ICMP query's as well, but adding them here seems strange XXX
 		 */
-		if ((ofin.fin_flx & FI_ICMPERR) != 0)
+		if ((ofin.fin_flx & FI_ICMPERR) != 0) {
+			DT1(iss_icmp_icmperr, fr_info_t *, &ofin);
+			SBUMP(ipf_state_stats.iss_icmp_icmperr);
 		    	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;
-		dst.in4 = oip->ip_dst;
-		hv += dst.in4.s_addr;
 		hv += icmp->icmp_id;
 		hv = DOUBLE_HASH(hv);
 
-		READ_ENTER(&ipf_state);
-		for (isp = &ips_table[hv]; ((is = *isp) != NULL); ) {
+		READ_ENTER(&softc->ipf_state);
+		for (isp = &softs->ipf_state_table[hv];
+		     ((is = *isp) != NULL); ) {
 			isp = &is->is_hnext;
 			if ((is->is_p != pr) || (is->is_v != 4))
 				continue;
 			if (is->is_pass & FR_NOICMPERR)
 				continue;
-			is = fr_matchsrcdst(&ofin, is, &src, &dst,
+
+			is = ipf_matchsrcdst(&ofin, is, &src, &dst,
 					    NULL, FI_ICMPCMP);
-			if (is != NULL) {
-				/*
-				 * i  : the index of this packet (the icmp
-				 *      unreachable)
-				 * oi : the index of the original packet found
-				 *      in the icmp header (i.e. the packet
-				 *      causing this icmp)
-				 * backward : original packet was backward
-				 *      compared to the state
-				 */
-				backward = IP6_NEQ(&is->is_src, &src);
-				fin->fin_rev = !backward;
-				i = (!backward << 1) + fin->fin_out;
-				oi = (backward << 1) + ofin.fin_out;
-				if (is->is_icmppkts[i] > is->is_pkts[oi])
-					continue;
-				ips_stats.iss_hits++;
-				is->is_icmppkts[i]++;
+			if ((is != NULL) && !ipf_allowstateicmp(fin, is, &src))
 				return is;
-			}
 		}
-		RWLOCK_EXIT(&ipf_state);
+		RWLOCK_EXIT(&softc->ipf_state);
+		SBUMPDX(ipf_state_stats, iss_icmp_miss, iss_icmp_miss_1);
 		return NULL;
 	case IPPROTO_TCP :
 	case IPPROTO_UDP :
 		break;
 	default :
+		SBUMPDX(ipf_state_stats, iss_icmp_miss, iss_icmp_miss_2);
 		return NULL;
 	}
 
 	tcp = (tcphdr_t *)((char *)oip + (IP_HL(oip) << 2));
-	dport = tcp->th_dport;
-	sport = tcp->th_sport;
 
-	hv = (pr = oip->ip_p);
-	src.in4 = oip->ip_src;
-	hv += src.in4.s_addr;
-	dst.in4 = oip->ip_dst;
-	hv += dst.in4.s_addr;
-	hv += dport;
-	hv += sport;
+	hv += tcp->th_dport;;
+	hv += tcp->th_sport;;
 	hv = DOUBLE_HASH(hv);
 
-	READ_ENTER(&ipf_state);
-	for (isp = &ips_table[hv]; ((is = *isp) != NULL); ) {
+	READ_ENTER(&softc->ipf_state);
+	for (isp = &softs->ipf_state_table[hv]; ((is = *isp) != NULL); ) {
 		isp = &is->is_hnext;
 		/*
 		 * Only allow this icmp though if the
@@ -2276,40 +2874,93 @@
 		 * short flag is set.
 		 */
 		if ((is->is_p == pr) && (is->is_v == 4) &&
-		    (is = fr_matchsrcdst(&ofin, is, &src, &dst,
-					 tcp, FI_ICMPCMP))) {
-			/*
-			 * i  : the index of this packet (the icmp unreachable)
-			 * oi : the index of the original packet found in the
-			 *      icmp header (i.e. the packet causing this icmp)
-			 * backward : original packet was backward compared to
-			 *            the state
-			 */
-			backward = IP6_NEQ(&is->is_src, &src);
-			fin->fin_rev = !backward;
-			i = (!backward << 1) + fin->fin_out;
-			oi = (backward << 1) + ofin.fin_out;
-
-			if (((is->is_pass & FR_NOICMPERR) != 0) ||
-			    (is->is_icmppkts[i] > is->is_pkts[oi]))
-				break;
-			ips_stats.iss_hits++;
-			is->is_icmppkts[i]++;
-			/*
-			 * we deliberately do not touch the timeouts
-			 * for the accompanying state table entry.
-			 * It remains to be seen if that is correct. XXX
-			 */
-			return is;
+		    (is = ipf_matchsrcdst(&ofin, is, &src, &dst,
+					  tcp, FI_ICMPCMP))) {
+			if (ipf_allowstateicmp(fin, is, &src) == 0)
+				return is;
 		}
 	}
-	RWLOCK_EXIT(&ipf_state);
+	RWLOCK_EXIT(&softc->ipf_state);
+	SBUMPDX(ipf_state_stats, iss_icmp_miss, iss_icmp_miss_3);
 	return NULL;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_ipsmove                                                  */
+/* Function:    ipf_allowstateicmp                                          */
+/* Returns:     int - 1 = packet denied, 0 = packet allowed                 */
+/* Parameters:  fin(I) - pointer to packet information                      */
+/*              is(I)  - pointer to state table entry                       */
+/*              src(I) - source address to check permission for             */
+/*                                                                          */
+/* For an ICMP packet that has so far matched a state table entry, check if */
+/* there are any further refinements that might mean we want to block this  */
+/* packet.  This code isn't specific to either IPv4 or IPv6.                */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_allowstateicmp(fin, is, src)
+	fr_info_t *fin;
+	ipstate_t *is;
+	i6addr_t *src;
+{
+	ipf_main_softc_t *softc = fin->fin_main_soft;
+	ipf_state_softc_t *softs = softc->ipf_state_soft;
+	frentry_t *savefr;
+	frentry_t *fr;
+	u_32_t ipass;
+	int backward;
+	int oi;
+	int i;
+
+	fr = is->is_rule;
+	if (fr != NULL && fr->fr_icmpgrp != NULL) {
+		savefr = fin->fin_fr;
+		fin->fin_fr = fr->fr_icmpgrp->fg_start;
+
+		ipass = ipf_scanlist(fin, softc->ipf_pass);
+		fin->fin_fr = savefr;
+		if (FR_ISBLOCK(ipass)) {
+			SBUMPD(ipf_state_stats, iss_icmp_headblock);
+			return 1;
+		}
+	}
+
+	/*
+	 * i  : the index of this packet (the icmp unreachable)
+	 * oi : the index of the original packet found in the
+	 *      icmp header (i.e. the packet causing this icmp)
+	 * backward : original packet was backward compared to
+	 *            the state
+	 */
+	backward = IP6_NEQ(&is->is_src, src);
+	fin->fin_rev = !backward;
+	i = (!backward << 1) + fin->fin_out;
+	oi = (backward << 1) + !fin->fin_out;
+
+	if (is->is_pass & FR_NOICMPERR) {
+		SBUMPD(ipf_state_stats, iss_icmp_banned);
+		return 1;
+	}
+	if (is->is_icmppkts[i] > is->is_pkts[oi]) {
+		SBUMPD(ipf_state_stats, iss_icmp_toomany);
+		return 1;
+	}
+
+	DT2(iss_icmp_hits, fr_info_t *, fin, ipstate_t *, is);
+	SBUMP(ipf_state_stats.iss_icmp_hits);
+	is->is_icmppkts[i]++;
+
+	/*
+	 * we deliberately do not touch the timeouts
+	 * for the accompanying state table entry.
+	 * It remains to be seen if that is correct. XXX
+	 */
+	return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_ipsmove                                                 */
 /* Returns:     Nil                                                         */
 /* Parameters:  is(I) - pointer to state table entry                        */
 /*              hv(I) - new hash value for state table entry                */
@@ -2317,14 +2968,19 @@
 /*                                                                          */
 /* Move a state entry from one position in the hash table to another.       */
 /* ------------------------------------------------------------------------ */
-static void fr_ipsmove(is, hv)
-ipstate_t *is;
-u_int hv;
+static void
+ipf_ipsmove(softs, is, hv)
+	ipf_state_softc_t *softs;
+	ipstate_t *is;
+	u_int hv;
 {
 	ipstate_t **isp;
 	u_int hvm;
 
 	hvm = is->is_hv;
+
+	/* TRACE is, is_hv, hvm */
+
 	/*
 	 * Remove the hash from the old location...
 	 */
@@ -2332,9 +2988,9 @@
 	if (is->is_hnext)
 		is->is_hnext->is_phnext = isp;
 	*isp = is->is_hnext;
-	if (ips_table[hvm] == NULL)
-		ips_stats.iss_inuse--;
-	ips_stats.iss_bucketlen[hvm]--;
+	if (softs->ipf_state_table[hvm] == NULL)
+		softs->ipf_state_stats.iss_inuse--;
+	softs->ipf_state_stats.iss_bucketlen[hvm]--;
 
 	/*
 	 * ...and put the hash in the new one.
@@ -2341,12 +2997,15 @@
 	 */
 	hvm = DOUBLE_HASH(hv);
 	is->is_hv = hvm;
-	isp = &ips_table[hvm];
+
+	/* TRACE is, hv, is_hv, hvm */
+
+	isp = &softs->ipf_state_table[hvm];
 	if (*isp)
 		(*isp)->is_phnext = &is->is_hnext;
 	else
-		ips_stats.iss_inuse++;
-	ips_stats.iss_bucketlen[hvm]++;
+		softs->ipf_state_stats.iss_inuse++;
+	softs->ipf_state_stats.iss_bucketlen[hvm]++;
 	is->is_phnext = isp;
 	is->is_hnext = *isp;
 	*isp = is;
@@ -2354,23 +3013,28 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_stlookup                                                 */
+/* Function:    ipf_state_lookup                                            */
 /* Returns:     ipstate_t* - NULL == no matching state found,               */
 /*                           else pointer to state information is returned  */
-/* Parameters:  fin(I) - pointer to packet information                      */
-/*              tcp(I) - pointer to TCP/UDP header.                         */
+/* Parameters:  fin(I)  - pointer to packet information                     */
+/*              tcp(I)  - pointer to TCP/UDP header.                        */
+/*              ifqp(O) - pointer for storing tailq timeout                 */
 /*                                                                          */
 /* Search the state table for a matching entry to the packet described by   */
-/* the contents of *fin.                                                    */
+/* the contents of *fin. For certain protocols, when a match is found the   */
+/* timeout queue is also selected and stored in ifpq if it is non-NULL.     */
 /*                                                                          */
 /* If we return NULL then no lock on ipf_state is held.                     */
 /* If we return non-null then a read-lock on ipf_state is held.             */
 /* ------------------------------------------------------------------------ */
-ipstate_t *fr_stlookup(fin, tcp, ifqp)
-fr_info_t *fin;
-tcphdr_t *tcp;
-ipftq_t **ifqp;
+ipstate_t *
+ipf_state_lookup(fin, tcp, ifqp)
+	fr_info_t *fin;
+	tcphdr_t *tcp;
+	ipftq_t **ifqp;
 {
+	ipf_main_softc_t *softc = fin->fin_main_soft;
+	ipf_state_softc_t *softs = softc->ipf_state_soft;
 	u_int hv, hvm, pr, v, tryagain;
 	ipstate_t *is, **isp;
 	u_short dport, sport;
@@ -2415,6 +3079,8 @@
 		}
 	}
 
+	/* TRACE fin_saddr, fin_daddr, hv */
+
 	/*
 	 * Search the hash table for matching packet header info.
 	 */
@@ -2429,28 +3095,22 @@
 				hv += ic->icmp_id;
 			}
 		}
-		READ_ENTER(&ipf_state);
+		READ_ENTER(&softc->ipf_state);
 icmp6again:
 		hvm = DOUBLE_HASH(hv);
-		for (isp = &ips_table[hvm]; ((is = *isp) != NULL); ) {
+		for (isp = &softs->ipf_state_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);
+			is = ipf_matchsrcdst(fin, is, &src, &dst, NULL, FI_CMP);
 			if (is != NULL &&
-			    fr_matchicmpqueryreply(v, &is->is_icmp,
+			    ipf_matchicmpqueryreply(v, &is->is_icmp,
 						   ic, fin->fin_rev)) {
 				if (fin->fin_rev)
-					ifq = &ips_icmpacktq;
+					ifq = &softs->ipf_state_icmpacktq;
 				else
-					ifq = &ips_icmptq;
+					ifq = &softs->ipf_state_icmptq;
 				break;
 			}
 		}
@@ -2461,12 +3121,12 @@
 				hv += fin->fin_fi.fi_src.i6[1];
 				hv += fin->fin_fi.fi_src.i6[2];
 				hv += fin->fin_fi.fi_src.i6[3];
-				fr_ipsmove(is, hv);
-				MUTEX_DOWNGRADE(&ipf_state);
+				ipf_ipsmove(softs, is, hv);
+				MUTEX_DOWNGRADE(&softc->ipf_state);
 			}
 			break;
 		}
-		RWLOCK_EXIT(&ipf_state);
+		RWLOCK_EXIT(&softc->ipf_state);
 
 		/*
 		 * No matching icmp state entry. Perhaps this is a
@@ -2478,18 +3138,19 @@
 		 * advantage of this requires some significant code changes
 		 * to handle the specific types where that is the case.
 		 */
-		if ((ips_stats.iss_wild != 0) && (v == 6) && (tryagain == 0) &&
-		    !IN6_IS_ADDR_MULTICAST(&fin->fin_fi.fi_src.in6)) {
+		if ((softs->ipf_state_stats.iss_wild != 0) &&
+		    ((fin->fin_flx & FI_NOWILD) == 0) &&
+		    (v == 6) && (tryagain == 0)) {
 			hv -= fin->fin_fi.fi_src.i6[0];
 			hv -= fin->fin_fi.fi_src.i6[1];
 			hv -= fin->fin_fi.fi_src.i6[2];
 			hv -= fin->fin_fi.fi_src.i6[3];
 			tryagain = 1;
-			WRITE_ENTER(&ipf_state);
+			WRITE_ENTER(&softc->ipf_state);
 			goto icmp6again;
 		}
 
-		is = fr_checkicmp6matchingstate(fin);
+		is = ipf_checkicmp6matchingstate(fin);
 		if (is != NULL)
 			return is;
 		break;
@@ -2500,25 +3161,26 @@
 			hv += ic->icmp_id;
 		}
 		hv = DOUBLE_HASH(hv);
-		READ_ENTER(&ipf_state);
-		for (isp = &ips_table[hv]; ((is = *isp) != NULL); ) {
+		READ_ENTER(&softc->ipf_state);
+		for (isp = &softs->ipf_state_table[hv];
+		     ((is = *isp) != NULL); ) {
 			isp = &is->is_hnext;
 			if ((is->is_p != pr) || (is->is_v != v))
 				continue;
-			is = fr_matchsrcdst(fin, is, &src, &dst, NULL, FI_CMP);
+			is = ipf_matchsrcdst(fin, is, &src, &dst, NULL, FI_CMP);
 			if ((is != NULL) &&
 			    (ic->icmp_id == is->is_icmp.ici_id) &&
-			    fr_matchicmpqueryreply(v, &is->is_icmp,
+			    ipf_matchicmpqueryreply(v, &is->is_icmp,
 						   ic, fin->fin_rev)) {
 				if (fin->fin_rev)
-					ifq = &ips_icmpacktq;
+					ifq = &softs->ipf_state_icmpacktq;
 				else
-					ifq = &ips_icmptq;
+					ifq = &softs->ipf_state_icmptq;
 				break;
 			}
 		}
 		if (is == NULL) {
-			RWLOCK_EXIT(&ipf_state);
+			RWLOCK_EXIT(&softc->ipf_state);
 		}
 		break;
 
@@ -2531,18 +3193,23 @@
 		hv += dport;
 		oow = 0;
 		tryagain = 0;
-		READ_ENTER(&ipf_state);
+		READ_ENTER(&softc->ipf_state);
 retry_tcpudp:
 		hvm = DOUBLE_HASH(hv);
-		for (isp = &ips_table[hvm]; ((is = *isp) != NULL); ) {
+
+		/* TRACE hv, hvm */
+
+		for (isp = &softs->ipf_state_table[hvm];
+		     ((is = *isp) != NULL); ) {
 			isp = &is->is_hnext;
 			if ((is->is_p != pr) || (is->is_v != v))
 				continue;
 			fin->fin_flx &= ~FI_OOW;
-			is = fr_matchsrcdst(fin, is, &src, &dst, tcp, FI_CMP);
+			is = ipf_matchsrcdst(fin, is, &src, &dst, tcp, FI_CMP);
 			if (is != NULL) {
 				if (pr == IPPROTO_TCP) {
-					if (!fr_tcpstate(fin, tcp, is)) {
+					if (!ipf_state_tcp(softc, softs, fin,
+							   tcp, is)) {
 						oow |= fin->fin_flx & FI_OOW;
 						continue;
 					}
@@ -2555,14 +3222,15 @@
 			    !(is->is_flags & (SI_CLONE|SI_WILDP|SI_WILDA))) {
 				hv += dport;
 				hv += sport;
-				fr_ipsmove(is, hv);
-				MUTEX_DOWNGRADE(&ipf_state);
+				ipf_ipsmove(softs, is, hv);
+				MUTEX_DOWNGRADE(&softc->ipf_state);
 			}
 			break;
 		}
-		RWLOCK_EXIT(&ipf_state);
+		RWLOCK_EXIT(&softc->ipf_state);
 
-		if (ips_stats.iss_wild) {
+		if ((softs->ipf_state_stats.iss_wild != 0) &&
+		    ((fin->fin_flx & FI_NOWILD) == 0)) {
 			if (tryagain == 0) {
 				hv -= dport;
 				hv -= sport;
@@ -2584,7 +3252,7 @@
 			}
 			tryagain++;
 			if (tryagain <= 2) {
-				WRITE_ENTER(&ipf_state);
+				WRITE_ENTER(&softc->ipf_state);
 				goto retry_tcpudp;
 			}
 		}
@@ -2602,19 +3270,20 @@
 	default :
 		ifqp = NULL;
 		hvm = DOUBLE_HASH(hv);
-		READ_ENTER(&ipf_state);
-		for (isp = &ips_table[hvm]; ((is = *isp) != NULL); ) {
+		READ_ENTER(&softc->ipf_state);
+		for (isp = &softs->ipf_state_table[hvm];
+		     ((is = *isp) != NULL); ) {
 			isp = &is->is_hnext;
 			if ((is->is_p != pr) || (is->is_v != v))
 				continue;
-			is = fr_matchsrcdst(fin, is, &src, &dst, NULL, FI_CMP);
+			is = ipf_matchsrcdst(fin, is, &src, &dst, NULL, FI_CMP);
 			if (is != NULL) {
-				ifq = &ips_iptq;
+				ifq = &softs->ipf_state_iptq;
 				break;
 			}
 		}
 		if (is == NULL) {
-			RWLOCK_EXIT(&ipf_state);
+			RWLOCK_EXIT(&softc->ipf_state);
 		}
 		break;
 	}
@@ -2625,6 +3294,8 @@
 			ifq = is->is_tqehead[fin->fin_rev];
 		if (ifq != NULL && ifqp != NULL)
 			*ifqp = ifq;
+	} else {
+		SBUMP(ipf_state_stats.iss_lookup_miss);
 	}
 	return is;
 }
@@ -2631,84 +3302,37 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_updatestate                                              */
-/* Returns:     Nil                                                         */
-/* Parameters:  fin(I) - pointer to packet information                      */
-/*              is(I)  - pointer to state table entry                       */
-/* Read Locks:  ipf_state                                                   */
-/*                                                                          */
-/* Updates packet and byte counters for a newly received packet.  Seeds the */
-/* fragment cache with a new entry as required.                             */
-/* ------------------------------------------------------------------------ */
-void fr_updatestate(fin, is, ifq)
-fr_info_t *fin;
-ipstate_t *is;
-ipftq_t *ifq;
-{
-	ipftqent_t *tqe;
-	int i, pass;
-
-	i = (fin->fin_rev << 1) + fin->fin_out;
-
-	/*
-	 * For TCP packets, ifq == NULL.  For all others, check if this new
-	 * queue is different to the last one it was on and move it if so.
-	 */
-	tqe = &is->is_sti;
-	MUTEX_ENTER(&is->is_lock);
-	if ((tqe->tqe_flags & TQE_RULEBASED) != 0)
-		ifq = is->is_tqehead[fin->fin_rev];
-
-	if (ifq != NULL)
-		fr_movequeue(tqe, tqe->tqe_ifq, ifq);
-
-	is->is_pkts[i]++;
-	is->is_bytes[i] += fin->fin_plen;
-	MUTEX_EXIT(&is->is_lock);
-
-#ifdef	IPFILTER_SYNC
-	if (is->is_flags & IS_STATESYNC)
-		ipfsync_update(SMC_STATE, fin, is->is_sync);
-#endif
-
-	ATOMIC_INCL(ips_stats.iss_hits);
-
-	fin->fin_fr = is->is_rule;
-
-	/*
-	 * If this packet is a fragment and the rule says to track fragments,
-	 * then create a new fragment cache entry.
-	 */
-	pass = is->is_pass;
-	if ((fin->fin_flx & FI_FRAG) && FR_ISPASS(pass))
-		(void) fr_newfrag(fin, pass ^ FR_KEEPSTATE);
-}
-
-
-/* ------------------------------------------------------------------------ */
-/* Function:    fr_checkstate                                               */
+/* Function:    ipf_state_check                                             */
 /* Returns:     frentry_t* - NULL == search failed,                         */
 /*                           else pointer to rule for matching state        */
-/* Parameters:  ifp(I)   - pointer to interface                             */
+/* Parameters:  fin(I)   - pointer to packet information                    */
 /*              passp(I) - pointer to filtering result flags                */
 /*                                                                          */
 /* Check if a packet is associated with an entry in the state table.        */
 /* ------------------------------------------------------------------------ */
-frentry_t *fr_checkstate(fin, passp)
-fr_info_t *fin;
-u_32_t *passp;
+frentry_t *
+ipf_state_check(fin, passp)
+	fr_info_t *fin;
+	u_32_t *passp;
 {
+	ipf_main_softc_t *softc = fin->fin_main_soft;
+	ipf_state_softc_t *softs = softc->ipf_state_soft;
+	ipftqent_t *tqe;
 	ipstate_t *is;
 	frentry_t *fr;
 	tcphdr_t *tcp;
 	ipftq_t *ifq;
 	u_int pass;
+	int inout;
 
-	if (fr_state_lock || (ips_list == NULL) ||
-	    (fin->fin_flx & (FI_SHORT|FI_STATE|FI_FRAGBODY|FI_BAD)))
+	if (softs->ipf_state_lock || (softs->ipf_state_list == NULL))
 		return NULL;
 
-	is = NULL;
+	if (fin->fin_flx & (FI_SHORT|FI_FRAGBODY|FI_BAD)) {
+		SBUMPD(ipf_state_stats, iss_check_bad);
+		return NULL;
+	}
+
 	if ((fin->fin_flx & FI_TCPUDP) ||
 	    (fin->fin_fi.fi_p == IPPROTO_ICMP)
 #ifdef	USE_INET6
@@ -2719,13 +3343,12 @@
 	else
 		tcp = NULL;
 
+	ifq = NULL;
 	/*
 	 * Search the hash table for matching packet header info.
 	 */
-	ifq = NULL;
-	is = fin->fin_state;
-	if (is == NULL)
-		is = fr_stlookup(fin, tcp, &ifq);
+	is = ipf_state_lookup(fin, tcp, &ifq);
+
 	switch (fin->fin_p)
 	{
 #ifdef	USE_INET6
@@ -2733,9 +3356,7 @@
 		if (is != NULL)
 			break;
 		if (fin->fin_v == 6) {
-			is = fr_checkicmp6matchingstate(fin);
-			if (is != NULL)
-				goto matched;
+			is = ipf_checkicmp6matchingstate(fin);
 		}
 		break;
 #endif
@@ -2746,10 +3367,9 @@
 		 * No matching icmp state entry. Perhaps this is a
 		 * response to another state entry.
 		 */
-		is = fr_checkicmpmatchingstate(fin);
-		if (is != NULL)
-			goto matched;
+		is = ipf_checkicmpmatchingstate(fin);
 		break;
+
 	case IPPROTO_TCP :
 		if (is == NULL)
 			break;
@@ -2756,46 +3376,84 @@
 
 		if (is->is_pass & FR_NEWISN) {
 			if (fin->fin_out == 0)
-				fr_fixinisn(fin, is);
+				ipf_fixinisn(fin, is);
 			else if (fin->fin_out == 1)
-				fr_fixoutisn(fin, is);
+				ipf_fixoutisn(fin, is);
 		}
 		break;
 	default :
 		if (fin->fin_rev)
-			ifq = &ips_udpacktq;
+			ifq = &softs->ipf_state_udpacktq;
 		else
-			ifq = &ips_udptq;
+			ifq = &softs->ipf_state_udptq;
 		break;
 	}
 	if (is == NULL) {
-		ATOMIC_INCL(ips_stats.iss_miss);
+		SBUMP(ipf_state_stats.iss_check_miss);
 		return NULL;
 	}
 
-matched:
 	fr = is->is_rule;
 	if (fr != NULL) {
 		if ((fin->fin_out == 0) && (fr->fr_nattag.ipt_num[0] != 0)) {
-			if (fin->fin_nattag == NULL)
+			if (fin->fin_nattag == NULL) {
+				RWLOCK_EXIT(&softc->ipf_state);
+				SBUMPD(ipf_state_stats, iss_check_notag);
 				return NULL;
-			if (fr_matchtag(&fr->fr_nattag, fin->fin_nattag) != 0)
+			}
+			if (ipf_matchtag(&fr->fr_nattag, fin->fin_nattag)!=0) {
+				RWLOCK_EXIT(&softc->ipf_state);
+				SBUMPD(ipf_state_stats, iss_check_nattag);
 				return NULL;
+			}
 		}
-		(void) strncpy(fin->fin_group, fr->fr_group, FR_GROUPLEN);
+		(void) strncpy(fin->fin_group, FR_NAME(fr, fr_group),
+			       FR_GROUPLEN);
 		fin->fin_icode = fr->fr_icode;
 	}
 
 	fin->fin_rule = is->is_rulen;
-	pass = is->is_pass;
-	fr_updatestate(fin, is, ifq);
+	fin->fin_fr = fr;
 
-	fin->fin_state = is;
-	is->is_touched = fr_ticks;
+	/*
+	 * If this packet is a fragment and the rule says to track fragments,
+	 * then create a new fragment cache entry.
+	 */
+	if (fin->fin_flx & FI_FRAG && FR_ISPASS(is->is_pass) &&
+	   is->is_pass & FR_KEEPFRAG)
+		(void) ipf_frag_new(softc, fin, is->is_pass);
+
+	/*
+	 * For TCP packets, ifq == NULL.  For all others, check if this new
+	 * queue is different to the last one it was on and move it if so.
+	 */
+	tqe = &is->is_sti;
+	if ((tqe->tqe_flags & TQE_RULEBASED) != 0)
+		ifq = is->is_tqehead[fin->fin_rev];
+
 	MUTEX_ENTER(&is->is_lock);
-	is->is_ref++;
+
+	if (ifq != NULL)
+		ipf_movequeue(softc->ipf_ticks, tqe, tqe->tqe_ifq, ifq);
+
+	inout = (fin->fin_rev << 1) + fin->fin_out;
+	is->is_pkts[inout]++;
+	is->is_bytes[inout] += fin->fin_plen;
+	fin->fin_pktnum = is->is_pkts[inout] + is->is_icmppkts[inout];
+
 	MUTEX_EXIT(&is->is_lock);
-	RWLOCK_EXIT(&ipf_state);
+
+	pass = is->is_pass;
+
+	if (is->is_flags & IS_STATESYNC)
+		ipf_sync_update(softc, SMC_STATE, fin, is->is_sync);
+
+	RWLOCK_EXIT(&softc->ipf_state);
+
+	SBUMP(ipf_state_stats.iss_hits);
+
+	fin->fin_dif = &is->is_dif;
+	fin->fin_tif = &is->is_tifs[fin->fin_rev];
 	fin->fin_flx |= FI_STATE;
 	if ((pass & FR_LOGFIRST) != 0)
 		pass &= ~(FR_LOGFIRST|FR_LOG);
@@ -2805,17 +3463,18 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_fixoutisn                                                */
+/* Function:    ipf_fixoutisn                                               */
 /* Returns:     Nil                                                         */
-/* Parameters:  fin(I)   - pointer to packet information                    */
+/* Parameters:  fin(I) - pointer to packet information                      */
 /*              is(I)  - pointer to master state structure                  */
 /*                                                                          */
 /* Called only for outbound packets, adjusts the sequence number and the    */
 /* TCP checksum to match that change.                                       */
 /* ------------------------------------------------------------------------ */
-static void fr_fixoutisn(fin, is)
-fr_info_t *fin;
-ipstate_t *is;
+static void
+ipf_fixoutisn(fin, is)
+	fr_info_t *fin;
+	ipstate_t *is;
 {
 	tcphdr_t *tcp;
 	int rev;
@@ -2824,19 +3483,19 @@
 	tcp = fin->fin_dp;
 	rev = fin->fin_rev;
 	if ((is->is_flags & IS_ISNSYN) != 0) {
-		if (rev == 0) {
+		if ((rev == 0) && (fin->fin_cksum < FI_CK_L4PART)) {
 			seq = ntohl(tcp->th_seq);
 			seq += is->is_isninc[0];
 			tcp->th_seq = htonl(seq);
-			fix_outcksum(fin, &tcp->th_sum, is->is_sumd[0]);
+			ipf_fix_outcksum(0, &tcp->th_sum, is->is_sumd[0], 0);
 		}
 	}
 	if ((is->is_flags & IS_ISNACK) != 0) {
-		if (rev == 1) {
+		if ((rev == 1) && (fin->fin_cksum < FI_CK_L4PART)) {
 			seq = ntohl(tcp->th_seq);
 			seq += is->is_isninc[1];
 			tcp->th_seq = htonl(seq);
-			fix_outcksum(fin, &tcp->th_sum, is->is_sumd[1]);
+			ipf_fix_outcksum(0, &tcp->th_sum, is->is_sumd[1], 0);
 		}
 	}
 }
@@ -2843,7 +3502,7 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_fixinisn                                                 */
+/* Function:    ipf_fixinisn                                                */
 /* Returns:     Nil                                                         */
 /* Parameters:  fin(I)   - pointer to packet information                    */
 /*              is(I)  - pointer to master state structure                  */
@@ -2851,9 +3510,10 @@
 /* Called only for inbound packets, adjusts the acknowledge number and the  */
 /* TCP checksum to match that change.                                       */
 /* ------------------------------------------------------------------------ */
-static void fr_fixinisn(fin, is)
-fr_info_t *fin;
-ipstate_t *is;
+static void
+ipf_fixinisn(fin, is)
+	fr_info_t *fin;
+	ipstate_t *is;
 {
 	tcphdr_t *tcp;
 	int rev;
@@ -2862,19 +3522,19 @@
 	tcp = fin->fin_dp;
 	rev = fin->fin_rev;
 	if ((is->is_flags & IS_ISNSYN) != 0) {
-		if (rev == 1) {
+		if ((rev == 1) && (fin->fin_cksum < FI_CK_L4PART)) {
 			ack = ntohl(tcp->th_ack);
 			ack -= is->is_isninc[0];
 			tcp->th_ack = htonl(ack);
-			fix_incksum(fin, &tcp->th_sum, is->is_sumd[0]);
+			ipf_fix_incksum(0, &tcp->th_sum, is->is_sumd[0], 0);
 		}
 	}
 	if ((is->is_flags & IS_ISNACK) != 0) {
-		if (rev == 0) {
+		if ((rev == 0) && (fin->fin_cksum < FI_CK_L4PART)) {
 			ack = ntohl(tcp->th_ack);
 			ack -= is->is_isninc[1];
 			tcp->th_ack = htonl(ack);
-			fix_incksum(fin, &tcp->th_sum, is->is_sumd[1]);
+			ipf_fix_incksum(0, &tcp->th_sum, is->is_sumd[1], 0);
 		}
 	}
 }
@@ -2881,9 +3541,10 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_statesync                                                */
+/* Function:    ipf_state_sync                                              */
 /* Returns:     Nil                                                         */
-/* Parameters:  ifp(I) - pointer to interface                               */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              ifp(I)   - pointer to interface                             */
 /*                                                                          */
 /* Walk through all state entries and if an interface pointer match is      */
 /* found then look it up again, based on its name in case the pointer has   */
@@ -2892,40 +3553,45 @@
 /* If ifp is passed in as being non-null then we are only doing updates for */
 /* existing, matching, uses of it.                                          */
 /* ------------------------------------------------------------------------ */
-void fr_statesync(ifp)
-void *ifp;
+void
+ipf_state_sync(softc, ifp)
+	ipf_main_softc_t *softc;
+	void *ifp;
 {
+	ipf_state_softc_t *softs = softc->ipf_state_soft;
 	ipstate_t *is;
 	int i;
 
-	if (fr_running <= 0)
+	if (softc->ipf_running <= 0)
 		return;
 
-	WRITE_ENTER(&ipf_state);
+	WRITE_ENTER(&softc->ipf_state);
 
-	if (fr_running <= 0) {
-		RWLOCK_EXIT(&ipf_state);
+	if (softc->ipf_running <= 0) {
+		RWLOCK_EXIT(&softc->ipf_state);
 		return;
 	}
 
-	for (is = ips_list; is; is = is->is_next) {
+	for (is = softs->ipf_state_list; is; is = is->is_next) {
 		/*
 		 * Look up all the interface names in the state entry.
 		 */
 		for (i = 0; i < 4; i++) {
 			if (ifp == NULL || ifp == is->is_ifp[i])
-				is->is_ifp[i] = fr_resolvenic(is->is_ifname[i],
+				is->is_ifp[i] = ipf_resolvenic(softc,
+							      is->is_ifname[i],
 							      is->is_v);
 		}
 	}
-	RWLOCK_EXIT(&ipf_state);
+	RWLOCK_EXIT(&softc->ipf_state);
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_delstate                                                 */
-/* Returns:     int - 0 = entry deleted, else reference count on struct     */
-/* Parameters:  is(I)  - pointer to state structure to delete               */
+/* Function:    ipf_state_del                                               */
+/* Returns:     int    - 0 = deleted, else refernce count on active struct  */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              is(I)  - pointer to state structure to delete               */
 /*              why(I) - if not 0, log reason why it was deleted            */
 /* Write Locks: ipf_state                                                   */
 /*                                                                          */
@@ -2933,10 +3599,15 @@
 /* and timeout queue lists.  Make adjustments to hash table statistics and  */
 /* global counters as required.                                             */
 /* ------------------------------------------------------------------------ */
-static int fr_delstate(is, why)
-ipstate_t *is;
-int why;
+static int
+ipf_state_del(softc, is, why)
+	ipf_main_softc_t *softc;
+	ipstate_t *is;
+	int why;
 {
+	ipf_state_softc_t *softs = softc->ipf_state_soft;
+	int orphan = 1;
+	frentry_t *fr;
 
 	/*
 	 * Since we want to delete this, remove it from the state table,
@@ -2946,22 +3617,23 @@
 		*is->is_phnext = is->is_hnext;
 		if (is->is_hnext != NULL)
 			is->is_hnext->is_phnext = is->is_phnext;
-		if (ips_table[is->is_hv] == NULL)
-			ips_stats.iss_inuse--;
-		ips_stats.iss_bucketlen[is->is_hv]--;
+		if (softs->ipf_state_table[is->is_hv] == NULL)
+			softs->ipf_state_stats.iss_inuse--;
+		softs->ipf_state_stats.iss_bucketlen[is->is_hv]--;
 
 		is->is_phnext = NULL;
 		is->is_hnext = NULL;
+		orphan = 0;
 	}
 
 	/*
-	 * Because ips_stats.iss_wild is a count of entries in the state
+	 * Because ipf_state_stats.iss_wild is a count of entries in the state
 	 * table that have wildcard flags set, only decerement it once
 	 * and do it here.
 	 */
 	if (is->is_flags & (SI_WILDP|SI_WILDA)) {
 		if (!(is->is_flags & SI_CLONED)) {
-			ATOMIC_DECL(ips_stats.iss_wild);
+			ATOMIC_DECL(softs->ipf_state_stats.iss_wild);
 		}
 		is->is_flags &= ~(SI_WILDP|SI_WILDA);
 	}
@@ -2970,47 +3642,56 @@
 	 * Next, remove it from the timeout queue it is in.
 	 */
 	if (is->is_sti.tqe_ifq != NULL)
-		fr_deletequeueentry(&is->is_sti);
+		ipf_deletequeueentry(&is->is_sti);
 
-	if (is->is_me != NULL) {
-		*is->is_me = NULL;
-		is->is_me = NULL;
-	}
-
 	/*
 	 * 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.  How can this
-	 * be?  fr_state_flush() calls fr_delete() directly because it wants
+	 * be?  ipf_state_flush() calls ipf_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.
 	 */
 	MUTEX_ENTER(&is->is_lock);
-	if (is->is_ref > 1) {
+	if (is->is_me != NULL) {
+		*is->is_me = NULL;
+		is->is_me = NULL;
 		is->is_ref--;
+	}
+	is->is_ref--;
+	if (is->is_ref > 0) {
+		int refs;
+
+		refs = is->is_ref;
 		MUTEX_EXIT(&is->is_lock);
-		return is->is_ref;
+		if (!orphan)
+			softs->ipf_state_stats.iss_orphan++;
+		return refs;
 	}
+
+	fr = is->is_rule;
+	is->is_rule = NULL;
+	if (fr != NULL) {
+		if (fr->fr_srctrack.ht_max_nodes != 0) {
+			(void) ipf_ht_node_del(&fr->fr_srctrack,
+					       is->is_family, &is->is_src);
+		}
+	}
+
+	ASSERT(is->is_ref == 0);
 	MUTEX_EXIT(&is->is_lock);
 
-	is->is_ref = 0;
-
 	if (is->is_tqehead[0] != NULL) {
-		if (fr_deletetimeoutqueue(is->is_tqehead[0]) == 0)
-			fr_freetimeoutqueue(is->is_tqehead[0]);
+		if (ipf_deletetimeoutqueue(is->is_tqehead[0]) == 0)
+			ipf_freetimeoutqueue(softc, is->is_tqehead[0]);
 	}
 	if (is->is_tqehead[1] != NULL) {
-		if (fr_deletetimeoutqueue(is->is_tqehead[1]) == 0)
-			fr_freetimeoutqueue(is->is_tqehead[1]);
+		if (ipf_deletetimeoutqueue(is->is_tqehead[1]) == 0)
+			ipf_freetimeoutqueue(softc, is->is_tqehead[1]);
 	}
 
-#ifdef	IPFILTER_SYNC
 	if (is->is_sync)
-		ipfsync_del(is->is_sync);
-#endif
-#ifdef	IPFILTER_SCAN
-	(void) ipsc_detachis(is);
-#endif
+		ipf_sync_del_state(softc->ipf_sync_soft, is->is_sync);
 
 	/*
 	 * Now remove it from the linked list of known states
@@ -3025,26 +3706,26 @@
 		is->is_next = NULL;
 	}
 
-	if (ipstate_logging != 0 && why != 0)
-		ipstate_log(is, why);
+	if (softs->ipf_state_logging != 0 && why != 0)
+		ipf_state_log(softc, is, why);
 
 	if (is->is_p == IPPROTO_TCP)
-		ips_stats.iss_fin++;
+		softs->ipf_state_stats.iss_fin++;
 	else
-		ips_stats.iss_expire++;
+		softs->ipf_state_stats.iss_expire++;
+	if (orphan)
+		softs->ipf_state_stats.iss_orphan--;
 
-	if (is->is_rule != NULL) {
-		is->is_rule->fr_statecnt--;
-		(void) fr_derefrule(&is->is_rule);
+	if (fr != NULL) {
+		fr->fr_statecnt--;
+		(void) ipf_derefrule(softc, &fr);
 	}
 
-#if defined(NEED_LOCAL_RAND) && defined(_KERNEL)
-	ipf_rand_push(is, sizeof(*is));
-#endif
+	softs->ipf_state_stats.iss_active_proto[is->is_p]--;
 
 	MUTEX_DESTROY(&is->is_lock);
 	KFREE(is);
-	ips_num--;
+	softs->ipf_state_stats.iss_active--;
 
 	return 0;
 }
@@ -3051,9 +3732,9 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_timeoutstate                                             */
+/* Function:    ipf_state_expire                                            */
 /* Returns:     Nil                                                         */
-/* Parameters:  Nil                                                         */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
 /*                                                                          */
 /* Slowly expire held state for thingslike UDP and ICMP.  The algorithm     */
 /* used here is to keep the queue sorted with the oldest things at the top  */
@@ -3060,8 +3741,11 @@
 /* and the youngest at the bottom.  So if the top one doesn't need to be    */
 /* expired then neither will any under it.                                  */
 /* ------------------------------------------------------------------------ */
-void fr_timeoutstate()
+void
+ipf_state_expire(softc)
+	ipf_main_softc_t *softc;
 {
+	ipf_state_softc_t *softs = softc->ipf_state_soft;
 	ipftq_t *ifq, *ifqnext;
 	ipftqent_t *tqe, *tqn;
 	ipstate_t *is;
@@ -3068,51 +3752,54 @@
 	SPL_INT(s);
 
 	SPL_NET(s);
-	WRITE_ENTER(&ipf_state);
-	for (ifq = ips_tqtqb; ifq != NULL; ifq = ifq->ifq_next)
+	WRITE_ENTER(&softc->ipf_state);
+	for (ifq = softs->ipf_state_tcptq; ifq != NULL; ifq = ifq->ifq_next)
 		for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); ) {
-			if (tqe->tqe_die > fr_ticks)
+			if (tqe->tqe_die > softc->ipf_ticks)
 				break;
 			tqn = tqe->tqe_next;
 			is = tqe->tqe_parent;
-			fr_delstate(is, ISL_EXPIRE);
+			ipf_state_del(softc, is, ISL_EXPIRE);
 		}
 
-	for (ifq = ips_utqe; ifq != NULL; ifq = ifqnext) {
+	for (ifq = softs->ipf_state_usertq; ifq != NULL; ifq = ifqnext) {
 		ifqnext = ifq->ifq_next;
 
 		for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); ) {
-			if (tqe->tqe_die > fr_ticks)
+			if (tqe->tqe_die > softc->ipf_ticks)
 				break;
 			tqn = tqe->tqe_next;
 			is = tqe->tqe_parent;
-			fr_delstate(is, ISL_EXPIRE);
+			ipf_state_del(softc, is, ISL_EXPIRE);
 		}
 	}
 
-	for (ifq = ips_utqe; ifq != NULL; ifq = ifqnext) {
+	for (ifq = softs->ipf_state_usertq; ifq != NULL; ifq = ifqnext) {
 		ifqnext = ifq->ifq_next;
 
 		if (((ifq->ifq_flags & IFQF_DELETE) != 0) &&
 		    (ifq->ifq_ref == 0)) {
-			fr_freetimeoutqueue(ifq);
+			ipf_freetimeoutqueue(softc, ifq);
 		}
 	}
 
-	if (fr_state_doflush) {
-		(void) fr_state_flush(2, 0);
-		fr_state_doflush = 0;
+	if (softs->ipf_state_doflush) {
+		(void) ipf_state_flush(softc, 2, 0);
+		softs->ipf_state_doflush = 0;
+		softs->ipf_state_wm_last = softc->ipf_ticks;
 	}
 
-	RWLOCK_EXIT(&ipf_state);
+	RWLOCK_EXIT(&softc->ipf_state);
 	SPL_X(s);
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_state_flush                                              */
+/* Function:    ipf_state_flush                                             */
 /* Returns:     int - 0 == success, -1 == failure                           */
-/* Parameters:  Nil                                                         */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              which(I) - which flush action to perform                    */
+/*              proto(I) - which protocol to flush (0 == ALL)               */
 /* Write Locks: ipf_state                                                   */
 /*                                                                          */
 /* Flush state tables.  Three actions currently defined:                    */
@@ -3126,12 +3813,15 @@
 /*            If that too fails, then work backwards in 30 second intervals */
 /*            for the last 30 minutes to at worst 30 seconds idle.          */
 /* ------------------------------------------------------------------------ */
-static int fr_state_flush(which, proto)
-int which, proto;
+int
+ipf_state_flush(softc, which, proto)
+	ipf_main_softc_t *softc;
+	int which, proto;
 {
-	ipftq_t *ifq, *ifqnext;
+	ipf_state_softc_t *softs = softc->ipf_state_soft;
 	ipftqent_t *tqe, *tqn;
 	ipstate_t *is, **isp;
+	ipftq_t *ifq;
 	int removed;
 	SPL_INT(s);
 
@@ -3142,15 +3832,16 @@
 	switch (which)
 	{
 	case 0 :
+		SBUMP(ipf_state_stats.iss_flush_all);
 		/*
 		 * Style 0 flush removes everything...
 		 */
-		for (isp = &ips_list; ((is = *isp) != NULL); ) {
+		for (isp = &softs->ipf_state_list; ((is = *isp) != NULL); ) {
 			if ((proto != 0) && (is->is_v != proto)) {
 				isp = &is->is_next;
 				continue;
 			}
-			if (fr_delstate(is, ISL_FLUSH) == 0)
+			if (ipf_state_del(softc, is, ISL_FLUSH) == 0)
 				removed++;
 			else
 				isp = &is->is_next;
@@ -3158,12 +3849,13 @@
 		break;
 
 	case 1 :
+		SBUMP(ipf_state_stats.iss_flush_closing);
 		/*
 		 * 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 (ifq = softs->ipf_state_tcptq + IPF_TCPS_CLOSE_WAIT;
+		     ifq != NULL; ifq = ifq->ifq_next) {
 
 			for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); ) {
 				tqn = tqe->tqe_next;
@@ -3170,7 +3862,7 @@
 				is = tqe->tqe_parent;
 				if (is->is_p != IPPROTO_TCP)
 					break;
-				if (fr_delstate(is, ISL_EXPIRE) == 0)
+				if (ipf_state_del(softc, is, ISL_FLUSH) == 0)
 					removed++;
 			}
 		}
@@ -3178,8 +3870,8 @@
 		/*
 		 * Also need to look through the user defined queues.
 		 */
-		for (ifq = ips_utqe; ifq != NULL; ifq = ifqnext) {
-			ifqnext = ifq->ifq_next;
+		for (ifq = softs->ipf_state_usertq; ifq != NULL;
+		     ifq = ifq->ifq_next) {
 			for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); ) {
 				tqn = tqe->tqe_next;
 				is = tqe->tqe_parent;
@@ -3188,7 +3880,8 @@
 
 				if ((is->is_state[0] > IPF_TCPS_ESTABLISHED) &&
 				    (is->is_state[1] > IPF_TCPS_ESTABLISHED)) {
-					if (fr_delstate(is, ISL_EXPIRE) == 0)
+					if (ipf_state_del(softc, is,
+							  ISL_FLUSH) == 0)
 						removed++;
 				}
 			}
@@ -3198,7 +3891,7 @@
 	case 2 :
 		break;
 
-		/*  
+		/*
 		 * Args 5-11 correspond to flushing those particular states
 		 * for TCP connections.
 		 */
@@ -3209,12 +3902,13 @@
 	case IPF_TCPS_FIN_WAIT_2 :
 	case IPF_TCPS_TIME_WAIT :
 	case IPF_TCPS_CLOSED :
-		tqn = ips_tqtqb[which].ifq_head;
+		SBUMP(ipf_state_stats.iss_flush_queue);
+		tqn = softs->ipf_state_tcptq[which].ifq_head;
 		while (tqn != NULL) {
 			tqe = tqn;
 			tqn = tqe->tqe_next;
 			is = tqe->tqe_parent;
-			if (fr_delstate(is, ISL_FLUSH) == 0)
+			if (ipf_state_del(softc, is, ISL_FLUSH) == 0)
 				removed++;
 		}
 		break;
@@ -3223,16 +3917,18 @@
 		if (which < 30)
 			break;
 
-		/* 
+		SBUMP(ipf_state_stats.iss_flush_state);
+		/*
 		 * 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); ) {
+		for (isp = &softs->ipf_state_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) {
+				if (softc->ipf_ticks - is->is_touched > which) {
+					if (ipf_state_del(softc, is,
+							  ISL_FLUSH) == 0) {
 						removed++;
 						continue;
 					}
@@ -3248,13 +3944,23 @@
 		return removed;
 	}
 
+	SBUMP(ipf_state_stats.iss_flush_timeout);
 	/*
-	 * Asked to remove inactive entries because the table is full.
+	 * 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.
 	 */
-	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);
+	if (softc->ipf_ticks - softs->ipf_state_wm_last >
+	    softs->ipf_state_wm_freq) {
+		removed = ipf_queueflush(softc, ipf_state_flush_entry,
+					 softs->ipf_state_tcptq,
+					 softs->ipf_state_usertq,
+					 &softs->ipf_state_stats.iss_active,
+					 softs->ipf_state_size,
+					 softs->ipf_state_wm_low);
+		softs->ipf_state_wm_last = softc->ipf_ticks;
 	}
 
 	SPL_X(s);
@@ -3263,29 +3969,33 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_state_flush_entry                                        */
+/* Function:    ipf_state_flush_entry                                       */
 /* Returns:     int - 0 = entry deleted, else not deleted                   */
-/* Parameters:  entry(I)  - pointer to state structure to delete            */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              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.                                               */
+/* ipf_state_del().  It is used so we can provide a uniform interface via   */
+/* the ipf_queueflush() function.                                           */
 /* ------------------------------------------------------------------------ */
-static int fr_state_flush_entry(entry)
-void *entry;
+static int
+ipf_state_flush_entry(softc, entry)
+	ipf_main_softc_t *softc;
+	void *entry;
 {
-	return fr_delstate(entry, ISL_FLUSH);
-}     
+	return ipf_state_del(softc, entry, ISL_FLUSH);
+}
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_tcp_age                                                  */
+/* Function:    ipf_tcp_age                                                 */
 /* Returns:     int - 1 == state transition made, 0 == no change (rejected) */
-/* Parameters:  tq(I)    - pointer to timeout queue information             */
+/* Parameters:  tqe(I)   - pointer to timeout queue information             */
 /*              fin(I)   - pointer to packet information                    */
 /*              tqtab(I) - TCP timeout queue table this is in               */
 /*              flags(I) - flags from state/NAT entry                       */
+/*              ok(I)    - can we advance state                             */
 /*                                                                          */
 /* Rewritten by Arjan de Vet <Arjan.deVet at adv.iae.nl>, 2000-07-29:          */
 /*                                                                          */
@@ -3297,7 +4007,7 @@
 /*                                                                          */
 /* - store the state of the source in state[0] such that ipfstat            */
 /*   displays the state as source/dest instead of dest/source; the calls    */
-/*   to fr_tcp_age have been changed accordingly.                           */
+/*   to ipf_tcp_age have been changed accordingly.                          */
 /*                                                                          */
 /* Internal Parameters:                                                     */
 /*                                                                          */
@@ -3328,12 +4038,14 @@
 /*                                                                          */
 /* Locking: it is assumed that the parent of the tqe structure is locked.   */
 /* ------------------------------------------------------------------------ */
-int fr_tcp_age(tqe, fin, tqtab, flags)
-ipftqent_t *tqe;
-fr_info_t *fin;
-ipftq_t *tqtab;
-int flags;
+int
+ipf_tcp_age(tqe, fin, tqtab, flags, ok)
+	ipftqent_t *tqe;
+	fr_info_t *fin;
+	ipftq_t *tqtab;
+	int flags, ok;
 {
+	ipf_main_softc_t *softc = fin->fin_main_soft;
 	int dlen, ostate, nstate, rval, dir;
 	u_char tcpflags;
 	tcphdr_t *tcp;
@@ -3344,6 +4056,8 @@
 	dir = fin->fin_rev;
 	tcpflags = tcp->th_flags;
 	dlen = fin->fin_dlen - (TCP_OFF(tcp) << 2);
+	ostate = tqe->tqe_state[1 - dir];
+	nstate = tqe->tqe_state[dir];
 
 	if (tcpflags & TH_RST) {
 		if (!(tcpflags & TH_PUSH) && !dlen)
@@ -3350,11 +4064,12 @@
 			nstate = IPF_TCPS_CLOSED;
 		else
 			nstate = IPF_TCPS_CLOSE_WAIT;
+
+		if (ostate <= IPF_TCPS_ESTABLISHED) {
+			tqe->tqe_state[1 - dir] = IPF_TCPS_CLOSE_WAIT;
+		}
 		rval = 1;
 	} else {
-		ostate = tqe->tqe_state[1 - dir];
-		nstate = tqe->tqe_state[dir];
-
 		switch (nstate)
 		{
 		case IPF_TCPS_LISTEN: /* 0 */
@@ -3410,7 +4125,7 @@
 			if ((tcpflags & ~(TH_ECN|TH_CWR)) == TH_SYN) {
 				/*
 				 * A retransmitted SYN packet.  We do not reset
-				 * the timeout here to fr_tcptimeout because a
+				 * the timeout here to ipf_tcptimeout because a
 				 * connection connect timeout does not renew
 				 * after every packet that is sent.  We need to
 				 * set rval so as to indicate the packet has
@@ -3578,7 +4293,7 @@
 				 * the FIN packet here? does the window code
 				 * guarantee that?
 				 */
-				nstate = IPF_TCPS_TIME_WAIT;
+				nstate = IPF_TCPS_LAST_ACK;
 			} else {
 				/*
 				 * we closed our side of the connection
@@ -3594,25 +4309,18 @@
 			if ((tcpflags & (TH_FIN|TH_ACK)) == TH_ACK) {
 				nstate = IPF_TCPS_TIME_WAIT;
 			}
-			rval = 2;
+			rval = 1;
 			break;
 
 		case IPF_TCPS_LAST_ACK: /* 8 */
 			if (tcpflags & TH_ACK) {
-				if ((tcpflags & TH_PUSH) || dlen)
-					/*
-					 * there is still data to be delivered,
-					 * reset timeout
-					 */
-					rval = 1;
-				else
-					rval = 2;
+				rval = 1;
 			}
 			/*
-			 * we cannot detect when we go out of LAST_ACK state to
-			 * CLOSED because that is based on the reception of ACK
-			 * packets; ipfilter can only detect that a packet
-			 * has been sent by a host
+			 * we cannot detect when we go out of LAST_ACK state
+			 * to CLOSED because that is based on the reception
+			 * of ACK packets; ipfilter can only detect that a
+			 * packet has been sent by a host
 			 */
 			break;
 
@@ -3624,8 +4332,10 @@
 			/* we're in 2MSL timeout now */
 			if (ostate == IPF_TCPS_LAST_ACK) {
 				nstate = IPF_TCPS_CLOSED;
+				rval = 1;
+			} else {
+				rval = 2;
 			}
-			rval = 1;
 			break;
 
 		case IPF_TCPS_CLOSED: /* 11 */
@@ -3633,18 +4343,7 @@
 			break;
 
 		default :
-#if defined(_KERNEL)
-# if SOLARIS
-			cmn_err(CE_NOTE,
-				"tcp %lx flags %x si %lx nstate %d ostate %d\n",
-				(u_long)tcp, tcpflags, (u_long)tqe,
-				nstate, ostate);
-# else
-			printf("tcp %lx flags %x si %lx nstate %d ostate %d\n",
-				(u_long)tcp, tcpflags, (u_long)tqe,
-				nstate, ostate);
-# endif
-#else
+#if !defined(_KERNEL)
 			abort();
 #endif
 			break;
@@ -3658,9 +4357,11 @@
 	if (rval == 2)
 		rval = 1;
 	else if (rval == 1) {
-		tqe->tqe_state[dir] = nstate;
+		if (ok)
+			tqe->tqe_state[dir] = nstate;
 		if ((tqe->tqe_flags & TQE_RULEBASED) == 0)
-			fr_movequeue(tqe, tqe->tqe_ifq, tqtab + nstate);
+			ipf_movequeue(softc->ipf_ticks, tqe, tqe->tqe_ifq,
+				      tqtab + nstate);
 	}
 
 	return rval;
@@ -3668,18 +4369,21 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    ipstate_log                                                 */
+/* Function:    ipf_state_log                                               */
 /* Returns:     Nil                                                         */
-/* Parameters:  is(I)   - pointer to state structure                        */
-/*              type(I) - type of log entry to create                       */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              is(I)    - pointer to state structure                       */
+/*              type(I)  - type of log entry to create                      */
 /*                                                                          */
 /* Creates a state table log entry using the state structure and type info. */
 /* passed in.  Log packet/byte counts, source/destination address and other */
 /* protocol specific information.                                           */
 /* ------------------------------------------------------------------------ */
-void ipstate_log(is, type)
-struct ipstate *is;
-u_int type;
+void
+ipf_state_log(softc, is, type)
+	ipf_main_softc_t *softc;
+	struct ipstate *is;
+	u_int type;
 {
 #ifdef	IPFILTER_LOG
 	struct	ipslog	ipsl;
@@ -3729,11 +4433,7 @@
 	sizes[0] = sizeof(ipsl);
 	types[0] = 0;
 
-	if (ipllog(IPL_LOGSTATE, NULL, items, sizes, types, 1)) {
-		ATOMIC_INCL(ips_stats.iss_logged);
-	} else {
-		ATOMIC_INCL(ips_stats.iss_logfail);
-	}
+	(void) ipf_log_items(softc, IPL_LOGSTATE, NULL, items, sizes, types, 1);
 #endif
 }
 
@@ -3740,7 +4440,7 @@
 
 #ifdef	USE_INET6
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_checkicmp6matchingstate                                  */
+/* Function:    ipf_checkicmp6matchingstate                                 */
 /* Returns:     ipstate_t* - NULL == no match found,                        */
 /*                           else  pointer to matching state entry          */
 /* Parameters:  fin(I) - pointer to packet information                      */
@@ -3749,11 +4449,13 @@
 /* If we've got an ICMPv6 error message, using the information stored in    */
 /* the ICMPv6 packet, look for a matching state table entry.                */
 /* ------------------------------------------------------------------------ */
-static ipstate_t *fr_checkicmp6matchingstate(fin)
-fr_info_t *fin;
+static ipstate_t *
+ipf_checkicmp6matchingstate(fin)
+	fr_info_t *fin;
 {
+	ipf_main_softc_t *softc = fin->fin_main_soft;
+	ipf_state_softc_t *softs = softc->ipf_state_soft;
 	struct icmp6_hdr *ic6, *oic;
-	int type, backward, i;
 	ipstate_t *is, **isp;
 	u_short sport, dport;
 	i6addr_t dst, src;
@@ -3762,8 +4464,9 @@
 	fr_info_t ofin;
 	tcphdr_t *tcp;
 	ip6_t *oip6;
-	u_char	pr;
+	u_char pr;
 	u_int hv;
+	int type;
 
 	/*
 	 * Does it at least have the return (basic) IP header ?
@@ -3772,15 +4475,19 @@
 	 * an ICMP error header.
 	 */
 	if ((fin->fin_v != 6) || (fin->fin_plen < ICMP6ERR_MINPKTLEN) ||
-	    !(fin->fin_flx & FI_ICMPERR))
+	    !(fin->fin_flx & FI_ICMPERR)) {
+		SBUMPD(ipf_state_stats, iss_icmp_bad);
 		return NULL;
+	}
 
 	ic6 = fin->fin_dp;
 	type = ic6->icmp6_type;
 
 	oip6 = (ip6_t *)((char *)ic6 + ICMPERR_ICMPHLEN);
-	if (fin->fin_plen < sizeof(*oip6))
+	if (fin->fin_plen < sizeof(*oip6)) {
+		SBUMPD(ipf_state_stats, iss_icmp_short);
 		return NULL;
+	}
 
 	bcopy((char *)fin, (char *)&ofin, sizeof(*fin));
 	ofin.fin_v = 6;
@@ -3794,21 +4501,31 @@
 	 * matchsrcdst. Note that not all fields are necessary
 	 * but this is the cleanest way. Note further we fill
 	 * in fin_mp such that if someone uses it we'll get
-	 * a kernel panic. fr_matchsrcdst does not use this.
+	 * a kernel panic. ipf_matchsrcdst does not use this.
 	 *
 	 * watch out here, as ip is in host order and oip6 in network
 	 * order. Any change we make must be undone afterwards.
 	 */
 	savelen = oip6->ip6_plen;
-	oip6->ip6_plen = fin->fin_dlen - ICMPERR_ICMPHLEN;
+	oip6->ip6_plen = htons(fin->fin_dlen - ICMPERR_ICMPHLEN);
 	ofin.fin_flx = FI_NOCKSUM;
 	ofin.fin_ip = (ip_t *)oip6;
-	(void) fr_makefrip(sizeof(*oip6), (ip_t *)oip6, &ofin);
+	(void) ipf_makefrip(sizeof(*oip6), (ip_t *)oip6, &ofin);
 	ofin.fin_flx &= ~(FI_BAD|FI_SHORT);
 	oip6->ip6_plen = savelen;
+	pr = ofin.fin_p;
 
+	/*
+	 * an ICMP error can never generate an ICMP error in response.
+	 */
+	if (ofin.fin_flx & FI_ICMPERR) {
+		DT1(iss_icmp6_icmperr, fr_info_t *, &ofin);
+		SBUMP(ipf_state_stats.iss_icmp6_icmperr);
+		return NULL;
+	}
+
 	if (oip6->ip6_nxt == IPPROTO_ICMPV6) {
-		oic = (struct icmp6_hdr *)(oip6 + 1);
+		oic = ofin.fin_dp;
 		/*
 		 * an ICMP error can only be generated as a result of an
 		 * ICMP query, not as the response on an ICMP error
@@ -3816,8 +4533,11 @@
 		 * XXX theoretically ICMP_ECHOREP and the other reply's are
 		 * ICMP query's as well, but adding them here seems strange XXX
 		 */
-		 if (!(oic->icmp6_type & ICMP6_INFOMSG_MASK))
-		    	return NULL;
+		 if (!(oic->icmp6_type & ICMP6_INFOMSG_MASK)) {
+			DT1(iss_icmp6_notinfo, fr_info_t *, &ofin);
+			SBUMP(ipf_state_stats.iss_icmp6_notinfo);
+			return NULL;
+		}
 
 		/*
 		 * perform a lookup of the ICMP packet in the state table
@@ -3831,8 +4551,9 @@
 		hv += oic->icmp6_seq;
 		hv = DOUBLE_HASH(hv);
 
-		READ_ENTER(&ipf_state);
-		for (isp = &ips_table[hv]; ((is = *isp) != NULL); ) {
+		READ_ENTER(&softc->ipf_state);
+		for (isp = &softs->ipf_state_table[hv];
+		     ((is = *isp) != NULL); ) {
 			ic = &is->is_icmp;
 			isp = &is->is_hnext;
 			if ((is->is_p == pr) &&
@@ -3839,7 +4560,7 @@
 			    !(is->is_pass & FR_NOICMPERR) &&
 			    (oic->icmp6_id == ic->ici_id) &&
 			    (oic->icmp6_seq == ic->ici_seq) &&
-			    (is = fr_matchsrcdst(&ofin, is, &src,
+			    (is = ipf_matchsrcdst(&ofin, is, &src,
 						 &dst, NULL, FI_ICMPCMP))) {
 			    	/*
 			    	 * in the state table ICMP query's are stored
@@ -3849,16 +4570,13 @@
 				if (((ic->ici_type == ICMP6_ECHO_REPLY) &&
 				     (oic->icmp6_type == ICMP6_ECHO_REQUEST)) ||
 				     (ic->ici_type - 1 == oic->icmp6_type )) {
-				    	ips_stats.iss_hits++;
-					backward = IP6_NEQ(&is->is_dst, &src);
-					fin->fin_rev = !backward;
-					i = (backward << 1) + fin->fin_out;
-    					is->is_icmppkts[i]++;
-					return is;
+					if (!ipf_allowstateicmp(fin, is, &src))
+						return is;
 				}
 			}
 		}
-		RWLOCK_EXIT(&ipf_state);
+		RWLOCK_EXIT(&softc->ipf_state);
+		SBUMPD(ipf_state_stats, iss_icmp6_miss);
 		return NULL;
 	}
 
@@ -3874,18 +4592,33 @@
 	hv += dst.i6[2];
 	hv += dst.i6[3];
 
-	if ((oip6->ip6_nxt == IPPROTO_TCP) || (oip6->ip6_nxt == IPPROTO_UDP)) {
+	tcp = NULL;
+
+	switch (oip6->ip6_nxt)
+	{
+	case IPPROTO_TCP :
+	case IPPROTO_UDP :
 		tcp = (tcphdr_t *)(oip6 + 1);
 		dport = tcp->th_dport;
 		sport = tcp->th_sport;
 		hv += dport;
 		hv += sport;
-	} else
-		tcp = NULL;
+		break;
+
+	case IPPROTO_ICMPV6 :
+		oic = (struct icmp6_hdr *)(oip6 + 1);
+		hv += oic->icmp6_id;
+		hv += oic->icmp6_seq;
+		break;
+
+	default :
+		break;
+	}
+
 	hv = DOUBLE_HASH(hv);
 
-	READ_ENTER(&ipf_state);
-	for (isp = &ips_table[hv]; ((is = *isp) != NULL); ) {
+	READ_ENTER(&softc->ipf_state);
+	for (isp = &softs->ipf_state_table[hv]; ((is = *isp) != NULL); ) {
 		isp = &is->is_hnext;
 		/*
 		 * Only allow this icmp though if the
@@ -3897,22 +4630,12 @@
 		if ((is->is_p != pr) || (is->is_v != 6) ||
 		    (is->is_pass & FR_NOICMPERR))
 			continue;
-		is = fr_matchsrcdst(&ofin, is, &src, &dst, tcp, FI_ICMPCMP);
-		if (is != NULL) {
-			ips_stats.iss_hits++;
-			backward = IP6_NEQ(&is->is_dst, &src);
-			fin->fin_rev = !backward;
-			i = (backward << 1) + fin->fin_out;
-			is->is_icmppkts[i]++;
-			/*
-			 * we deliberately do not touch the timeouts
-			 * for the accompanying state table entry.
-			 * It remains to be seen if that is correct. XXX
-			 */
+		is = ipf_matchsrcdst(&ofin, is, &src, &dst, tcp, FI_ICMPCMP);
+		if ((is != NULL) && (ipf_allowstateicmp(fin, is, &src) == 0))
 			return is;
-		}
 	}
-	RWLOCK_EXIT(&ipf_state);
+	RWLOCK_EXIT(&softc->ipf_state);
+	SBUMPD(ipf_state_stats, iss_icmp_miss);
 	return NULL;
 }
 #endif
@@ -3919,43 +4642,42 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_sttab_init                                               */
+/* Function:    ipf_sttab_init                                              */
 /* Returns:     Nil                                                         */
-/* Parameters:  tqp(I) - pointer to an array of timeout queues for TCP      */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              tqp(I)   - pointer to an array of timeout queues for TCP    */
 /*                                                                          */
 /* Initialise the array of timeout queues for TCP.                          */
 /* ------------------------------------------------------------------------ */
-void fr_sttab_init(tqp)
-ipftq_t *tqp;
+void
+ipf_sttab_init(softc, tqp)
+	ipf_main_softc_t *softc;
+	ipftq_t *tqp;
 {
 	int i;
 
 	for (i = IPF_TCP_NSTATES - 1; i >= 0; i--) {
-		tqp[i].ifq_ttl = 0;
-		tqp[i].ifq_ref = 1;
-		tqp[i].ifq_head = NULL;
-		tqp[i].ifq_tail = &tqp[i].ifq_head;
+		IPFTQ_INIT(&tqp[i], 0, "ipftq tcp tab");
 		tqp[i].ifq_next = tqp + i + 1;
-		MUTEX_INIT(&tqp[i].ifq_lock, "ipftq tcp tab");
 	}
 	tqp[IPF_TCP_NSTATES - 1].ifq_next = NULL;
-	tqp[IPF_TCPS_CLOSED].ifq_ttl = fr_tcpclosed;
-	tqp[IPF_TCPS_LISTEN].ifq_ttl = fr_tcptimeout;
-	tqp[IPF_TCPS_SYN_SENT].ifq_ttl = fr_tcptimeout;
-	tqp[IPF_TCPS_SYN_RECEIVED].ifq_ttl = fr_tcptimeout;
-	tqp[IPF_TCPS_ESTABLISHED].ifq_ttl = fr_tcpidletimeout;
-	tqp[IPF_TCPS_CLOSE_WAIT].ifq_ttl = fr_tcphalfclosed;
-	tqp[IPF_TCPS_FIN_WAIT_1].ifq_ttl = fr_tcphalfclosed;
-	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_tcptimewait;
-	tqp[IPF_TCPS_HALF_ESTAB].ifq_ttl = fr_tcptimeout;
+	tqp[IPF_TCPS_CLOSED].ifq_ttl = softc->ipf_tcpclosed;
+	tqp[IPF_TCPS_LISTEN].ifq_ttl = softc->ipf_tcptimeout;
+	tqp[IPF_TCPS_SYN_SENT].ifq_ttl = softc->ipf_tcpsynsent;
+	tqp[IPF_TCPS_SYN_RECEIVED].ifq_ttl = softc->ipf_tcpsynrecv;
+	tqp[IPF_TCPS_ESTABLISHED].ifq_ttl = softc->ipf_tcpidletimeout;
+	tqp[IPF_TCPS_CLOSE_WAIT].ifq_ttl = softc->ipf_tcphalfclosed;
+	tqp[IPF_TCPS_FIN_WAIT_1].ifq_ttl = softc->ipf_tcphalfclosed;
+	tqp[IPF_TCPS_CLOSING].ifq_ttl = softc->ipf_tcptimeout;
+	tqp[IPF_TCPS_LAST_ACK].ifq_ttl = softc->ipf_tcplastack;
+	tqp[IPF_TCPS_FIN_WAIT_2].ifq_ttl = softc->ipf_tcpclosewait;
+	tqp[IPF_TCPS_TIME_WAIT].ifq_ttl = softc->ipf_tcptimewait;
+	tqp[IPF_TCPS_HALF_ESTAB].ifq_ttl = softc->ipf_tcptimeout;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_sttab_destroy                                            */
+/* Function:    ipf_sttab_destroy                                           */
 /* Returns:     Nil                                                         */
 /* Parameters:  tqp(I) - pointer to an array of timeout queues for TCP      */
 /*                                                                          */
@@ -3962,8 +4684,9 @@
 /* Do whatever is necessary to "destroy" each of the entries in the array   */
 /* of timeout queues for TCP.                                               */
 /* ------------------------------------------------------------------------ */
-void fr_sttab_destroy(tqp)
-ipftq_t *tqp;
+void
+ipf_sttab_destroy(tqp)
+	ipftq_t *tqp;
 {
 	int i;
 
@@ -3973,9 +4696,10 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_statederef                                               */
+/* Function:    ipf_state_deref                                             */
 /* Returns:     Nil                                                         */
-/* Parameters:  isp(I) - pointer to pointer to state table entry            */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              isp(I) - pointer to pointer to state table entry            */
 /*                                                                          */
 /* Decrement the reference counter for this state table entry and free it   */
 /* if there are no more things using it.                                    */
@@ -4003,10 +4727,12 @@
 /*    dir == 0 : a packet from source to dest                               */
 /*    dir == 1 : a packet from dest to source                               */
 /* ------------------------------------------------------------------------ */
-void fr_statederef(isp)
-ipstate_t **isp;
+void
+ipf_state_deref(softc, isp)
+	ipf_main_softc_t *softc;
+	ipstate_t **isp;
 {
-	ipstate_t *is;
+	ipstate_t *is = *isp;
 
 	is = *isp;
 	*isp = NULL;
@@ -4017,8 +4743,8 @@
 		MUTEX_EXIT(&is->is_lock);
 #ifndef	_KERNEL
 		if ((is->is_sti.tqe_state[0] > IPF_TCPS_ESTABLISHED) ||
-		   (is->is_sti.tqe_state[1] > IPF_TCPS_ESTABLISHED)) {
-			fr_delstate(is, ISL_ORPHAN);
+		    (is->is_sti.tqe_state[1] > IPF_TCPS_ESTABLISHED)) {
+			ipf_state_del(softc, is, ISL_EXPIRE);
 		}
 #endif
 		return;
@@ -4025,29 +4751,32 @@
 	}
 	MUTEX_EXIT(&is->is_lock);
 
-	WRITE_ENTER(&ipf_state);
-	fr_delstate(is, ISL_EXPIRE);
-	RWLOCK_EXIT(&ipf_state);
+	WRITE_ENTER(&softc->ipf_state);
+	ipf_state_del(softc, is, ISL_ORPHAN);
+	RWLOCK_EXIT(&softc->ipf_state);
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_setstatequeue                                            */
+/* Function:    ipf_state_setqueue                                          */
 /* Returns:     Nil                                                         */
-/* Parameters:  is(I) - pointer to state structure                          */
-/*              rev(I) - forward(0) or reverse(1) direction                 */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              is(I)    - pointer to state structure                       */
+/*              rev(I)   - forward(0) or reverse(1) direction               */
 /* Locks:       ipf_state (read or write)                                   */
 /*                                                                          */
 /* Put the state entry on its default queue entry, using rev as a helped in */
 /* determining which queue it should be placed on.                          */
 /* ------------------------------------------------------------------------ */
-void fr_setstatequeue(is, rev)
-ipstate_t *is;
-int rev;
+void
+ipf_state_setqueue(softc, is, rev)
+	ipf_main_softc_t *softc;
+	ipstate_t *is;
+	int rev;
 {
+	ipf_state_softc_t *softs = softc->ipf_state_soft;
 	ipftq_t *oifq, *nifq;
 
-
 	if ((is->is_sti.tqe_flags & TQE_RULEBASED) != 0)
 		nifq = is->is_tqehead[rev];
 	else
@@ -4059,30 +4788,30 @@
 #ifdef USE_INET6
 		case IPPROTO_ICMPV6 :
 			if (rev == 1)
-				nifq = &ips_icmpacktq;
+				nifq = &softs->ipf_state_icmpacktq;
 			else
-				nifq = &ips_icmptq;
+				nifq = &softs->ipf_state_icmptq;
 			break;
 #endif
 		case IPPROTO_ICMP :
 			if (rev == 1)
-				nifq = &ips_icmpacktq;
+				nifq = &softs->ipf_state_icmpacktq;
 			else
-				nifq = &ips_icmptq;
+				nifq = &softs->ipf_state_icmptq;
 			break;
 		case IPPROTO_TCP :
-			nifq = ips_tqtqb + is->is_state[rev];
+			nifq = softs->ipf_state_tcptq + is->is_state[rev];
 			break;
 
 		case IPPROTO_UDP :
 			if (rev == 1)
-				nifq = &ips_udpacktq;
+				nifq = &softs->ipf_state_udpacktq;
 			else
-				nifq = &ips_udptq;
+				nifq = &softs->ipf_state_udptq;
 			break;
 
 		default :
-			nifq = &ips_iptq;
+			nifq = &softs->ipf_state_iptq;
 			break;
 		}
 	}
@@ -4093,126 +4822,575 @@
 	 * another, else put it on the end of the newly determined queue.
 	 */
 	if (oifq != NULL)
-		fr_movequeue(&is->is_sti, oifq, nifq);
+		ipf_movequeue(softc->ipf_ticks, &is->is_sti, oifq, nifq);
 	else
-		fr_queueappend(&is->is_sti, nifq, is);
+		ipf_queueappend(softc->ipf_ticks, &is->is_sti, nifq, is);
 	return;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_stateiter                                                */
+/* Function:    ipf_state_iter                                              */
 /* Returns:     int - 0 == success, else error                              */
-/* Parameters:  token(I) - pointer to ipftoken structure                    */
+/* Parameters:  softc(I) - pointer to main soft context                     */
+/*              token(I) - pointer to ipftoken structure                    */
 /*              itp(I)   - pointer to ipfgeniter structure                  */
+/*              obj(I)   - pointer to data description 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.)    */
+/* walks through the list of entries in the state table list (softs->ipf_state_list.)    */
 /* ------------------------------------------------------------------------ */
-static int fr_stateiter(token, itp)
-ipftoken_t *token;
-ipfgeniter_t *itp;
+static int
+ipf_state_iter(softc, token, itp, obj)
+	ipf_main_softc_t *softc;
+	ipftoken_t *token;
+	ipfgeniter_t *itp;
+	ipfobj_t *obj;
 {
+	ipf_state_softc_t *softs = softc->ipf_state_soft;
 	ipstate_t *is, *next, zero;
-	int error, count;
-	char *dst;
+	int error;
 
-	if (itp->igi_data == NULL)
+	if (itp->igi_data == NULL) {
+		IPFERROR(100026);
 		return EFAULT;
+	}
 
-	if (itp->igi_nitems < 1)
+	if (itp->igi_nitems < 1) {
+		IPFERROR(100027);
 		return ENOSPC;
+	}
 
-	if (itp->igi_type != IPFGENITER_STATE)
+	if (itp->igi_type != IPFGENITER_STATE) {
+		IPFERROR(100028);
 		return EINVAL;
+	}
 
 	is = token->ipt_data;
 	if (is == (void *)-1) {
-		ipf_freetoken(token);
+		IPFERROR(100029);
 		return ESRCH;
 	}
 
 	error = 0;
-	dst = itp->igi_data;
+	obj->ipfo_type = IPFOBJ_IPSTATE;
+	obj->ipfo_size = sizeof(ipstate_t);
 
-	READ_ENTER(&ipf_state);
+	READ_ENTER(&softc->ipf_state);
+
+	is = token->ipt_data;
 	if (is == NULL) {
-		next = ips_list;
+		next = softs->ipf_state_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);
+	/*
+	 * 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 (next != NULL) {
+		MUTEX_ENTER(&next->is_lock);
+		next->is_ref++;
+		MUTEX_EXIT(&next->is_lock);
+		token->ipt_data = next;
+	} else {
+		bzero(&zero, sizeof(zero));
+		next = &zero;
+		token->ipt_data = NULL;
+	}
+	if (next->is_next == NULL)
+		ipf_token_mark_complete(token);
 
-		/*
-		 * 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;
+	RWLOCK_EXIT(&softc->ipf_state);
 
-		dst += sizeof(*next);
-		count--;
+	obj->ipfo_ptr = itp->igi_data;
+	error = ipf_outobjk(softc, obj, next);
+	if (is != NULL)
+		ipf_state_deref(softc, &is);
 
-		READ_ENTER(&ipf_state);
-		next = next->is_next;
-	}
-
-	if (is != NULL) {
-		fr_statederef(&is);
-	}
-
 	return error;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_stgettable                                               */
+/* Function:    ipf_state_gettable                                          */
 /* Returns:     int     - 0 = success, else error                           */
-/* Parameters:  data(I) - pointer to ioctl data                             */
+/* Parameters:  softc(I) - pointer to main soft context                     */
+/*              softs(I) - pointer to state context structure               */
+/*              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;
+static int
+ipf_state_gettable(softc, softs, data)
+	ipf_main_softc_t *softc;
+	ipf_state_softc_t *softs;
+	char *data;
 {
 	ipftable_t table;
 	int error;
 
-	error = fr_inobj(data, &table, IPFOBJ_GTABLE);
+	error = ipf_inobj(softc, data, NULL, &table, IPFOBJ_GTABLE);
 	if (error != 0)
 		return error;
 
-	if (table.ita_type != IPFTABLE_BUCKETS)
+	if (table.ita_type != IPFTABLE_BUCKETS) {
+		IPFERROR(100031);
 		return EINVAL;
+	}
 
-	error = COPYOUT(ips_stats.iss_bucketlen, table.ita_table, 
-			fr_statesize * sizeof(u_long));
-	if (error != 0)
+	error = COPYOUT(softs->ipf_state_stats.iss_bucketlen, table.ita_table,
+			softs->ipf_state_size * sizeof(u_int));
+	if (error != 0) {
+		IPFERROR(100032);
 		error = EFAULT;
+	}
 	return error;
 }
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_state_setpending                                        */
+/* Returns:     Nil                                                         */
+/* Parameters:  softc(I) - pointer to main soft context                     */
+/*              is(I)    - pointer to state structure                       */
+/* Locks:       ipf_state (read or write)                                   */
+/*                                                                          */
+/* Put the state entry on to the pending queue - this queue has a very      */
+/* short lifetime where items are put that can't be deleted straight away   */
+/* because of locking issues but we want to delete them ASAP, anyway.       */
+/* ------------------------------------------------------------------------ */
+void
+ipf_state_setpending(softc, is)
+	ipf_main_softc_t *softc;
+	ipstate_t *is;
+{
+	ipf_state_softc_t *softs = softc->ipf_state_soft;
+	ipftq_t *oifq;
+
+	oifq = is->is_sti.tqe_ifq;
+	if (oifq != NULL)
+		ipf_movequeue(softc->ipf_ticks, &is->is_sti, oifq,
+			      &softs->ipf_state_pending);
+	else
+		ipf_queueappend(softc->ipf_ticks, &is->is_sti,
+				&softs->ipf_state_pending, is);
+
+	MUTEX_ENTER(&is->is_lock);
+	if (is->is_me != NULL) {
+		*is->is_me = NULL;
+		is->is_me = NULL;
+		is->is_ref--;
+	}
+	MUTEX_EXIT(&is->is_lock);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_state_matchflush                                        */
+/* Returns:     Nil                                                         */
+/* Parameters:  softc(I) - pointer to main soft context                     */
+/*              data(I)  - pointer to state structure                       */
+/* Locks:       ipf_state (read or write)                                   */
+/*                                                                          */
+/* Flush all entries from the list of state entries that match the          */
+/* properties in the array loaded.                                          */
+/* ------------------------------------------------------------------------ */
+int
+ipf_state_matchflush(softc, data)
+	ipf_main_softc_t *softc;
+	caddr_t data;
+{
+	ipf_state_softc_t *softs = softc->ipf_state_soft;
+	int *array, flushed, error;
+	ipstate_t *state, *statenext;
+	ipfobj_t obj;
+
+	error = ipf_matcharray_load(softc, data, &obj, &array);
+	if (error != 0)
+		return error;
+
+	flushed = 0;
+
+	for (state = softs->ipf_state_list; state != NULL; state = statenext) {
+		statenext = state->is_next;
+		if (ipf_state_matcharray(state, array, softc->ipf_ticks) == 0) {
+			ipf_state_del(softc, state, ISL_FLUSH);
+			flushed++;
+		}
+	}
+
+	obj.ipfo_retval = flushed;
+	error = BCOPYOUT(&obj, data, sizeof(obj));
+
+	KFREES(array, array[0] * sizeof(*array));
+
+	return error;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_state_matcharray                                        */
+/* Returns:     int   - 0 = no match, 1 = match                             */
+/* Parameters:  state(I) - pointer to state structure                       */
+/*              array(I) - pointer to ipf matching expression               */
+/*              ticks(I) - current value of ipfilter tick timer             */
+/* Locks:       ipf_state (read or write)                                   */
+/*                                                                          */
+/* Compare a state entry with the match array passed in and return a value  */
+/* to indicate whether or not the matching was successful.                  */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_state_matcharray(state, array, ticks)
+	ipstate_t *state;
+	int *array;
+	u_long ticks;
+{
+	int i, n, *x, rv, p;
+	ipfexp_t *e;
+
+	rv = 0;
+	n = array[0];
+	x = array + 1;
+
+	for (; n > 0; x += 3 + x[3], rv = 0) {
+		e = (ipfexp_t *)x;
+		n -= e->ipfe_size;
+		if (x[0] == IPF_EXP_END)
+			break;
+
+		/*
+		 * If we need to match the protocol and that doesn't match,
+		 * don't even both with the instruction array.
+		 */
+		p = e->ipfe_cmd >> 16;
+		if ((p != 0) && (p != state->is_p))
+			break;
+
+		switch (e->ipfe_cmd)
+		{
+		case IPF_EXP_IP_PR :
+			for (i = 0; !rv && i < e->ipfe_narg; i++) {
+				rv |= (state->is_p == e->ipfe_arg0[i]);
+			}
+			break;
+
+		case IPF_EXP_IP_SRCADDR :
+			if (state->is_v != 4)
+				break;
+			for (i = 0; !rv && i < e->ipfe_narg; i++) {
+				rv |= ((state->is_saddr &
+					e->ipfe_arg0[i * 2 + 1]) ==
+				      e->ipfe_arg0[i * 2]);
+			}
+			break;
+
+		case IPF_EXP_IP_DSTADDR :
+			if (state->is_v != 4)
+				break;
+			for (i = 0; !rv && i < e->ipfe_narg; i++) {
+				rv |= ((state->is_daddr &
+					e->ipfe_arg0[i * 2 + 1]) ==
+				       e->ipfe_arg0[i * 2]);
+			}
+			break;
+
+		case IPF_EXP_IP_ADDR :
+			if (state->is_v != 4)
+				break;
+			for (i = 0; !rv && i < e->ipfe_narg; i++) {
+				rv |= ((state->is_saddr &
+					e->ipfe_arg0[i * 2 + 1]) ==
+				       e->ipfe_arg0[i * 2]) ||
+				       ((state->is_daddr &
+					e->ipfe_arg0[i * 2 + 1]) ==
+				       e->ipfe_arg0[i * 2]);
+			}
+			break;
+
+#ifdef USE_INET6
+		case IPF_EXP_IP6_SRCADDR :
+			if (state->is_v != 6)
+				break;
+			for (i = 0; !rv && i < x[3]; i++) {
+				rv |= IP6_MASKEQ(&state->is_src.in6,
+						 &e->ipfe_arg0[i * 8 + 4],
+						 &e->ipfe_arg0[i * 8]);
+			}
+			break;
+
+		case IPF_EXP_IP6_DSTADDR :
+			if (state->is_v != 6)
+				break;
+			for (i = 0; !rv && i < x[3]; i++) {
+				rv |= IP6_MASKEQ(&state->is_dst.in6,
+						 &e->ipfe_arg0[i * 8 + 4],
+						 &e->ipfe_arg0[i * 8]);
+			}
+			break;
+
+		case IPF_EXP_IP6_ADDR :
+			if (state->is_v != 6)
+				break;
+			for (i = 0; !rv && i < x[3]; i++) {
+				rv |= IP6_MASKEQ(&state->is_src.in6,
+						 &e->ipfe_arg0[i * 8 + 4],
+						 &e->ipfe_arg0[i * 8]) ||
+				      IP6_MASKEQ(&state->is_dst.in6,
+						 &e->ipfe_arg0[i * 8 + 4],
+						 &e->ipfe_arg0[i * 8]);
+			}
+			break;
+#endif
+
+		case IPF_EXP_UDP_PORT :
+		case IPF_EXP_TCP_PORT :
+			for (i = 0; !rv && i < e->ipfe_narg; i++) {
+				rv |= (state->is_sport == e->ipfe_arg0[i]) ||
+				      (state->is_dport == e->ipfe_arg0[i]);
+			}
+			break;
+
+		case IPF_EXP_UDP_SPORT :
+		case IPF_EXP_TCP_SPORT :
+			for (i = 0; !rv && i < e->ipfe_narg; i++) {
+				rv |= (state->is_sport == e->ipfe_arg0[i]);
+			}
+			break;
+
+		case IPF_EXP_UDP_DPORT :
+		case IPF_EXP_TCP_DPORT :
+			for (i = 0; !rv && i < e->ipfe_narg; i++) {
+				rv |= (state->is_dport == e->ipfe_arg0[i]);
+			}
+			break;
+
+		case IPF_EXP_TCP_STATE :
+			for (i = 0; !rv && i < e->ipfe_narg; i++) {
+				rv |= (state->is_state[0] == e->ipfe_arg0[i]) ||
+				      (state->is_state[1] == e->ipfe_arg0[i]);
+			}
+			break;
+
+		case IPF_EXP_IDLE_GT :
+			rv |= (ticks - state->is_touched > e->ipfe_arg0[0]);
+			break;
+		}
+
+		/*
+		 * Factor in doing a negative match.
+		 */
+		rv ^= e->ipfe_not;
+
+		if (rv == 0)
+			break;
+	}
+
+	return rv;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_state_settimeout                                        */
+/* Returns:     int 0 = success, else failure                               */
+/* Parameters:  softc(I)  - pointer to main soft context                    */
+/*              t(I)      - pointer to tuneable being changed               */
+/*              p(I)      - pointer to the new value                        */
+/*                                                                          */
+/* Sets a timeout value for one of the many timeout queues.  We find the    */
+/* correct queue using a somewhat manual process of comparing the timeout   */
+/* names for each specific value available and calling ipf_apply_timeout on */
+/* that queue so that all of the items on it are updated accordingly.       */
+/* ------------------------------------------------------------------------ */
+int
+ipf_state_settimeout(softc, t, p)
+	struct ipf_main_softc_s *softc;
+	ipftuneable_t *t;
+	ipftuneval_t *p;
+{
+	ipf_state_softc_t *softs = softc->ipf_state_soft;
+
+	/*
+	 * In case there is nothing to do...
+	 */
+	if (*t->ipft_pint == p->ipftu_int)
+		return 0;
+
+	if (!strncmp(t->ipft_name, "tcp_", 4))
+		return ipf_settimeout_tcp(t, p, softs->ipf_state_tcptq);
+
+	if (!strcmp(t->ipft_name, "udp_timeout")) {
+		ipf_apply_timeout(&softs->ipf_state_udptq, p->ipftu_int);
+	} else if (!strcmp(t->ipft_name, "udp_ack_timeout")) {
+		ipf_apply_timeout(&softs->ipf_state_udpacktq, p->ipftu_int);
+	} else if (!strcmp(t->ipft_name, "icmp_timeout")) {
+		ipf_apply_timeout(&softs->ipf_state_icmptq, p->ipftu_int);
+	} else if (!strcmp(t->ipft_name, "icmp_ack_timeout")) {
+		ipf_apply_timeout(&softs->ipf_state_icmpacktq, p->ipftu_int);
+	} else if (!strcmp(t->ipft_name, "ip_timeout")) {
+		ipf_apply_timeout(&softs->ipf_state_iptq, p->ipftu_int);
+	} else {
+		IPFERROR(100034);
+		return ESRCH;
+	}
+
+	/*
+	 * Update the tuneable being set.
+	 */
+	*t->ipft_pint = p->ipftu_int;
+
+	return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_state_rehash                                            */
+/* Returns:     int 0 = success, else failure                               */
+/* Parameters:  softc(I)  - pointer to main soft context                    */
+/*              t(I)      - pointer to tuneable being changed               */
+/*              p(I)      - pointer to the new value                        */
+/*                                                                          */
+/* To change the size of the state hash table at runtime, a new table has   */
+/* to be allocated and then all of the existing entries put in it, bumping  */
+/* up the bucketlength for it as we go along.                               */
+/* ------------------------------------------------------------------------ */
+int
+ipf_state_rehash(softc, t, p)
+	ipf_main_softc_t *softc;
+	ipftuneable_t *t;
+	ipftuneval_t *p;
+{
+	ipf_state_softc_t *softs = softc->ipf_state_soft;
+	ipstate_t **newtab, *is;
+	u_long *newseed;
+	u_int *bucketlens;
+	u_int maxbucket;
+	u_int newsize;
+	u_int hv;
+	int i;
+
+	newsize = p->ipftu_int;
+	/*
+	 * In case there is nothing to do...
+	 */
+	if (newsize == softs->ipf_state_size)
+		return 0;
+
+	KMALLOCS(newtab, ipstate_t **, newsize * sizeof(ipstate_t *));
+	if (newtab == NULL) {
+		IPFERROR(100035);
+		return ENOMEM;
+	}
+
+	KMALLOCS(bucketlens, u_int *, newsize * sizeof(u_int));
+	if (bucketlens == NULL) {
+		KFREES(newtab, newsize * sizeof(*softs->ipf_state_table));
+		IPFERROR(100036);
+		return ENOMEM;
+	}
+
+	newseed = ipf_state_seed_alloc(newsize, softs->ipf_state_max);
+	if (newseed == NULL) {
+		KFREES(bucketlens, newsize * sizeof(*bucketlens));
+		KFREES(newtab, newsize * sizeof(*newtab));
+		IPFERROR(100037);
+		return ENOMEM;
+	}
+
+	for (maxbucket = 0, i = newsize; i > 0; i >>= 1)
+		maxbucket++;
+	maxbucket *= 2;
+
+	bzero((char *)newtab, newsize * sizeof(ipstate_t *));
+	bzero((char *)bucketlens, newsize * sizeof(u_int));
+
+	WRITE_ENTER(&softc->ipf_state);
+
+	if (softs->ipf_state_table != NULL) {
+		KFREES(softs->ipf_state_table,
+		       softs->ipf_state_size * sizeof(*softs->ipf_state_table));
+	}
+	softs->ipf_state_table = newtab;
+
+	if (softs->ipf_state_seed != NULL) {
+		KFREES(softs->ipf_state_seed,
+		       softs->ipf_state_size * sizeof(*softs->ipf_state_seed));
+	}
+	softs->ipf_state_seed = newseed;
+
+	if (softs->ipf_state_stats.iss_bucketlen != NULL) {
+		KFREES(softs->ipf_state_stats.iss_bucketlen,
+		       softs->ipf_state_size * sizeof(u_int));
+	}
+	softs->ipf_state_stats.iss_bucketlen = bucketlens;
+	softs->ipf_state_maxbucket = maxbucket;
+	softs->ipf_state_size = newsize;
+
+	/*
+	 * Walk through the entire list of state table entries and put them
+	 * in the new state table, somewhere.  Because we have a new table,
+	 * we need to restart the counter of how many chains are in use.
+	 */
+	softs->ipf_state_stats.iss_inuse = 0;
+	for (is = softs->ipf_state_list; is != NULL; is = is->is_next) {
+		is->is_hnext = NULL;
+		is->is_phnext = NULL;
+		hv = is->is_hv % softs->ipf_state_size;
+
+		if (softs->ipf_state_table[hv] != NULL)
+			softs->ipf_state_table[hv]->is_phnext = &is->is_hnext;
+		else
+			softs->ipf_state_stats.iss_inuse++;
+		is->is_phnext = softs->ipf_state_table + hv;
+		is->is_hnext = softs->ipf_state_table[hv];
+		softs->ipf_state_table[hv] = is;
+		softs->ipf_state_stats.iss_bucketlen[hv]++;
+	}
+	RWLOCK_EXIT(&softc->ipf_state);
+
+	return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_state_add_tq                                            */
+/* Returns:     ipftq_t * - NULL = failure, else pointer to new timeout     */
+/*                          queue                                           */
+/* Parameters:  softc(I)  - pointer to main soft context                    */
+/*              ttl(I)    - pointer to the ttl for the new queue            */
+/*                                                                          */
+/* Request a pointer to a timeout queue that has a ttl as given by the      */
+/* value being passed in.  The timeout queue is added tot the list of those */
+/* used internally for stateful filtering.                                  */
+/* ------------------------------------------------------------------------ */
+ipftq_t *
+ipf_state_add_tq(softc, ttl)
+	ipf_main_softc_t *softc;
+	int ttl;
+{
+	ipf_state_softc_t *softs = softc->ipf_state_soft;
+
+        return ipf_addtimeoutqueue(softc, &softs->ipf_state_usertq, ttl);
+}
+
+
+#ifndef _KERNEL
+/*
+ * Display the built up state table rules and mapping entries.
+ */
+void
+ipf_state_dump(softc, arg)
+	ipf_main_softc_t *softc;
+	void *arg;
+{
+	ipf_state_softc_t *softs = arg;
+	ipstate_t *ips;
+
+	printf("List of active state sessions:\n");
+	for (ips = softs->ipf_state_list; ips != NULL; )
+		ips = printstate(ips, opts & (OPT_DEBUG|OPT_VERBOSE),
+				 softc->ipf_ticks);
+}
+#endif

Modified: trunk/sys/contrib/ipfilter/netinet/ip_state.h
===================================================================
--- trunk/sys/contrib/ipfilter/netinet/ip_state.h	2018-05-28 18:55:30 UTC (rev 10138)
+++ trunk/sys/contrib/ipfilter/netinet/ip_state.h	2018-05-28 18:56:30 UTC (rev 10139)
@@ -1,12 +1,13 @@
-/*	$FreeBSD$	*/
+/* $MidnightBSD$ */
+/*	$FreeBSD: stable/10/sys/contrib/ipfilter/netinet/ip_state.h 255332 2013-09-06 23:11:19Z cy $	*/
 
 /*
- * Copyright (C) 1995-2001 by Darren Reed.
+ * Copyright (C) 2012 by Darren Reed.
  *
  * See the IPFILTER.LICENCE file for details on licencing.
  *
  * @(#)ip_state.h	1.3 1/12/96 (C) 1995 Darren Reed
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/contrib/ipfilter/netinet/ip_state.h 255332 2013-09-06 23:11:19Z cy $
  * Id: ip_state.h,v 2.68.2.10 2007/10/16 09:33:24 darrenr Exp $
  */
 #ifndef	__IP_STATE_H__
@@ -27,8 +28,10 @@
 # define	IPSTATE_MAX	4013	/* Maximum number of states held */
 #endif
 
-#define	SEQ_GE(a,b)	((int)((a) - (b)) >= 0)
-#define	SEQ_GT(a,b)	((int)((a) - (b)) > 0)
+#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)
 
 
 typedef struct ipstate {
@@ -56,6 +59,7 @@
 	u_int	is_pass;
 	u_char	is_p;			/* Protocol */
 	u_char	is_v;
+	int	is_family;
 	u_32_t	is_hv;
 	u_32_t	is_tag;
 	u_32_t	is_opt[2];		/* packet options set */
@@ -75,6 +79,8 @@
 	u_32_t	is_rulen;		/* rule number when created */
 	u_32_t	is_s0[2];
 	u_short	is_smsk[2];
+	frdest_t	is_dif;
+	frdest_t	is_tifs[2];
 	char	is_group[FR_GROUPLEN];
 	char	is_sbuf[2][16];
 	char	is_ifname[4][LIFNAMSIZ];
@@ -87,7 +93,6 @@
 #define	is_daddr	is_dst.in4.s_addr
 #define	is_icmp		is_ps.is_ics
 #define	is_type		is_icmp.ici_type
-#define	is_code		is_icmp.ici_code
 #define	is_tcp		is_ps.is_ts
 #define	is_udp		is_ps.is_us
 #define is_send		is_tcp.ts_data[0].td_end
@@ -119,6 +124,7 @@
 #define	IS_ISNSYN			   0x40000
 #define	IS_ISNACK			   0x80000
 #define	IS_STATESYNC			   0x100000
+#define	IS_LOOSE			   0x200000
 /*
  * IS_SC flags are for scan-operations that need to be recognised in state.
  */
@@ -130,7 +136,7 @@
 #define	IS_SC_ALL	(IS_SC_MATCHC|IS_SC_MATCHC|IS_SC_CLIENT|IS_SC_SERVER)
 
 /*
- * Flags that can be passed into fr_addstate
+ * Flags that can be passed into ipf_addstate
  */
 #define	IS_INHERITED			0x0fffff00
 
@@ -181,6 +187,7 @@
 
 #define	ISL_NEW			0
 #define	ISL_CLONE		1
+#define	ISL_STATECHANGE		2
 #define	ISL_EXPIRE		0xffff
 #define	ISL_FLUSH		0xfffe
 #define	ISL_REMOVE		0xfffd
@@ -191,71 +198,141 @@
 
 
 typedef	struct	ips_stat {
+	u_int	iss_active;
+	u_int	iss_active_proto[256];
+	u_long	iss_add_bad;
+	u_long	iss_add_dup;
+	u_long	iss_add_locked;
+	u_long	iss_add_oow;
+	u_long	iss_bucket_full;
+	u_long	iss_check_bad;
+	u_long	iss_check_miss;
+	u_long	iss_check_nattag;
+	u_long	iss_check_notag;
+	u_long	iss_clone_nomem;
+	u_long	iss_cloned;
+	u_long	iss_expire;
+	u_long	iss_fin;
+	u_long	iss_flush_all;
+	u_long	iss_flush_closing;
+	u_long	iss_flush_queue;
+	u_long	iss_flush_state;
+	u_long	iss_flush_timeout;
 	u_long	iss_hits;
-	u_long	iss_miss;
+	u_long	iss_icmp6_icmperr;
+	u_long	iss_icmp6_miss;
+	u_long	iss_icmp6_notinfo;
+	u_long	iss_icmp6_notquery;
+	u_long	iss_icmp_bad;
+	u_long	iss_icmp_banned;
+	u_long	iss_icmp_headblock;
+	u_long	iss_icmp_hits;
+	u_long	iss_icmp_icmperr;
+	u_long	iss_icmp_miss;
+	u_long	iss_icmp_notquery;
+	u_long	iss_icmp_short;
+	u_long	iss_icmp_toomany;
+	u_int	iss_inuse;
+	ipstate_t *iss_list;
+	u_long	iss_log_fail;
+	u_long	iss_log_ok;
+	u_long	iss_lookup_badifp;
+	u_long	iss_lookup_badport;
+	u_long	iss_lookup_miss;
 	u_long	iss_max;
-	u_long	iss_maxref;
-	u_long	iss_tcp;
-	u_long	iss_udp;
-	u_long	iss_icmp;
+	u_long	iss_max_ref;
+	u_long	iss_max_track;
+	u_long	iss_miss_mask;
 	u_long	iss_nomem;
-	u_long	iss_expire;
-	u_long	iss_fin;
-	u_long	iss_active;
-	u_long	iss_logged;
-	u_long	iss_logfail;
-	u_long	iss_inuse;
-	u_long	iss_wild;
-	u_long	iss_killed;
-	u_long	iss_ticks;
-	u_long	iss_bucketfull;
-	int	iss_statesize;
-	int	iss_statemax;
+	u_long	iss_oow;
+	u_long	iss_orphan;
+	u_long	iss_proto[256];
+	u_long	iss_scan_block;
+	u_long	iss_state_max;
+	u_long	iss_state_size;
+	u_long	iss_states[IPF_TCP_NSTATES];
 	ipstate_t **iss_table;
-	ipstate_t *iss_list;
-	u_long	*iss_bucketlen;
+	u_long	iss_tcp_closing;
+	u_long	iss_tcp_oow;
+	u_long	iss_tcp_rstadd;
+	u_long	iss_tcp_toosmall;
+	u_long	iss_tcp_badopt;
+	u_long	iss_tcp_fsm;
+	u_long	iss_tcp_strict;
 	ipftq_t	*iss_tcptab;
+	u_int	iss_ticks;
+	u_long	iss_wild;
+	u_long	iss_winsack;
+	u_int	*iss_bucketlen;
 } ips_stat_t;
 
 
-extern	u_long	fr_tcpidletimeout;
-extern	u_long	fr_tcpclosewait;
-extern	u_long	fr_tcplastack;
-extern	u_long	fr_tcptimeout;
-extern	u_long	fr_tcpclosed;
-extern	u_long	fr_tcphalfclosed;
-extern	u_long	fr_udptimeout;
-extern	u_long	fr_udpacktimeout;
-extern	u_long	fr_icmptimeout;
-extern	u_long	fr_icmpacktimeout;
-extern	u_long	fr_iptimeout;
-extern	int	fr_statemax;
-extern	int	fr_statesize;
-extern	int	fr_state_lock;
-extern	int	fr_state_maxbucket;
-extern	int	fr_state_maxbucket_reset;
-extern	ipstate_t	*ips_list;
-extern	ipftq_t	*ips_utqe;
-extern	ipftq_t	ips_tqtqb[IPF_TCP_NSTATES];
+typedef struct ipf_state_softc_s {
+	ipfmutex_t	ipf_stinsert;
+	int		ipf_state_logging;
+	int		ipf_state_lock;
+	int		ipf_state_doflush;
+	u_int		ipf_state_inited;
+	u_int		ipf_state_max;
+	u_int		ipf_state_maxbucket;
+	u_int		ipf_state_size;
+	u_int		ipf_state_wm_freq;
+	u_int		ipf_state_wm_high;
+	u_int		ipf_state_wm_low;
+	u_int		ipf_state_wm_last;
+	u_long		*ipf_state_seed;
+	ipstate_t	*ipf_state_list;
+	ipstate_t	**ipf_state_table;
+	ipftuneable_t	*ipf_state_tune;
+	ipftq_t		*ipf_state_usertq;
+	ipftq_t		ipf_state_pending;
+	ipftq_t		ipf_state_deletetq;
+	ipftq_t		ipf_state_udptq;
+	ipftq_t		ipf_state_udpacktq;
+	ipftq_t		ipf_state_iptq;
+	ipftq_t		ipf_state_icmptq;
+	ipftq_t		ipf_state_icmpacktq;
+	ipftq_t		ipf_state_tcptq[IPF_TCP_NSTATES];
+	ips_stat_t	ipf_state_stats;
+} ipf_state_softc_t;
 
-extern	int	fr_stateinit __P((void));
-extern	ipstate_t *fr_addstate __P((fr_info_t *, ipstate_t **, u_int));
-extern	frentry_t *fr_checkstate __P((struct fr_info *, u_32_t *));
-extern	ipstate_t *fr_stlookup __P((fr_info_t *, tcphdr_t *, ipftq_t **));
-extern	void	fr_statesync __P((void *));
-extern	void	fr_timeoutstate __P((void));
-extern	int	fr_tcp_age __P((struct ipftqent *, struct fr_info *,
-				struct ipftq *, int));
-extern	int	fr_tcpinwindow __P((struct fr_info *, struct tcpdata *,
+
+#ifndef _KERNEL
+extern	void	ipf_state_dump __P((ipf_main_softc_t *, void *));
+#endif
+extern	int	ipf_tcp_age __P((struct ipftqent *, struct fr_info *,
+				struct ipftq *, int, int));
+extern	int	ipf_tcpinwindow __P((struct fr_info *, struct tcpdata *,
 				    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, 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((ipstate_t **));
-extern	void	fr_setstatequeue __P((ipstate_t *, int));
 
+extern	int	ipf_state_add __P((ipf_main_softc_t *, fr_info_t *,
+				   ipstate_t **, u_int));
+extern	frentry_t *ipf_state_check __P((struct fr_info *, u_32_t *));
+extern	void	ipf_state_deref __P((ipf_main_softc_t *, ipstate_t **));
+extern	void	ipf_state_expire __P((ipf_main_softc_t *));
+extern	int	ipf_state_flush __P((ipf_main_softc_t *, int, int));
+extern	ipstate_t *ipf_state_lookup __P((fr_info_t *, tcphdr_t *, ipftq_t **));
+extern	int	ipf_state_init __P((void));
+extern	int	ipf_state_insert __P((ipf_main_softc_t *, struct ipstate *, int));
+extern	int	ipf_state_ioctl __P((ipf_main_softc_t *, caddr_t, ioctlcmd_t, int, int, void *));
+extern	void	ipf_state_log __P((ipf_main_softc_t *, struct ipstate *, u_int));
+extern	int	ipf_state_matchflush __P((ipf_main_softc_t *, caddr_t));
+extern	int	ipf_state_rehash __P((ipf_main_softc_t *, ipftuneable_t *, ipftuneval_t *));
+extern	void	ipf_state_setqueue __P((ipf_main_softc_t *, ipstate_t *, int));
+extern	void	ipf_state_setpending __P((ipf_main_softc_t *, ipstate_t *));
+extern	int	ipf_state_settimeout __P((struct ipf_main_softc_s *, ipftuneable_t *, ipftuneval_t *));
+extern	void	ipf_state_sync __P((ipf_main_softc_t *, void *));
+extern	void	ipf_state_update __P((fr_info_t *, ipstate_t *));
+
+extern	void	ipf_sttab_init __P((ipf_main_softc_t *, struct ipftq *));
+extern	void	ipf_sttab_destroy __P((struct ipftq *));
+extern	void	ipf_state_setlock __P((void *, int));
+extern	int	ipf_state_main_load __P((void));
+extern	int	ipf_state_main_unload __P((void));
+extern	void	*ipf_state_soft_create __P((ipf_main_softc_t *));
+extern	void	ipf_state_soft_destroy __P((ipf_main_softc_t *, void *));
+extern	int	ipf_state_soft_init __P((ipf_main_softc_t *, void *));
+extern	int	ipf_state_soft_fini __P((ipf_main_softc_t *, void *));
+extern	ipftq_t	*ipf_state_add_tq __P((ipf_main_softc_t *, int));
+
 #endif /* __IP_STATE_H__ */

Modified: trunk/sys/contrib/ipfilter/netinet/ip_sync.c
===================================================================
--- trunk/sys/contrib/ipfilter/netinet/ip_sync.c	2018-05-28 18:55:30 UTC (rev 10138)
+++ trunk/sys/contrib/ipfilter/netinet/ip_sync.c	2018-05-28 18:56:30 UTC (rev 10139)
@@ -1,7 +1,8 @@
-/*	$FreeBSD$	*/
+/* $MidnightBSD$ */
+/*	$FreeBSD: stable/10/sys/contrib/ipfilter/netinet/ip_sync.c 319633 2017-06-06 19:21:35Z cy $	*/
 
 /*
- * Copyright (C) 1995-1998 by Darren Reed.
+ * Copyright (C) 2012 by Darren Reed.
  *
  * See the IPFILTER.LICENCE file for details on licencing.
  */
@@ -32,6 +33,10 @@
 # if !defined(__SVR4) && !defined(__svr4__)
 #  include <sys/mbuf.h>
 # endif
+# include <sys/select.h>
+# if __FreeBSD_version >= 500000
+#  include <sys/selinfo.h>
+# endif
 #endif
 #if defined(__NetBSD__) && (__NetBSD_Version__ >= 104000000)
 # include <sys/proc.h>
@@ -39,9 +44,6 @@
 #if defined(_KERNEL) && (__FreeBSD_version >= 220000)
 # include <sys/filio.h>
 # include <sys/fcntl.h>
-# if (__FreeBSD_version >= 300000) && !defined(IPFILTER_LKM)
-#  include "opt_ipfilter.h"
-# endif
 #else
 # include <sys/ioctl.h>
 #endif
@@ -64,7 +66,6 @@
 #ifdef sun
 # include <net/af.h>
 #endif
-#include <net/route.h>
 #include <netinet/in.h>
 #include <netinet/in_systm.h>
 #include <netinet/ip.h>
@@ -98,40 +99,85 @@
 /* END OF INCLUDES */
 
 #if !defined(lint)
-static const char rcsid[] = "@(#)$Id: ip_sync.c,v 1.5 2013-01-08 01:31:40 laffer1 Exp $";
+static const char rcsid[] = "@(#)$Id$";
 #endif
 
 #define	SYNC_STATETABSZ	256
 #define	SYNC_NATTABSZ	256
 
-#ifdef	IPFILTER_SYNC
-ipfmutex_t	ipf_syncadd, ipsl_mutex;
-ipfrwlock_t	ipf_syncstate, ipf_syncnat;
+typedef struct ipf_sync_softc_s {
+	ipfmutex_t	ipf_syncadd;
+	ipfmutex_t	ipsl_mutex;
+	ipfrwlock_t	ipf_syncstate;
+	ipfrwlock_t	ipf_syncnat;
 #if SOLARIS && defined(_KERNEL)
-kcondvar_t	ipslwait;
+	kcondvar_t	ipslwait;
 #endif
-synclist_t	*syncstatetab[SYNC_STATETABSZ];
-synclist_t	*syncnattab[SYNC_NATTABSZ];
-synclogent_t	synclog[SYNCLOG_SZ];
-syncupdent_t	syncupd[SYNCLOG_SZ];
-u_int		ipf_syncnum = 1;
-u_int		ipf_syncwrap = 0;
-u_int		sl_idx = 0,	/* next available sync log entry */
-		su_idx = 0,	/* next available sync update entry */
-		sl_tail = 0,	/* next sync log entry to read */
-		su_tail = 0;	/* next sync update entry to read */
-int		ipf_sync_debug = 0;
+#if defined(linux) && defined(_KERNEL)
+	wait_queue_head_t	sl_tail_linux;
+#endif
+	synclist_t	**syncstatetab;
+	synclist_t	**syncnattab;
+	synclogent_t	*synclog;
+	syncupdent_t	*syncupd;
+	u_int		ipf_sync_num;
+	u_int		ipf_sync_wrap;
+	u_int		sl_idx;		/* next available sync log entry */
+	u_int		su_idx;		/* next available sync update entry */
+	u_int		sl_tail;	/* next sync log entry to read */
+	u_int		su_tail;	/* next sync update entry to read */
+	int		ipf_sync_log_sz;
+	int		ipf_sync_nat_tab_sz;
+	int		ipf_sync_state_tab_sz;
+	int		ipf_sync_debug;
+	int		ipf_sync_events;
+	u_32_t		ipf_sync_lastwakeup;
+	int		ipf_sync_wake_interval;
+	int		ipf_sync_event_high_wm;
+	int		ipf_sync_queue_high_wm;
+	int		ipf_sync_inited;
+} ipf_sync_softc_t;
 
+static int ipf_sync_flush_table __P((ipf_sync_softc_t *, int, synclist_t **));
+static void ipf_sync_wakeup __P((ipf_main_softc_t *));
+static void ipf_sync_del __P((ipf_sync_softc_t *, synclist_t *));
+static void ipf_sync_poll_wakeup __P((ipf_main_softc_t *));
+static int ipf_sync_nat __P((ipf_main_softc_t *, synchdr_t *, void *));
+static int ipf_sync_state __P((ipf_main_softc_t *, synchdr_t *, void *));
 
 # if !defined(sparc) && !defined(__hppa)
-void ipfsync_tcporder __P((int, struct tcpdata *));
-void ipfsync_natorder __P((int, struct nat *));
-void ipfsync_storder __P((int, struct ipstate *));
+void ipf_sync_tcporder __P((int, struct tcpdata *));
+void ipf_sync_natorder __P((int, struct nat *));
+void ipf_sync_storder __P((int, struct ipstate *));
 # endif
 
 
+void *
+ipf_sync_soft_create(softc)
+	ipf_main_softc_t *softc;
+{
+	ipf_sync_softc_t *softs;
+
+	KMALLOC(softs, ipf_sync_softc_t *);
+	if (softs == NULL) {
+		IPFERROR(110024);
+		return NULL;
+	}
+
+	bzero((char *)softs, sizeof(*softs));
+
+	softs->ipf_sync_log_sz = SYNCLOG_SZ;
+	softs->ipf_sync_nat_tab_sz = SYNC_STATETABSZ;
+	softs->ipf_sync_state_tab_sz = SYNC_STATETABSZ;
+	softs->ipf_sync_event_high_wm = SYNCLOG_SZ * 100 / 90;	/* 90% */
+	softs->ipf_sync_queue_high_wm = SYNCLOG_SZ * 100 / 90;	/* 90% */
+
+	return softs;
+}
+
+
 /* ------------------------------------------------------------------------ */
-/* Function:    ipfsync_init                                                */
+/* Function:    ipf_sync_init                                               */
 /* Returns:     int - 0 == success, -1 == failure                           */
 /* Parameters:  Nil                                                         */
 /*                                                                          */
@@ -138,26 +184,134 @@
 /* Initialise all of the locks required for the sync code and initialise    */
 /* any data structures, as required.                                        */
 /* ------------------------------------------------------------------------ */
-int ipfsync_init()
+int
+ipf_sync_soft_init(softc, arg)
+	ipf_main_softc_t *softc;
+	void *arg;
 {
-	RWLOCK_INIT(&ipf_syncstate, "add things to state sync table");
-	RWLOCK_INIT(&ipf_syncnat, "add things to nat sync table");
-	MUTEX_INIT(&ipf_syncadd, "add things to sync table");
-	MUTEX_INIT(&ipsl_mutex, "add things to sync table");
+	ipf_sync_softc_t *softs = arg;
+
+	KMALLOCS(softs->synclog, synclogent_t *,
+		 softs->ipf_sync_log_sz * sizeof(*softs->synclog));
+	if (softs->synclog == NULL)
+		return -1;
+	bzero((char *)softs->synclog,
+	      softs->ipf_sync_log_sz * sizeof(*softs->synclog));
+
+	KMALLOCS(softs->syncupd, syncupdent_t *,
+		 softs->ipf_sync_log_sz * sizeof(*softs->syncupd));
+	if (softs->syncupd == NULL)
+		return -2;
+	bzero((char *)softs->syncupd,
+	      softs->ipf_sync_log_sz * sizeof(*softs->syncupd));
+
+	KMALLOCS(softs->syncstatetab, synclist_t **,
+		 softs->ipf_sync_state_tab_sz * sizeof(*softs->syncstatetab));
+	if (softs->syncstatetab == NULL)
+		return -3;
+	bzero((char *)softs->syncstatetab,
+	      softs->ipf_sync_state_tab_sz * sizeof(*softs->syncstatetab));
+
+	KMALLOCS(softs->syncnattab, synclist_t **,
+		 softs->ipf_sync_nat_tab_sz * sizeof(*softs->syncnattab));
+	if (softs->syncnattab == NULL)
+		return -3;
+	bzero((char *)softs->syncnattab,
+	      softs->ipf_sync_nat_tab_sz * sizeof(*softs->syncnattab));
+
+	softs->ipf_sync_num = 1;
+	softs->ipf_sync_wrap = 0;
+	softs->sl_idx = 0;
+	softs->su_idx = 0;
+	softs->sl_tail = 0;
+	softs->su_tail = 0;
+	softs->ipf_sync_events = 0;
+	softs->ipf_sync_lastwakeup = 0;
+
+
 # if SOLARIS && defined(_KERNEL)
-	cv_init(&ipslwait, "ipsl condvar", CV_DRIVER, NULL);
+	cv_init(&softs->ipslwait, "ipsl condvar", CV_DRIVER, NULL);
 # endif
+	RWLOCK_INIT(&softs->ipf_syncstate, "add things to state sync table");
+	RWLOCK_INIT(&softs->ipf_syncnat, "add things to nat sync table");
+	MUTEX_INIT(&softs->ipf_syncadd, "add things to sync table");
+	MUTEX_INIT(&softs->ipsl_mutex, "read ring lock");
 
-	bzero((char *)syncnattab, sizeof(syncnattab));
-	bzero((char *)syncstatetab, sizeof(syncstatetab));
+	softs->ipf_sync_inited = 1;
 
 	return 0;
 }
 
 
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_sync_unload                                             */
+/* Returns:     int - 0 == success, -1 == failure                           */
+/* Parameters:  Nil                                                         */
+/*                                                                          */
+/* Destroy the locks created when initialising and free any memory in use   */
+/* with the synchronisation tables.                                         */
+/* ------------------------------------------------------------------------ */
+int
+ipf_sync_soft_fini(softc, arg)
+	ipf_main_softc_t *softc;
+	void *arg;
+{
+	ipf_sync_softc_t *softs = arg;
+
+	if (softs->syncnattab != NULL) {
+		ipf_sync_flush_table(softs, softs->ipf_sync_nat_tab_sz,
+				     softs->syncnattab);
+		KFREES(softs->syncnattab,
+		       softs->ipf_sync_nat_tab_sz * sizeof(*softs->syncnattab));
+		softs->syncnattab = NULL;
+	}
+
+	if (softs->syncstatetab != NULL) {
+		ipf_sync_flush_table(softs, softs->ipf_sync_state_tab_sz,
+				     softs->syncstatetab);
+		KFREES(softs->syncstatetab,
+		       softs->ipf_sync_state_tab_sz *
+		       sizeof(*softs->syncstatetab));
+		softs->syncstatetab = NULL;
+	}
+
+	if (softs->syncupd != NULL) {
+		KFREES(softs->syncupd,
+		       softs->ipf_sync_log_sz * sizeof(*softs->syncupd));
+		softs->syncupd = NULL;
+	}
+
+	if (softs->synclog != NULL) {
+		KFREES(softs->synclog,
+		       softs->ipf_sync_log_sz * sizeof(*softs->synclog));
+		softs->synclog = NULL;
+	}
+
+	if (softs->ipf_sync_inited == 1) {
+		MUTEX_DESTROY(&softs->ipsl_mutex);
+		MUTEX_DESTROY(&softs->ipf_syncadd);
+		RW_DESTROY(&softs->ipf_syncnat);
+		RW_DESTROY(&softs->ipf_syncstate);
+		softs->ipf_sync_inited = 0;
+	}
+
+	return 0;
+}
+
+void
+ipf_sync_soft_destroy(softc, arg)
+	ipf_main_softc_t *softc;
+	void *arg;
+{
+	ipf_sync_softc_t *softs = arg;
+
+	KFREE(softs);
+}
+
+
 # if !defined(sparc) && !defined(__hppa)
 /* ------------------------------------------------------------------------ */
-/* Function:    ipfsync_tcporder                                            */
+/* Function:    ipf_sync_tcporder                                           */
 /* Returns:     Nil                                                         */
 /* Parameters:  way(I) - direction of byte order conversion.                */
 /*              td(IO) - pointer to data to be converted.                   */
@@ -165,9 +319,10 @@
 /* Do byte swapping on values in the TCP state information structure that   */
 /* need to be used at both ends by the host in their native byte order.     */
 /* ------------------------------------------------------------------------ */
-void ipfsync_tcporder(way, td)
-int way;
-tcpdata_t *td;
+void
+ipf_sync_tcporder(way, td)
+	int way;
+	tcpdata_t *td;
 {
 	if (way) {
 		td->td_maxwin = htons(td->td_maxwin);
@@ -182,7 +337,7 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    ipfsync_natorder                                            */
+/* Function:    ipf_sync_natorder                                           */
 /* Returns:     Nil                                                         */
 /* Parameters:  way(I)  - direction of byte order conversion.               */
 /*              nat(IO) - pointer to data to be converted.                  */
@@ -190,9 +345,10 @@
 /* Do byte swapping on values in the NAT data structure that need to be     */
 /* used at both ends by the host in their native byte order.                */
 /* ------------------------------------------------------------------------ */
-void ipfsync_natorder(way, n)
-int way;
-nat_t *n;
+void
+ipf_sync_natorder(way, n)
+	int way;
+	nat_t *n;
 {
 	if (way) {
 		n->nat_age = htonl(n->nat_age);
@@ -211,7 +367,7 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    ipfsync_storder                                             */
+/* Function:    ipf_sync_storder                                            */
 /* Returns:     Nil                                                         */
 /* Parameters:  way(I)  - direction of byte order conversion.               */
 /*              ips(IO) - pointer to data to be converted.                  */
@@ -219,12 +375,13 @@
 /* Do byte swapping on values in the IP state data structure that need to   */
 /* be used at both ends by the host in their native byte order.             */
 /* ------------------------------------------------------------------------ */
-void ipfsync_storder(way, ips)
-int way;
-ipstate_t *ips;
+void
+ipf_sync_storder(way, ips)
+	int way;
+	ipstate_t *ips;
 {
-	ipfsync_tcporder(way, &ips->is_tcp.ts_data[0]);
-	ipfsync_tcporder(way, &ips->is_tcp.ts_data[1]);
+	ipf_sync_tcporder(way, &ips->is_tcp.ts_data[0]);
+	ipf_sync_tcporder(way, &ips->is_tcp.ts_data[1]);
 
 	if (way) {
 		ips->is_hv = htonl(ips->is_hv);
@@ -263,16 +420,14 @@
 	}
 }
 # else /* !defined(sparc) && !defined(__hppa) */
-#  define	ipfsync_tcporder(x,y)
-#  define	ipfsync_natorder(x,y)
-#  define	ipfsync_storder(x,y)
+#  define	ipf_sync_tcporder(x,y)
+#  define	ipf_sync_natorder(x,y)
+#  define	ipf_sync_storder(x,y)
 # endif /* !defined(sparc) && !defined(__hppa) */
 
-/* enable this for debugging */
 
-# ifdef _KERNEL
 /* ------------------------------------------------------------------------ */
-/* Function:    ipfsync_write                                               */
+/* Function:    ipf_sync_write                                              */
 /* Returns:     int    - 0 == success, else error value.                    */
 /* Parameters:  uio(I) - pointer to information about data to write         */
 /*                                                                          */
@@ -279,20 +434,23 @@
 /* Moves data from user space into the kernel and uses it for updating data */
 /* structures in the state/NAT tables.                                      */
 /* ------------------------------------------------------------------------ */
-int ipfsync_write(uio)
-struct uio *uio;
+int
+ipf_sync_write(softc, uio)
+	ipf_main_softc_t *softc;
+	struct uio *uio;
 {
+	ipf_sync_softc_t *softs = softc->ipf_sync_soft;
 	synchdr_t sh;
 
-	/* 
+	/*
 	 * THIS MUST BE SUFFICIENT LARGE TO STORE
-	 * ANY POSSIBLE DATA TYPE 
+	 * ANY POSSIBLE DATA TYPE
 	 */
-	char data[2048]; 
+	char data[2048];
 
 	int err = 0;
 
-#  if (BSD >= 199306) || defined(__FreeBSD__) || defined(__osf__)
+#  if BSD_GE_YEAR(199306) || defined(__FreeBSD__) || defined(__osf__)
 	uio->uio_rw = UIO_WRITE;
 #  endif
 
@@ -304,7 +462,7 @@
 			err = UIOMOVE(&sh, sizeof(sh), UIO_WRITE, uio);
 
 			if (err) {
-				if (ipf_sync_debug > 2)
+				if (softs->ipf_sync_debug > 2)
 					printf("uiomove(header) failed: %d\n",
 						err);
 				return err;
@@ -315,7 +473,7 @@
 			sh.sm_len = ntohl(sh.sm_len);
 			sh.sm_num = ntohl(sh.sm_num);
 
-			if (ipf_sync_debug > 8)
+			if (softs->ipf_sync_debug > 8)
 				printf("[%d] Read v:%d p:%d cmd:%d table:%d rev:%d len:%d magic:%x\n",
 					sh.sm_num, sh.sm_v, sh.sm_p, sh.sm_cmd,
 					sh.sm_table, sh.sm_rev, sh.sm_len,
@@ -322,52 +480,58 @@
 					sh.sm_magic);
 
 			if (sh.sm_magic != SYNHDRMAGIC) {
-				if (ipf_sync_debug > 2)
-					printf("uiomove(header) invalud %s\n",
+				if (softs->ipf_sync_debug > 2)
+					printf("uiomove(header) invalid %s\n",
 						"magic");
+				IPFERROR(110001);
 				return EINVAL;
 			}
 
 			if (sh.sm_v != 4 && sh.sm_v != 6) {
-				if (ipf_sync_debug > 2)
+				if (softs->ipf_sync_debug > 2)
 					printf("uiomove(header) invalid %s\n",
 						"protocol");
+				IPFERROR(110002);
 				return EINVAL;
 			}
 
 			if (sh.sm_cmd > SMC_MAXCMD) {
-				if (ipf_sync_debug > 2)
+				if (softs->ipf_sync_debug > 2)
 					printf("uiomove(header) invalid %s\n",
 						"command");
+				IPFERROR(110003);
 				return EINVAL;
 			}
 
 
 			if (sh.sm_table > SMC_MAXTBL) {
-				if (ipf_sync_debug > 2)
+				if (softs->ipf_sync_debug > 2)
 					printf("uiomove(header) invalid %s\n",
 						"table");
+				IPFERROR(110004);
 				return EINVAL;
 			}
 
 		} else {
 			/* unsufficient data, wait until next call */
-			if (ipf_sync_debug > 2)
+			if (softs->ipf_sync_debug > 2)
 				printf("uiomove(header) insufficient data");
+			IPFERROR(110005);
 			return EAGAIN;
 	 	}
 
 
 		/*
-		 * We have a header, so try to read the amount of data 
+		 * We have a header, so try to read the amount of data
 		 * needed for the request
 		 */
 
 		/* not supported */
 		if (sh.sm_len == 0) {
-			if (ipf_sync_debug > 2)
+			if (softs->ipf_sync_debug > 2)
 				printf("uiomove(data zero length %s\n",
 					"not supported");
+			IPFERROR(110006);
 			return EINVAL;
 		}
 
@@ -376,33 +540,34 @@
 			err = UIOMOVE(data, sh.sm_len, UIO_WRITE, uio);
 
 			if (err) {
-				if (ipf_sync_debug > 2)
+				if (softs->ipf_sync_debug > 2)
 					printf("uiomove(data) failed: %d\n",
 						err);
 				return err;
 			}
 
-			if (ipf_sync_debug > 7)
+			if (softs->ipf_sync_debug > 7)
 				printf("uiomove(data) %d bytes read\n",
 					sh.sm_len);
 
 			if (sh.sm_table == SMC_STATE)
-				err = ipfsync_state(&sh, data);
+				err = ipf_sync_state(softc, &sh, data);
 			else if (sh.sm_table == SMC_NAT)
-				err = ipfsync_nat(&sh, data);
-			if (ipf_sync_debug > 7)
+				err = ipf_sync_nat(softc, &sh, data);
+			if (softs->ipf_sync_debug > 7)
 				printf("[%d] Finished with error %d\n",
 					sh.sm_num, err);
 
 		} else {
 			/* insufficient data, wait until next call */
-			if (ipf_sync_debug > 2)
+			if (softs->ipf_sync_debug > 2)
 				printf("uiomove(data) %s %d bytes, got %d\n",
 					"insufficient data, need",
-					sh.sm_len, uio->uio_resid);
+					sh.sm_len, (int)uio->uio_resid);
+			IPFERROR(110007);
 			return EAGAIN;
 		}
-	}	 
+	}
 
 	/* no more data */
 	return 0;
@@ -410,7 +575,7 @@
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    ipfsync_read                                                */
+/* Function:    ipf_sync_read                                               */
 /* Returns:     int    - 0 == success, else error value.                    */
 /* Parameters:  uio(O) - pointer to information about where to store data   */
 /*                                                                          */
@@ -418,89 +583,105 @@
 /* for pending state/NAT updates.  If no data is available, the caller is   */
 /* put to sleep, pending a wakeup from the "lower half" of this code.       */
 /* ------------------------------------------------------------------------ */
-int ipfsync_read(uio)
-struct uio *uio;
+int
+ipf_sync_read(softc, uio)
+	ipf_main_softc_t *softc;
+	struct uio *uio;
 {
+	ipf_sync_softc_t *softs = softc->ipf_sync_soft;
 	syncupdent_t *su;
 	synclogent_t *sl;
 	int err = 0;
 
-	if ((uio->uio_resid & 3) || (uio->uio_resid < 8))
+	if ((uio->uio_resid & 3) || (uio->uio_resid < 8)) {
+		IPFERROR(110008);
 		return EINVAL;
+	}
 
-#  if (BSD >= 199306) || defined(__FreeBSD__) || defined(__osf__)
+#  if BSD_GE_YEAR(199306) || defined(__FreeBSD__) || defined(__osf__)
 	uio->uio_rw = UIO_READ;
 #  endif
 
-	MUTEX_ENTER(&ipsl_mutex);
-	while ((sl_tail == sl_idx) && (su_tail == su_idx)) {
-#  if SOLARIS && defined(_KERNEL)
-		if (!cv_wait_sig(&ipslwait, &ipsl_mutex)) {
-			MUTEX_EXIT(&ipsl_mutex);
+	MUTEX_ENTER(&softs->ipsl_mutex);
+	while ((softs->sl_tail == softs->sl_idx) &&
+	       (softs->su_tail == softs->su_idx)) {
+#  if defined(_KERNEL)
+#   if SOLARIS
+		if (!cv_wait_sig(&softs->ipslwait, &softs->ipsl_mutex.ipf_lk)) {
+			MUTEX_EXIT(&softs->ipsl_mutex);
+			IPFERROR(110009);
 			return EINTR;
 		}
-#  else
-#   ifdef __hpux
+#   else
+#    ifdef __hpux
 		{
 		lock_t *l;
 
-		l = get_sleep_lock(&sl_tail);
-		err = sleep(&sl_tail, PZERO+1);
+		l = get_sleep_lock(&softs->sl_tail);
+		err = sleep(&softs->sl_tail, PZERO+1);
 		if (err) {
-			MUTEX_EXIT(&ipsl_mutex);
+			MUTEX_EXIT(&softs->ipsl_mutex);
+			IPFERROR(110010);
 			return EINTR;
 		}
 		spinunlock(l);
 		}
-#   else /* __hpux */
-#    ifdef __osf__
-		err = mpsleep(&sl_tail, PSUSP|PCATCH,  "ipl sleep", 0,
-			      &ipsl_mutex, MS_LOCK_SIMPLE);
-		if (err)
+#    else /* __hpux */
+#     ifdef __osf__
+		err = mpsleep(&softs->sl_tail, PSUSP|PCATCH,  "ipl sleep", 0,
+			      &softs->ipsl_mutex, MS_LOCK_SIMPLE);
+		if (err) {
+			IPFERROR(110011);
 			return EINTR;
-#    else
-		MUTEX_EXIT(&ipsl_mutex);
-		err = SLEEP(&sl_tail, "ipl sleep");
-		if (err)
+		}
+#     else
+		MUTEX_EXIT(&softs->ipsl_mutex);
+		err = SLEEP(&softs->sl_tail, "ipl sleep");
+		if (err) {
+			IPFERROR(110012);
 			return EINTR;
-		MUTEX_ENTER(&ipsl_mutex);
-#    endif /* __osf__ */
-#   endif /* __hpux */
-#  endif /* SOLARIS */
+		}
+		MUTEX_ENTER(&softs->ipsl_mutex);
+#     endif /* __osf__ */
+#    endif /* __hpux */
+#   endif /* SOLARIS */
+#  endif /* _KERNEL */
 	}
-	MUTEX_EXIT(&ipsl_mutex);
 
-	READ_ENTER(&ipf_syncstate);
-	while ((sl_tail < sl_idx)  && (uio->uio_resid > sizeof(*sl))) {
-		sl = synclog + sl_tail++;
+	while ((softs->sl_tail < softs->sl_idx) &&
+	       (uio->uio_resid > sizeof(*sl))) {
+		sl = softs->synclog + softs->sl_tail++;
+		MUTEX_EXIT(&softs->ipsl_mutex);
 		err = UIOMOVE(sl, sizeof(*sl), UIO_READ, uio);
 		if (err != 0)
-			break;
+			goto goterror;
+		MUTEX_ENTER(&softs->ipsl_mutex);
 	}
 
-	while ((su_tail < su_idx)  && (uio->uio_resid > sizeof(*su))) {
-		su = syncupd + su_tail;
-		su_tail++;
+	while ((softs->su_tail < softs->su_idx) &&
+	       (uio->uio_resid > sizeof(*su))) {
+		su = softs->syncupd + softs->su_tail;
+		softs->su_tail++;
+		MUTEX_EXIT(&softs->ipsl_mutex);
 		err = UIOMOVE(su, sizeof(*su), UIO_READ, uio);
 		if (err != 0)
-			break;
+			goto goterror;
+		MUTEX_ENTER(&softs->ipsl_mutex);
 		if (su->sup_hdr.sm_sl != NULL)
 			su->sup_hdr.sm_sl->sl_idx = -1;
 	}
-
-	MUTEX_ENTER(&ipf_syncadd);
-	if (su_tail == su_idx)
-		su_tail = su_idx = 0;
-	if (sl_tail == sl_idx)
-		sl_tail = sl_idx = 0;
-	MUTEX_EXIT(&ipf_syncadd);
-	RWLOCK_EXIT(&ipf_syncstate);
+	if (softs->sl_tail == softs->sl_idx)
+		softs->sl_tail = softs->sl_idx = 0;
+	if (softs->su_tail == softs->su_idx)
+		softs->su_tail = softs->su_idx = 0;
+	MUTEX_EXIT(&softs->ipsl_mutex);
+goterror:
 	return err;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    ipfsync_state                                               */
+/* Function:    ipf_sync_state                                              */
 /* Returns:     int    - 0 == success, else error value.                    */
 /* Parameters:  sp(I)  - pointer to sync packet data header                 */
 /*              uio(I) - pointer to user data for further information       */
@@ -511,10 +692,13 @@
 /* create a new state entry or update one.  Deletion is left to the state   */
 /* structures being timed out correctly.                                    */
 /* ------------------------------------------------------------------------ */
-int ipfsync_state(sp, data)
-synchdr_t *sp;
-void *data;
+static int
+ipf_sync_state(softc, sp, data)
+	ipf_main_softc_t *softc;
+	synchdr_t *sp;
+	void *data;
 {
+	ipf_sync_softc_t *softs = softc->ipf_sync_soft;
 	synctcp_update_t su;
 	ipstate_t *is, sn;
 	synclist_t *sl;
@@ -522,7 +706,7 @@
 	u_int hv;
 	int err = 0;
 
-	hv = sp->sm_num & (SYNC_STATETABSZ - 1);
+	hv = sp->sm_num & (softs->ipf_sync_state_tab_sz - 1);
 
 	switch (sp->sm_cmd)
 	{
@@ -531,6 +715,7 @@
 		bcopy(data, &sn, sizeof(sn));
 		KMALLOC(is, ipstate_t *);
 		if (is == NULL) {
+			IPFERROR(110013);
 			err = ENOMEM;
 			break;
 		}
@@ -537,6 +722,7 @@
 
 		KMALLOC(sl, synclist_t *);
 		if (sl == NULL) {
+			IPFERROR(110014);
 			err = ENOMEM;
 			KFREE(is);
 			break;
@@ -545,14 +731,14 @@
 		bzero((char *)is, offsetof(ipstate_t, is_die));
 		bcopy((char *)&sn.is_die, (char *)&is->is_die,
 		      sizeof(*is) - offsetof(ipstate_t, is_die));
-		ipfsync_storder(0, is);
+		ipf_sync_storder(0, is);
 
 		/*
 		 * We need to find the same rule on the slave as was used on
 		 * the master to create this state entry.
 		 */
-		READ_ENTER(&ipf_mutex);
-		fr = fr_getrulen(IPL_LOGIPF, sn.is_group, sn.is_rulen);
+		READ_ENTER(&softc->ipf_mutex);
+		fr = ipf_getrulen(softc, IPL_LOGIPF, sn.is_group, sn.is_rulen);
 		if (fr != NULL) {
 			MUTEX_ENTER(&fr->fr_lock);
 			fr->fr_ref++;
@@ -559,9 +745,9 @@
 			fr->fr_statecnt++;
 			MUTEX_EXIT(&fr->fr_lock);
 		}
-		RWLOCK_EXIT(&ipf_mutex);
+		RWLOCK_EXIT(&softc->ipf_mutex);
 
-		if (ipf_sync_debug > 4)
+		if (softs->ipf_sync_debug > 4)
 			printf("[%d] Filter rules = %p\n", sp->sm_num, fr);
 
 		is->is_rule = fr;
@@ -571,16 +757,16 @@
 		sl->sl_ips = is;
 		bcopy(sp, &sl->sl_hdr, sizeof(struct synchdr));
 
-		WRITE_ENTER(&ipf_syncstate);
-		WRITE_ENTER(&ipf_state);
+		WRITE_ENTER(&softs->ipf_syncstate);
+		WRITE_ENTER(&softc->ipf_state);
 
-		sl->sl_pnext = syncstatetab + hv;
-		sl->sl_next = syncstatetab[hv];
-		if (syncstatetab[hv] != NULL)
-			syncstatetab[hv]->sl_pnext = &sl->sl_next;
-		syncstatetab[hv] = sl;
-		MUTEX_DOWNGRADE(&ipf_syncstate);
-		fr_stinsert(is, sp->sm_rev);
+		sl->sl_pnext = softs->syncstatetab + hv;
+		sl->sl_next = softs->syncstatetab[hv];
+		if (softs->syncstatetab[hv] != NULL)
+			softs->syncstatetab[hv]->sl_pnext = &sl->sl_next;
+		softs->syncstatetab[hv] = sl;
+		MUTEX_DOWNGRADE(&softs->ipf_syncstate);
+		ipf_state_insert(softc, is, sp->sm_rev);
 		/*
 		 * Do not initialise the interface pointers for the state
 		 * entry as the full complement of interface names may not
@@ -594,29 +780,31 @@
 	case SMC_UPDATE :
 		bcopy(data, &su, sizeof(su));
 
-		if (ipf_sync_debug > 4)
+		if (softs->ipf_sync_debug > 4)
 			printf("[%d] Update age %lu state %d/%d \n",
 				sp->sm_num, su.stu_age, su.stu_state[0],
 				su.stu_state[1]);
 
-		READ_ENTER(&ipf_syncstate);
-		for (sl = syncstatetab[hv]; (sl != NULL); sl = sl->sl_next)
+		READ_ENTER(&softs->ipf_syncstate);
+		for (sl = softs->syncstatetab[hv]; (sl != NULL);
+		     sl = sl->sl_next)
 			if (sl->sl_hdr.sm_num == sp->sm_num)
 				break;
 		if (sl == NULL) {
-			if (ipf_sync_debug > 1)
+			if (softs->ipf_sync_debug > 1)
 				printf("[%d] State not found - can't update\n",
 					sp->sm_num);
-			RWLOCK_EXIT(&ipf_syncstate);
+			RWLOCK_EXIT(&softs->ipf_syncstate);
+			IPFERROR(110015);
 			err = ENOENT;
 			break;
 		}
 
-		READ_ENTER(&ipf_state);
+		READ_ENTER(&softc->ipf_state);
 
-		if (ipf_sync_debug > 6)
-			printf("[%d] Data from state v:%d p:%d cmd:%d table:%d rev:%d\n", 
-				sp->sm_num, sl->sl_hdr.sm_v, sl->sl_hdr.sm_p, 
+		if (softs->ipf_sync_debug > 6)
+			printf("[%d] Data from state v:%d p:%d cmd:%d table:%d rev:%d\n",
+				sp->sm_num, sl->sl_hdr.sm_v, sl->sl_hdr.sm_p,
 				sl->sl_hdr.sm_cmd, sl->sl_hdr.sm_table,
 				sl->sl_hdr.sm_rev);
 
@@ -640,56 +828,97 @@
 			break;
 		}
 
-		if (ipf_sync_debug > 6)
+		if (softs->ipf_sync_debug > 6)
 			printf("[%d] Setting timers for state\n", sp->sm_num);
 
-		fr_setstatequeue(is, sp->sm_rev);
+		ipf_state_setqueue(softc, is, sp->sm_rev);
 
 		MUTEX_EXIT(&is->is_lock);
 		break;
 
 	default :
+		IPFERROR(110016);
 		err = EINVAL;
 		break;
 	}
 
 	if (err == 0) {
-		RWLOCK_EXIT(&ipf_state);
-		RWLOCK_EXIT(&ipf_syncstate);
+		RWLOCK_EXIT(&softc->ipf_state);
+		RWLOCK_EXIT(&softs->ipf_syncstate);
 	}
 
-	if (ipf_sync_debug > 6)
+	if (softs->ipf_sync_debug > 6)
 		printf("[%d] Update completed with error %d\n",
 			sp->sm_num, err);
 
 	return err;
 }
-# endif /* _KERNEL */
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    ipfsync_del                                                 */
+/* Function:    ipf_sync_del                                                */
 /* Returns:     Nil                                                         */
 /* Parameters:  sl(I) - pointer to synclist object to delete                */
 /*                                                                          */
-/* Deletes an object from the synclist table and free's its memory.         */
+/* Deletes an object from the synclist.                                     */
 /* ------------------------------------------------------------------------ */
-void ipfsync_del(sl)
-synclist_t *sl;
+static void
+ipf_sync_del(softs, sl)
+	ipf_sync_softc_t *softs;
+	synclist_t *sl;
 {
-	WRITE_ENTER(&ipf_syncstate);
 	*sl->sl_pnext = sl->sl_next;
 	if (sl->sl_next != NULL)
 		sl->sl_next->sl_pnext = sl->sl_pnext;
 	if (sl->sl_idx != -1)
-		syncupd[sl->sl_idx].sup_hdr.sm_sl = NULL;
-	RWLOCK_EXIT(&ipf_syncstate);
+		softs->syncupd[sl->sl_idx].sup_hdr.sm_sl = NULL;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_sync_del_state                                          */
+/* Returns:     Nil                                                         */
+/* Parameters:  sl(I) - pointer to synclist object to delete                */
+/*                                                                          */
+/* Deletes an object from the synclist state table and free's its memory.   */
+/* ------------------------------------------------------------------------ */
+void
+ipf_sync_del_state(arg, sl)
+	void *arg;
+	synclist_t *sl;
+{
+	ipf_sync_softc_t *softs = arg;
+
+	WRITE_ENTER(&softs->ipf_syncstate);
+	ipf_sync_del(softs, sl);
+	RWLOCK_EXIT(&softs->ipf_syncstate);
 	KFREE(sl);
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    ipfsync_nat                                                 */
+/* Function:    ipf_sync_del_nat                                            */
+/* Returns:     Nil                                                         */
+/* Parameters:  sl(I) - pointer to synclist object to delete                */
+/*                                                                          */
+/* Deletes an object from the synclist nat table and free's its memory.     */
+/* ------------------------------------------------------------------------ */
+void
+ipf_sync_del_nat(arg, sl)
+	void *arg;
+	synclist_t *sl;
+{
+	ipf_sync_softc_t *softs = arg;
+
+	WRITE_ENTER(&softs->ipf_syncnat);
+	ipf_sync_del(softs, sl);
+	RWLOCK_EXIT(&softs->ipf_syncnat);
+	KFREE(sl);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_sync_nat                                                */
 /* Returns:     int    - 0 == success, else error value.                    */
 /* Parameters:  sp(I)  - pointer to sync packet data header                 */
 /*              uio(I) - pointer to user data for further information       */
@@ -700,17 +929,20 @@
 /* create a new NAT entry or update one.  Deletion is left to the NAT       */
 /* structures being timed out correctly.                                    */
 /* ------------------------------------------------------------------------ */
-int ipfsync_nat(sp, data)
-synchdr_t *sp;
-void *data;
+static int
+ipf_sync_nat(softc, sp, data)
+	ipf_main_softc_t *softc;
+	synchdr_t *sp;
+	void *data;
 {
+	ipf_sync_softc_t *softs = softc->ipf_sync_soft;
 	syncupdent_t su;
 	nat_t *n, *nat;
 	synclist_t *sl;
 	u_int hv = 0;
-	int err;
+	int err = 0;
 
-	READ_ENTER(&ipf_syncstate);
+	READ_ENTER(&softs->ipf_syncnat);
 
 	switch (sp->sm_cmd)
 	{
@@ -717,6 +949,7 @@
 	case SMC_CREATE :
 		KMALLOC(n, nat_t *);
 		if (n == NULL) {
+			IPFERROR(110017);
 			err = ENOMEM;
 			break;
 		}
@@ -723,6 +956,7 @@
 
 		KMALLOC(sl, synclist_t *);
 		if (sl == NULL) {
+			IPFERROR(110018);
 			err = ENOMEM;
 			KFREE(n);
 			break;
@@ -732,59 +966,63 @@
 		bzero((char *)n, offsetof(nat_t, nat_age));
 		bcopy((char *)&nat->nat_age, (char *)&n->nat_age,
 		      sizeof(*n) - offsetof(nat_t, nat_age));
-		ipfsync_natorder(0, n);
+		ipf_sync_natorder(0, n);
 		n->nat_sync = sl;
+		n->nat_rev = sl->sl_rev;
 
 		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)
-			syncstatetab[hv]->sl_pnext = &sl->sl_next;
-		syncstatetab[hv] = sl;
-		nat_insert(n, sl->sl_rev);
-		RWLOCK_EXIT(&ipf_nat);
+		WRITE_ENTER(&softc->ipf_nat);
+		sl->sl_pnext = softs->syncnattab + hv;
+		sl->sl_next = softs->syncnattab[hv];
+		if (softs->syncnattab[hv] != NULL)
+			softs->syncnattab[hv]->sl_pnext = &sl->sl_next;
+		softs->syncnattab[hv] = sl;
+		(void) ipf_nat_insert(softc, softc->ipf_nat_soft, n);
+		RWLOCK_EXIT(&softc->ipf_nat);
 		break;
 
 	case SMC_UPDATE :
 		bcopy(data, &su, sizeof(su));
 
-		READ_ENTER(&ipf_syncstate);
-		for (sl = syncstatetab[hv]; (sl != NULL); sl = sl->sl_next)
+		for (sl = softs->syncnattab[hv]; (sl != NULL);
+		     sl = sl->sl_next)
 			if (sl->sl_hdr.sm_num == sp->sm_num)
 				break;
 		if (sl == NULL) {
+			IPFERROR(110019);
 			err = ENOENT;
 			break;
 		}
 
-		READ_ENTER(&ipf_nat);
+		READ_ENTER(&softc->ipf_nat);
 
 		nat = sl->sl_ipn;
+		nat->nat_rev = sl->sl_rev;
 
 		MUTEX_ENTER(&nat->nat_lock);
-		fr_setnatqueue(nat, sl->sl_rev);
+		ipf_nat_setqueue(softc, softc->ipf_nat_soft, nat);
 		MUTEX_EXIT(&nat->nat_lock);
 
-		RWLOCK_EXIT(&ipf_nat);
+		RWLOCK_EXIT(&softc->ipf_nat);
 
 		break;
 
 	default :
+		IPFERROR(110020);
 		err = EINVAL;
 		break;
 	}
 
-	RWLOCK_EXIT(&ipf_syncstate);
-	return 0;
+	RWLOCK_EXIT(&softs->ipf_syncnat);
+	return err;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    ipfsync_new                                                 */
+/* Function:    ipf_sync_new                                                */
 /* Returns:     synclist_t* - NULL == failure, else pointer to new synclist */
 /*                            data structure.                               */
 /* Parameters:  tab(I) - type of synclist_t to create                       */
@@ -794,43 +1032,36 @@
 /* Creates a new sync table entry and notifies any sleepers that it's there */
 /* waiting to be processed.                                                 */
 /* ------------------------------------------------------------------------ */
-synclist_t *ipfsync_new(tab, fin, ptr)
-int tab;
-fr_info_t *fin;
-void *ptr;
+synclist_t *
+ipf_sync_new(softc, tab, fin, ptr)
+	ipf_main_softc_t *softc;
+	int tab;
+	fr_info_t *fin;
+	void *ptr;
 {
+	ipf_sync_softc_t *softs = softc->ipf_sync_soft;
 	synclist_t *sl, *ss;
 	synclogent_t *sle;
 	u_int hv, sz;
 
-	if (sl_idx == SYNCLOG_SZ)
+	if (softs->sl_idx == softs->ipf_sync_log_sz)
 		return NULL;
 	KMALLOC(sl, synclist_t *);
 	if (sl == NULL)
 		return NULL;
 
-	MUTEX_ENTER(&ipf_syncadd);
+	MUTEX_ENTER(&softs->ipf_syncadd);
 	/*
 	 * Get a unique number for this synclist_t.  The number is only meant
 	 * to be unique for the lifetime of the structure and may be reused
 	 * later.
 	 */
-	ipf_syncnum++;
-	if (ipf_syncnum == 0) {
-		ipf_syncnum = 1;
-		ipf_syncwrap = 1;
+	softs->ipf_sync_num++;
+	if (softs->ipf_sync_num == 0) {
+		softs->ipf_sync_num = 1;
+		softs->ipf_sync_wrap++;
 	}
 
-	hv = ipf_syncnum & (SYNC_STATETABSZ - 1);
-	while (ipf_syncwrap != 0) {
-		for (ss = syncstatetab[hv]; ss; ss = ss->sl_next)
-			if (ss->sl_hdr.sm_num == ipf_syncnum)
-				break;
-		if (ss == NULL)
-			break;
-		ipf_syncnum++;
-		hv = ipf_syncnum & (SYNC_STATETABSZ - 1);
-	}
 	/*
 	 * Use the synch number of the object as the hash key.  Should end up
 	 * with relatively even distribution over time.
@@ -839,12 +1070,49 @@
 	 * nth connection they make, where n is a value in the interval
 	 * [0, SYNC_STATETABSZ-1].
 	 */
-	sl->sl_pnext = syncstatetab + hv;
-	sl->sl_next = syncstatetab[hv];
-	syncstatetab[hv] = sl;
-	sl->sl_num = ipf_syncnum;
-	MUTEX_EXIT(&ipf_syncadd);
+	switch (tab)
+	{
+	case SMC_STATE :
+		hv = softs->ipf_sync_num & (softs->ipf_sync_state_tab_sz - 1);
+		while (softs->ipf_sync_wrap != 0) {
+			for (ss = softs->syncstatetab[hv]; ss; ss = ss->sl_next)
+				if (ss->sl_hdr.sm_num == softs->ipf_sync_num)
+					break;
+			if (ss == NULL)
+				break;
+			softs->ipf_sync_num++;
+			hv = softs->ipf_sync_num &
+			     (softs->ipf_sync_state_tab_sz - 1);
+		}
+		sl->sl_pnext = softs->syncstatetab + hv;
+		sl->sl_next = softs->syncstatetab[hv];
+		softs->syncstatetab[hv] = sl;
+		break;
 
+	case SMC_NAT :
+		hv = softs->ipf_sync_num & (softs->ipf_sync_nat_tab_sz - 1);
+		while (softs->ipf_sync_wrap != 0) {
+			for (ss = softs->syncnattab[hv]; ss; ss = ss->sl_next)
+				if (ss->sl_hdr.sm_num == softs->ipf_sync_num)
+					break;
+			if (ss == NULL)
+				break;
+			softs->ipf_sync_num++;
+			hv = softs->ipf_sync_num &
+			     (softs->ipf_sync_nat_tab_sz - 1);
+		}
+		sl->sl_pnext = softs->syncnattab + hv;
+		sl->sl_next = softs->syncnattab[hv];
+		softs->syncnattab[hv] = sl;
+		break;
+
+	default :
+		break;
+	}
+
+	sl->sl_num = softs->ipf_sync_num;
+	MUTEX_EXIT(&softs->ipf_syncadd);
+
 	sl->sl_magic = htonl(SYNHDRMAGIC);
 	sl->sl_v = fin->fin_v;
 	sl->sl_p = fin->fin_p;
@@ -868,8 +1136,8 @@
 	 * Create the log entry to be read by a user daemon.  When it has been
 	 * finished and put on the queue, send a signal to wakeup any waiters.
 	 */
-	MUTEX_ENTER(&ipf_syncadd);
-	sle = synclog + sl_idx++;
+	MUTEX_ENTER(&softs->ipf_syncadd);
+	sle = softs->synclog + softs->sl_idx++;
 	bcopy((char *)&sl->sl_hdr, (char *)&sle->sle_hdr,
 	      sizeof(sle->sle_hdr));
 	sle->sle_hdr.sm_num = htonl(sle->sle_hdr.sm_num);
@@ -877,31 +1145,20 @@
 	if (ptr != NULL) {
 		bcopy((char *)ptr, (char *)&sle->sle_un, sz);
 		if (tab == SMC_STATE) {
-			ipfsync_storder(1, &sle->sle_un.sleu_ips);
+			ipf_sync_storder(1, &sle->sle_un.sleu_ips);
 		} else if (tab == SMC_NAT) {
-			ipfsync_natorder(1, &sle->sle_un.sleu_ipn);
+			ipf_sync_natorder(1, &sle->sle_un.sleu_ipn);
 		}
 	}
-	MUTEX_EXIT(&ipf_syncadd);
+	MUTEX_EXIT(&softs->ipf_syncadd);
 
-	MUTEX_ENTER(&ipsl_mutex);
-# if SOLARIS
-#  ifdef _KERNEL
-	cv_signal(&ipslwait);
-#  endif
-	MUTEX_EXIT(&ipsl_mutex);
-# else
-	MUTEX_EXIT(&ipsl_mutex);
-#  ifdef _KERNEL
-	wakeup(&sl_tail);
-#  endif
-# endif
+	ipf_sync_wakeup(softc);
 	return sl;
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    ipfsync_update                                              */
+/* Function:    ipf_sync_update                                             */
 /* Returns:     Nil                                                         */
 /* Parameters:  tab(I) - type of synclist_t to create                       */
 /*              fin(I) - pointer to packet information                      */
@@ -910,24 +1167,36 @@
 /* For outbound packets, only, create an sync update record for the user    */
 /* process to read.                                                         */
 /* ------------------------------------------------------------------------ */
-void ipfsync_update(tab, fin, sl)
-int tab;
-fr_info_t *fin;
-synclist_t *sl;
+void
+ipf_sync_update(softc, tab, fin, sl)
+	ipf_main_softc_t *softc;
+	int tab;
+	fr_info_t *fin;
+	synclist_t *sl;
 {
+	ipf_sync_softc_t *softs = softc->ipf_sync_soft;
 	synctcp_update_t *st;
 	syncupdent_t *slu;
 	ipstate_t *ips;
 	nat_t *nat;
+	ipfrwlock_t *lock;
 
 	if (fin->fin_out == 0 || sl == NULL)
 		return;
 
-	WRITE_ENTER(&ipf_syncstate);
-	MUTEX_ENTER(&ipf_syncadd);
+	if (tab == SMC_STATE) {
+		lock = &softs->ipf_syncstate;
+	} else {
+		lock = &softs->ipf_syncnat;
+	}
+
+	READ_ENTER(lock);
 	if (sl->sl_idx == -1) {
-		slu = syncupd + su_idx;
-		sl->sl_idx = su_idx++;
+		MUTEX_ENTER(&softs->ipf_syncadd);
+		slu = softs->syncupd + softs->su_idx;
+		sl->sl_idx = softs->su_idx++;
+		MUTEX_EXIT(&softs->ipf_syncadd);
+
 		bcopy((char *)&sl->sl_hdr, (char *)&slu->sup_hdr,
 		      sizeof(slu->sup_hdr));
 		slu->sup_hdr.sm_magic = htonl(SYNHDRMAGIC);
@@ -944,9 +1213,7 @@
 		}
 # endif
 	} else
-		slu = syncupd + sl->sl_idx;
-	MUTEX_EXIT(&ipf_syncadd);
-	MUTEX_DOWNGRADE(&ipf_syncstate);
+		slu = softs->syncupd + sl->sl_idx;
 
 	/*
 	 * Only TCP has complex timeouts, others just use default timeouts.
@@ -970,25 +1237,61 @@
 			st->stu_age = htonl(nat->nat_age);
 		}
 	}
-	RWLOCK_EXIT(&ipf_syncstate);
+	RWLOCK_EXIT(lock);
 
-	MUTEX_ENTER(&ipsl_mutex);
-# if SOLARIS
-#  ifdef _KERNEL
-	cv_signal(&ipslwait);
-#  endif
-	MUTEX_EXIT(&ipsl_mutex);
-# else
-	MUTEX_EXIT(&ipsl_mutex);
-#  ifdef _KERNEL
-	wakeup(&sl_tail);
-#  endif
-# endif
+	ipf_sync_wakeup(softc);
 }
 
 
 /* ------------------------------------------------------------------------ */
-/* Function:    fr_sync_ioctl                                               */
+/* Function:    ipf_sync_flush_table                                        */
+/* Returns:     int - number of entries freed by flushing table             */
+/* Parameters:  tabsize(I) - size of the array pointed to by table          */
+/*              table(I)   - pointer to sync table to empty                 */
+/*                                                                          */
+/* Walk through a table of sync entries and free each one.  It is assumed   */
+/* that some lock is held so that nobody else tries to access the table     */
+/* during this cleanup.                                                     */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_sync_flush_table(softs, tabsize, table)
+	ipf_sync_softc_t *softs;
+	int tabsize;
+	synclist_t **table;
+{
+	synclist_t *sl;
+	int i, items;
+
+	items = 0;
+
+	for (i = 0; i < tabsize; i++) {
+		while ((sl = table[i]) != NULL) {
+			switch (sl->sl_table) {
+			case SMC_STATE :
+				if (sl->sl_ips != NULL)
+					sl->sl_ips->is_sync = NULL;
+				break;
+			case SMC_NAT :
+				if (sl->sl_ipn != NULL)
+					sl->sl_ipn->nat_sync = NULL;
+				break;
+			}
+			if (sl->sl_next != NULL)
+				sl->sl_next->sl_pnext = sl->sl_pnext;
+			table[i] = sl->sl_next;
+			if (sl->sl_idx != -1)
+				softs->syncupd[sl->sl_idx].sup_hdr.sm_sl = NULL;
+			KFREE(sl);
+			items++;
+		}
+	}
+
+	return items;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_sync_ioctl                                              */
 /* Returns:     int - 0 == success, != 0 == failure                         */
 /* Parameters:  data(I) - pointer to ioctl data                             */
 /*              cmd(I)  - ioctl command integer                             */
@@ -997,24 +1300,199 @@
 /* This function currently does not handle any ioctls and so just returns   */
 /* EINVAL on all occasions.                                                 */
 /* ------------------------------------------------------------------------ */
-int fr_sync_ioctl(data, cmd, mode, uid, ctx)
-caddr_t data;
-ioctlcmd_t cmd;
-int mode, uid;
-void *ctx;
+int
+ipf_sync_ioctl(softc, data, cmd, mode, uid, ctx)
+	ipf_main_softc_t *softc;
+	caddr_t data;
+	ioctlcmd_t cmd;
+	int mode, uid;
+	void *ctx;
 {
-	return EINVAL;
+	ipf_sync_softc_t *softs = softc->ipf_sync_soft;
+	int error, i;
+	SPL_INT(s);
+
+	switch (cmd)
+	{
+        case SIOCIPFFL:
+		error = BCOPYIN(data, &i, sizeof(i));
+		if (error != 0) {
+			IPFERROR(110023);
+			error = EFAULT;
+			break;
+		}
+
+		switch (i)
+		{
+		case SMC_RLOG :
+			SPL_NET(s);
+			MUTEX_ENTER(&softs->ipsl_mutex);
+			i = (softs->sl_tail - softs->sl_idx) +
+			    (softs->su_tail - softs->su_idx);
+			softs->sl_idx = 0;
+			softs->su_idx = 0;
+			softs->sl_tail = 0;
+			softs->su_tail = 0;
+			MUTEX_EXIT(&softs->ipsl_mutex);
+			SPL_X(s);
+			break;
+
+		case SMC_NAT :
+			SPL_NET(s);
+			WRITE_ENTER(&softs->ipf_syncnat);
+			i = ipf_sync_flush_table(softs, SYNC_NATTABSZ,
+						 softs->syncnattab);
+			RWLOCK_EXIT(&softs->ipf_syncnat);
+			SPL_X(s);
+			break;
+
+		case SMC_STATE :
+			SPL_NET(s);
+			WRITE_ENTER(&softs->ipf_syncstate);
+			i = ipf_sync_flush_table(softs, SYNC_STATETABSZ,
+						 softs->syncstatetab);
+			RWLOCK_EXIT(&softs->ipf_syncstate);
+			SPL_X(s);
+			break;
+		}
+
+		error = BCOPYOUT(&i, data, sizeof(i));
+		if (error != 0) {
+			IPFERROR(110022);
+			error = EFAULT;
+		}
+		break;
+
+	default :
+		IPFERROR(110021);
+		error = EINVAL;
+		break;
+	}
+
+	return error;
 }
 
 
-int ipfsync_canread()
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_sync_canread                                            */
+/* Returns:     int - 0 == success, != 0 == failure                         */
+/* Parameters:  Nil                                                         */
+/*                                                                          */
+/* This function provides input to the poll handler about whether or not    */
+/* there is data waiting to be read from the /dev/ipsync device.            */
+/* ------------------------------------------------------------------------ */
+int
+ipf_sync_canread(arg)
+	void *arg;
 {
-	return !((sl_tail == sl_idx) && (su_tail == su_idx));
+	ipf_sync_softc_t *softs = arg;
+	return !((softs->sl_tail == softs->sl_idx) &&
+		 (softs->su_tail == softs->su_idx));
 }
 
 
-int ipfsync_canwrite()
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_sync_canwrite                                           */
+/* Returns:     int - 1 == can always write                                 */
+/* Parameters:  Nil                                                         */
+/*                                                                          */
+/* This function lets the poll handler know that it is always ready willing */
+/* to accept write events.                                                  */
+/* XXX Maybe this should return false if the sync table is full?            */
+/* ------------------------------------------------------------------------ */
+int
+ipf_sync_canwrite(arg)
+	void *arg;
 {
 	return 1;
 }
-#endif /* IPFILTER_SYNC */
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_sync_wakeup                                             */
+/* Parameters:  Nil                                                         */
+/* Returns:     Nil                                                         */
+/*                                                                          */
+/* This function implements the heuristics that decide how often to         */
+/* generate a poll wakeup for programs that are waiting for information     */
+/* about when they can do a read on /dev/ipsync.                            */
+/*                                                                          */
+/* There are three different considerations here:                           */
+/* - do not keep a program waiting too long: ipf_sync_wake_interval is the  */
+/*   maximum number of ipf ticks to let pass by;                            */
+/* - do not let the queue of ouststanding things to generate notifies for   */
+/*   get too full (ipf_sync_queue_high_wm is the high water mark);          */
+/* - do not let too many events get collapsed in before deciding that the   */
+/*   other host(s) need an update (ipf_sync_event_high_wm is the high water */
+/*   mark for this counter.)                                                */
+/* ------------------------------------------------------------------------ */
+static void
+ipf_sync_wakeup(softc)
+	ipf_main_softc_t *softc;
+{
+	ipf_sync_softc_t *softs = softc->ipf_sync_soft;
+
+	softs->ipf_sync_events++;
+	if ((softc->ipf_ticks >
+	    softs->ipf_sync_lastwakeup + softs->ipf_sync_wake_interval) ||
+	    (softs->ipf_sync_events > softs->ipf_sync_event_high_wm) ||
+	    ((softs->sl_tail - softs->sl_idx) >
+	     softs->ipf_sync_queue_high_wm) ||
+	    ((softs->su_tail - softs->su_idx) >
+	     softs->ipf_sync_queue_high_wm)) {
+
+		ipf_sync_poll_wakeup(softc);
+	}
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_sync_poll_wakeup                                        */
+/* Parameters:  Nil                                                         */
+/* Returns:     Nil                                                         */
+/*                                                                          */
+/* Deliver a poll wakeup and reset counters for two of the three heuristics */
+/* ------------------------------------------------------------------------ */
+static void
+ipf_sync_poll_wakeup(softc)
+	ipf_main_softc_t *softc;
+{
+	ipf_sync_softc_t *softs = softc->ipf_sync_soft;
+
+	softs->ipf_sync_events = 0;
+	softs->ipf_sync_lastwakeup = softc->ipf_ticks;
+
+# ifdef _KERNEL
+#  if SOLARIS
+	MUTEX_ENTER(&softs->ipsl_mutex);
+	cv_signal(&softs->ipslwait);
+	MUTEX_EXIT(&softs->ipsl_mutex);
+	pollwakeup(&softc->ipf_poll_head[IPL_LOGSYNC], POLLIN|POLLRDNORM);
+#  else
+	WAKEUP(&softs->sl_tail, 0);
+	POLLWAKEUP(IPL_LOGSYNC);
+#  endif
+# endif
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_sync_expire                                             */
+/* Parameters:  Nil                                                         */
+/* Returns:     Nil                                                         */
+/*                                                                          */
+/* This is the function called even ipf_tick.  It implements one of the     */
+/* three heuristics above *IF* there are events waiting.                    */
+/* ------------------------------------------------------------------------ */
+void
+ipf_sync_expire(softc)
+	ipf_main_softc_t *softc;
+{
+	ipf_sync_softc_t *softs = softc->ipf_sync_soft;
+
+	if ((softs->ipf_sync_events > 0) &&
+	    (softc->ipf_ticks >
+	     softs->ipf_sync_lastwakeup + softs->ipf_sync_wake_interval)) {
+		ipf_sync_poll_wakeup(softc);
+	}
+}

Modified: trunk/sys/contrib/ipfilter/netinet/ip_sync.h
===================================================================
--- trunk/sys/contrib/ipfilter/netinet/ip_sync.h	2018-05-28 18:55:30 UTC (rev 10138)
+++ trunk/sys/contrib/ipfilter/netinet/ip_sync.h	2018-05-28 18:56:30 UTC (rev 10139)
@@ -1,10 +1,11 @@
+/* $MidnightBSD$ */
 /*
- * Copyright (C) 1993-2001 by Darren Reed.
+ * Copyright (C) 2012 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 1.2 2008-09-19 02:15:13 laffer1 Exp $
+ * $Id$
  */
 
 #ifndef __IP_SYNC_H__
@@ -36,6 +37,7 @@
 /*
  * Tables
  */
+#define	SMC_RLOG	-2	/* Only used with SIOCIPFFL */
 #define	SMC_NAT		0
 #define	SMC_STATE	1
 #define	SMC_MAXTBL	1
@@ -99,19 +101,22 @@
 	struct	synctcp_update	sup_tcp;
 } syncupdent_t;
 
-extern	synclogent_t	synclog[SYNCLOG_SZ];
+extern	void *ipf_sync_create __P((ipf_main_softc_t *));
+extern	int ipf_sync_soft_init __P((ipf_main_softc_t *, void *));
+extern	int ipf_sync_soft_fini __P((ipf_main_softc_t *, void *));
+extern	int ipf_sync_canread __P((void *));
+extern	int ipf_sync_canwrite __P((void *));
+extern	void ipf_sync_del_nat __P((void *, synclist_t *));
+extern	void ipf_sync_del_state __P((void *, synclist_t *));
+extern	int ipf_sync_init __P((void));
+extern	int ipf_sync_ioctl __P((ipf_main_softc_t *, caddr_t, ioctlcmd_t, int, int, void *));
+extern	synclist_t *ipf_sync_new __P((ipf_main_softc_t *, int, fr_info_t *, void *));
+extern	int ipf_sync_read __P((ipf_main_softc_t *, struct uio *uio));
+extern	int ipf_sync_write __P((ipf_main_softc_t *, struct uio *uio));
+extern	int ipf_sync_main_unload __P((void));
+extern	void ipf_sync_update __P((ipf_main_softc_t *, int, fr_info_t *, synclist_t *));
+extern	void ipf_sync_expire __P((ipf_main_softc_t *));
+extern	void	ipf_sync_soft_destroy __P((ipf_main_softc_t *, void *));
+extern	void	*ipf_sync_soft_create __P((ipf_main_softc_t *));
 
-
-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 */
+#endif /* __IP_SYNC_H__ */

Added: trunk/sys/contrib/ipfilter/netinet/ip_tftp_pxy.c
===================================================================
--- trunk/sys/contrib/ipfilter/netinet/ip_tftp_pxy.c	                        (rev 0)
+++ trunk/sys/contrib/ipfilter/netinet/ip_tftp_pxy.c	2018-05-28 18:56:30 UTC (rev 10139)
@@ -0,0 +1,509 @@
+/* $MidnightBSD$ */
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id: ip_tftp_pxy.c,v 1.1.2.9 2012/07/22 08:04:23 darren_r Exp $
+ */
+
+#define IPF_TFTP_PROXY
+
+typedef struct ipf_tftp_softc_s {
+        int     	ipf_p_tftp_readonly;
+	ipftuneable_t	*ipf_p_tftp_tune;
+} ipf_tftp_softc_t;
+
+int ipf_p_tftp_backchannel __P((fr_info_t *, ap_session_t *, nat_t *));
+int ipf_p_tftp_client __P((ipf_tftp_softc_t *, fr_info_t *, ap_session_t *,
+			   nat_t *));
+int ipf_p_tftp_in __P((void *, fr_info_t *, ap_session_t *, nat_t *));
+void ipf_p_tftp_main_load __P((void));
+void ipf_p_tftp_main_unload __P((void));
+int ipf_p_tftp_new __P((void *, fr_info_t *, ap_session_t *, nat_t *));
+void ipf_p_tftp_del __P((ipf_main_softc_t *, ap_session_t *));
+int ipf_p_tftp_out __P((void *, fr_info_t *, ap_session_t *, nat_t *));
+int ipf_p_tftp_server __P((ipf_tftp_softc_t *, fr_info_t *, ap_session_t *,
+			   nat_t *));
+void *ipf_p_tftp_soft_create __P((ipf_main_softc_t *));
+void ipf_p_tftp_soft_destroy __P((ipf_main_softc_t *, void *));
+
+static	frentry_t	tftpfr;
+static	int		tftp_proxy_init = 0;
+
+typedef enum tftp_cmd_e {
+	TFTP_CMD_READ = 1,
+	TFTP_CMD_WRITE = 2,
+	TFTP_CMD_DATA = 3,
+	TFTP_CMD_ACK = 4,
+	TFTP_CMD_ERROR = 5
+} tftp_cmd_t;
+
+typedef struct tftpinfo {
+	tftp_cmd_t	ti_lastcmd;
+	int		ti_nextblk;
+	int		ti_lastblk;
+	int		ti_lasterror;
+	char		ti_filename[80];
+	ipnat_t		*ti_rule;
+} tftpinfo_t;
+
+static  ipftuneable_t   ipf_tftp_tuneables[] = {
+	{ { (void *)offsetof(ipf_tftp_softc_t, ipf_p_tftp_readonly) },
+		"tftp_read_only",	0,	1,
+		stsizeof(ipf_tftp_softc_t, ipf_p_tftp_readonly),
+		0, NULL, NULL },
+	{ { NULL }, NULL, 0, 0, 0, 0, NULL, NULL }
+};
+
+
+/*
+ * TFTP application proxy initialization.
+ */
+void
+ipf_p_tftp_main_load()
+{
+
+	bzero((char *)&tftpfr, sizeof(tftpfr));
+	tftpfr.fr_ref = 1;
+	tftpfr.fr_flags = FR_INQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE;
+	MUTEX_INIT(&tftpfr.fr_lock, "TFTP proxy rule lock");
+	tftp_proxy_init = 1;
+}
+
+
+void
+ipf_p_tftp_main_unload()
+{
+
+	if (tftp_proxy_init == 1) {
+		MUTEX_DESTROY(&tftpfr.fr_lock);
+		tftp_proxy_init = 0;
+	}
+}
+
+
+void *
+ipf_p_tftp_soft_create(softc)
+	ipf_main_softc_t *softc;
+{
+	ipf_tftp_softc_t *softt;
+
+	KMALLOC(softt, ipf_tftp_softc_t *);
+	if (softt == NULL)
+		return NULL;
+
+	bzero((char *)softt, sizeof(*softt));
+
+	softt->ipf_p_tftp_tune = ipf_tune_array_copy(softt,
+						     sizeof(ipf_tftp_tuneables),
+						     ipf_tftp_tuneables);
+	if (softt->ipf_p_tftp_tune == NULL) {
+		ipf_p_tftp_soft_destroy(softc, softt);
+		return NULL;
+	}
+	if (ipf_tune_array_link(softc, softt->ipf_p_tftp_tune) == -1) {
+		ipf_p_tftp_soft_destroy(softc, softt);
+		return NULL;
+	}
+
+	softt->ipf_p_tftp_readonly = 1;
+
+	return softt;
+}
+
+
+void
+ipf_p_tftp_soft_destroy(softc, arg)
+        ipf_main_softc_t *softc;
+        void *arg;
+{
+	ipf_tftp_softc_t *softt = arg;
+
+	if (softt->ipf_p_tftp_tune != NULL) {
+		ipf_tune_array_unlink(softc, softt->ipf_p_tftp_tune);
+		KFREES(softt->ipf_p_tftp_tune, sizeof(ipf_tftp_tuneables));
+		softt->ipf_p_tftp_tune = NULL;
+	}
+
+	KFREE(softt);
+}
+
+
+int
+ipf_p_tftp_out(arg, fin, aps, nat)
+	void *arg;
+	fr_info_t *fin;
+	ap_session_t *aps;
+	nat_t *nat;
+{
+	ipf_tftp_softc_t *softt = arg;
+
+	fin->fin_flx |= FI_NOWILD;
+	if (nat->nat_dir == NAT_OUTBOUND)
+		return ipf_p_tftp_client(softt, fin, aps, nat);
+	return ipf_p_tftp_server(softt, fin, aps, nat);
+}
+
+
+int
+ipf_p_tftp_in(arg, fin, aps, nat)
+	void *arg;
+	fr_info_t *fin;
+	ap_session_t *aps;
+	nat_t *nat;
+{
+	ipf_tftp_softc_t *softt = arg;
+
+	fin->fin_flx |= FI_NOWILD;
+	if (nat->nat_dir == NAT_INBOUND)
+		return ipf_p_tftp_client(softt, fin, aps, nat);
+	return ipf_p_tftp_server(softt, fin, aps, nat);
+}
+
+
+int
+ipf_p_tftp_new(arg, fin, aps, nat)
+	void *arg;
+	fr_info_t *fin;
+	ap_session_t *aps;
+	nat_t *nat;
+{
+	udphdr_t *udp;
+	tftpinfo_t *ti;
+	ipnat_t *ipn;
+	ipnat_t *np;
+	int size;
+
+	fin = fin;	/* LINT */
+
+	np = nat->nat_ptr;
+	size = np->in_size;
+
+	KMALLOC(ti, tftpinfo_t *);
+	if (ti == NULL)
+		return -1;
+	KMALLOCS(ipn, ipnat_t *, size);
+	if (ipn == NULL) {
+		KFREE(ti);
+		return -1;
+	}
+
+	aps->aps_data = ti;
+	aps->aps_psiz = sizeof(*ti);
+	bzero((char *)ti, sizeof(*ti));
+	bzero((char *)ipn, size);
+	ti->ti_rule = ipn;
+
+	udp = (udphdr_t *)fin->fin_dp;
+	aps->aps_sport = udp->uh_sport;
+	aps->aps_dport = udp->uh_dport;
+
+	ipn->in_size = size;
+	ipn->in_apr = NULL;
+	ipn->in_use = 1;
+	ipn->in_hits = 1;
+	ipn->in_ippip = 1;
+	ipn->in_pr[0] = IPPROTO_UDP;
+	ipn->in_pr[1] = IPPROTO_UDP;
+	ipn->in_ifps[0] = nat->nat_ifps[0];
+	ipn->in_ifps[1] = nat->nat_ifps[1];
+	ipn->in_v[0] = nat->nat_ptr->in_v[1];
+	ipn->in_v[1] = nat->nat_ptr->in_v[0];
+	ipn->in_flags = IPN_UDP|IPN_FIXEDDPORT|IPN_PROXYRULE;
+
+	ipn->in_nsrcip6 = nat->nat_odst6;
+	ipn->in_osrcip6 = nat->nat_ndst6;
+
+	if ((np->in_redir & NAT_REDIRECT) != 0) {
+		ipn->in_redir = NAT_MAP;
+		if (ipn->in_v[0] == 4) {
+			ipn->in_snip = ntohl(nat->nat_odstaddr);
+			ipn->in_dnip = ntohl(nat->nat_nsrcaddr);
+		} else {
+#ifdef USE_INET6
+			ipn->in_snip6 = nat->nat_odst6;
+			ipn->in_dnip6 = nat->nat_nsrc6;
+#endif
+		}
+		ipn->in_ndstip6 = nat->nat_nsrc6;
+		ipn->in_odstip6 = nat->nat_osrc6;
+	} else {
+		ipn->in_redir = NAT_REDIRECT;
+		if (ipn->in_v[0] == 4) {
+			ipn->in_snip = ntohl(nat->nat_odstaddr);
+			ipn->in_dnip = ntohl(nat->nat_osrcaddr);
+		} else {
+#ifdef USE_INET6
+			ipn->in_snip6 = nat->nat_odst6;
+			ipn->in_dnip6 = nat->nat_osrc6;
+#endif
+		}
+		ipn->in_ndstip6 = nat->nat_osrc6;
+		ipn->in_odstip6 = nat->nat_nsrc6;
+	}
+	ipn->in_odport = htons(fin->fin_sport);
+	ipn->in_ndport = htons(fin->fin_sport);
+
+	IP6_SETONES(&ipn->in_osrcmsk6);
+	IP6_SETONES(&ipn->in_nsrcmsk6);
+	IP6_SETONES(&ipn->in_odstmsk6);
+	IP6_SETONES(&ipn->in_ndstmsk6);
+	MUTEX_INIT(&ipn->in_lock, "tftp proxy NAT rule");
+
+	ipn->in_namelen = np->in_namelen;
+	bcopy(np->in_names, ipn->in_ifnames, ipn->in_namelen);
+	ipn->in_ifnames[0] = np->in_ifnames[0];
+	ipn->in_ifnames[1] = np->in_ifnames[1];
+
+	ti->ti_lastcmd = 0;
+
+	return 0;
+}
+
+
+void
+ipf_p_tftp_del(softc, aps)
+	ipf_main_softc_t *softc;
+	ap_session_t *aps;
+{
+	tftpinfo_t *tftp;
+
+	tftp = aps->aps_data;
+	if (tftp != NULL) {
+		tftp->ti_rule->in_flags |= IPN_DELETE;
+		ipf_nat_rule_deref(softc, &tftp->ti_rule);
+	}
+}
+
+
+/*
+ * Setup for a new TFTP proxy.
+ */
+int
+ipf_p_tftp_backchannel(fin, aps, nat)
+	fr_info_t *fin;
+	ap_session_t *aps;
+	nat_t *nat;
+{
+	ipf_main_softc_t *softc = fin->fin_main_soft;
+#ifdef USE_MUTEXES
+	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
+#endif
+#ifdef USE_INET6
+	i6addr_t swip6, sw2ip6;
+	ip6_t *ip6;
+#endif
+	struct in_addr swip, sw2ip;
+	tftpinfo_t *ti;
+	udphdr_t udp;
+	fr_info_t fi;
+	u_short slen = 0; /* silence gcc */
+	nat_t *nat2;
+	int nflags;
+	ip_t *ip;
+	int dir;
+
+	ti = aps->aps_data;
+	/*
+	 * Add skeleton NAT entry for connection which will come back the
+	 * other way.
+	 */
+	bcopy((char *)fin, (char *)&fi, sizeof(fi));
+	fi.fin_flx |= FI_IGNORE;
+	fi.fin_data[1] = 0;
+
+	bzero((char *)&udp, sizeof(udp));
+	udp.uh_sport = 0;	/* XXX - don't specify remote port */
+	udp.uh_dport = ti->ti_rule->in_ndport;
+	udp.uh_ulen = htons(sizeof(udp));
+	udp.uh_sum = 0;
+
+	fi.fin_fr = &tftpfr;
+	fi.fin_dp = (char *)&udp;
+	fi.fin_sport = 0;
+	fi.fin_dport = ntohs(ti->ti_rule->in_ndport);
+	fi.fin_dlen = sizeof(udp);
+	fi.fin_plen = fi.fin_hlen + sizeof(udp);
+	fi.fin_flx &= FI_LOWTTL|FI_FRAG|FI_TCPUDP|FI_OPTIONS|FI_IGNORE;
+	nflags = NAT_SLAVE|IPN_UDP|SI_W_SPORT;
+#ifdef USE_INET6
+	ip6 = (ip6_t *)fin->fin_ip;
+#endif
+	ip = fin->fin_ip;
+	sw2ip.s_addr = 0;
+	swip.s_addr = 0;
+
+	fi.fin_src6 = nat->nat_ndst6;
+	fi.fin_dst6 = nat->nat_nsrc6;
+	if (nat->nat_v[0] == 4) {
+		slen = ip->ip_len;
+		ip->ip_len = htons(fin->fin_hlen + sizeof(udp));
+		swip = ip->ip_src;
+		sw2ip = ip->ip_dst;
+		ip->ip_src = nat->nat_ndstip;
+		ip->ip_dst = nat->nat_nsrcip;
+	} else {
+#ifdef USE_INET6
+		slen = ip6->ip6_plen;
+		ip6->ip6_plen = htons(sizeof(udp));
+		swip6.in6 = ip6->ip6_src;
+		sw2ip6.in6 = ip6->ip6_dst;
+		ip6->ip6_src = nat->nat_ndst6.in6;
+		ip6->ip6_dst = nat->nat_nsrc6.in6;
+#endif
+	}
+
+	if (nat->nat_dir == NAT_INBOUND) {
+		dir = NAT_OUTBOUND;
+		fi.fin_out = 1;
+	} else {
+		dir = NAT_INBOUND;
+		fi.fin_out = 0;
+	}
+	nflags |= NAT_NOTRULEPORT;
+
+	MUTEX_ENTER(&softn->ipf_nat_new);
+#ifdef USE_INET6
+	if (nat->nat_v[0] == 6)
+		nat2 = ipf_nat6_add(&fi, ti->ti_rule, NULL, nflags, dir);
+	else
+#endif
+		nat2 = ipf_nat_add(&fi, ti->ti_rule, NULL, nflags, dir);
+	MUTEX_EXIT(&softn->ipf_nat_new);
+	if (nat2 != NULL) {
+		(void) ipf_nat_proto(&fi, nat2, IPN_UDP);
+		ipf_nat_update(&fi, nat2);
+		fi.fin_ifp = NULL;
+		if (ti->ti_rule->in_redir == NAT_MAP) {
+			fi.fin_src6 = nat->nat_ndst6;
+			fi.fin_dst6 = nat->nat_nsrc6;
+			if (nat->nat_v[0] == 4) {
+				ip->ip_src = nat->nat_ndstip;
+				ip->ip_dst = nat->nat_nsrcip;
+			} else {
+#ifdef USE_INET6
+				ip6->ip6_src = nat->nat_ndst6.in6;
+				ip6->ip6_dst = nat->nat_nsrc6.in6;
+#endif
+			}
+		} else {
+			fi.fin_src6 = nat->nat_odst6;
+			fi.fin_dst6 = nat->nat_osrc6;
+			if (fin->fin_v == 4) {
+				ip->ip_src = nat->nat_odstip;
+				ip->ip_dst = nat->nat_osrcip;
+			} else {
+#ifdef USE_INET6
+				ip6->ip6_src = nat->nat_odst6.in6;
+				ip6->ip6_dst = nat->nat_osrc6.in6;
+#endif
+			}
+		}
+		if (ipf_state_add(softc, &fi, NULL, SI_W_SPORT) != 0) {
+			ipf_nat_setpending(softc, nat2);
+		}
+	}
+	if (nat->nat_v[0] == 4) {
+		ip->ip_len = slen;
+		ip->ip_src = swip;
+		ip->ip_dst = sw2ip;
+	} else {
+#ifdef USE_INET6
+		ip6->ip6_plen = slen;
+		ip6->ip6_src = swip6.in6;
+		ip6->ip6_dst = sw2ip6.in6;
+#endif
+	}
+	return 0;
+}
+
+
+int
+ipf_p_tftp_client(softt, fin, aps, nat)
+	ipf_tftp_softc_t *softt;
+	fr_info_t *fin;
+	ap_session_t *aps;
+	nat_t *nat;
+{
+	u_char *msg, *s, *t;
+	tftpinfo_t *ti;
+	u_short opcode;
+	udphdr_t *udp;
+	int len;
+
+	if (fin->fin_dlen < 4)
+		return 0;
+
+	ti = aps->aps_data;
+	msg = fin->fin_dp;
+	msg += sizeof(udphdr_t);
+	opcode = (msg[0] << 8) | msg[1];
+	DT3(tftp_cmd, fr_info_t *, fin, int, opcode, nat_t *, nat);
+
+	switch (opcode)
+	{
+	case TFTP_CMD_WRITE :
+		if (softt->ipf_p_tftp_readonly != 0) 
+			break;
+		/* FALLTHROUGH */
+	case TFTP_CMD_READ :
+		len = fin->fin_dlen - sizeof(*udp) - 2;
+		if (len > sizeof(ti->ti_filename) - 1)
+			len = sizeof(ti->ti_filename) - 1;
+		s = msg + 2;
+		for (t = (u_char *)ti->ti_filename; (len > 0); len--, s++) {
+			*t++ = *s;
+			if (*s == '\0')
+				break;
+		}
+		ipf_p_tftp_backchannel(fin, aps, nat);
+		break;
+	default :
+		return -1;
+	}
+
+	ti = aps->aps_data;
+	ti->ti_lastcmd = opcode;
+	return 0;
+}
+
+
+int
+ipf_p_tftp_server(softt, fin, aps, nat)
+	ipf_tftp_softc_t *softt;
+	fr_info_t *fin;
+	ap_session_t *aps;
+	nat_t *nat;
+{
+	tftpinfo_t *ti;
+	u_short opcode;
+	u_short arg;
+	u_char *msg;
+
+	if (fin->fin_dlen < 4)
+		return 0;
+
+	ti = aps->aps_data;
+	msg = fin->fin_dp;
+	msg += sizeof(udphdr_t);
+	arg = (msg[2] << 8) | msg[3];
+	opcode = (msg[0] << 8) | msg[1];
+
+	switch (opcode)
+	{
+	case TFTP_CMD_ACK :
+		ti->ti_lastblk = arg;
+		break;
+
+	case TFTP_CMD_ERROR :
+		ti->ti_lasterror = arg;
+		break;
+
+	default :
+		return -1;
+	}
+
+	ti->ti_lastcmd = opcode;
+	return 0;
+}


Property changes on: trunk/sys/contrib/ipfilter/netinet/ip_tftp_pxy.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/contrib/ipfilter/netinet/ipf_rb.h
===================================================================
--- trunk/sys/contrib/ipfilter/netinet/ipf_rb.h	                        (rev 0)
+++ trunk/sys/contrib/ipfilter/netinet/ipf_rb.h	2018-05-28 18:56:30 UTC (rev 10139)
@@ -0,0 +1,365 @@
+/* $MidnightBSD$ */
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ */
+typedef enum rbcolour_e {
+	C_BLACK = 0,
+	C_RED = 1
+} rbcolour_t;
+
+#define	RBI_LINK(_n, _t)							\
+	struct _n##_rb_link {						\
+		struct _t	*left;					\
+		struct _t	*right;					\
+		struct _t	*parent;				\
+		rbcolour_t	colour;					\
+	}
+
+#define	RBI_HEAD(_n, _t)						\
+struct _n##_rb_head {							\
+	struct _t	top;						\
+	int		count;						\
+	int		(* compare)(struct _t *, struct _t *);		\
+}
+
+#define	RBI_CODE(_n, _t, _f, _cmp)					\
+									\
+typedef	void	(*_n##_rb_walker_t)(_t *, void *);			\
+									\
+_t *	_n##_rb_delete(struct _n##_rb_head *, _t *);			\
+void	_n##_rb_init(struct _n##_rb_head *);				\
+void	_n##_rb_insert(struct _n##_rb_head *, _t *);			\
+_t *	_n##_rb_search(struct _n##_rb_head *, void *);			\
+void	_n##_rb_walktree(struct _n##_rb_head *, _n##_rb_walker_t, void *);\
+									\
+static void								\
+rotate_left(struct _n##_rb_head *head, _t *node)			\
+{									\
+	_t *parent, *tmp1, *tmp2;					\
+									\
+	parent = node->_f.parent;					\
+	tmp1 = node->_f.right;						\
+	tmp2 = tmp1->_f.left;						\
+	node->_f.right = tmp2;						\
+	if (tmp2 != & _n##_rb_zero)					\
+		tmp2->_f.parent = node;					\
+	if (parent == & _n##_rb_zero)					\
+		head->top._f.right = tmp1;				\
+	else if (parent->_f.right == node)				\
+		parent->_f.right = tmp1;				\
+	else								\
+		parent->_f.left = tmp1;					\
+	tmp1->_f.left = node;						\
+	tmp1->_f.parent = parent;					\
+	node->_f.parent = tmp1;						\
+}									\
+									\
+static void								\
+rotate_right(struct _n##_rb_head *head, _t *node)			\
+{									\
+	_t *parent, *tmp1, *tmp2;					\
+									\
+	parent = node->_f.parent;					\
+	tmp1 = node->_f.left;						\
+	tmp2 = tmp1->_f.right;						\
+	node->_f.left = tmp2;						\
+	if (tmp2 != &_n##_rb_zero)					\
+		tmp2->_f.parent = node;					\
+	if (parent == &_n##_rb_zero)					\
+		head->top._f.right = tmp1;				\
+	else if (parent->_f.right == node)				\
+		parent->_f.right = tmp1;				\
+	else								\
+		parent->_f.left = tmp1;					\
+	tmp1->_f.right = node;						\
+	tmp1->_f.parent = parent;					\
+	node->_f.parent = tmp1;						\
+}									\
+									\
+void									\
+_n##_rb_insert(struct _n##_rb_head *head, _t *node)			\
+{									\
+	_t *n, *parent, **p, *tmp1, *gparent;				\
+									\
+	parent = &head->top;						\
+	node->_f.left = &_n##_rb_zero;					\
+	node->_f.right = &_n##_rb_zero;					\
+	p = &head->top._f.right;					\
+	while ((n = *p) != &_n##_rb_zero) {				\
+		if (_cmp(node, n) < 0)					\
+			p = &n->_f.left;				\
+		else							\
+			p = &n->_f.right;				\
+		parent = n;						\
+	}								\
+	*p = node;							\
+	node->_f.colour = C_RED;					\
+	node->_f.parent = parent;					\
+									\
+	while ((node != &_n##_rb_zero) && (parent->_f.colour == C_RED)){\
+		gparent = parent->_f.parent;				\
+		if (parent == gparent->_f.left) {			\
+			tmp1 = gparent->_f.right;			\
+			if (tmp1->_f.colour == C_RED) {			\
+				parent->_f.colour = C_BLACK;		\
+				tmp1->_f.colour = C_BLACK;		\
+				gparent->_f.colour = C_RED;		\
+				node = gparent;				\
+			} else {					\
+				if (node == parent->_f.right) {		\
+					node = parent;			\
+					rotate_left(head, node);	\
+					parent = node->_f.parent;	\
+				}					\
+				parent->_f.colour = C_BLACK;		\
+				gparent->_f.colour = C_RED;		\
+				rotate_right(head, gparent);		\
+			}						\
+		} else {						\
+			tmp1 = gparent->_f.left;			\
+			if (tmp1->_f.colour == C_RED) {			\
+				parent->_f.colour = C_BLACK;		\
+				tmp1->_f.colour = C_BLACK;		\
+				gparent->_f.colour = C_RED;		\
+				node = gparent;				\
+			} else {					\
+				if (node == parent->_f.left) {		\
+					node = parent;			\
+					rotate_right(head, node);	\
+					parent = node->_f.parent;	\
+				}					\
+				parent->_f.colour = C_BLACK;		\
+				gparent->_f.colour = C_RED;		\
+				rotate_left(head, parent->_f.parent);	\
+			}						\
+		}							\
+		parent = node->_f.parent;				\
+	}								\
+	head->top._f.right->_f.colour = C_BLACK;			\
+	head->count++;						\
+}									\
+									\
+static void								\
+deleteblack(struct _n##_rb_head *head, _t *parent, _t *node)		\
+{									\
+	_t *tmp;							\
+									\
+	while ((node == &_n##_rb_zero || node->_f.colour == C_BLACK) &&	\
+	       node != &head->top) {					\
+		if (parent->_f.left == node) {				\
+			tmp = parent->_f.right;				\
+			if (tmp->_f.colour == C_RED) {			\
+				tmp->_f.colour = C_BLACK;		\
+				parent->_f.colour = C_RED;		\
+				rotate_left(head, parent);		\
+				tmp = parent->_f.right;			\
+			}						\
+			if ((tmp->_f.left == &_n##_rb_zero ||		\
+			     tmp->_f.left->_f.colour == C_BLACK) &&	\
+			    (tmp->_f.right == &_n##_rb_zero ||		\
+			     tmp->_f.right->_f.colour == C_BLACK)) {	\
+				tmp->_f.colour = C_RED;			\
+				node = parent;				\
+				parent = node->_f.parent;		\
+			} else {					\
+				if (tmp->_f.right == &_n##_rb_zero ||	\
+				    tmp->_f.right->_f.colour == C_BLACK) {\
+					_t *tmp2 = tmp->_f.left;	\
+									\
+					if (tmp2 != &_n##_rb_zero)	\
+						tmp2->_f.colour = C_BLACK;\
+					tmp->_f.colour = C_RED;		\
+					rotate_right(head, tmp);	\
+					tmp = parent->_f.right;		\
+				}					\
+				tmp->_f.colour = parent->_f.colour;	\
+				parent->_f.colour = C_BLACK;		\
+				if (tmp->_f.right != &_n##_rb_zero)	\
+					tmp->_f.right->_f.colour = C_BLACK;\
+				rotate_left(head, parent);		\
+				node = head->top._f.right;		\
+			}						\
+		} else {						\
+			tmp = parent->_f.left;				\
+			if (tmp->_f.colour == C_RED) {			\
+				tmp->_f.colour = C_BLACK;		\
+				parent->_f.colour = C_RED;		\
+				rotate_right(head, parent);		\
+				tmp = parent->_f.left;			\
+			}						\
+			if ((tmp->_f.left == &_n##_rb_zero ||		\
+			     tmp->_f.left->_f.colour == C_BLACK) &&	\
+			    (tmp->_f.right == &_n##_rb_zero ||		\
+			     tmp->_f.right->_f.colour == C_BLACK)) {	\
+				tmp->_f.colour = C_RED;			\
+				node = parent;				\
+				parent = node->_f.parent;		\
+			} else {					\
+				if (tmp->_f.left == &_n##_rb_zero ||	\
+				    tmp->_f.left->_f.colour == C_BLACK) {\
+					_t *tmp2 = tmp->_f.right;	\
+									\
+					if (tmp2 != &_n##_rb_zero)	\
+						tmp2->_f.colour = C_BLACK;\
+					tmp->_f.colour = C_RED;		\
+					rotate_left(head, tmp);		\
+					tmp = parent->_f.left;		\
+				}					\
+				tmp->_f.colour = parent->_f.colour;	\
+				parent->_f.colour = C_BLACK;		\
+				if (tmp->_f.left != &_n##_rb_zero)	\
+					tmp->_f.left->_f.colour = C_BLACK;\
+				rotate_right(head, parent);		\
+				node = head->top._f.right;		\
+				break;					\
+			}						\
+		}							\
+	}								\
+	if (node != &_n##_rb_zero)					\
+		node->_f.colour = C_BLACK;				\
+}									\
+									\
+_t *									\
+_n##_rb_delete(struct _n##_rb_head *head, _t *node)			\
+{									\
+	_t *child, *parent, *old = node, *left;				\
+	rbcolour_t color;						\
+									\
+	if (node->_f.left == &_n##_rb_zero) {				\
+		child = node->_f.right;					\
+	} else if (node->_f.right == &_n##_rb_zero) {			\
+		child = node->_f.left;					\
+	} else {							\
+		node = node->_f.right;					\
+		while ((left = node->_f.left) != &_n##_rb_zero)		\
+			node = left;					\
+		child = node->_f.right;					\
+		parent = node->_f.parent;				\
+		color = node->_f.colour;				\
+		if (child != &_n##_rb_zero)				\
+			child->_f.parent = parent;			\
+		if (parent != &_n##_rb_zero) {				\
+			if (parent->_f.left == node)			\
+				parent->_f.left = child;		\
+			else						\
+				parent->_f.right = child;		\
+		} else {						\
+			head->top._f.right = child;			\
+		}							\
+		if (node->_f.parent == old)				\
+			parent = node;					\
+		*node = *old;						\
+		if (old->_f.parent != &_n##_rb_zero) {			\
+			if (old->_f.parent->_f.left == old)		\
+				old->_f.parent->_f.left = node;		\
+			else						\
+				old->_f.parent->_f.right = node;	\
+		} else {						\
+			head->top._f.right = child;			\
+		}							\
+		old->_f.left->_f.parent = node;				\
+		if (old->_f.right != &_n##_rb_zero)			\
+			old->_f.right->_f.parent = node;		\
+		if (parent != &_n##_rb_zero) {				\
+			left = parent;					\
+		}							\
+		goto colour;						\
+	}								\
+	parent = node->_f.parent;					\
+	color= node->_f.colour;						\
+	if (child != &_n##_rb_zero)					\
+		child->_f.parent = parent;				\
+	if (parent != &_n##_rb_zero) {					\
+		if (parent->_f.left == node)				\
+			parent->_f.left = child;			\
+		else							\
+			parent->_f.right = child;			\
+	} else {							\
+		head->top._f.right = child;				\
+	}								\
+colour:									\
+	if (color == C_BLACK)						\
+		deleteblack(head, parent, node);			\
+	head->count--;							\
+	return old;							\
+}									\
+									\
+void									\
+_n##_rb_init(struct _n##_rb_head *head)					\
+{									\
+	memset(head, 0, sizeof(*head));					\
+	memset(&_n##_rb_zero, 0, sizeof(_n##_rb_zero));			\
+	head->top._f.left = &_n##_rb_zero;				\
+	head->top._f.right = &_n##_rb_zero;				\
+	head->top._f.parent = &head->top;				\
+	_n##_rb_zero._f.left = &_n##_rb_zero;				\
+	_n##_rb_zero._f.right = &_n##_rb_zero;				\
+	_n##_rb_zero._f.parent = &_n##_rb_zero;				\
+}									\
+									\
+void									\
+_n##_rb_walktree(struct _n##_rb_head *head, _n##_rb_walker_t func, void *arg)\
+{									\
+	_t *prev;							\
+	_t *next;							\
+	_t *node = head->top._f.right;					\
+	_t *base;							\
+									\
+	while (node != &_n##_rb_zero)					\
+		node = node->_f.left;					\
+									\
+	for (;;) {							\
+		base = node;						\
+		prev = node;						\
+		while ((node->_f.parent->_f.right == node) &&		\
+		       (node != &_n##_rb_zero))	{			\
+			prev = node;					\
+			node = node->_f.parent;				\
+		}							\
+									\
+		node = prev;						\
+		for (node = node->_f.parent->_f.right; node != &_n##_rb_zero;\
+		     node = node->_f.left)				\
+			prev = node;					\
+		next = prev;						\
+									\
+		if (node != &_n##_rb_zero)				\
+			func(node, arg);				\
+									\
+		node = next;						\
+		if (node == &_n##_rb_zero)				\
+			break;						\
+	}								\
+}									\
+									\
+_t *									\
+_n##_rb_search(struct _n##_rb_head *head, void *key)			\
+{									\
+	int	match;							\
+	_t	*node;							\
+	node = head->top._f.right;					\
+	while (node != &_n##_rb_zero) {					\
+		match = _cmp(key, node);				\
+		if (match == 0)						\
+			break;						\
+		if (match< 0)						\
+			node = node->_f.left;				\
+		else							\
+			node = node->_f.right;				\
+	}								\
+	if (node == &_n##_rb_zero || match != 0)			\
+		return (NULL);						\
+	return (node);							\
+}
+
+#define	RBI_DELETE(_n, _h, _v)		_n##_rb_delete(_h, _v)
+#define	RBI_FIELD(_n)			struct _n##_rb_link
+#define	RBI_INIT(_n, _h)		_n##_rb_init(_h)
+#define	RBI_INSERT(_n, _h, _v)		_n##_rb_insert(_h, _v)
+#define	RBI_ISEMPTY(_h)			((_h)->count == 0)
+#define	RBI_SEARCH(_n, _h, _k)		_n##_rb_search(_h, _k)
+#define	RBI_WALK(_n, _h, _w, _a)	_n##_rb_walktree(_h, _w, _a)
+#define	RBI_ZERO(_n)			_n##_rb_zero


Property changes on: trunk/sys/contrib/ipfilter/netinet/ipf_rb.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Modified: trunk/sys/contrib/ipfilter/netinet/ipl.h
===================================================================
--- trunk/sys/contrib/ipfilter/netinet/ipl.h	2018-05-28 18:55:30 UTC (rev 10138)
+++ trunk/sys/contrib/ipfilter/netinet/ipl.h	2018-05-28 18:56:30 UTC (rev 10139)
@@ -1,12 +1,13 @@
-/*	$FreeBSD$	*/
+/* $MidnightBSD$ */
+/*	$FreeBSD: stable/10/sys/contrib/ipfilter/netinet/ipl.h 255332 2013-09-06 23:11:19Z cy $	*/
 
 /*
- * Copyright (C) 1993-2001, 2003 by Darren Reed.
+ * Copyright (C) 2012 by Darren Reed.
  *
  * See the IPFILTER.LICENCE file for details on licencing.
  *
  * @(#)ipl.h	1.21 6/5/96
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/contrib/ipfilter/netinet/ipl.h 255332 2013-09-06 23:11:19Z cy $
  * Id: ipl.h,v 2.52.2.30 2007/10/16 09:41:00 darrenr Exp $
  */
 
@@ -13,8 +14,8 @@
 #ifndef	__IPL_H__
 #define	__IPL_H__
 
-#define	IPL_VERSION	"IP Filter: v4.1.28"
+#define	IPL_VERSION	"IP Filter: v5.1.2"
 
-#define	IPFILTER_VERSION	4012800
+#define	IPFILTER_VERSION	5010200
 
-#endif
+#endif	/* __IPL_H__ */

Modified: trunk/sys/contrib/ipfilter/netinet/mlfk_ipl.c
===================================================================
--- trunk/sys/contrib/ipfilter/netinet/mlfk_ipl.c	2018-05-28 18:55:30 UTC (rev 10138)
+++ trunk/sys/contrib/ipfilter/netinet/mlfk_ipl.c	2018-05-28 18:56:30 UTC (rev 10139)
@@ -1,9 +1,10 @@
-/*	$FreeBSD$	*/
+/* $MidnightBSD$ */
+/*	$FreeBSD: stable/10/sys/contrib/ipfilter/netinet/mlfk_ipl.c 266829 2014-05-29 02:55:07Z cy $	*/
 
 /*
- * Copyright (C) 2000 by Darren Reed.
+ * Copyright (C) 2012 by Darren Reed.
  *
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/contrib/ipfilter/netinet/mlfk_ipl.c 266829 2014-05-29 02:55:07Z cy $
  * See the IPFILTER.LICENCE file for details on licencing.
  */
 
@@ -18,21 +19,23 @@
 #include <sys/select.h>
 #if __FreeBSD_version >= 500000
 # include <sys/selinfo.h>
-#endif                  
+#endif
 #include <net/if.h>
 #include <netinet/in_systm.h>
 #include <netinet/in.h>
 
 
-#include <netinet/ipl.h>
-#include <netinet/ip_compat.h>
-#include <netinet/ip_fil.h>
-#include <netinet/ip_state.h>
-#include <netinet/ip_nat.h>
-#include <netinet/ip_auth.h>
-#include <netinet/ip_frag.h>
-#include <netinet/ip_sync.h>
+#include "netinet/ipl.h"
+#include "netinet/ip_compat.h"
+#include "netinet/ip_fil.h"
+#include "netinet/ip_state.h"
+#include "netinet/ip_nat.h"
+#include "netinet/ip_auth.h"
+#include "netinet/ip_frag.h"
+#include "netinet/ip_sync.h"
 
+extern ipf_main_softc_t ipfmain;
+
 #if __FreeBSD_version >= 502116
 static struct cdev *ipf_devs[IPL_LOGSIZE];
 #else
@@ -42,99 +45,102 @@
 static int sysctl_ipf_int ( SYSCTL_HANDLER_ARGS );
 static int ipf_modload(void);
 static int ipf_modunload(void);
+static int ipf_fbsd_sysctl_create(ipf_main_softc_t*);
+static int ipf_fbsd_sysctl_destroy(ipf_main_softc_t*);
 
+#if (__FreeBSD_version >= 500024)
+# if (__FreeBSD_version >= 502116)
+static	int	ipfopen __P((struct cdev*, int, int, struct thread *));
+static	int	ipfclose __P((struct cdev*, int, int, struct thread *));
+# else
+static	int	ipfopen __P((dev_t, int, int, struct thread *));
+static	int	ipfclose __P((dev_t, int, int, struct thread *));
+# endif /* __FreeBSD_version >= 502116 */
+#else
+static	int	ipfopen __P((dev_t, int, int, struct proc *));
+static	int	ipfclose __P((dev_t, int, int, struct proc *));
+#endif
+#if (__FreeBSD_version >= 502116)
+static	int	ipfread __P((struct cdev*, struct uio *, int));
+static	int	ipfwrite __P((struct cdev*, struct uio *, int));
+#else
+static	int	ipfread __P((dev_t, struct uio *, int));
+static	int	ipfwrite __P((dev_t, struct uio *, int));
+#endif /* __FreeBSD_version >= 502116 */
+
+
 SYSCTL_DECL(_net_inet);
 #define SYSCTL_IPF(parent, nbr, name, access, ptr, val, descr) \
 	SYSCTL_OID(parent, nbr, name, CTLTYPE_INT|access, \
 		   ptr, val, sysctl_ipf_int, "I", descr);
+#define SYSCTL_DYN_IPF(parent, nbr, name, access,ptr, val, descr) \
+	SYSCTL_ADD_OID(&ipf_clist, SYSCTL_STATIC_CHILDREN(parent), nbr, name, \
+	CTLFLAG_DYN|CTLTYPE_INT|access, ptr, val, sysctl_ipf_int, "I", descr)
+static struct sysctl_ctx_list ipf_clist;
 #define	CTLFLAG_OFF	0x00800000	/* IPFilter must be disabled */
 #define	CTLFLAG_RWO	(CTLFLAG_RW|CTLFLAG_OFF)
 SYSCTL_NODE(_net_inet, OID_AUTO, ipf, CTLFLAG_RW, 0, "IPF");
-SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_flags, CTLFLAG_RW, &fr_flags, 0, "");
-SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_pass, CTLFLAG_RW, &fr_pass, 0, "");
-SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_active, CTLFLAG_RD, &fr_active, 0, "");
+SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_flags, CTLFLAG_RW, &ipfmain.ipf_flags, 0, "IPF flags");
+SYSCTL_IPF(_net_inet_ipf, OID_AUTO, ipf_pass, CTLFLAG_RW, &ipfmain.ipf_pass, 0, "default pass/block");
+SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_active, CTLFLAG_RD, &ipfmain.ipf_active, 0, "IPF is active");
 SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcpidletimeout, CTLFLAG_RWO,
-	   &fr_tcpidletimeout, 0, "");
+	   &ipfmain.ipf_tcpidletimeout, 0, "TCP idle timeout in seconds");
 SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcphalfclosed, CTLFLAG_RWO,
-	   &fr_tcphalfclosed, 0, "");
+	   &ipfmain.ipf_tcphalfclosed, 0, "timeout for half closed TCP sessions");
 SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcpclosewait, CTLFLAG_RWO,
-	   &fr_tcpclosewait, 0, "");
+	   &ipfmain.ipf_tcpclosewait, 0, "timeout for TCP sessions in closewait status");
 SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcplastack, CTLFLAG_RWO,
-	   &fr_tcplastack, 0, "");
+	   &ipfmain.ipf_tcplastack, 0, "timeout for TCP sessions in last ack status");
 SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcptimeout, CTLFLAG_RWO,
-	   &fr_tcptimeout, 0, "");
+	   &ipfmain.ipf_tcptimeout, 0, "");
 SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcpclosed, CTLFLAG_RWO,
-	   &fr_tcpclosed, 0, "");
+	   &ipfmain.ipf_tcpclosed, 0, "");
 SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_udptimeout, CTLFLAG_RWO,
-	   &fr_udptimeout, 0, "");
+	   &ipfmain.ipf_udptimeout, 0, "UDP timeout");
 SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_udpacktimeout, CTLFLAG_RWO,
-	   &fr_udpacktimeout, 0, "");
+	   &ipfmain.ipf_udpacktimeout, 0, "");
 SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_icmptimeout, CTLFLAG_RWO,
-	   &fr_icmptimeout, 0, "");
-SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_defnatage, CTLFLAG_RWO,
-	   &fr_defnatage, 0, "");
-SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_ipfrttl, CTLFLAG_RW,
-	   &fr_ipfrttl, 0, "");
+	   &ipfmain.ipf_icmptimeout, 0, "ICMP timeout");
 SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_running, CTLFLAG_RD,
-	   &fr_running, 0, "");
-SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_statesize, CTLFLAG_RWO,
-	   &fr_statesize, 0, "");
-SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_statemax, CTLFLAG_RWO,
-	   &fr_statemax, 0, "");
-SYSCTL_IPF(_net_inet_ipf, OID_AUTO, ipf_nattable_sz, CTLFLAG_RWO,
-	   &ipf_nattable_sz, 0, "");
-SYSCTL_IPF(_net_inet_ipf, OID_AUTO, ipf_natrules_sz, CTLFLAG_RWO,
-	   &ipf_natrules_sz, 0, "");
-SYSCTL_IPF(_net_inet_ipf, OID_AUTO, ipf_rdrrules_sz, CTLFLAG_RWO,
-	   &ipf_rdrrules_sz, 0, "");
-SYSCTL_IPF(_net_inet_ipf, OID_AUTO, ipf_hostmap_sz, CTLFLAG_RWO,
-	   &ipf_hostmap_sz, 0, "");
-SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_authsize, CTLFLAG_RWO,
-	   &fr_authsize, 0, "");
-SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_authused, CTLFLAG_RD,
-	   &fr_authused, 0, "");
-SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_defaultauthage, CTLFLAG_RW,
-	   &fr_defaultauthage, 0, "");
-SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_chksrc, CTLFLAG_RW, &fr_chksrc, 0, "");
-SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_minttl, CTLFLAG_RW, &fr_minttl, 0, "");
+	   &ipfmain.ipf_running, 0, "IPF is running");
+SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_chksrc, CTLFLAG_RW, &ipfmain.ipf_chksrc, 0, "");
+SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_minttl, CTLFLAG_RW, &ipfmain.ipf_minttl, 0, "");
 
 #define CDEV_MAJOR 79
 #include <sys/poll.h>
 #if __FreeBSD_version >= 500043
 # include <sys/select.h>
-static int iplpoll(struct cdev *dev, int events, struct thread *td);
+static int ipfpoll(struct cdev *dev, int events, struct thread *td);
 
-static struct cdevsw ipl_cdevsw = {
-# if __FreeBSD_version >= 502103
+static struct cdevsw ipf_cdevsw = {
+#if __FreeBSD_version >= 502103
 	.d_version =	D_VERSION,
 	.d_flags =	0,	/* D_NEEDGIANT - Should be SMP safe */
-# endif
-	.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
+#endif
+	.d_open =	ipfopen,
+	.d_close =	ipfclose,
+	.d_read =	ipfread,
+	.d_write =	ipfwrite,
+	.d_ioctl =	ipfioctl,
+	.d_poll =	ipfpoll,
+	.d_name =	"ipf",
+#if __FreeBSD_version < 600000
 	.d_maj =	CDEV_MAJOR,
-# endif
+#endif
 };
 #else
-static int iplpoll(dev_t dev, int events, struct proc *p);
+static int ipfpoll(dev_t dev, int events, struct proc *td);
 
-static struct cdevsw ipl_cdevsw = {
-	/* open */	iplopen,
-	/* close */	iplclose,
-	/* read */	iplread,
-	/* write */	iplwrite,
-	/* ioctl */	iplioctl,
-	/* poll */	iplpoll,
+static struct cdevsw ipf_cdevsw = {
+	/* open */	ipfopen,
+	/* close */	ipfclose,
+	/* read */	ipfread,
+	/* write */	ipfwrite,
+	/* ioctl */	ipfioctl,
+	/* poll */	ipfpoll,
 	/* mmap */	nommap,
 	/* strategy */	nostrategy,
-	/* name */	"ipl",
+	/* name */	"ipf",
 	/* maj */	CDEV_MAJOR,
 	/* dump */	nodump,
 	/* psize */	nopsize,
@@ -142,7 +148,7 @@
 # if (__FreeBSD_version < 500043)
 	/* bmaj */	-1,
 # endif
-# if (__FreeBSD_version > 430000)
+# if (__FreeBSD_version >= 430000)
 	/* kqfilter */	NULL
 # endif
 };
@@ -151,7 +157,6 @@
 static char *ipf_devfiles[] = {	IPL_NAME, IPNAT_NAME, IPSTATE_NAME, IPAUTH_NAME,
 				IPSYNC_NAME, IPSCAN_NAME, IPLOOKUP_NAME, NULL };
 
-
 static int
 ipfilter_modevent(module_t mod, int type, void *unused)
 {
@@ -180,17 +185,18 @@
 	char *defpass, *c, *str;
 	int i, j, error;
 
-	RWLOCK_INIT(&ipf_global, "ipf filter load/unload mutex");
-	RWLOCK_INIT(&ipf_mutex, "ipf filter rwlock");
-	RWLOCK_INIT(&ipf_frcache, "ipf cache rwlock");
+	if (ipf_load_all() != 0)
+		return EIO;
 
-	error = ipfattach();
-	if (error) {
-		RW_DESTROY(&ipf_global);
-		RW_DESTROY(&ipf_mutex);
-		RW_DESTROY(&ipf_frcache);
+	if (ipf_create_all(&ipfmain) == NULL)
+		return EIO;
+
+	if (ipf_fbsd_sysctl_create(&ipfmain) != 0)
+		return EIO;
+
+	error = ipfattach(&ipfmain);
+	if (error)
 		return error;
-	}
 
 	for (i = 0; i < IPL_LOGSIZE; i++)
 		ipf_devs[i] = NULL;
@@ -204,7 +210,7 @@
 			}
 		if (!c)
 			c = str;
-		ipf_devs[i] = make_dev(&ipl_cdevsw, i, 0, 0, 0600, "%s", c);
+		ipf_devs[i] = make_dev(&ipf_cdevsw, i, 0, 0, 0600, "%s", c);
 	}
 
 	error = ipf_pfil_hook();
@@ -212,15 +218,15 @@
 		return error;
 	ipf_event_reg();
 
-	if (FR_ISPASS(fr_pass))
+	if (FR_ISPASS(ipfmain.ipf_pass))
 		defpass = "pass";
-	else if (FR_ISBLOCK(fr_pass))
+	else if (FR_ISBLOCK(ipfmain.ipf_pass))
 		defpass = "block";
-	else          
+	else
 		defpass = "no-match -> block";
 
 	printf("%s initialized.  Default = %s all, Logging = %s%s\n",
-		ipfilter_version, defpass,                
+		ipfilter_version, defpass,
 #ifdef IPFILTER_LOG
 		"enabled",
 #else
@@ -231,7 +237,7 @@
 #else
 		""
 #endif
-		);         
+		);
 	return 0;
 }
 
@@ -241,26 +247,29 @@
 {
 	int error, i;
 
-	if (fr_refcnt)
+	if (ipfmain.ipf_refcnt)
 		return EBUSY;
 
-	if (fr_running >= 0) {
-		ipf_pfil_unhook();
-		ipf_event_dereg();
-		WRITE_ENTER(&ipf_global);
-		error = ipfdetach();
-		RWLOCK_EXIT(&ipf_global);
+	if (ipf_fbsd_sysctl_destroy(&ipfmain) != 0)
+		return EIO;
+
+	error = ipf_pfil_unhook();
+	if (error != 0)
+		return error;
+
+	if (ipfmain.ipf_running >= 0) {
+		error = ipfdetach(&ipfmain);
 		if (error != 0)
 			return error;
+
+		ipf_fbsd_sysctl_destroy(&ipfmain);
+		ipf_destroy_all(&ipfmain);
+		ipf_unload_all();
 	} else
 		error = 0;
 
-	RW_DESTROY(&ipf_global);
-	RW_DESTROY(&ipf_mutex);
-	RW_DESTROY(&ipf_frcache);
+	ipfmain.ipf_running = -2;
 
-	fr_running = -2;
-
 	for (i = 0; ipf_devfiles[i]; i++) {
 		if (ipf_devs[i] != NULL)
 			destroy_dev(ipf_devs[i]);
@@ -302,7 +311,7 @@
 	if (!arg1)
 		error = EPERM;
 	else {
-		if ((oidp->oid_kind & CTLFLAG_OFF) && (fr_running > 0))
+		if ((oidp->oid_kind & CTLFLAG_OFF) && (ipfmain.ipf_running > 0))
 			error = EBUSY;
 		else
 			error = SYSCTL_IN(req, arg1, sizeof(int));
@@ -314,40 +323,38 @@
 
 static int
 #if __FreeBSD_version >= 500043
-iplpoll(struct cdev *dev, int events, struct thread *td)
+ipfpoll(struct cdev *dev, int events, struct thread *td)
 #else
-iplpoll(dev_t dev, int events, struct proc *td)
+ipfpoll(dev_t dev, int events, struct proc *td)
 #endif
 {
-	u_int xmin = GET_MINOR(dev);
+	int unit = GET_MINOR(dev);
 	int revents;
 
-	if (xmin < 0 || xmin > IPL_LOGMAX)
+	if (unit < 0 || unit > IPL_LOGMAX)
 		return 0;
 
 	revents = 0;
 
-	switch (xmin) 
+	switch (unit)
 	{
 	case IPL_LOGIPF :
 	case IPL_LOGNAT :
 	case IPL_LOGSTATE :
 #ifdef IPFILTER_LOG
-		if ((events & (POLLIN | POLLRDNORM)) && ipflog_canread(xmin))
+		if ((events & (POLLIN | POLLRDNORM)) && ipf_log_canread(&ipfmain, unit))
 			revents |= events & (POLLIN | POLLRDNORM);
-#endif  
+#endif
 		break;
 	case IPL_LOGAUTH :
-		if ((events & (POLLIN | POLLRDNORM)) && fr_auth_waiting())
+		if ((events & (POLLIN | POLLRDNORM)) && ipf_auth_waiting(&ipfmain))
 			revents |= events & (POLLIN | POLLRDNORM);
-		break; 
+		break;
 	case IPL_LOGSYNC :
-#ifdef IPFILTER_SYNC
-		if ((events & (POLLIN | POLLRDNORM)) && ipfsync_canread())
+		if ((events & (POLLIN | POLLRDNORM)) && ipf_sync_canread(&ipfmain))
 			revents |= events & (POLLIN | POLLRDNORM);
-		if ((events & (POLLOUT | POLLWRNORM)) && ipfsync_canwrite())
+		if ((events & (POLLOUT | POLLWRNORM)) && ipf_sync_canwrite(&ipfmain))
 			revents |= events & (POLLOUT | POLLWRNORM);
-#endif
 		break;
 	case IPL_LOGSCAN :
 	case IPL_LOGLOOKUP :
@@ -356,7 +363,207 @@
 	}
 
 	if ((revents == 0) && ((events & (POLLIN|POLLRDNORM)) != 0))
-		selrecord(td, &ipfselwait[xmin]);
+		selrecord(td, &ipfmain.ipf_selwait[unit]);
 
 	return revents;
 }
+
+
+/*
+ * routines below for saving IP headers to buffer
+ */
+static int ipfopen(dev, flags
+#if ((BSD >= 199506) || (__FreeBSD_version >= 220000))
+, devtype, p)
+	int devtype;
+# if (__FreeBSD_version >= 500024)
+	struct thread *p;
+# else
+	struct proc *p;
+# endif /* __FreeBSD_version >= 500024 */
+#else
+)
+#endif
+#if (__FreeBSD_version >= 502116)
+	struct cdev *dev;
+#else
+	dev_t dev;
+#endif
+	int flags;
+{
+	int unit = GET_MINOR(dev);
+	int error;
+
+	if (IPL_LOGMAX < unit)
+		error = ENXIO;
+	else {
+		switch (unit)
+		{
+		case IPL_LOGIPF :
+		case IPL_LOGNAT :
+		case IPL_LOGSTATE :
+		case IPL_LOGAUTH :
+		case IPL_LOGLOOKUP :
+		case IPL_LOGSYNC :
+#ifdef IPFILTER_SCAN
+		case IPL_LOGSCAN :
+#endif
+			error = 0;
+			break;
+		default :
+			error = ENXIO;
+			break;
+		}
+	}
+	return error;
+}
+
+
+static int ipfclose(dev, flags
+#if ((BSD >= 199506) || (__FreeBSD_version >= 220000))
+, devtype, p)
+	int devtype;
+# if (__FreeBSD_version >= 500024)
+	struct thread *p;
+# else
+	struct proc *p;
+# endif /* __FreeBSD_version >= 500024 */
+#else
+)
+#endif
+#if (__FreeBSD_version >= 502116)
+	struct cdev *dev;
+#else
+	dev_t dev;
+#endif
+	int flags;
+{
+	int	unit = GET_MINOR(dev);
+
+	if (IPL_LOGMAX < unit)
+		unit = ENXIO;
+	else
+		unit = 0;
+	return unit;
+}
+
+/*
+ * ipfread/ipflog
+ * both of these must operate with at least splnet() lest they be
+ * called during packet processing and cause an inconsistancy to appear in
+ * the filter lists.
+ */
+#if (BSD >= 199306)
+static int ipfread(dev, uio, ioflag)
+	int ioflag;
+#else
+static int ipfread(dev, uio)
+#endif
+#if (__FreeBSD_version >= 502116)
+	struct cdev *dev;
+#else
+	dev_t dev;
+#endif
+	struct uio *uio;
+{
+	int	unit = GET_MINOR(dev);
+
+	if (unit < 0)
+		return ENXIO;
+
+	if (ipfmain.ipf_running < 1)
+		return EIO;
+
+	if (unit == IPL_LOGSYNC)
+		return ipf_sync_read(&ipfmain, uio);
+
+#ifdef IPFILTER_LOG
+	return ipf_log_read(&ipfmain, unit, uio);
+#else
+	return ENXIO;
+#endif
+}
+
+
+/*
+ * ipfwrite
+ * both of these must operate with at least splnet() lest they be
+ * called during packet processing and cause an inconsistancy to appear in
+ * the filter lists.
+ */
+#if (BSD >= 199306)
+static int ipfwrite(dev, uio, ioflag)
+	int ioflag;
+#else
+static int ipfwrite(dev, uio)
+#endif
+#if (__FreeBSD_version >= 502116)
+	struct cdev *dev;
+#else
+	dev_t dev;
+#endif
+	struct uio *uio;
+{
+
+	if (ipfmain.ipf_running < 1)
+		return EIO;
+
+	if (GET_MINOR(dev) == IPL_LOGSYNC)
+		return ipf_sync_write(&ipfmain, uio);
+	return ENXIO;
+}
+
+static int
+ipf_fbsd_sysctl_create(main_softc)
+	ipf_main_softc_t *main_softc;
+{
+	ipf_nat_softc_t	*nat_softc;
+	ipf_state_softc_t *state_softc;
+	ipf_auth_softc_t *auth_softc;
+	ipf_frag_softc_t *frag_softc;
+
+	nat_softc = main_softc->ipf_nat_soft;
+	state_softc = main_softc->ipf_state_soft;
+	auth_softc = main_softc->ipf_auth_soft;
+	frag_softc = main_softc->ipf_frag_soft;
+
+	sysctl_ctx_init(&ipf_clist);
+
+	SYSCTL_DYN_IPF(_net_inet_ipf, OID_AUTO, "fr_defnatage", CTLFLAG_RWO,
+	    &nat_softc->ipf_nat_defage, 0, "");
+	SYSCTL_DYN_IPF(_net_inet_ipf, OID_AUTO, "fr_statesize", CTLFLAG_RWO,
+	    &state_softc->ipf_state_size, 0, "");
+	SYSCTL_DYN_IPF(_net_inet_ipf, OID_AUTO, "fr_statemax", CTLFLAG_RWO,
+	    &state_softc->ipf_state_max, 0, "");
+	SYSCTL_DYN_IPF(_net_inet_ipf, OID_AUTO, "ipf_nattable_max", CTLFLAG_RWO,
+	    &nat_softc->ipf_nat_table_max, 0, "");
+	SYSCTL_DYN_IPF(_net_inet_ipf, OID_AUTO, "ipf_nattable_sz", CTLFLAG_RWO,
+	    &nat_softc->ipf_nat_table_sz, 0, "");
+	SYSCTL_DYN_IPF(_net_inet_ipf, OID_AUTO, "ipf_natrules_sz", CTLFLAG_RWO,
+	    &nat_softc->ipf_nat_maprules_sz, 0, "");
+	SYSCTL_DYN_IPF(_net_inet_ipf, OID_AUTO, "ipf_rdrrules_sz", CTLFLAG_RWO,
+	    &nat_softc->ipf_nat_rdrrules_sz, 0, "");
+	SYSCTL_DYN_IPF(_net_inet_ipf, OID_AUTO, "ipf_hostmap_sz", CTLFLAG_RWO,
+	    &nat_softc->ipf_nat_hostmap_sz, 0, "");
+	SYSCTL_DYN_IPF(_net_inet_ipf, OID_AUTO, "fr_authsize", CTLFLAG_RWO,
+	   &auth_softc->ipf_auth_size, 0, "");
+	SYSCTL_DYN_IPF(_net_inet_ipf, OID_AUTO, "fr_authused", CTLFLAG_RD,
+	   &auth_softc->ipf_auth_used, 0, "");
+	SYSCTL_DYN_IPF(_net_inet_ipf, OID_AUTO, "fr_defaultauthage", CTLFLAG_RW,
+	   &auth_softc->ipf_auth_defaultage, 0, "");
+	SYSCTL_DYN_IPF(_net_inet_ipf, OID_AUTO, "fr_ipfrttl", CTLFLAG_RW,
+	   &frag_softc->ipfr_ttl, 0, "");
+	return 0;
+}
+
+static int
+ipf_fbsd_sysctl_destroy(main_softc)
+	ipf_main_softc_t *main_softc;
+{
+	if (sysctl_ctx_free(&ipf_clist)) {
+		printf("sysctl_ctx_free failed");
+		return(ENOTEMPTY);
+	}
+	return 0;
+}
+

Added: trunk/sys/contrib/ipfilter/netinet/radix_ipf.c
===================================================================
--- trunk/sys/contrib/ipfilter/netinet/radix_ipf.c	                        (rev 0)
+++ trunk/sys/contrib/ipfilter/netinet/radix_ipf.c	2018-05-28 18:56:30 UTC (rev 10139)
@@ -0,0 +1,1531 @@
+/* $MidnightBSD$ */
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ */
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#if !defined(_KERNEL)
+# include <stddef.h>
+# include <stdlib.h>
+# include <strings.h>
+# include <string.h>
+#endif
+#include "netinet/ip_compat.h"
+#include "netinet/ip_fil.h"
+#ifdef RDX_DEBUG
+# include <arpa/inet.h>
+# include <stdlib.h>
+# include <stdio.h>
+#endif
+#include "netinet/radix_ipf.h"
+
+#define	ADF_OFF	offsetof(addrfamily_t, adf_addr)
+#define	ADF_OFF_BITS	(ADF_OFF << 3)
+
+static ipf_rdx_node_t *ipf_rx_insert __P((ipf_rdx_head_t *,
+					  ipf_rdx_node_t nodes[2], int *));
+static void ipf_rx_attach_mask __P((ipf_rdx_node_t *, ipf_rdx_mask_t *));
+static int count_mask_bits __P((addrfamily_t *, u_32_t **));
+static void buildnodes __P((addrfamily_t *, addrfamily_t *,
+			    ipf_rdx_node_t n[2]));
+static ipf_rdx_node_t *ipf_rx_find_addr __P((ipf_rdx_node_t *, u_32_t *));
+static ipf_rdx_node_t *ipf_rx_lookup __P((ipf_rdx_head_t *, addrfamily_t *,
+					  addrfamily_t *));
+static ipf_rdx_node_t *ipf_rx_match __P((ipf_rdx_head_t *, addrfamily_t *));
+
+/*
+ * Foreword.
+ * ---------
+ * The code in this file has been written to target using the addrfamily_t
+ * data structure to house the address information and no other. Thus there
+ * are certain aspects of thise code (such as offsets to the address itself)
+ * that are hard coded here whilst they might be more variable elsewhere.
+ * Similarly, this code enforces no maximum key length as that's implied by
+ * all keys needing to be stored in addrfamily_t.
+ */
+
+/* ------------------------------------------------------------------------ */
+/* Function:    count_mask_bits                                             */
+/* Returns:     number of consecutive bits starting at "mask".              */
+/*                                                                          */
+/* Count the number of bits set in the address section of addrfamily_t and  */
+/* return both that number and a pointer to the last word with a bit set if */
+/* lastp is not NULL. The bit count is performed using network byte order   */
+/* as the guide for which bit is the most significant bit.                  */
+/* ------------------------------------------------------------------------ */
+static int
+count_mask_bits(mask, lastp)
+	addrfamily_t *mask;
+	u_32_t **lastp;
+{
+	u_32_t *mp = (u_32_t *)&mask->adf_addr;
+	u_32_t m;
+	int count = 0;
+	int mlen;
+
+	mlen = mask->adf_len - offsetof(addrfamily_t, adf_addr);
+	for (; mlen > 0; mlen -= 4, mp++) {
+		if ((m = ntohl(*mp)) == 0)
+			break;
+		if (lastp != NULL)
+			*lastp = mp;
+		for (; m & 0x80000000; m <<= 1)
+			count++;
+	}
+
+	return count;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    buildnodes                                                  */
+/* Returns:     Nil                                                         */
+/* Parameters:  addr(I)  - network address for this radix node              */
+/*              mask(I)  - netmask associated with the above address        */
+/*              nodes(O) - pair of ipf_rdx_node_t's to initialise with data */
+/*                         associated with addr and mask.                   */
+/*                                                                          */
+/* Initialise the fields in a pair of radix tree nodes according to the     */
+/* data supplied in the paramters "addr" and "mask". It is expected that    */
+/* "mask" will contain a consecutive string of bits set. Masks with gaps in */
+/* the middle are not handled by this implementation.                       */
+/* ------------------------------------------------------------------------ */
+static void
+buildnodes(addr, mask, nodes)
+	addrfamily_t *addr, *mask;
+	ipf_rdx_node_t nodes[2];
+{
+	u_32_t maskbits;
+	u_32_t lastmask;
+	u_32_t *last;
+	int masklen;
+
+	last = NULL;
+	maskbits = count_mask_bits(mask, &last);
+	if (last == NULL) {
+		masklen = 0;
+		lastmask = 0;
+	} else {
+		masklen = last - (u_32_t *)mask;
+		lastmask = *last;
+	}
+
+	bzero(&nodes[0], sizeof(ipf_rdx_node_t) * 2);
+	nodes[0].maskbitcount = maskbits;
+	nodes[0].index = -1 - (ADF_OFF_BITS + maskbits);
+	nodes[0].addrkey = (u_32_t *)addr;
+	nodes[0].maskkey = (u_32_t *)mask;
+	nodes[0].addroff = nodes[0].addrkey + masklen;
+	nodes[0].maskoff = nodes[0].maskkey + masklen;
+	nodes[0].parent = &nodes[1];
+	nodes[0].offset = masklen;
+	nodes[0].lastmask = lastmask;
+	nodes[1].offset = masklen;
+	nodes[1].left = &nodes[0];
+	nodes[1].maskbitcount = maskbits;
+#ifdef RDX_DEBUG
+	(void) strcpy(nodes[0].name, "_BUILD.0");
+	(void) strcpy(nodes[1].name, "_BUILD.1");
+#endif
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_rx_find_addr                                            */
+/* Returns:     ipf_rdx_node_t * - pointer to a node in the radix tree.     */
+/* Parameters:  tree(I)  - pointer to first right node in tree to search    */
+/*              addr(I)  - pointer to address to match                      */
+/*                                                                          */
+/* Walk the radix tree given by "tree", looking for a leaf node that is a   */
+/* match for the address given by "addr".                                   */
+/* ------------------------------------------------------------------------ */
+static ipf_rdx_node_t *
+ipf_rx_find_addr(tree, addr)
+	ipf_rdx_node_t *tree;
+	u_32_t *addr;
+{
+	ipf_rdx_node_t *cur;
+
+	for (cur = tree; cur->index >= 0;) {
+		if (cur->bitmask & addr[cur->offset]) {
+			cur = cur->right;
+		} else {
+			cur = cur->left;
+		}
+	}
+
+	return (cur);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_rx_match                                                */
+/* Returns:     ipf_rdx_node_t * - NULL on error, else pointer to the node  */
+/*                                 added to the tree.                       */
+/* Paramters:   head(I)  - pointer to tree head to search                   */
+/*              addr(I)  - pointer to address to find                       */
+/*                                                                          */
+/* Search the radix tree for the best match to the address pointed to by    */
+/* "addr" and return a pointer to that node. This search will not match the */
+/* address information stored in either of the root leaves as neither of    */
+/* them are considered to be part of the tree of data being stored.         */
+/* ------------------------------------------------------------------------ */
+static ipf_rdx_node_t *
+ipf_rx_match(head, addr)
+	ipf_rdx_head_t *head;
+	addrfamily_t *addr;
+{
+	ipf_rdx_mask_t *masknode;
+	ipf_rdx_node_t *prev;
+	ipf_rdx_node_t *node;
+	ipf_rdx_node_t *cur;
+	u_32_t *data;
+	u_32_t *mask;
+	u_32_t *key;
+	u_32_t *end;
+	int len;
+	int i;
+
+	len = addr->adf_len;
+	end = (u_32_t *)((u_char *)addr + len);
+	node = ipf_rx_find_addr(head->root, (u_32_t *)addr);
+
+	/*
+	 * Search the dupkey list for a potential match.
+	 */
+	for (cur = node; (cur != NULL) && (cur->root == 0); cur = cur->dupkey) {
+		i = cur[0].addroff - cur[0].addrkey;
+		data = cur[0].addrkey + i;
+		mask = cur[0].maskkey + i;
+		key = (u_32_t *)addr + i;
+		for (; key < end; data++, key++, mask++)
+			if ((*key & *mask) != *data)
+				break;
+		if ((end == key) && (cur->root == 0))
+			return (cur);	/* Equal keys */
+	}
+	prev = node->parent;
+	key = (u_32_t *)addr;
+
+	for (node = prev; node->root == 0; node = node->parent) {
+		/*
+		 * We know that the node hasn't matched so therefore only
+		 * the entries in the mask list are searched, not the top
+		 * node nor the dupkey list.
+		 */
+		masknode = node->masks;
+		for (; masknode != NULL; masknode = masknode->next) {
+			if (masknode->maskbitcount > node->maskbitcount)
+				continue;
+			cur = masknode->node;
+			for (i = ADF_OFF >> 2; i <= node->offset; i++) {
+				if ((key[i] & masknode->mask[i]) ==
+				    cur->addrkey[i])
+					return (cur);
+			}
+		}
+	}
+
+	return NULL;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_rx_lookup                                               */
+/* Returns:     ipf_rdx_node_t * - NULL on error, else pointer to the node  */
+/*                                 added to the tree.                       */
+/* Paramters:   head(I)  - pointer to tree head to search                   */
+/*              addr(I)  - address part of the key to match                 */
+/*              mask(I)  - netmask part of the key to match                 */
+/*                                                                          */
+/* ipf_rx_lookup searches for an exact match on (addr,mask). The intention  */
+/* is to see if a given key is in the tree, not to see if a route exists.   */
+/* ------------------------------------------------------------------------ */
+ipf_rdx_node_t *
+ipf_rx_lookup(head, addr, mask)
+	ipf_rdx_head_t *head;
+	addrfamily_t *addr, *mask;
+{
+	ipf_rdx_node_t *found;
+	ipf_rdx_node_t *node;
+	u_32_t *akey;
+	int count;
+
+	found = ipf_rx_find_addr(head->root, (u_32_t *)addr);
+	if (found->root == 1)
+		return NULL;
+
+	/*
+	 * It is possible to find a matching address in the tree but for the
+	 * netmask to not match. If the netmask does not match and there is
+	 * no list of alternatives present at dupkey, return a failure.
+	 */
+	count = count_mask_bits(mask, NULL);
+	if (count != found->maskbitcount && found->dupkey == NULL)
+		return (NULL);
+
+	akey = (u_32_t *)addr;
+	if ((found->addrkey[found->offset] & found->maskkey[found->offset]) !=
+	    akey[found->offset])
+		return NULL;
+
+	if (found->dupkey != NULL) {
+		node = found;
+		while (node != NULL && node->maskbitcount != count)
+			node = node->dupkey;
+		if (node == NULL)
+			return (NULL);
+		found = node;
+	}
+	return found;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_rx_attach_mask                                          */
+/* Returns:     Nil                                                         */
+/* Parameters:  node(I)  - pointer to a radix tree node                     */
+/*              mask(I)  - pointer to mask structure to add                 */
+/*                                                                          */
+/* Add the netmask to the given node in an ordering where the most specific */
+/* netmask is at the top of the list.                                       */
+/* ------------------------------------------------------------------------ */
+static void
+ipf_rx_attach_mask(node, mask)
+	ipf_rdx_node_t *node;
+	ipf_rdx_mask_t *mask;
+{
+	ipf_rdx_mask_t **pm;
+	ipf_rdx_mask_t *m;
+
+	for (pm = &node->masks; (m = *pm) != NULL; pm = &m->next)
+		if (m->maskbitcount < mask->maskbitcount)
+			break;
+	mask->next = *pm;
+	*pm = mask;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_rx_insert                                               */
+/* Returns:     ipf_rdx_node_t * - NULL on error, else pointer to the node  */
+/*                                 added to the tree.                       */
+/* Paramters:   head(I)  - pointer to tree head to add nodes to             */
+/*              nodes(I) - pointer to radix nodes to be added               */
+/*              dup(O)   - set to 1 if node is a duplicate, else 0.         */
+/*                                                                          */
+/* Add the new radix tree entry that owns nodes[] to the tree given by head.*/
+/* If there is already a matching key in the table, "dup" will be set to 1  */
+/* and the existing node pointer returned if there is a complete key match. */
+/* A complete key match is a matching of all key data that is presented by  */
+/* by the netmask.                                                          */
+/* ------------------------------------------------------------------------ */
+static ipf_rdx_node_t *
+ipf_rx_insert(head, nodes, dup)
+	ipf_rdx_head_t *head;
+	ipf_rdx_node_t nodes[2];
+	int *dup;
+{
+	ipf_rdx_mask_t **pmask;
+	ipf_rdx_node_t *node;
+	ipf_rdx_node_t *prev;
+	ipf_rdx_mask_t *mask;
+	ipf_rdx_node_t *cur;
+	u_32_t nodemask;
+	u_32_t *addr;
+	u_32_t *data;
+	int nodebits;
+	u_32_t *key;
+	u_32_t *end;
+	u_32_t bits;
+	int nodekey;
+	int nodeoff;
+	int nlen;
+	int len;
+
+	addr = nodes[0].addrkey;
+
+	node = ipf_rx_find_addr(head->root, addr);
+	len = ((addrfamily_t *)addr)->adf_len;
+	key = (u_32_t *)&((addrfamily_t *)addr)->adf_addr;
+	data= (u_32_t *)&((addrfamily_t *)node->addrkey)->adf_addr;
+	end = (u_32_t *)((u_char *)addr + len);
+	for (nlen = 0; key < end; data++, key++, nlen += 32)
+		if (*key != *data)
+			break;
+	if (end == data) {
+		*dup = 1;
+		return (node);	/* Equal keys */
+	}
+	*dup = 0;
+
+	bits = (ntohl(*data) ^ ntohl(*key));
+	for (; bits != 0; nlen++) {
+		if ((bits & 0x80000000) != 0)
+			break;
+		bits <<= 1;
+	}
+	nlen += ADF_OFF_BITS;
+	nodes[1].index = nlen;
+	nodes[1].bitmask = htonl(0x80000000 >> (nlen & 0x1f));
+	nodes[0].offset = nlen / 32;
+	nodes[1].offset = nlen / 32;
+
+	/*
+	 * Walk through the tree and look for the correct place to attach
+	 * this node. ipf_rx_fin_addr is not used here because the place
+	 * to attach this node may be an internal node (same key, different
+	 * netmask.) Additionally, the depth of the search is forcibly limited
+	 * here to not exceed the netmask, so that a short netmask will be
+	 * added higher up the tree even if there are lower branches.
+	 */
+	cur = head->root;
+	key = nodes[0].addrkey;
+	do {
+		prev = cur;
+		if (key[cur->offset] & cur->bitmask) {
+			cur = cur->right;
+		} else {
+			cur = cur->left;
+		}
+	} while (nlen > (unsigned)cur->index);
+
+	if ((key[prev->offset] & prev->bitmask) == 0) {
+		prev->left = &nodes[1];
+	} else {
+		prev->right = &nodes[1];
+	}
+	cur->parent = &nodes[1];
+	nodes[1].parent = prev;
+	if ((key[nodes[1].offset] & nodes[1].bitmask) == 0) {
+		nodes[1].right = cur;
+	} else {
+		nodes[1].right = &nodes[0];
+		nodes[1].left = cur;
+	}
+
+	nodeoff = nodes[0].offset;
+	nodekey = nodes[0].addrkey[nodeoff];
+	nodemask = nodes[0].lastmask;
+	nodebits = nodes[0].maskbitcount;
+	prev = NULL;
+	/*
+	 * Find the node up the tree with the largest pattern that still
+	 * matches the node being inserted to see if this mask can be
+	 * moved there.
+	 */
+	for (cur = nodes[1].parent; cur->root == 0; cur = cur->parent) {
+		if (cur->maskbitcount <= nodebits)
+			break;
+		if (((cur - 1)->addrkey[nodeoff] & nodemask) != nodekey)
+			break;
+		prev = cur;
+	}
+
+	KMALLOC(mask, ipf_rdx_mask_t *);
+	if (mask == NULL)
+		return NULL;
+	bzero(mask, sizeof(*mask));
+	mask->next = NULL;
+	mask->node = &nodes[0];
+	mask->maskbitcount = nodebits;
+	mask->mask = nodes[0].maskkey;
+	nodes[0].mymask = mask;
+
+	if (prev != NULL) {
+		ipf_rdx_mask_t *m;
+
+		for (pmask = &prev->masks; (m = *pmask) != NULL;
+		     pmask = &m->next) {
+			if (m->maskbitcount < nodebits)
+				break;
+		}
+	} else {
+		/*
+		 * No higher up nodes qualify, so attach mask locally.
+		 */
+		pmask = &nodes[0].masks;
+	}
+	mask->next = *pmask;
+	*pmask = mask;
+
+	/*
+	 * Search the mask list on each child to see if there are any masks
+	 * there that can be moved up to this newly inserted node.
+	 */
+	cur = nodes[1].right;
+	if (cur->root == 0) {
+		for (pmask = &cur->masks; (mask = *pmask) != NULL; ) {
+			if (mask->maskbitcount < nodebits) {
+				*pmask = mask->next;
+				ipf_rx_attach_mask(&nodes[0], mask);
+			} else {
+				pmask = &mask->next;
+			}
+		}
+	}
+	cur = nodes[1].left;
+	if (cur->root == 0 && cur != &nodes[0]) {
+		for (pmask = &cur->masks; (mask = *pmask) != NULL; ) {
+			if (mask->maskbitcount < nodebits) {
+				*pmask = mask->next;
+				ipf_rx_attach_mask(&nodes[0], mask);
+			} else {
+				pmask = &mask->next;
+			}
+		}
+	}
+	return (&nodes[0]);
+}
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_rx_addroute                                             */
+/* Returns:     ipf_rdx_node_t * - NULL on error, else pointer to the node  */
+/*                                 added to the tree.                       */
+/* Paramters:   head(I)  - pointer to tree head to search                   */
+/*              addr(I)  - address portion of "route" to add                */
+/*              mask(I)  - netmask portion of "route" to add                */
+/*              nodes(I) - radix tree data nodes inside allocate structure  */
+/*                                                                          */
+/* Attempt to add a node to the radix tree. The key for the node is the     */
+/* (addr,mask). No memory allocation for the radix nodes themselves is      */
+/* performed here, the data structure that this radix node is being used to */
+/* find is expected to house the node data itself however the call to       */
+/* ipf_rx_insert() will attempt to allocate memory in order for netmask to  */
+/* be promoted further up the tree.                                         */
+/* In this case, the ip_pool_node_t structure from ip_pool.h contains both  */
+/* the key material (addr,mask) and the radix tree nodes[].                 */
+/*                                                                          */
+/* The mechanics of inserting the node into the tree is handled by the      */
+/* function ipf_rx_insert() above. Here, the code deals with the case       */
+/* where the data to be inserted is a duplicate.                            */
+/* ------------------------------------------------------------------------ */
+ipf_rdx_node_t *
+ipf_rx_addroute(head, addr, mask, nodes)
+	ipf_rdx_head_t *head;
+	addrfamily_t *addr, *mask;
+	ipf_rdx_node_t *nodes;
+{
+	ipf_rdx_node_t *node;
+	ipf_rdx_node_t *prev;
+	ipf_rdx_node_t *x;
+	int dup;
+
+	buildnodes(addr, mask, nodes);
+	x = ipf_rx_insert(head, nodes, &dup);
+	if (x == NULL)
+		return NULL;
+
+	if (dup == 1) {
+		node = &nodes[0];
+		prev = NULL;
+		/*
+		 * The duplicate list is kept sorted with the longest
+		 * mask at the top, meaning that the most specific entry
+		 * in the listis found first. This list thus allows for
+		 * duplicates such as 128.128.0.0/32 and 128.128.0.0/16.
+		 */
+		while ((x != NULL) && (x->maskbitcount > node->maskbitcount)) {
+			prev = x;
+			x = x->dupkey;
+		}
+
+		/*
+		 * Is it a complete duplicate? If so, return NULL and
+		 * fail the insert. Otherwise, insert it into the list
+		 * of netmasks active for this key.
+		 */
+		if ((x != NULL) && (x->maskbitcount == node->maskbitcount))
+			return (NULL);
+
+		if (prev != NULL) {
+			nodes[0].dupkey = x;
+			prev->dupkey = &nodes[0];
+			nodes[0].parent = prev;
+			if (x != NULL)
+				x->parent = &nodes[0];
+		} else {
+			nodes[0].dupkey = x->dupkey;
+			prev = x->parent;
+			nodes[0].parent = prev;
+			x->parent = &nodes[0];
+			if (prev->left == x)
+				prev->left = &nodes[0];
+			else
+				prev->right = &nodes[0];
+		}
+	}
+
+	return &nodes[0];
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_rx_delete                                               */
+/* Returns:     ipf_rdx_node_t * - NULL on error, else node removed from    */
+/*                                 the tree.                                */
+/* Paramters:   head(I)  - pointer to tree head to search                   */
+/*              addr(I)  - pointer to the address part of the key           */
+/*              mask(I)  - pointer to the netmask part of the key           */
+/*                                                                          */
+/* Search for an entry in the radix tree that is an exact match for (addr,  */
+/* mask) and remove it if it exists. In the case where (addr,mask) is a not */
+/* a unique key, the tree structure itself is not changed - only the list   */
+/* of duplicate keys.                                                       */
+/* ------------------------------------------------------------------------ */
+ipf_rdx_node_t *
+ipf_rx_delete(head, addr, mask)
+        ipf_rdx_head_t *head;
+        addrfamily_t *addr, *mask;
+{
+	ipf_rdx_mask_t **pmask;
+	ipf_rdx_node_t *parent;
+	ipf_rdx_node_t *found;
+	ipf_rdx_node_t *prev;
+	ipf_rdx_node_t *node;
+	ipf_rdx_node_t *cur;
+	ipf_rdx_mask_t *m;
+	int count;
+
+	found = ipf_rx_find_addr(head->root, (u_32_t *)addr);
+	if (found == NULL)
+		return NULL;
+	if (found->root == 1)
+		return NULL;
+	count = count_mask_bits(mask, NULL);
+	parent = found->parent;
+	if (found->dupkey != NULL) {
+		node = found;
+		while (node != NULL && node->maskbitcount != count)
+			node = node->dupkey;
+		if (node == NULL)
+			return (NULL);
+		if (node != found) {
+			/*
+			 * Remove from the dupkey list. Here, "parent" is
+			 * the previous node on the list (rather than tree)
+			 * and "dupkey" is the next node on the list.
+			 */
+			parent = node->parent;
+			parent->dupkey = node->dupkey;
+			node->dupkey->parent = parent;
+		} else {
+			/*
+			 * 
+			 * When removing the top node of the dupkey list,
+			 * the pointers at the top of the list that point
+			 * to other tree nodes need to be preserved and
+			 * any children must have their parent updated.
+			 */
+			node = node->dupkey;
+			node->parent = found->parent;
+			node->right = found->right;
+			node->left = found->left;
+			found->right->parent = node;
+			found->left->parent = node;
+			if (parent->left == found)
+				parent->left = node;
+			else
+				parent->right= node;
+		}
+	} else {
+		if (count != found->maskbitcount)
+			return (NULL);
+		/*
+		 * Remove the node from the tree and reconnect the subtree
+		 * below.
+		 */
+		/*
+		 * If there is a tree to the left, look for something to
+		 * attach in place of "found".
+		 */
+		prev = found + 1;
+		cur = parent->parent;
+		if (parent != found + 1) {
+			if ((found + 1)->parent->right == found + 1)
+				(found + 1)->parent->right = parent;
+			else
+				(found + 1)->parent->left = parent;
+			if (cur->right == parent) {
+				if (parent->left == found) {
+					cur->right = parent->right;
+				} else if (parent->left != parent - 1) {
+					cur->right = parent->left;
+				} else {
+					cur->right = parent - 1;
+				}
+				cur->right->parent = cur;
+			} else {
+				if (parent->right == found) {
+					cur->left = parent->left;
+				} else if (parent->right != parent - 1) {
+					cur->left = parent->right;
+				} else {
+					cur->left = parent - 1;
+				}
+				cur->left->parent = cur;
+			}
+			parent->left = (found + 1)->left;
+			if ((found + 1)->right != parent)
+				parent->right = (found + 1)->right;
+			parent->left->parent = parent;
+			parent->right->parent = parent;
+			parent->parent = (found + 1)->parent;
+
+			parent->bitmask = prev->bitmask;
+			parent->offset = prev->offset;
+			parent->index = prev->index;
+		} else {
+			/*
+			 * We found an edge node.
+			 */
+			cur = parent->parent;
+			if (cur->left == parent) {
+				if (parent->left == found) {
+					cur->left = parent->right;
+					parent->right->parent = cur;
+				} else {
+					cur->left = parent->left;
+					parent->left->parent = cur;
+				}
+			} else {
+				if (parent->right != found) {
+					cur->right = parent->right;
+					parent->right->parent = cur;
+				} else {
+					cur->right = parent->left;
+					prev->left->parent = cur;
+				}
+			}
+		}
+	}
+
+	/*
+	 * Remove mask associated with this node.
+	 */
+	for (cur = parent; cur->root == 0; cur = cur->parent) {
+		ipf_rdx_mask_t **pm;
+
+		if (cur->maskbitcount <= found->maskbitcount)
+			break;
+		if (((cur - 1)->addrkey[found->offset] & found->bitmask) !=
+		    found->addrkey[found->offset])
+			break;
+		for (pm = &cur->masks; (m = *pm) != NULL; )
+			if (m->node == cur) {
+				*pm = m->next;
+				break;
+			} else {
+				pm = &m->next;
+			}
+	}
+	KFREE(found->mymask);
+
+	/*
+	 * Masks that have been brought up to this node from below need to
+	 * be sent back down.
+	 */
+	for (pmask = &parent->masks; (m = *pmask) != NULL; ) {
+		*pmask = m->next;
+		cur = m->node;
+		if (cur == found)
+			continue;
+		if (found->addrkey[cur->offset] & cur->lastmask) {
+			ipf_rx_attach_mask(parent->right, m);
+		} else if (parent->left != found) {
+			ipf_rx_attach_mask(parent->left, m);
+		}
+	}
+
+	return (found);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_rx_walktree                                             */
+/* Returns:     Nil                                                         */
+/* Paramters:   head(I)   - pointer to tree head to search                  */
+/*              walker(I) - function to call for each node in the tree      */
+/*              arg(I)    - parameter to pass to walker, in addition to the */
+/*                          node pointer                                    */
+/*                                                                          */
+/* A standard tree walking function except that it is iterative, rather     */
+/* than recursive and tracks the next node in case the "walker" function    */
+/* should happen to delete and free the current node. It thus goes without  */
+/* saying that the "walker" function is not permitted to cause any change   */
+/* in the validity of the data found at either the left or right child.     */
+/* ------------------------------------------------------------------------ */
+void
+ipf_rx_walktree(head, walker, arg)
+	ipf_rdx_head_t *head;
+	radix_walk_func_t walker;
+	void *arg;
+{
+	ipf_rdx_node_t *next;
+	ipf_rdx_node_t *node = head->root;
+	ipf_rdx_node_t *base;
+
+	while (node->index >= 0)
+		node = node->left;
+
+	for (;;) {
+		base = node;
+		while ((node->parent->right == node) && (node->root == 0))
+			node = node->parent;
+
+		for (node = node->parent->right; node->index >= 0; )
+			node = node->left;
+		next = node;
+
+		for (node = base; node != NULL; node = base) {
+			base = node->dupkey;
+			if (node->root == 0)
+				walker(node, arg);
+		}
+		node = next;
+		if (node->root)
+			return;
+	}
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_rx_inithead                                             */
+/* Returns:     int       - 0 = success, else failure                       */
+/* Paramters:   softr(I)  - pointer to radix context                        */
+/*              headp(O)  - location for where to store allocated tree head */
+/*                                                                          */
+/* This function allocates and initialises a radix tree head structure.     */
+/* As a traditional radix tree, node 0 is used as the "0" sentinel and node */
+/* "2" is used as the all ones sentinel, leaving node "1" as the root from  */
+/* which the tree is hung with node "0" on its left and node "2" to the     */
+/* right. The context, "softr", is used here to provide a common source of  */
+/* the zeroes and ones data rather than have one per head.                  */
+/* ------------------------------------------------------------------------ */
+int
+ipf_rx_inithead(softr, headp)
+	radix_softc_t *softr;
+	ipf_rdx_head_t **headp;
+{
+	ipf_rdx_head_t *ptr;
+	ipf_rdx_node_t *node;
+
+	KMALLOC(ptr, ipf_rdx_head_t *);
+	*headp = ptr;
+	if (ptr == NULL)
+		return -1;
+	bzero(ptr, sizeof(*ptr));
+	node = ptr->nodes;
+	ptr->root = node + 1;
+	node[0].index = ADF_OFF_BITS;
+	node[0].index = -1 - node[0].index;
+	node[1].index = ADF_OFF_BITS;
+	node[2].index = node[0].index;
+	node[0].parent = node + 1;
+	node[1].parent = node + 1;
+	node[2].parent = node + 1;
+	node[1].bitmask = htonl(0x80000000);
+	node[0].root = 1;
+	node[1].root = 1;
+	node[2].root = 1;
+	node[0].offset = ADF_OFF_BITS >> 5;
+	node[1].offset = ADF_OFF_BITS >> 5;
+	node[2].offset = ADF_OFF_BITS >> 5;
+	node[1].left = &node[0];
+	node[1].right = &node[2];
+	node[0].addrkey = (u_32_t *)softr->zeros;
+	node[2].addrkey = (u_32_t *)softr->ones;
+#ifdef RDX_DEBUG
+	(void) strcpy(node[0].name, "0_ROOT");
+	(void) strcpy(node[1].name, "1_ROOT");
+	(void) strcpy(node[2].name, "2_ROOT");
+#endif
+
+	ptr->addaddr = ipf_rx_addroute;
+	ptr->deladdr = ipf_rx_delete;
+	ptr->lookup = ipf_rx_lookup;
+	ptr->matchaddr = ipf_rx_match;
+	ptr->walktree = ipf_rx_walktree;
+	return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_rx_freehead                                             */
+/* Returns:     Nil                                                         */
+/* Paramters:   head(I)  - pointer to tree head to free                     */
+/*                                                                          */
+/* This function simply free's up the radix tree head. Prior to calling     */
+/* this function, it is expected that the tree will have been emptied.      */
+/* ------------------------------------------------------------------------ */
+void
+ipf_rx_freehead(head)
+	ipf_rdx_head_t *head;
+{
+	KFREE(head);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_rx_create                                               */
+/* Parameters:  Nil                                                         */
+/*                                                                          */
+/* ------------------------------------------------------------------------ */
+void *
+ipf_rx_create()
+{
+	radix_softc_t *softr;
+
+	KMALLOC(softr, radix_softc_t *);
+	if (softr == NULL)
+		return NULL;
+	bzero((char *)softr, sizeof(*softr));
+
+	KMALLOCS(softr->zeros, u_char *, 3 * sizeof(addrfamily_t));
+	if (softr->zeros == NULL) {
+		KFREE(softr);
+		return (NULL);
+	}
+	softr->ones = softr->zeros + sizeof(addrfamily_t);
+
+	return softr;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_rx_init                                                 */
+/* Returns:     int       - 0 = success (always)                            */
+/*                                                                          */
+/* ------------------------------------------------------------------------ */
+int
+ipf_rx_init(ctx)
+	void *ctx;
+{
+	radix_softc_t *softr = ctx;
+
+	memset(softr->zeros, 0, 3 * sizeof(addrfamily_t));
+	memset(softr->ones, 0xff, sizeof(addrfamily_t));
+
+	return (0);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_rx_destroy                                              */
+/* Returns:     Nil                                                         */
+/*                                                                          */
+/* ------------------------------------------------------------------------ */
+void
+ipf_rx_destroy(ctx)
+	void *ctx;
+{
+	radix_softc_t *softr = ctx;
+
+	if (softr->zeros != NULL)
+		KFREES(softr->zeros, 3 * sizeof(addrfamily_t));
+	KFREE(softr);
+}
+
+/* ====================================================================== */
+
+#ifdef RDX_DEBUG
+/*
+ * To compile this file as a standalone test unit, use -DRDX_DEBUG=1
+ */
+#define	NAME(x)	((x)->index < 0 ? (x)->name : (x)->name)
+#define	GNAME(y)	((y) == NULL ? "NULL" : NAME(y))
+
+typedef struct myst {
+	struct ipf_rdx_node nodes[2];
+	addrfamily_t	dst;
+	addrfamily_t	mask;
+	struct myst	*next;
+	int		printed;
+} myst_t;
+
+typedef struct tabe_s {
+	char	*host;
+	char	*mask;
+	char	*what;
+} tabe_t;
+
+tabe_t builtin[] = {
+#if 1
+	{ "192:168:100::0",	"48",			"d" },
+	{ "192:168:100::2",	"128",			"d" },
+#else
+	{ "127.192.0.0",	"255.255.255.0",	"d" },
+	{ "127.128.0.0",	"255.255.255.0",	"d" },
+	{ "127.96.0.0",		"255.255.255.0",	"d" },
+	{ "127.80.0.0",		"255.255.255.0",	"d" },
+	{ "127.72.0.0",		"255.255.255.0",	"d" },
+	{ "127.64.0.0",		"255.255.255.0",	"d" },
+	{ "127.56.0.0",		"255.255.255.0",	"d" },
+	{ "127.48.0.0",		"255.255.255.0",	"d" },
+	{ "127.40.0.0",		"255.255.255.0",	"d" },
+	{ "127.32.0.0",		"255.255.255.0",	"d" },
+	{ "127.24.0.0",		"255.255.255.0",	"d" },
+	{ "127.16.0.0",		"255.255.255.0",	"d" },
+	{ "127.8.0.0",		"255.255.255.0",	"d" },
+	{ "124.0.0.0",		"255.0.0.0",		"d" },
+	{ "125.0.0.0",		"255.0.0.0",		"d" },
+	{ "126.0.0.0",		"255.0.0.0",		"d" },
+	{ "127.0.0.0",		"255.0.0.0",		"d" },
+	{ "10.0.0.0",		"255.0.0.0",		"d" },
+	{ "128.250.0.0",	"255.255.0.0",		"d" },
+	{ "192.168.0.0",	"255.255.0.0",		"d" },
+	{ "192.168.1.0",	"255.255.255.0",	"d" },
+#endif
+	{ NULL, NULL, NULL }
+};
+
+char *mtable[][1] = {
+#if 1
+	{ "192:168:100::2" },
+	{ "192:168:101::2" },
+#else
+	{ "9.0.0.0" },
+	{ "9.0.0.1" },
+	{ "11.0.0.0" },
+	{ "11.0.0.1" },
+	{ "127.0.0.1" },
+	{ "127.0.1.0" },
+	{ "255.255.255.0" },
+	{ "126.0.0.1" },
+	{ "128.251.0.0" },
+	{ "128.251.0.1" },
+	{ "128.251.255.255" },
+	{ "129.250.0.0" },
+	{ "129.250.0.1" },
+	{ "192.168.255.255" },
+#endif
+	{ NULL }
+};
+
+
+int forder[22] = {
+	14, 13, 12,  5, 10,  3, 19,  7,  4, 20,  8,
+	 2, 17,  9, 16, 11, 15,  1,  6, 18,  0, 21
+};
+
+static int nodecount = 0;
+myst_t *myst_top = NULL;
+tabe_t *ttable = NULL;
+
+void add_addr(ipf_rdx_head_t *, int , int);
+void checktree(ipf_rdx_head_t *);
+void delete_addr(ipf_rdx_head_t *rnh, int item);
+void dumptree(ipf_rdx_head_t *rnh);
+void nodeprinter(ipf_rdx_node_t *, void *);
+void printroots(ipf_rdx_head_t *);
+void random_add(ipf_rdx_head_t *);
+void random_delete(ipf_rdx_head_t *);
+void test_addr(ipf_rdx_head_t *rnh, int pref, addrfamily_t *, int);
+
+
+static void
+ipf_rx_freenode(node, arg)
+	ipf_rdx_node_t *node;
+	void *arg;
+{
+	ipf_rdx_head_t *head = arg;
+	ipf_rdx_node_t *rv;
+	myst_t *stp;
+
+	stp = (myst_t *)node;
+	rv = ipf_rx_delete(head, &stp->dst, &stp->mask);
+	if (rv != NULL) {
+		free(rv);
+	}
+}
+
+
+const char *
+addrname(ap)
+	addrfamily_t *ap;
+{
+	static char name[80];
+	const char *txt;
+
+	bzero((char *)name, sizeof(name));
+	txt =  inet_ntop(ap->adf_family, &ap->adf_addr, name,
+			 sizeof(name));
+	return txt;
+}
+
+
+void
+fill6bits(bits, msk)
+	int bits;
+	u_int *msk;
+{
+	if (bits == 0) {
+		msk[0] = 0;
+		msk[1] = 0;
+		msk[2] = 0;
+		msk[3] = 0;
+		return;
+	}
+
+	msk[0] = 0xffffffff;
+	msk[1] = 0xffffffff;
+	msk[2] = 0xffffffff;
+	msk[3] = 0xffffffff;
+
+	if (bits == 128)
+		return;
+	if (bits > 96) {
+		msk[3] = htonl(msk[3] << (128 - bits));
+	} else if (bits > 64) {
+		msk[3] = 0;
+		msk[2] = htonl(msk[2] << (96 - bits));
+	} else if (bits > 32) {
+		msk[3] = 0;
+		msk[2] = 0;
+		msk[1] = htonl(msk[1] << (64 - bits));
+	} else {
+		msk[3] = 0;
+		msk[2] = 0;
+		msk[1] = 0;
+		msk[0] = htonl(msk[0] << (32 - bits));
+	}
+}
+
+
+void
+setaddr(afp, str)
+	addrfamily_t *afp;
+	char *str;
+{
+
+	bzero((char *)afp, sizeof(*afp));
+
+	if (strchr(str, ':') == NULL) {
+		afp->adf_family = AF_INET;
+		afp->adf_len = offsetof(addrfamily_t, adf_addr) + 4;
+	} else {
+		afp->adf_family = AF_INET6;
+		afp->adf_len = offsetof(addrfamily_t, adf_addr) + 16;
+	}
+	inet_pton(afp->adf_family, str, &afp->adf_addr);
+}
+
+
+void
+setmask(afp, str)
+	addrfamily_t *afp;
+	char *str;
+{
+	if (strchr(str, '.') != NULL) {
+		afp->adf_addr.in4.s_addr = inet_addr(str);
+		afp->adf_len = offsetof(addrfamily_t, adf_addr) + 4;
+	} else if (afp->adf_family == AF_INET) {
+		afp->adf_addr.i6[0] = htonl(0xffffffff << (32 - atoi(str)));
+		afp->adf_len = offsetof(addrfamily_t, adf_addr) + 4;
+	} else if (afp->adf_family == AF_INET6) {
+		fill6bits(atoi(str), afp->adf_addr.i6);
+		afp->adf_len = offsetof(addrfamily_t, adf_addr) + 16;
+	}
+}
+
+
+void
+nodeprinter(node, arg)
+	ipf_rdx_node_t *node;
+	void *arg;
+{
+	myst_t *stp = (myst_t *)node;
+
+	printf("Node %-9.9s L %-9.9s R %-9.9s P %9.9s/%-9.9s %s/%d\n",
+		node[0].name,
+		GNAME(node[1].left), GNAME(node[1].right),
+		GNAME(node[0].parent), GNAME(node[1].parent),
+		addrname(&stp->dst), node[0].maskbitcount);
+	if (stp->printed == -1)
+		printf("!!! %d\n", stp->printed);
+	else
+		stp->printed = 1;
+}
+
+
+void
+printnode(stp)
+	myst_t *stp;
+{
+	ipf_rdx_node_t *node = &stp->nodes[0];
+
+	if (stp->nodes[0].index > 0)
+		stp = (myst_t *)&stp->nodes[-1];
+
+	printf("Node %-9.9s ", node[0].name);
+	printf("L %-9.9s ", GNAME(node[1].left));
+	printf("R %-9.9s ", GNAME(node[1].right));
+	printf("P %9.9s", GNAME(node[0].parent));
+	printf("/%-9.9s ", GNAME(node[1].parent));
+	printf("%s P%d\n", addrname(&stp->dst), stp->printed);
+}
+
+
+void
+buildtab(void)
+{
+	char line[80], *s;
+	tabe_t *tab;
+	int lines;
+	FILE *fp;
+
+	lines = 0;
+	fp = fopen("hosts", "r");
+
+	while (fgets(line, sizeof(line), fp) != NULL) {
+		s = strchr(line, '\n');
+		if (s != NULL)
+			*s = '\0';
+		lines++;
+		if (lines == 1)
+			tab = malloc(sizeof(*tab) * 2);
+		else
+			tab = realloc(tab, (lines + 1) * sizeof(*tab));
+		tab[lines - 1].host = strdup(line);
+		s = strchr(tab[lines - 1].host, '/');
+		*s++ = '\0';
+		tab[lines - 1].mask = s;
+		tab[lines - 1].what = "d";
+	}
+	fclose(fp);
+
+	tab[lines].host = NULL;
+	tab[lines].mask = NULL;
+	tab[lines].what = NULL;
+	ttable = tab;
+}
+
+
+void
+printroots(rnh)
+	ipf_rdx_head_t *rnh;
+{
+	printf("Root.0.%s b %3d p %-9.9s l %-9.9s r %-9.9s\n",
+		GNAME(&rnh->nodes[0]),
+		rnh->nodes[0].index, GNAME(rnh->nodes[0].parent),
+		GNAME(rnh->nodes[0].left), GNAME(rnh->nodes[0].right));
+	printf("Root.1.%s b %3d p %-9.9s l %-9.9s r %-9.9s\n",
+		GNAME(&rnh->nodes[1]),
+		rnh->nodes[1].index, GNAME(rnh->nodes[1].parent),
+		GNAME(rnh->nodes[1].left), GNAME(rnh->nodes[1].right));
+	printf("Root.2.%s b %3d p %-9.9s l %-9.9s r %-9.9s\n",
+		GNAME(&rnh->nodes[2]),
+		rnh->nodes[2].index, GNAME(rnh->nodes[2].parent),
+		GNAME(rnh->nodes[2].left), GNAME(rnh->nodes[2].right));
+}
+
+
+int
+main(int argc, char *argv[])
+{
+	addrfamily_t af;
+	ipf_rdx_head_t *rnh;
+	radix_softc_t *ctx;
+	int j;
+	int i;
+
+	rnh = NULL;
+
+	buildtab();
+	ctx = ipf_rx_create();
+	ipf_rx_init(ctx);
+	ipf_rx_inithead(ctx, &rnh);
+
+	printf("=== ADD-0 ===\n");
+	for (i = 0; ttable[i].host != NULL; i++) {
+		add_addr(rnh, i, i);
+		checktree(rnh);
+	}
+	printroots(rnh);
+	ipf_rx_walktree(rnh, nodeprinter, NULL);
+	printf("=== DELETE-0 ===\n");
+	for (i = 0; ttable[i].host != NULL; i++) {
+		delete_addr(rnh, i);
+		printroots(rnh);
+		ipf_rx_walktree(rnh, nodeprinter, NULL);
+	}
+	printf("=== ADD-1 ===\n");
+	for (i = 0; ttable[i].host != NULL; i++) {
+		setaddr(&af, ttable[i].host);
+		add_addr(rnh, i, i); /*forder[i]); */
+		checktree(rnh);
+	}
+	dumptree(rnh);
+	ipf_rx_walktree(rnh, nodeprinter, NULL);
+	printf("=== TEST-1 ===\n");
+	for (i = 0; ttable[i].host != NULL; i++) {
+		setaddr(&af, ttable[i].host);
+		test_addr(rnh, i, &af, -1);
+	}
+
+	printf("=== TEST-2 ===\n");
+	for (i = 0; mtable[i][0] != NULL; i++) {
+		setaddr(&af, mtable[i][0]);
+		test_addr(rnh, i, &af, -1);
+	}
+	printf("=== DELETE-1 ===\n");
+	for (i = 0; ttable[i].host != NULL; i++) {
+		if (ttable[i].what[0] != 'd')
+			continue;
+		delete_addr(rnh, i);
+		for (j = 0; ttable[j].host != NULL; j++) {
+			setaddr(&af, ttable[j].host);
+			test_addr(rnh, i, &af, 3);
+		}
+		printroots(rnh);
+		ipf_rx_walktree(rnh, nodeprinter, NULL);
+	}
+
+	dumptree(rnh);
+
+	printf("=== ADD-2 ===\n");
+	random_add(rnh);
+	checktree(rnh);
+	dumptree(rnh);
+	ipf_rx_walktree(rnh, nodeprinter, NULL);
+	printf("=== DELETE-2 ===\n");
+	random_delete(rnh);
+	checktree(rnh);
+	dumptree(rnh);
+
+	ipf_rx_walktree(rnh, ipf_rx_freenode, rnh);
+
+	return 0;
+}
+
+
+void
+dumptree(rnh)
+	ipf_rdx_head_t *rnh;
+{
+	myst_t *stp;
+
+	printf("VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV\n");
+	printroots(rnh);
+	for (stp = myst_top; stp; stp = stp->next)
+		printnode(stp);
+	printf("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n");
+}
+
+
+void
+test_addr(rnh, pref, addr, limit)
+	ipf_rdx_head_t *rnh;
+	int pref;
+	addrfamily_t *addr;
+{
+	static int extras[14] = { 0, -1, 1, 3, 5, 8, 9,
+				  15, 16, 19, 255, 256, 65535, 65536
+	};
+	ipf_rdx_node_t *rn;
+	addrfamily_t af;
+	char name[80];
+	myst_t *stp;
+	int i;
+
+	memset(&af, 0, sizeof(af));
+#if 0
+	if (limit < 0 || limit > 14)
+		limit = 14;
+
+	for (i = 0; i < limit; i++) {
+		if (ttable[i].host == NULL)
+			break;
+		setaddr(&af, ttable[i].host);
+		printf("%d.%d.LOOKUP(%s)", pref, i, addrname(&af));
+		rn = ipf_rx_match(rnh, &af);
+		stp = (myst_t *)rn;
+		printf(" = %s (%s/%d)\n", GNAME(rn),
+			rn ? addrname(&stp->dst) : "NULL",
+			rn ? rn->maskbitcount : 0);
+	}
+#else
+	printf("%d.%d.LOOKUP(%s)", pref, -1, addrname(addr));
+	rn = ipf_rx_match(rnh, addr);
+	stp = (myst_t *)rn;
+	printf(" = %s (%s/%d)\n", GNAME(rn),
+		rn ? addrname(&stp->dst) : "NULL", rn ? rn->maskbitcount : 0);
+#endif
+}
+
+
+void
+delete_addr(rnh, item)
+	ipf_rdx_head_t *rnh;
+	int item;
+{
+	ipf_rdx_node_t *rn;
+	addrfamily_t mask;
+	addrfamily_t af;
+	myst_t **pstp;
+	myst_t *stp;
+
+	memset(&af, 0, sizeof(af));
+	memset(&mask, 0, sizeof(mask));
+	setaddr(&af, ttable[item].host);
+	mask.adf_family = af.adf_family;
+	setmask(&mask, ttable[item].mask);
+
+	printf("DELETE(%s)\n", addrname(&af));
+	rn = ipf_rx_delete(rnh, &af, &mask);
+	if (rn == NULL) {
+		printf("FAIL LOOKUP DELETE\n");
+		checktree(rnh);
+		for (stp = myst_top; stp != NULL; stp = stp->next)
+			if (stp->printed != -1)
+				stp->printed = -2;
+		ipf_rx_walktree(rnh, nodeprinter, NULL);
+		dumptree(rnh);
+		abort();
+	}
+	printf("%d.delete(%s) = %s\n", item, addrname(&af), GNAME(rn));
+
+	for (pstp = &myst_top; (stp = *pstp) != NULL; pstp = &stp->next)
+		if (stp == (myst_t *)rn)
+			break;
+	stp->printed = -1;
+	stp->nodes[0].parent = &stp->nodes[0];
+	stp->nodes[1].parent = &stp->nodes[1];
+	*pstp = stp->next;
+	free(stp);
+	nodecount--;
+	checktree(rnh);
+}
+
+
+void
+add_addr(rnh, n, item)
+	ipf_rdx_head_t *rnh;
+	int n, item;
+{
+	ipf_rdx_node_t *rn;
+	myst_t *stp;
+
+	stp = calloc(1, sizeof(*stp));
+	rn = (ipf_rdx_node_t *)stp;
+	setaddr(&stp->dst, ttable[item].host);
+	stp->mask.adf_family = stp->dst.adf_family;
+	setmask(&stp->mask, ttable[item].mask);
+	stp->next = myst_top;
+	myst_top = stp;
+	(void) sprintf(rn[0].name, "_BORN.0");
+	(void) sprintf(rn[1].name, "_BORN.1");
+	rn = ipf_rx_addroute(rnh, &stp->dst, &stp->mask, stp->nodes);
+	(void) sprintf(rn[0].name, "%d_NODE.0", item);
+	(void) sprintf(rn[1].name, "%d_NODE.1", item);
+	printf("ADD %d/%d %s/%s\n", n, item, rn[0].name, rn[1].name);
+	nodecount++;
+	checktree(rnh);
+}
+
+
+void
+checktree(ipf_rdx_head_t *head)
+{
+	myst_t *s1;
+	ipf_rdx_node_t *rn;
+
+	if (nodecount <= 1)
+		return;
+
+	for (s1 = myst_top; s1 != NULL; s1 = s1->next) {
+		int fault = 0;
+		if (s1->printed == -1)
+			continue;
+		rn = &s1->nodes[1];
+		if (rn->right->parent != rn)
+			fault |= 1;
+		if (rn->left->parent != rn)
+			fault |= 2;
+		if (rn->parent->left != rn && rn->parent->right != rn)
+			fault |= 4;
+		if (fault != 0) {
+			printf("FAULT %#x %s\n", fault, rn->name);
+			dumptree(head);
+			ipf_rx_walktree(head, nodeprinter, NULL);
+			fflush(stdout);
+			fflush(stderr);
+			printf("--\n");
+			abort();
+		}
+	}
+}
+
+
+int *
+randomize(int *pnitems)
+{
+	int *order;
+	int nitems;
+	int choice;
+	int j;
+	int i;
+
+	nitems = sizeof(ttable) / sizeof(ttable[0]);
+	*pnitems = nitems;
+	order = calloc(nitems, sizeof(*order));
+	srandom(getpid() * time(NULL));
+	memset(order, 0xff, nitems * sizeof(*order));
+	order[21] = 21;
+	for (i = 0; i < nitems - 1; i++) {
+		do {
+			choice = rand() % (nitems - 1);
+			for (j = 0; j < nitems; j++)
+				if (order[j] == choice)
+					break;
+		} while (j != nitems);
+		order[i] = choice;
+	}
+
+	return order;
+}
+
+
+void
+random_add(rnh)
+	ipf_rdx_head_t *rnh;
+{
+	int *order;
+	int nitems;
+	int i;
+
+	order = randomize(&nitems);
+
+	for (i = 0; i < nitems - 1; i++) {
+		add_addr(rnh, i, order[i]);
+		checktree(rnh);
+	}
+
+	free(order);
+}
+
+
+void
+random_delete(rnh)
+	ipf_rdx_head_t *rnh;
+{
+	int *order;
+	int nitems;
+	int i;
+
+	order = randomize(&nitems);
+
+	for (i = 0; i < nitems - 1; i++) {
+		delete_addr(rnh, i);
+		checktree(rnh);
+	}
+
+	free(order);
+}
+#endif /* RDX_DEBUG */


Property changes on: trunk/sys/contrib/ipfilter/netinet/radix_ipf.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/contrib/ipfilter/netinet/radix_ipf.h
===================================================================
--- trunk/sys/contrib/ipfilter/netinet/radix_ipf.h	                        (rev 0)
+++ trunk/sys/contrib/ipfilter/netinet/radix_ipf.h	2018-05-28 18:56:30 UTC (rev 10139)
@@ -0,0 +1,96 @@
+/* $MidnightBSD$ */
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ */
+#ifndef __RADIX_IPF_H__
+#define	__RADIX_IPF_H__
+
+#ifndef U_32_T
+typedef unsigned int u_32_t;
+# define	U_32_T	1
+#endif
+
+typedef struct ipf_rdx_mask {
+	struct ipf_rdx_mask	*next;
+	struct ipf_rdx_node	*node;
+	u_32_t			*mask;
+	int			maskbitcount;
+} ipf_rdx_mask_t;
+
+typedef struct ipf_rdx_node {
+	struct ipf_rdx_node	*left;
+	struct ipf_rdx_node	*right;
+	struct ipf_rdx_node	*parent;
+	struct ipf_rdx_node	*dupkey;
+	struct ipf_rdx_mask	*masks;
+	struct ipf_rdx_mask	*mymask;
+	u_32_t			*addrkey;
+	u_32_t			*maskkey;
+	u_32_t			*addroff;
+	u_32_t			*maskoff;
+	u_32_t			lastmask;
+	u_32_t			bitmask;
+	int			offset;
+	int			index;
+	int			maskbitcount;
+	int			root;
+#ifdef RDX_DEBUG
+	char			name[40];
+#endif
+} ipf_rdx_node_t;
+
+struct ipf_rdx_head;
+
+typedef	void		(* radix_walk_func_t)(ipf_rdx_node_t *, void *);
+typedef	ipf_rdx_node_t	*(* idx_hamn_func_t)(struct ipf_rdx_head *,
+					     addrfamily_t *, addrfamily_t *,
+					     ipf_rdx_node_t *);
+typedef	ipf_rdx_node_t	*(* idx_ham_func_t)(struct ipf_rdx_head *,
+					    addrfamily_t *, addrfamily_t *);
+typedef	ipf_rdx_node_t	*(* idx_ha_func_t)(struct ipf_rdx_head *,
+					   addrfamily_t *);
+typedef	void		(* idx_walk_func_t)(struct ipf_rdx_head *,
+					    radix_walk_func_t, void *);
+
+typedef struct ipf_rdx_head {
+	ipf_rdx_node_t	*root;
+	ipf_rdx_node_t	nodes[3];
+	ipfmutex_t	lock;
+	idx_hamn_func_t	addaddr;	/* add addr/mask to tree */
+	idx_ham_func_t	deladdr;	/* delete addr/mask from tree */
+	idx_ham_func_t	lookup;		/* look for specific addr/mask */
+	idx_ha_func_t	matchaddr;	/* search tree for address match */
+	idx_walk_func_t	walktree;	/* walk entire tree */
+} ipf_rdx_head_t;
+
+typedef struct radix_softc {
+	u_char			*zeros;
+	u_char			*ones;
+} radix_softc_t;
+
+#undef	RADIX_NODE_HEAD_LOCK
+#undef	RADIX_NODE_HEAD_UNLOCK
+#ifdef	_KERNEL
+# define	RADIX_NODE_HEAD_LOCK(x)		MUTEX_ENTER(&(x)->lock)
+# define	RADIX_NODE_HEAD_UNLOCK(x)	MUTEX_UNLOCK(&(x)->lock)
+#else
+# define	RADIX_NODE_HEAD_LOCK(x)
+# define	RADIX_NODE_HEAD_UNLOCK(x)
+#endif
+
+extern	void	*ipf_rx_create __P((void));
+extern	int	ipf_rx_init __P((void *));
+extern	void	ipf_rx_destroy __P((void *));   
+extern	int	ipf_rx_inithead __P((radix_softc_t *, ipf_rdx_head_t **));
+extern	void	ipf_rx_freehead __P((ipf_rdx_head_t *));
+extern	ipf_rdx_node_t *ipf_rx_addroute __P((ipf_rdx_head_t *,
+					     addrfamily_t *, addrfamily_t *,
+					     ipf_rdx_node_t *));
+extern	ipf_rdx_node_t *ipf_rx_delete __P((ipf_rdx_head_t *, addrfamily_t *,
+					   addrfamily_t *));
+extern	void	ipf_rx_walktree __P((ipf_rdx_head_t *, radix_walk_func_t,
+				     void *));
+
+#endif /* __RADIX_IPF_H__ */


Property changes on: trunk/sys/contrib/ipfilter/netinet/radix_ipf.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property


More information about the Midnightbsd-cvs mailing list