Index: buildset/default.ini
===================================================================
--- buildset/default.ini	(revision f62c62d2fe57ec02c1350144f7739f8e866ee6d4)
+++ buildset/default.ini	(revision 63084c1988e3c8c0858fd747485f250a2160f434)
@@ -42,5 +42,4 @@
 fdt = on
 in_cksum = on
-ipfw = on
 mdnsresponder = on
 mghttpd = on
Index: eebsd/sys/netinet6/ip_fw_nat64.h
===================================================================
--- freebsd/sys/netinet6/ip_fw_nat64.h	(revision f62c62d2fe57ec02c1350144f7739f8e866ee6d4)
+++ 	(revision )
@@ -1,154 +1,0 @@
-/*-
- * Copyright (c) 2015 Yandex LLC
- * Copyright (c) 2015 Alexander V. Chernikov <melifaro@FreeBSD.org>
- * Copyright (c) 2016 Andrey V. Elsukov <ae@FreeBSD.org>
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
- *
- * $FreeBSD$
- */
-
-#ifndef	_NETINET6_IP_FW_NAT64_H_
-#define	_NETINET6_IP_FW_NAT64_H_
-
-struct ipfw_nat64stl_stats {
-	uint64_t	opcnt64;	/* 6to4 of packets translated */
-	uint64_t	opcnt46;	/* 4to6 of packets translated */
-	uint64_t	ofrags;		/* number of fragments generated */
-	uint64_t	ifrags;		/* number of fragments received */
-	uint64_t	oerrors;	/* number of output errors */
-	uint64_t	noroute4;
-	uint64_t	noroute6;
-	uint64_t	noproto;	/* Protocol not supported */
-	uint64_t	nomem;		/* mbuf allocation filed */
-	uint64_t	dropped;	/* dropped due to some errors */
-};
-
-struct ipfw_nat64lsn_stats {
-	uint64_t	opcnt64;	/* 6to4 of packets translated */
-	uint64_t	opcnt46;	/* 4to6 of packets translated */
-	uint64_t	ofrags;		/* number of fragments generated */
-	uint64_t	ifrags;		/* number of fragments received */
-	uint64_t	oerrors;	/* number of output errors */
-	uint64_t	noroute4;
-	uint64_t	noroute6;
-	uint64_t	noproto;	/* Protocol not supported */
-	uint64_t	nomem;		/* mbuf allocation filed */
-	uint64_t	dropped;	/* dropped due to some errors */
-
-	uint64_t	nomatch4;	/* No addr/port match */
-	uint64_t	jcalls;		/* Number of job handler calls */
-	uint64_t	jrequests;	/* Number of job requests */
-	uint64_t	jhostsreq;	/* Number of job host requests */
-	uint64_t	jportreq;	/* Number of portgroup requests */
-	uint64_t	jhostfails;	/* Number of failed host allocs */
-	uint64_t	jportfails;	/* Number of failed portgroup allocs */
-	uint64_t	jreinjected;	/* Number of packets reinjected to q */
-	uint64_t	jmaxlen;	/* Max queue length reached */
-	uint64_t	jnomem;		/* No memory to alloc queue item */
-
-	uint64_t	screated;	/* Number of states created */
-	uint64_t	sdeleted;	/* Number of states deleted */
-	uint64_t	spgcreated;	/* Number of portgroups created */
-	uint64_t	spgdeleted;	/* Number of portgroups deleted */
-	uint64_t	hostcount;	/* Number of hosts  */
-	uint64_t	tcpchunks;	/* Number of TCP chunks */
-	uint64_t	udpchunks;	/* Number of UDP chunks */
-	uint64_t	icmpchunks;	/* Number of ICMP chunks */
-
-	uint64_t	_reserved[4];
-};
-
-#define	NAT64_LOG	0x0001		/* Enable logging via BPF */
-
-typedef struct _ipfw_nat64stl_cfg {
-	char		name[64];	/* NAT name			*/
-	ipfw_obj_ntlv	ntlv6;		/* object name tlv		*/
-	ipfw_obj_ntlv	ntlv4;		/* object name tlv		*/
-	struct in6_addr	prefix6;	/* NAT64 prefix */
-	uint8_t		plen6;		/* Prefix length */
-	uint8_t		set;		/* Named instance set [0..31] */
-	uint8_t		spare[2];
-	uint32_t	flags;
-} ipfw_nat64stl_cfg;
-
-/*
- * NAT64LSN default configuration values
- */
-#define	NAT64LSN_MAX_PORTS	2048	/* Max number of ports per host */
-#define	NAT64LSN_JMAXLEN	2048	/* Max outstanding requests. */
-#define	NAT64LSN_TCP_SYN_AGE	10	/* State's TTL after SYN received. */
-#define	NAT64LSN_TCP_EST_AGE	(2 * 3600) /* TTL for established connection */
-#define	NAT64LSN_TCP_FIN_AGE	180	/* State's TTL after FIN/RST received */
-#define	NAT64LSN_UDP_AGE	120	/* TTL for UDP states */
-#define	NAT64LSN_ICMP_AGE	60	/* TTL for ICMP states */
-#define	NAT64LSN_HOST_AGE	3600	/* TTL for stale host entry */
-#define	NAT64LSN_PG_AGE		900	/* TTL for stale ports groups */
-
-typedef struct _ipfw_nat64lsn_cfg {
-	char		name[64];	/* NAT name			*/
-	uint32_t	flags;
-	uint32_t	max_ports;	/* Max ports per client */
-	uint32_t	agg_prefix_len;	/* Prefix length to count */
-	uint32_t	agg_prefix_max;	/* Max hosts per agg prefix */
-	struct in_addr	prefix4;
-	uint16_t	plen4;		/* Prefix length */
-	uint16_t	plen6;		/* Prefix length */
-	struct in6_addr	prefix6;	/* NAT64 prefix */
-	uint32_t	jmaxlen;	/* Max jobqueue length */
-	uint16_t	min_port;	/* Min port group # to use */
-	uint16_t	max_port;	/* Max port group # to use */
-	uint16_t	nh_delete_delay;/* Stale host delete delay */
-	uint16_t	pg_delete_delay;/* Stale portgroup delete delay */
-	uint16_t	st_syn_ttl;	/* TCP syn expire */
-	uint16_t	st_close_ttl;	/* TCP fin expire */
-	uint16_t	st_estab_ttl;	/* TCP established expire */
-	uint16_t	st_udp_ttl;	/* UDP expire */
-	uint16_t	st_icmp_ttl;	/* ICMP expire */
-	uint8_t		set;		/* Named instance set [0..31] */
-	uint8_t		spare;
-} ipfw_nat64lsn_cfg;
-
-typedef struct _ipfw_nat64lsn_state {
-	struct in_addr	daddr;		/* Remote IPv4 address */
-	uint16_t	dport;		/* Remote destination port */
-	uint16_t	aport;		/* Local alias port */
-	uint16_t	sport;		/* Source port */
-	uint8_t		flags;		/* State flags */
-	uint8_t		spare[3];
-	uint16_t	idle;		/* Last used time */
-} ipfw_nat64lsn_state;
-
-typedef struct _ipfw_nat64lsn_stg {
-	uint64_t	next_idx;	/* next state index */
-	struct in_addr	alias4;		/* IPv4 alias address */
-	uint8_t		proto;		/* protocol */
-	uint8_t		flags;
-	uint16_t	spare;
-	struct in6_addr	host6;		/* Bound IPv6 host */
-	uint32_t	count;		/* Number of states */
-	uint32_t	spare2;
-} ipfw_nat64lsn_stg;
-
-#endif /* _NETINET6_IP_FW_NAT64_H_ */
-
Index: eebsd/sys/netinet6/ip_fw_nptv6.h
===================================================================
--- freebsd/sys/netinet6/ip_fw_nptv6.h	(revision f62c62d2fe57ec02c1350144f7739f8e866ee6d4)
+++ 	(revision )
@@ -1,51 +1,0 @@
-/*-
- * Copyright (c) 2016 Yandex LLC
- * Copyright (c) 2016 Andrey V. Elsukov <ae@FreeBSD.org>
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
- *
- * $FreeBSD$
- */
-
-#ifndef	_NETINET6_IP_FW_NPTV6_H_
-#define	_NETINET6_IP_FW_NPTV6_H_
-
-struct ipfw_nptv6_stats {
-	uint64_t	in2ex;		/* Int->Ext packets translated */
-	uint64_t	ex2in;		/* Ext->Int packets translated */
-	uint64_t	dropped;	/* dropped due to some errors */
-	uint64_t	reserved[5];
-};
-
-typedef struct _ipfw_nptv6_cfg {
-	char		name[64];	/* NPTv6 instance name */
-	struct in6_addr	internal;	/* NPTv6 internal prefix */
-	struct in6_addr	external;	/* NPTv6 external prefix */
-	uint8_t		plen;		/* Prefix length */
-	uint8_t		set;		/* Named instance set [0..31] */
-	uint8_t		spare[2];
-	uint32_t	flags;
-} ipfw_nptv6_cfg;
-
-#endif /* _NETINET6_IP_FW_NPTV6_H_ */
-
Index: eebsd/sys/netpfil/ipfw/dn_aqm.h
===================================================================
--- freebsd/sys/netpfil/ipfw/dn_aqm.h	(revision f62c62d2fe57ec02c1350144f7739f8e866ee6d4)
+++ 	(revision )
@@ -1,167 +1,0 @@
-/*-
- * Copyright (C) 2016 Centre for Advanced Internet Architectures,
- *  Swinburne University of Technology, Melbourne, Australia.
- * Portions of this code were made possible in part by a gift from 
- *  The Comcast Innovation Fund.
- * Implemented by Rasool Al-Saadi <ralsaadi@swin.edu.au>
- *
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
- */
-
-/*
- * API for writing an Active Queue Management algorithm for Dummynet
- *
- * $FreeBSD$
- */
-
-#ifndef _IP_DN_AQM_H
-#define _IP_DN_AQM_H
-
-
-/* NOW is the current time in millisecond*/
-#define NOW ((dn_cfg.curr_time * tick) / 1000)
-
-#define AQM_UNOW (dn_cfg.curr_time * tick)
-#define AQM_TIME_1US ((aqm_time_t)(1))
-#define AQM_TIME_1MS ((aqm_time_t)(1000))
-#define AQM_TIME_1S ((aqm_time_t)(AQM_TIME_1MS * 1000))
-
-/* aqm time allows to store up to 4294 seconds */
-typedef uint32_t aqm_time_t;
-typedef int32_t aqm_stime_t;
-
-#define DN_AQM_MTAG_TS 55345
-
-/* Macro for variable bounding */
-#define BOUND_VAR(x,l,h)  ((x) > (h)? (h) : ((x) > (l)? (x) : (l)))
-
-/* sysctl variable to count number of dropped packets */
-extern unsigned long io_pkt_drop; 
-
-/*
- * Structure for holding data and function pointers that together represent a
- * AQM algorithm.
- */
- struct dn_aqm {
-#define DN_AQM_NAME_MAX 50
-	char			name[DN_AQM_NAME_MAX];	/* name of AQM algorithm */
-	uint32_t	type;	/* AQM type number */
-	
-	/* Methods implemented by AQM algorithm:
-	 * 
-	 * enqueue	enqueue packet 'm' on queue 'q'.
-	 * 	Return 0 on success, 1 on drop.
-	 * 
-	 * dequeue	dequeue a packet from queue 'q'.
-	 * 	Return a packet, NULL if no packet available.
-	 * 
-	 * config	configure AQM algorithm
-	 * If required, this function should allocate space to store 
-	 * the configurations and set 'fs->aqmcfg' to point to this space.
-	 * 'dn_extra_parms' includes array of parameters send
-	 * from ipfw userland command.
-	 * 	Return 0 on success, non-zero otherwise.
-	 * 
-	 * deconfig	deconfigure AQM algorithm.
-	 * The allocated configuration memory space should be freed here.
-	 * 	Return 0 on success, non-zero otherwise.
-	 * 
-	 * init	initialise AQM status variables of queue 'q'
-	 * This function is used to allocate space and init AQM status for a
-	 * queue and q->aqm_status to point to this space.
-	 * 	Return 0 on success, non-zero otherwise.
-	 * 
-	 * cleanup	cleanup AQM status variables of queue 'q'
-	 * The allocated memory space for AQM status should be freed here.
-	 * 	Return 0 on success, non-zero otherwise.
-	 * 
-	 * getconfig	retrieve AQM configurations 
-	 * This function is used to return AQM parameters to userland
-	 * command. The function should fill 'dn_extra_parms' struct with 
-	 * the AQM configurations using 'par' array.
-	 * 
-	 */
-	
-	int (*enqueue)(struct dn_queue *, struct mbuf *);
-	struct mbuf * (*dequeue)(struct dn_queue *);
-	int (*config)(struct dn_fsk *, struct dn_extra_parms *ep, int);
-	int (*deconfig)(struct dn_fsk *);
-	int (*init)(struct dn_queue *);
-	int (*cleanup)(struct dn_queue *);
-	int (*getconfig)(struct dn_fsk *, struct dn_extra_parms *);
-
-	int	ref_count; /*Number of queues instances in the system */
-	int	cfg_ref_count;	/*Number of AQM instances in the system */
-	SLIST_ENTRY (dn_aqm) next; /* Next AQM in the list */
-};
-
-/* Helper function to update queue and scheduler statistics.
- * negative len + drop -> drop
- * negative len -> dequeue
- * positive len -> enqueue
- * positive len + drop -> drop during enqueue
- */
-__inline static void
-update_stats(struct dn_queue *q, int len, int drop)
-{
-	int inc = 0;
-	struct dn_flow *sni;
-	struct dn_flow *qni;
-	
-	sni = &q->_si->ni;
-	qni = &q->ni;
-
-	if (len < 0)
-			inc = -1;
-	else if(len > 0)
-			inc = 1;
-
-	if (drop) {
-			qni->drops++;
-			sni->drops++;
-			io_pkt_drop++;
-	} else {
-		/*update queue stats */
-		qni->length += inc;
-		qni->len_bytes += len;
-
-		/*update scheduler instance stats */
-		sni->length += inc;
-		sni->len_bytes += len;
-	}
-	/* tot_pkts  is updated in dn_enqueue function */
-}
-
-
-/* kernel module related function */
-int
-dn_aqm_modevent(module_t mod, int cmd, void *arg);
-
-#define DECLARE_DNAQM_MODULE(name, dnaqm)			\
-	static moduledata_t name##_mod = {			\
-		#name, dn_aqm_modevent, dnaqm		\
-	};							\
-	DECLARE_MODULE(name, name##_mod, 			\
-		SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY); 	\
-        MODULE_DEPEND(name, dummynet, 3, 3, 3)
-
-#endif
Index: eebsd/sys/netpfil/ipfw/dn_aqm_codel.h
===================================================================
--- freebsd/sys/netpfil/ipfw/dn_aqm_codel.h	(revision f62c62d2fe57ec02c1350144f7739f8e866ee6d4)
+++ 	(revision )
@@ -1,222 +1,0 @@
-/*
- * Codel - The Controlled-Delay Active Queue Management algorithm.
- *
- * $FreeBSD$
- * 
- * Copyright (C) 2016 Centre for Advanced Internet Architectures,
- *  Swinburne University of Technology, Melbourne, Australia.
- * Portions of this code were made possible in part by a gift from 
- *  The Comcast Innovation Fund.
- * Implemented by Rasool Al-Saadi <ralsaadi@swin.edu.au>
- * 
- * Copyright (C) 2011-2014 Kathleen Nichols <nichols@pollere.com>.
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * o  Redistributions of source code must retain the above copyright
- *  notice, this list of conditions, and the following disclaimer,
- *  without modification.
- *
- * o  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.
- * 
- * o  The names of the authors may not be used to endorse or promote
- *  products derived from this software without specific prior written
- *  permission.
- *
- * Alternatively, provided that this notice is retained in full, this
- * software may be distributed under the terms of the GNU General Public
- * License ("GPL") version 2, in which case the provisions of the GPL
- * apply INSTEAD OF those given above.
-
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT
- * OWNER 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.
- */
-
-#ifndef _IP_DN_AQM_CODEL_H
-#define _IP_DN_AQM_CODEL_H
-
-
-// XXX How to choose MTAG?
-#define FIX_POINT_BITS 16 
-
-enum {
-	CODEL_ECN_ENABLED = 1
-};
-
-/* Codel parameters */
-struct dn_aqm_codel_parms {
-	aqm_time_t	target;
-	aqm_time_t	interval;
-	uint32_t	flags;
-};
-
-/* codel status variables */
-struct codel_status {
-	uint32_t	count;	/* number of dropped pkts since entering drop state */
-	uint16_t	dropping;	/* dropping state */
-	aqm_time_t	drop_next_time;	/* time for next drop */
-	aqm_time_t	first_above_time;	/* time for first ts over target we observed */
-	uint16_t	isqrt;	/* last isqrt for control low */
-	uint16_t	maxpkt_size;	/* max packet size seen so far */
-};
-
-struct mbuf *codel_extract_head(struct dn_queue *, aqm_time_t *);
-aqm_time_t control_law(struct codel_status *,
-	struct dn_aqm_codel_parms *, aqm_time_t );
-
-__inline static struct mbuf *
-codel_dodequeue(struct dn_queue *q, aqm_time_t now, uint16_t *ok_to_drop)
-{
-	struct mbuf * m;
-	struct dn_aqm_codel_parms *cprms;
-	struct codel_status *cst;
-	aqm_time_t  pkt_ts, sojourn_time;
-
-	*ok_to_drop = 0;
-	m = codel_extract_head(q, &pkt_ts);
-	
-	cst = q->aqm_status;
-	
-	if (m == NULL) {
-		/* queue is empty - we can't be above target */
-		cst->first_above_time= 0;
-		return m;
-	}
-
-	cprms = q->fs->aqmcfg;
-
-	/* To span a large range of bandwidths, CoDel runs two
-	 * different AQMs in parallel. One is sojourn-time-based
-	 * and takes effect when the time to send an MTU-sized
-	 * packet is less than target.  The 1st term of the "if"
-	 * below does this.  The other is backlog-based and takes
-	 * effect when the time to send an MTU-sized packet is >=
-	* target. The goal here is to keep the output link
-	* utilization high by never allowing the queue to get
-	* smaller than the amount that arrives in a typical
-	 * interarrival time (MTU-sized packets arriving spaced
-	 * by the amount of time it takes to send such a packet on
-	 * the bottleneck). The 2nd term of the "if" does this.
-	 */
-	sojourn_time = now - pkt_ts;
-	if (sojourn_time < cprms->target || q->ni.len_bytes <= cst->maxpkt_size) {
-		/* went below - stay below for at least interval */
-		cst->first_above_time = 0;
-	} else {
-		if (cst->first_above_time == 0) {
-			/* just went above from below. if still above at
-			 * first_above_time, will say it's ok to drop. */
-			cst->first_above_time = now + cprms->interval;
-		} else if (now >= cst->first_above_time) {
-			*ok_to_drop = 1;
-		}
-	}
-	return m;
-}
-
-/* 
- * Dequeue a packet from queue 'q'
- */
-__inline static struct mbuf * 
-codel_dequeue(struct dn_queue *q)
-{
-	struct mbuf *m;
-	struct dn_aqm_codel_parms *cprms;
-	struct codel_status *cst;
-	aqm_time_t now;
-	uint16_t ok_to_drop;
-
-	cst = q->aqm_status;;
-	cprms = q->fs->aqmcfg;
-	now = AQM_UNOW;
-
-	m = codel_dodequeue(q, now, &ok_to_drop);
-	if (cst->dropping) {
-		if (!ok_to_drop) {
-			/* sojourn time below target - leave dropping state */
-			cst->dropping = false;
-		}
-		/*
-		 * Time for the next drop. Drop current packet and dequeue
-		 * next.  If the dequeue doesn't take us out of dropping
-		 * state, schedule the next drop. A large backlog might
-		 * result in drop rates so high that the next drop should
-		 * happen now, hence the 'while' loop.
-		 */
-		while (now >= cst->drop_next_time && cst->dropping) {
-
-			/* mark the packet */
-			if (cprms->flags & CODEL_ECN_ENABLED && ecn_mark(m)) {
-				cst->count++;
-				/* schedule the next mark. */
-				cst->drop_next_time = control_law(cst, cprms,
-					cst->drop_next_time);
-				return m;
-			}
-
-			/* drop the packet */
-			update_stats(q, 0, 1);
-			FREE_PKT(m);
-			m = codel_dodequeue(q, now, &ok_to_drop);
-
-			if (!ok_to_drop) {
-				/* leave dropping state */
-				cst->dropping = false;
-			} else {
-				cst->count++;
-				/* schedule the next drop. */
-				cst->drop_next_time = control_law(cst, cprms,
-					cst->drop_next_time);
-			}
-		}
-	/* If we get here we're not in dropping state. The 'ok_to_drop'
-	 * return from dodequeue means that the sojourn time has been
-	 * above 'target' for 'interval' so enter dropping state.
-	 */
-	} else if (ok_to_drop) {
-
-		/* if ECN option is disabled or the packet cannot be marked,
-		 * drop the packet and extract another.
-		 */
-		if (!(cprms->flags & CODEL_ECN_ENABLED) || !ecn_mark(m)) {
-			update_stats(q, 0, 1);
-			FREE_PKT(m);
-			m = codel_dodequeue(q, now, &ok_to_drop);
-		}
-
-		cst->dropping = true;
-
-		/* If min went above target close to when it last went
-		 * below, assume that the drop rate that controlled the
-		 * queue on the last cycle is a good starting point to
-		 * control it now. ('drop_next' will be at most 'interval'
-		 * later than the time of the last drop so 'now - drop_next'
-		 * is a good approximation of the time from the last drop
-		 * until now.)
-		 */
-		cst->count = (cst->count > 2 && ((aqm_stime_t)now - 
-			(aqm_stime_t)cst->drop_next_time) < 8* cprms->interval)?
-				cst->count - 2 : 1;
-		/* we don't have to set initial guess for Newton's method isqrt as
-		 * we initilaize  isqrt in control_law function when count == 1 */
-		cst->drop_next_time = control_law(cst, cprms, now);
-	}
-	
-	return m;
-}
-
-#endif
Index: eebsd/sys/netpfil/ipfw/dn_aqm_pie.h
===================================================================
--- freebsd/sys/netpfil/ipfw/dn_aqm_pie.h	(revision f62c62d2fe57ec02c1350144f7739f8e866ee6d4)
+++ 	(revision )
@@ -1,153 +1,0 @@
-/*
- * PIE - Proportional Integral controller Enhanced AQM algorithm.
- *
- * $FreeBSD$
- * 
- * Copyright (C) 2016 Centre for Advanced Internet Architectures,
- *  Swinburne University of Technology, Melbourne, Australia.
- * Portions of this code were made possible in part by a gift from 
- *  The Comcast Innovation Fund.
- * Implemented by Rasool Al-Saadi <ralsaadi@swin.edu.au>
- *
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
- */
-
-#ifndef _IP_DN_AQM_PIE_H
-#define _IP_DN_AQM_PIE_H
-
-#define DN_AQM_PIE 2
-#define PIE_DQ_THRESHOLD_BITS 14
-/* 2^14 =16KB */
-#define PIE_DQ_THRESHOLD (1L << PIE_DQ_THRESHOLD_BITS) 
-#define MEAN_PKTSIZE 800
-
-/* 31-bits because random() generates range from 0->(2**31)-1 */
-#define PIE_PROB_BITS 31
-#define PIE_MAX_PROB ((1LL<<PIE_PROB_BITS) -1)
-
-/* for 16-bits, we have 3-bits for integer part and 13-bits for fraction */
-#define PIE_FIX_POINT_BITS 13
-#define PIE_SCALE (1L<<PIE_FIX_POINT_BITS)
-
-
-/* PIE options */
-enum {
-	PIE_ECN_ENABLED =1,
-	PIE_CAPDROP_ENABLED = 2,
-	PIE_ON_OFF_MODE_ENABLED = 4,
-	PIE_DEPRATEEST_ENABLED = 8,
-	PIE_DERAND_ENABLED = 16
-};
-
-/* PIE parameters */
-struct dn_aqm_pie_parms {
-	aqm_time_t	qdelay_ref;	/* AQM Latency Target (default: 15ms) */
-	aqm_time_t	tupdate;		/* a period to calculate drop probability (default:15ms) */
-	aqm_time_t	max_burst;	/* AQM Max Burst Allowance (default: 150ms) */
-	uint16_t	max_ecnth;	/*AQM Max ECN Marking Threshold (default: 10%) */
-	uint16_t	alpha;			/* (default: 1/8) */
-	uint16_t	beta;			/* (default: 1+1/4) */
-	uint32_t	flags;			/* PIE options */
-};
-
-/* PIE status variables */
-struct pie_status{
-	struct callout	aqm_pie_callout;
-	aqm_time_t	burst_allowance;
-	uint32_t	drop_prob;
-	aqm_time_t	current_qdelay;
-	aqm_time_t	qdelay_old;
-	uint64_t	accu_prob;
-	aqm_time_t	measurement_start;
-	aqm_time_t	avg_dq_time;
-	uint32_t	dq_count;
-	uint32_t	sflags;
-	struct dn_aqm_pie_parms *parms;	/* pointer to PIE configurations */
-	/* pointer to parent queue of FQ-PIE sub-queues, or  queue of owner fs. */
-	struct dn_queue	*pq;	
-	struct mtx	lock_mtx;
-	uint32_t one_third_q_size; /* 1/3 of queue size, for speed optization */
-};
-
-enum { 
-	ENQUE = 1,
-	DROP,
-	MARKECN
-};
-
-/* PIE current state */
-enum { 
-	PIE_ACTIVE = 1,
-	PIE_INMEASUREMENT = 2
-};
-
-/* 
- * Check if eneque should drop packet to control delay or not based on
- * PIe algorithm.
- * return  DROP if it is time to drop or  ENQUE otherwise.
- * This function is used by PIE and FQ-PIE.
- */
-__inline static int
-drop_early(struct pie_status *pst, uint32_t qlen)
-{
-	struct dn_aqm_pie_parms *pprms;
-
-	pprms = pst->parms;
-
-	/* queue is not congested */
-
-	if ((pst->qdelay_old < (pprms->qdelay_ref >> 1)
-		&& pst->drop_prob < PIE_MAX_PROB / 5 )
-		||  qlen <= 2 * MEAN_PKTSIZE)
-		return ENQUE;
-
-
-	if (pst->drop_prob == 0)
-		pst->accu_prob = 0;
-
-	/* increment accu_prob */
-	if (pprms->flags & PIE_DERAND_ENABLED)
-		pst->accu_prob += pst->drop_prob;
-
-	/* De-randomize option 
-	 * if accu_prob < 0.85 -> enqueue
-	 * if accu_prob>8.5 ->drop
-	 * between 0.85 and 8.5 || !De-randomize --> drop on prob
-	 * 
-	 * (0.85 = 17/20 ,8.5 = 17/2)
-	 */
-	if (pprms->flags & PIE_DERAND_ENABLED) {
-		if(pst->accu_prob < (uint64_t) (PIE_MAX_PROB * 17 / 20))
-			return ENQUE;
-		 if( pst->accu_prob >= (uint64_t) (PIE_MAX_PROB * 17 / 2))
-			return DROP;
-	}
-
-	if (random() < pst->drop_prob) {
-		pst->accu_prob = 0;
-		return DROP;
-	}
-
-	return ENQUE;
-}
-
-#endif
Index: eebsd/sys/netpfil/ipfw/dn_heap.h
===================================================================
--- freebsd/sys/netpfil/ipfw/dn_heap.h	(revision f62c62d2fe57ec02c1350144f7739f8e866ee6d4)
+++ 	(revision )
@@ -1,191 +1,0 @@
-/*-
- * Copyright (c) 1998-2010 Luigi Rizzo, Universita` di Pisa
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
- */
-
-/*
- * Binary heap and hash tables, header file
- *
- * $FreeBSD$
- */
-
-#ifndef _IP_DN_HEAP_H
-#define _IP_DN_HEAP_H
-
-#define DN_KEY_LT(a,b)     ((int64_t)((a)-(b)) < 0)
-#define DN_KEY_LEQ(a,b)    ((int64_t)((a)-(b)) <= 0)
-
-/*
- * This module implements a binary heap supporting random extraction.
- *
- * A heap entry contains an uint64_t key and a pointer to object.
- * DN_KEY_LT(a,b) returns true if key 'a' is smaller than 'b'
- *
- * The heap is a struct dn_heap plus a dynamically allocated
- * array of dn_heap_entry entries. 'size' represents the size of
- * the array, 'elements' count entries in use. The topmost
- * element has the smallest key.
- * The heap supports ordered insert, and extract from the top.
- * To extract an object from the middle of the heap, we the object
- * must reserve an 'int32_t' to store the position of the object
- * in the heap itself, and the location of this field must be
- * passed as an argument to heap_init() -- use -1 if the feature
- * is not used.
- */
-struct dn_heap_entry {
-	uint64_t key;	/* sorting key, smallest comes first */
-	void *object;	/* object pointer */
-};
-
-struct dn_heap {
-	int size;	/* the size of the array */
-	int elements;	/* elements in use */
-	int ofs;	/* offset in the object of heap index */
-	struct dn_heap_entry *p;	/* array of "size" entries */
-};
-
-enum {
-	HEAP_SCAN_DEL = 1,
-	HEAP_SCAN_END = 2,
-};
-
-/*
- * heap_init() reinitializes the heap setting the size and the offset
- *	of the index for random extraction (use -1 if not used).
- *	The 'elements' counter is set to 0.
- *
- * SET_HEAP_OFS() indicates where, in the object, is stored the index
- *	for random extractions from the heap.
- *
- * heap_free() frees the memory associated to a heap.
- *
- * heap_insert() adds a key-pointer pair to the heap
- *
- * HEAP_TOP() returns a pointer to the top element of the heap,
- *	but makes no checks on its existence (XXX should we change ?)
- *
- * heap_extract() removes the entry at the top, returning the pointer.
- *	(the key should have been read before).
- *
- * heap_scan() invokes a callback on each entry of the heap.
- *	The callback can return a combination of HEAP_SCAN_DEL and
- *	HEAP_SCAN_END. HEAP_SCAN_DEL means the current element must
- *	be removed, and HEAP_SCAN_END means to terminate the scan.
- *	heap_scan() returns the number of elements removed.
- *	Because the order is not guaranteed, we should use heap_scan()
- *	only as a last resort mechanism.
- */
-#define HEAP_TOP(h)	((h)->p)
-#define SET_HEAP_OFS(h, n)	do { (h)->ofs = n; } while (0)
-int     heap_init(struct dn_heap *h, int size, int ofs);
-int     heap_insert(struct dn_heap *h, uint64_t key1, void *p);
-void    heap_extract(struct dn_heap *h, void *obj);
-void heap_free(struct dn_heap *h);
-int heap_scan(struct dn_heap *, int (*)(void *, uintptr_t), uintptr_t);
-
-/*------------------------------------------------------
- * This module implements a generic hash table with support for
- * running callbacks on the entire table. To avoid allocating
- * memory during hash table operations, objects must reserve
- * space for a link field. XXX if the heap is moderately full,
- * an SLIST suffices, and we can tolerate the cost of a hash
- * computation on each removal.
- *
- * dn_ht_init() initializes the table, setting the number of
- *	buckets, the offset of the link field, the main callbacks.
- *	Callbacks are:
- * 
- *	hash(key, flags, arg) called to return a bucket index.
- *	match(obj, key, flags, arg) called to determine if key
- *		matches the current 'obj' in the heap
- *	newh(key, flags, arg) optional, used to allocate a new
- *		object during insertions.
- *
- * dn_ht_free() frees the heap or unlink elements.
- *	DNHT_REMOVE unlink elements, 0 frees the heap.
- *	You need two calls to do both.
- *
- * dn_ht_find() is the main lookup function, which can also be
- *	used to insert or delete elements in the hash table.
- *	The final 'arg' is passed to all callbacks.
- *
- * dn_ht_scan() is used to invoke a callback on all entries of
- *	the heap, or possibly on just one bucket. The callback
- *	is invoked with a pointer to the object, and must return
- *	one of DNHT_SCAN_DEL or DNHT_SCAN_END to request the
- *	removal of the object from the heap and the end of the
- *	scan, respectively.
- *
- * dn_ht_scan_bucket() is similar to dn_ht_scan(), except that it scans
- *	only the specific bucket of the table. The bucket is a in-out
- *	parameter and return a valid bucket number if the original
- *	is invalid.
- *
- * A combination of flags can be used to modify the operation
- * of the dn_ht_find(), and of the callbacks:
- *
- * DNHT_KEY_IS_OBJ	means the key is the object pointer.
- *	It is usually of interest for the hash and match functions.
- *
- * DNHT_MATCH_PTR	during a lookup, match pointers instead
- *	of calling match(). Normally used when removing specific
- *	entries. Does not imply KEY_IS_OBJ as the latter _is_ used
- *	by the match function.
- *
- * DNHT_INSERT		insert the element if not found.
- *	Calls new() to allocates a new object unless
- *	DNHT_KEY_IS_OBJ is set.
- *
- * DNHT_UNIQUE		only insert if object not found.
- *	XXX should it imply DNHT_INSERT ?
- *
- * DNHT_REMOVE		remove objects if we find them.
- */
-struct dn_ht;	/* should be opaque */
-
-struct dn_ht *dn_ht_init(struct dn_ht *, int buckets, int ofs, 
-        uint32_t (*hash)(uintptr_t, int, void *),
-        int (*match)(void *, uintptr_t, int, void *),
-        void *(*newh)(uintptr_t, int, void *));
-void dn_ht_free(struct dn_ht *, int flags);
-
-void *dn_ht_find(struct dn_ht *, uintptr_t, int, void *);
-int dn_ht_scan(struct dn_ht *, int (*)(void *, void *), void *);
-int dn_ht_scan_bucket(struct dn_ht *, int * , int (*)(void *, void *), void *);
-int dn_ht_entries(struct dn_ht *);
-
-enum {  /* flags values.
-	 * first two are returned by the scan callback to indicate
-	 * to delete the matching element or to end the scan
-	 */
-        DNHT_SCAN_DEL	= 0x0001,
-        DNHT_SCAN_END	= 0x0002,
-        DNHT_KEY_IS_OBJ	= 0x0004,	/* key is the obj pointer */
-        DNHT_MATCH_PTR	= 0x0008,	/* match by pointer, not match() */
-        DNHT_INSERT	= 0x0010,	/* insert if not found */
-        DNHT_UNIQUE	= 0x0020,	/* report error if already there */
-        DNHT_REMOVE	= 0x0040,	/* remove on find or dn_ht_free */
-}; 
-
-#endif /* _IP_DN_HEAP_H */
Index: eebsd/sys/netpfil/ipfw/dn_sched.h
===================================================================
--- freebsd/sys/netpfil/ipfw/dn_sched.h	(revision f62c62d2fe57ec02c1350144f7739f8e866ee6d4)
+++ 	(revision )
@@ -1,201 +1,0 @@
-/*
- * Copyright (c) 2010 Riccardo Panicucci, Luigi Rizzo, Universita` di Pisa
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
- */
-
-/*
- * The API to write a packet scheduling algorithm for dummynet.
- *
- * $FreeBSD$
- */
-
-#ifndef _DN_SCHED_H
-#define _DN_SCHED_H
-
-#define	DN_MULTIQUEUE	0x01
-/*
- * Descriptor for a scheduling algorithm.
- * Contains all function pointers for a given scheduler
- * This is typically created when a module is loaded, and stored
- * in a global list of schedulers.
- */
-struct dn_alg {
-	uint32_t type;           /* the scheduler type */
-	const char *name;   /* scheduler name */
-	uint32_t flags;	/* DN_MULTIQUEUE if supports multiple queues */
-
-	/*
-	 * The following define the size of 3 optional data structures
-	 * that may need to be allocated at runtime, and are appended
-	 * to each of the base data structures: scheduler, sched.inst,
-	 * and queue. We don't have a per-flowset structure.
-	 */
-	/*    + parameters attached to the template, e.g.
-	 *	default queue sizes, weights, quantum size, and so on;
-	 */
-	size_t schk_datalen;
-
-	/*    + per-instance parameters, such as timestamps,
-	 *	containers for queues, etc;
-	 */
-	size_t si_datalen;
-
-	size_t q_datalen;	/* per-queue parameters (e.g. S,F) */
-
-	/*
-	 * Methods implemented by the scheduler:
-	 * enqueue	enqueue packet 'm' on scheduler 's', queue 'q'.
-	 *	q is NULL for !MULTIQUEUE.
-	 *	Return 0 on success, 1 on drop (packet consumed anyways).
-	 *	Note that q should be interpreted only as a hint
-	 *	on the flow that the mbuf belongs to: while a
-	 *	scheduler will normally enqueue m into q, it is ok
-	 *	to leave q alone and put the mbuf elsewhere.
-	 *	This function is called in two cases:
-	 *	 - when a new packet arrives to the scheduler;
-	 *	 - when a scheduler is reconfigured. In this case the
-	 *	   call is issued by the new_queue callback, with a 
-	 *	   non empty queue (q) and m pointing to the first
-	 *	   mbuf in the queue. For this reason, the function
-	 *	   should internally check for (m != q->mq.head)
-	 *	   before calling dn_enqueue().
-	 *
-	 * dequeue	Called when scheduler instance 's' can
-	 *	dequeue a packet. Return NULL if none are available.
-	 *	XXX what about non work-conserving ?
-	 *
-	 * config	called on 'sched X config ...', normally writes
-	 *	in the area of size sch_arg
-	 *
-	 * destroy	called on 'sched delete', frees everything
-	 *	in sch_arg (other parts are handled by more specific
-	 *	functions)
-	 *
-	 * new_sched    called when a new instance is created, e.g.
-	 *	to create the local queue for !MULTIQUEUE, set V or
-	 *	copy parameters for WFQ, and so on.
-	 *
-	 * free_sched	called when deleting an instance, cleans
-	 *	extra data in the per-instance area.
-	 *
-	 * new_fsk	called when a flowset is linked to a scheduler,
-	 *	e.g. to validate parameters such as weights etc.
-	 * free_fsk	when a flowset is unlinked from a scheduler.
-	 *	(probably unnecessary)
-	 *
-	 * new_queue	called to set the per-queue parameters,
-	 *	e.g. S and F, adjust sum of weights in the parent, etc.
-	 *
-	 *	The new_queue callback is normally called from when
-	 *	creating a new queue. In some cases (such as a
-	 *	scheduler change or reconfiguration) it can be called
-	 *	with a non empty queue. In this case, the queue
-	 *	In case of non empty queue, the new_queue callback could
-	 *	need to call the enqueue function. In this case,
-	 *	the callback should eventually call enqueue() passing
-	 *	as m the first element in the queue.
-	 *
-	 * free_queue	actions related to a queue removal, e.g. undo
-	 *	all the above. If the queue has data in it, also remove
-	 *	from the scheduler. This can e.g. happen during a reconfigure.
-	 */
-	int (*enqueue)(struct dn_sch_inst *, struct dn_queue *,
-		struct mbuf *);
-	struct mbuf * (*dequeue)(struct dn_sch_inst *);
-
-	int (*config)(struct dn_schk *);
-	int (*destroy)(struct dn_schk*);
-	int (*new_sched)(struct dn_sch_inst *);
-	int (*free_sched)(struct dn_sch_inst *);
-	int (*new_fsk)(struct dn_fsk *f);
-	int (*free_fsk)(struct dn_fsk *f);
-	int (*new_queue)(struct dn_queue *q);
-	int (*free_queue)(struct dn_queue *q);
-#ifdef NEW_AQM
-	/* Getting scheduler extra parameters */
-	int (*getconfig)(struct dn_schk *, struct dn_extra_parms *);
-#endif
-
-	/* run-time fields */
-	int ref_count;      /* XXX number of instances in the system */
-	SLIST_ENTRY(dn_alg) next; /* Next scheduler in the list */
-};
-
-/* MSVC does not support initializers so we need this ugly macro */
-#ifdef _WIN32
-#define _SI(fld)
-#else
-#define _SI(fld)	fld
-#endif
-
-/*
- * Additionally, dummynet exports some functions and macros
- * to be used by schedulers:
- */
-
-void dn_free_pkts(struct mbuf *mnext);
-int dn_enqueue(struct dn_queue *q, struct mbuf* m, int drop);
-/* bound a variable between min and max */
-int ipdn_bound_var(int *v, int dflt, int lo, int hi, const char *msg);
-
-/*
- * Extract the head of a queue, update stats. Must be the very last
- * thing done on a dequeue as the queue itself may go away.
- */
-static __inline struct mbuf*
-dn_dequeue(struct dn_queue *q)
-{
-	struct mbuf *m = q->mq.head;
-	if (m == NULL)
-		return NULL;
-#ifdef NEW_AQM
-	/* Call AQM dequeue function  */
-	if (q->fs->aqmfp && q->fs->aqmfp->dequeue )
-		return q->fs->aqmfp->dequeue(q);
-#endif
-	q->mq.head = m->m_nextpkt;
-	q->mq.count--;
-
-	/* Update stats for the queue */
-	q->ni.length--;
-	q->ni.len_bytes -= m->m_pkthdr.len;
-	if (q->_si) {
-		q->_si->ni.length--;
-		q->_si->ni.len_bytes -= m->m_pkthdr.len;
-	}
-	if (q->ni.length == 0) /* queue is now idle */
-		q->q_time = dn_cfg.curr_time;
-	return m;
-}
-
-int dn_sched_modevent(module_t mod, int cmd, void *arg);
-
-#define DECLARE_DNSCHED_MODULE(name, dnsched)			\
-	static moduledata_t name##_mod = {			\
-		#name, dn_sched_modevent, dnsched		\
-	};							\
-	DECLARE_MODULE(name, name##_mod, 			\
-		SI_SUB_PROTO_FIREWALL, SI_ORDER_ANY); 		\
-        MODULE_DEPEND(name, dummynet, 3, 3, 3)
-#endif /* _DN_SCHED_H */
Index: eebsd/sys/netpfil/ipfw/dn_sched_fq_codel.h
===================================================================
--- freebsd/sys/netpfil/ipfw/dn_sched_fq_codel.h	(revision f62c62d2fe57ec02c1350144f7739f8e866ee6d4)
+++ 	(revision )
@@ -1,167 +1,0 @@
-/*-
- * Copyright (C) 2016 Centre for Advanced Internet Architectures,
- *  Swinburne University of Technology, Melbourne, Australia.
- * Portions of this code were made possible in part by a gift from 
- *  The Comcast Innovation Fund.
- * Implemented by Rasool Al-Saadi <ralsaadi@swin.edu.au>
- *
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
- */
-
-/*
- * FQ_Codel Structures and helper functions
- *
- * $FreeBSD$
- */
-
-#ifndef _IP_DN_SCHED_FQ_CODEL_H
-#define _IP_DN_SCHED_FQ_CODEL_H
-
-/* list of queues */
-STAILQ_HEAD(fq_codel_list, fq_codel_flow) ;
-
-/* fq_codel parameters including codel */
-struct dn_sch_fq_codel_parms {
-	struct dn_aqm_codel_parms	ccfg;	/* CoDel Parameters */
-	/* FQ_CODEL Parameters */
-	uint32_t flows_cnt;	/* number of flows */
-	uint32_t limit;	/* hard limit of fq_codel queue size*/
-	uint32_t quantum;
-};	/* defaults */
-
-/* flow (sub-queue) stats */
-struct flow_stats {
-	uint64_t tot_pkts;	/* statistics counters  */
-	uint64_t tot_bytes;
-	uint32_t length;		/* Queue length, in packets */
-	uint32_t len_bytes;	/* Queue length, in bytes */
-	uint32_t drops;
-};
-
-/* A flow of packets (sub-queue).*/
-struct fq_codel_flow {
-	struct mq	mq;	/* list of packets */
-	struct flow_stats stats;	/* statistics */
-	int	deficit;
-	int active;		/* 1: flow is active (in a list) */
-	struct codel_status cst;
-	STAILQ_ENTRY(fq_codel_flow) flowchain;
-};
-
-/* extra fq_codel scheduler configurations */
-struct fq_codel_schk {
-	struct dn_sch_fq_codel_parms cfg;
-};
-
-/* fq_codel scheduler instance */
-struct fq_codel_si {
-	struct dn_sch_inst _si;	/* standard scheduler instance */
-	struct dn_queue main_q; /* main queue is after si directly */
-
-	struct fq_codel_flow *flows; /* array of flows (queues) */
-	uint32_t perturbation; /* random value */
-	struct fq_codel_list newflows;	/* list of new queues */
-	struct fq_codel_list oldflows;		/* list of old queues */
-};
-
-/* Helper function to update queue&main-queue and scheduler statistics.
- * negative len + drop -> drop
- * negative len -> dequeue
- * positive len -> enqueue
- * positive len + drop -> drop during enqueue
- */
-__inline static void
-fq_update_stats(struct fq_codel_flow *q, struct fq_codel_si *si, int len,
-	int drop)
-{
-	int inc = 0;
-
-	if (len < 0) 
-		inc = -1;
-	else if (len > 0)
-		inc = 1;
-
-	if (drop) {
-		si->main_q.ni.drops ++;
-		q->stats.drops ++;
-		si->_si.ni.drops ++;
-		io_pkt_drop ++;
-	} 
-
-	if (!drop || (drop && len < 0)) {
-		/* Update stats for the main queue */
-		si->main_q.ni.length += inc;
-		si->main_q.ni.len_bytes += len;
-
-		/*update sub-queue stats */
-		q->stats.length += inc;
-		q->stats.len_bytes += len;
-
-		/*update scheduler instance stats */
-		si->_si.ni.length += inc;
-		si->_si.ni.len_bytes += len;
-	}
-
-	if (inc > 0) {
-		si->main_q.ni.tot_bytes += len;
-		si->main_q.ni.tot_pkts ++;
-		
-		q->stats.tot_bytes +=len;
-		q->stats.tot_pkts++;
-		
-		si->_si.ni.tot_bytes +=len;
-		si->_si.ni.tot_pkts ++;
-	}
-
-}
-
-/* extract the head of fq_codel sub-queue */
-__inline static struct mbuf *
-fq_codel_extract_head(struct fq_codel_flow *q, aqm_time_t *pkt_ts, struct fq_codel_si *si)
-{
-	struct mbuf *m = q->mq.head;
-
-	if (m == NULL)
-		return m;
-	q->mq.head = m->m_nextpkt;
-
-	fq_update_stats(q, si, -m->m_pkthdr.len, 0);
-
-	if (si->main_q.ni.length == 0) /* queue is now idle */
-			si->main_q.q_time = dn_cfg.curr_time;
-
-	/* extract packet timestamp*/
-	struct m_tag *mtag;
-	mtag = m_tag_locate(m, MTAG_ABI_COMPAT, DN_AQM_MTAG_TS, NULL);
-	if (mtag == NULL){
-		D("timestamp tag is not found!");
-		*pkt_ts = 0;
-	} else {
-		*pkt_ts = *(aqm_time_t *)(mtag + 1);
-		m_tag_delete(m,mtag); 
-	}
-
-	return m;
-}
-
-
-#endif
Index: eebsd/sys/netpfil/ipfw/dn_sched_fq_codel_helper.h
===================================================================
--- freebsd/sys/netpfil/ipfw/dn_sched_fq_codel_helper.h	(revision f62c62d2fe57ec02c1350144f7739f8e866ee6d4)
+++ 	(revision )
@@ -1,187 +1,0 @@
-/*
- * Codel - The Controlled-Delay Active Queue Management algorithm.
- *
- * $FreeBSD$
- * 
- * Copyright (C) 2016 Centre for Advanced Internet Architectures,
- *  Swinburne University of Technology, Melbourne, Australia.
- * Portions of this code were made possible in part by a gift from 
- *  The Comcast Innovation Fund.
- * Implemented by Rasool Al-Saadi <ralsaadi@swin.edu.au>
- *
- * Copyright (C) 2011-2014 Kathleen Nichols <nichols@pollere.com>.
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * o  Redistributions of source code must retain the above copyright
- *  notice, this list of conditions, and the following disclaimer,
- *  without modification.
- *
- * o  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.
- * 
- * o  The names of the authors may not be used to endorse or promote
- *  products derived from this software without specific prior written
- *  permission.
- *
- * Alternatively, provided that this notice is retained in full, this
- * software may be distributed under the terms of the GNU General Public
- * License ("GPL") version 2, in which case the provisions of the GPL
- * apply INSTEAD OF those given above.
-
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT
- * OWNER 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.
- */
-
-#ifndef _IP_DN_SCHED_FQ_CODEL_HELPER_H
-#define _IP_DN_SCHED_FQ_CODEL_HELPER_H
-
-__inline static struct mbuf *
-fqc_dodequeue(struct fq_codel_flow *q, aqm_time_t now, uint16_t *ok_to_drop,
-	struct fq_codel_si *si)
-{
-	struct mbuf * m;
-	struct fq_codel_schk *schk = (struct fq_codel_schk *)(si->_si.sched+1);
-	aqm_time_t  pkt_ts, sojourn_time;
-
-	*ok_to_drop = 0;
-	m = fq_codel_extract_head(q, &pkt_ts, si);
-
-	if (m == NULL) {
-		/*queue is empty - we can't be above target*/
-		q->cst.first_above_time= 0;
-		return m;
-	}
-
-	/* To span a large range of bandwidths, CoDel runs two
-	 * different AQMs in parallel. One is sojourn-time-based
-	 * and takes effect when the time to send an MTU-sized
-	 * packet is less than target.  The 1st term of the "if"
-	 * below does this.  The other is backlog-based and takes
-	 * effect when the time to send an MTU-sized packet is >=
-	* target. The goal here is to keep the output link
-	* utilization high by never allowing the queue to get
-	* smaller than the amount that arrives in a typical
-	 * interarrival time (MTU-sized packets arriving spaced
-	 * by the amount of time it takes to send such a packet on
-	 * the bottleneck). The 2nd term of the "if" does this.
-	 */
-	sojourn_time = now - pkt_ts;
-	if (sojourn_time < schk->cfg.ccfg.target || q->stats.len_bytes <= q->cst.maxpkt_size) {
-		/* went below - stay below for at least interval */
-		q->cst.first_above_time = 0;
-	} else {
-		if (q->cst.first_above_time == 0) {
-			/* just went above from below. if still above at
-			 * first_above_time, will say it's ok to drop. */
-			q->cst.first_above_time = now + schk->cfg.ccfg.interval;
-		} else if (now >= q->cst.first_above_time) {
-			*ok_to_drop = 1;
-		}
-	}
-	return m;
-}
-
-/* Codel dequeue function */
-__inline static struct mbuf * 
-fqc_codel_dequeue(struct fq_codel_flow *q, struct fq_codel_si *si)
-{
-	struct mbuf *m;
-	struct dn_aqm_codel_parms *cprms;
-	struct codel_status *cst;
-	aqm_time_t now;
-	uint16_t ok_to_drop;
-	struct fq_codel_schk *schk = (struct fq_codel_schk *)(si->_si.sched+1);
-
-	cst = &q->cst;
-	cprms = &schk->cfg.ccfg;
-
-	now = AQM_UNOW;
-	m = fqc_dodequeue(q, now, &ok_to_drop, si);
-
-	if (cst->dropping) {
-		if (!ok_to_drop) {
-			/* sojourn time below target - leave dropping state */
-			cst->dropping = false;
-		}
-
-		/* Time for the next drop. Drop current packet and dequeue
-		 * next.  If the dequeue doesn't take us out of dropping
-		 * state, schedule the next drop. A large backlog might
-		 * result in drop rates so high that the next drop should
-		 * happen now, hence the 'while' loop.
-		 */
-		while (now >= cst->drop_next_time && cst->dropping) {
-
-			/* mark the packet */
-			if (cprms->flags & CODEL_ECN_ENABLED && ecn_mark(m)) {
-				cst->count++;
-				/* schedule the next mark. */
-				cst->drop_next_time = control_law(cst, cprms, cst->drop_next_time);
-				return m;
-			}
-
-			/* drop the packet */
-			fq_update_stats(q, si, 0, 1);
-			m_freem(m);
-			m = fqc_dodequeue(q, now, &ok_to_drop, si);
-
-			if (!ok_to_drop) {
-				/* leave dropping state */
-				cst->dropping = false;
-			} else {
-				cst->count++;
-				/* schedule the next drop. */
-				cst->drop_next_time = control_law(cst, cprms, cst->drop_next_time);
-			}
-		}
-	/* If we get here we're not in dropping state. The 'ok_to_drop'
-	 * return from dodequeue means that the sojourn time has been
-	 * above 'target' for 'interval' so enter dropping state.
-	 */
-	} else if (ok_to_drop) {
-
-		/* if ECN option is disabled or the packet cannot be marked,
-		 * drop the packet and extract another.
-		 */
-		if (!(cprms->flags & CODEL_ECN_ENABLED) || !ecn_mark(m)) {
-			fq_update_stats(q, si, 0, 1);
-			m_freem(m);
-			m = fqc_dodequeue(q, now, &ok_to_drop,si);
-		}
-
-		cst->dropping = true;
-
-		/* If min went above target close to when it last went
-		 * below, assume that the drop rate that controlled the
-		 * queue on the last cycle is a good starting point to
-		 * control it now. ('drop_next' will be at most 'interval'
-		 * later than the time of the last drop so 'now - drop_next'
-		 * is a good approximation of the time from the last drop
-		 * until now.)
-		 */
-		cst->count = (cst->count > 2 && ((aqm_stime_t)now - 
-			(aqm_stime_t)cst->drop_next_time) < 8* cprms->interval)? cst->count - 2 : 1;
-
-		/* we don't have to set initial guess for Newton's method isqrt as
-		 * we initilaize  isqrt in control_law function when count == 1 */
-		cst->drop_next_time = control_law(cst, cprms, now);
-	}
-
-	return m;
-}
-
-#endif
Index: eebsd/sys/netpfil/ipfw/ip_dn_private.h
===================================================================
--- freebsd/sys/netpfil/ipfw/ip_dn_private.h	(revision f62c62d2fe57ec02c1350144f7739f8e866ee6d4)
+++ 	(revision )
@@ -1,463 +1,0 @@
-/*-
- * Copyright (c) 2010 Luigi Rizzo, Riccardo Panicucci, Universita` di Pisa
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
- */
-
-/*
- * internal dummynet APIs.
- *
- * $FreeBSD$
- */
-
-#ifndef _IP_DN_PRIVATE_H
-#define _IP_DN_PRIVATE_H
-
-/* debugging support
- * use ND() to remove debugging, D() to print a line,
- * DX(level, ...) to print above a certain level
- * If you redefine D() you are expected to redefine all.
- */
-#ifndef D
-#define ND(fmt, ...) do {} while (0)
-#define D1(fmt, ...) do {} while (0)
-#define D(fmt, ...) printf("%-10s " fmt "\n",      \
-        __FUNCTION__, ## __VA_ARGS__)
-#define DX(lev, fmt, ...) do {              \
-        if (dn_cfg.debug > lev) D(fmt, ## __VA_ARGS__); } while (0)
-#endif
-
-MALLOC_DECLARE(M_DUMMYNET);
-
-#ifndef __linux__
-#define div64(a, b)  ((int64_t)(a) / (int64_t)(b))
-#endif
-
-#define DN_LOCK_INIT() do {				\
-	mtx_init(&dn_cfg.uh_mtx, "dn_uh", NULL, MTX_DEF);	\
-	mtx_init(&dn_cfg.bh_mtx, "dn_bh", NULL, MTX_DEF);	\
-	} while (0)
-#define DN_LOCK_DESTROY() do {				\
-	mtx_destroy(&dn_cfg.uh_mtx);			\
-	mtx_destroy(&dn_cfg.bh_mtx);			\
-	} while (0)
-#if 0 /* not used yet */
-#define DN_UH_RLOCK()		mtx_lock(&dn_cfg.uh_mtx)
-#define DN_UH_RUNLOCK()		mtx_unlock(&dn_cfg.uh_mtx)
-#define DN_UH_WLOCK()		mtx_lock(&dn_cfg.uh_mtx)
-#define DN_UH_WUNLOCK()		mtx_unlock(&dn_cfg.uh_mtx)
-#define DN_UH_LOCK_ASSERT()	mtx_assert(&dn_cfg.uh_mtx, MA_OWNED)
-#endif
-
-#define DN_BH_RLOCK()		mtx_lock(&dn_cfg.uh_mtx)
-#define DN_BH_RUNLOCK()		mtx_unlock(&dn_cfg.uh_mtx)
-#define DN_BH_WLOCK()		mtx_lock(&dn_cfg.uh_mtx)
-#define DN_BH_WUNLOCK()		mtx_unlock(&dn_cfg.uh_mtx)
-#define DN_BH_LOCK_ASSERT()	mtx_assert(&dn_cfg.uh_mtx, MA_OWNED)
-
-SLIST_HEAD(dn_schk_head, dn_schk);
-SLIST_HEAD(dn_sch_inst_head, dn_sch_inst);
-SLIST_HEAD(dn_fsk_head, dn_fsk);
-SLIST_HEAD(dn_queue_head, dn_queue);
-SLIST_HEAD(dn_alg_head, dn_alg);
-
-#ifdef NEW_AQM
-SLIST_HEAD(dn_aqm_head, dn_aqm); /* for new AQMs */
-#endif
-
-struct mq {	/* a basic queue of packets*/
-        struct mbuf *head, *tail;
-	int count;
-};
-
-static inline void
-set_oid(struct dn_id *o, int type, int len)
-{
-        o->type = type;
-        o->len = len;
-        o->subtype = 0;
-}
-
-/*
- * configuration and global data for a dummynet instance
- *
- * When a configuration is modified from userland, 'id' is incremented
- * so we can use the value to check for stale pointers.
- */
-struct dn_parms {
-	uint32_t	id;		/* configuration version */
-
-	/* defaults (sysctl-accessible) */
-	int	red_lookup_depth;
-	int	red_avg_pkt_size;
-	int	red_max_pkt_size;
-	int	hash_size;
-	int	max_hash_size;
-	long	byte_limit;		/* max queue sizes */
-	long	slot_limit;
-
-	int	io_fast;
-	int	debug;
-
-	/* timekeeping */
-	struct timeval prev_t;		/* last time dummynet_tick ran */
-	struct dn_heap	evheap;		/* scheduled events */
-
-	/* counters of objects -- used for reporting space */
-	int	schk_count;
-	int	si_count;
-	int	fsk_count;
-	int	queue_count;
-
-	/* ticks and other stuff */
-	uint64_t	curr_time;
-	/* flowsets and schedulers are in hash tables, with 'hash_size'
-	 * buckets. fshash is looked up at every packet arrival
-	 * so better be generous if we expect many entries.
-	 */
-	struct dn_ht	*fshash;
-	struct dn_ht	*schedhash;
-	/* list of flowsets without a scheduler -- use sch_chain */
-	struct dn_fsk_head	fsu;	/* list of unlinked flowsets */
-	struct dn_alg_head	schedlist;	/* list of algorithms */
-#ifdef NEW_AQM
-	struct dn_aqm_head	aqmlist;	/* list of AQMs */
-#endif
-
-	/* Store the fs/sch to scan when draining. The value is the
-	 * bucket number of the hash table. Expire can be disabled
-	 * with net.inet.ip.dummynet.expire=0, or it happens every
-	 * expire ticks.
-	 **/
-	int drain_fs;
-	int drain_sch;
-	uint32_t expire;
-	uint32_t expire_cycle;	/* tick count */
-
-	int init_done;
-
-	/* if the upper half is busy doing something long,
-	 * can set the busy flag and we will enqueue packets in
-	 * a queue for later processing.
-	 */
-	int	busy;
-	struct	mq	pending;
-
-#ifdef _KERNEL
-	/*
-	 * This file is normally used in the kernel, unless we do
-	 * some userland tests, in which case we do not need a mtx.
-	 * uh_mtx arbitrates between system calls and also
-	 * protects fshash, schedhash and fsunlinked.
-	 * These structures are readonly for the lower half.
-	 * bh_mtx protects all other structures which may be
-	 * modified upon packet arrivals
-	 */
-#if defined( __linux__ ) || defined( _WIN32 )
-	spinlock_t uh_mtx;
-	spinlock_t bh_mtx;
-#else
-	struct mtx uh_mtx;
-	struct mtx bh_mtx;
-#endif
-
-#endif /* _KERNEL */
-};
-
-/*
- * Delay line, contains all packets on output from a link.
- * Every scheduler instance has one.
- */
-struct delay_line {
-	struct dn_id oid;
-	struct dn_sch_inst *si;
-	struct mq mq;
-};
-
-/*
- * The kernel side of a flowset. It is linked in a hash table
- * of flowsets, and in a list of children of their parent scheduler.
- * qht is either the queue or (if HAVE_MASK) a hash table queues.
- * Note that the mask to use is the (flow_mask|sched_mask), which
- * changes as we attach/detach schedulers. So we store it here.
- *
- * XXX If we want to add scheduler-specific parameters, we need to
- * put them in external storage because the scheduler may not be
- * available when the fsk is created.
- */
-struct dn_fsk { /* kernel side of a flowset */
-	struct dn_fs fs;
-	SLIST_ENTRY(dn_fsk) fsk_next;	/* hash chain for fshash */
-
-	struct ipfw_flow_id fsk_mask;
-
-	/* qht is a hash table of queues, or just a single queue
-	 * a bit in fs.flags tells us which one
-	 */
-	struct dn_ht	*qht;
-	struct dn_schk *sched;		/* Sched we are linked to */
-	SLIST_ENTRY(dn_fsk) sch_chain;	/* list of fsk attached to sched */
-
-	/* bucket index used by drain routine to drain queues for this
-	 * flowset
-	 */
-	int drain_bucket;
-	/* Parameter realted to RED / GRED */
-	/* original values are in dn_fs*/
-	int w_q ;		/* queue weight (scaled) */
-	int max_th ;		/* maximum threshold for queue (scaled) */
-	int min_th ;		/* minimum threshold for queue (scaled) */
-	int max_p ;		/* maximum value for p_b (scaled) */
-
-	u_int c_1 ;		/* max_p/(max_th-min_th) (scaled) */
-	u_int c_2 ;		/* max_p*min_th/(max_th-min_th) (scaled) */
-	u_int c_3 ;		/* for GRED, (1-max_p)/max_th (scaled) */
-	u_int c_4 ;		/* for GRED, 1 - 2*max_p (scaled) */
-	u_int * w_q_lookup ;	/* lookup table for computing (1-w_q)^t */
-	u_int lookup_depth ;	/* depth of lookup table */
-	int lookup_step ;	/* granularity inside the lookup table */
-	int lookup_weight ;	/* equal to (1-w_q)^t / (1-w_q)^(t+1) */
-	int avg_pkt_size ;	/* medium packet size */
-	int max_pkt_size ;	/* max packet size */
-#ifdef NEW_AQM
-	struct dn_aqm *aqmfp;	/* Pointer to AQM functions */
-	void *aqmcfg;	/* configuration parameters for AQM */
-#endif
-};
-
-/*
- * A queue is created as a child of a flowset unless it belongs to
- * a !MULTIQUEUE scheduler. It is normally in a hash table in the
- * flowset. fs always points to the parent flowset.
- * si normally points to the sch_inst, unless the flowset has been
- * detached from the scheduler -- in this case si == NULL and we
- * should not enqueue.
- */
-struct dn_queue {
-	struct dn_flow ni;	/* oid, flow_id, stats */
-	struct mq mq;	/* packets queue */
-	struct dn_sch_inst *_si;	/* owner scheduler instance */
-	SLIST_ENTRY(dn_queue) q_next; /* hash chain list for qht */
-	struct dn_fsk *fs;		/* parent flowset. */
-
-	/* RED parameters */
-	int avg;		/* average queue length est. (scaled) */
-	int count;		/* arrivals since last RED drop */
-	int random;		/* random value (scaled) */
-	uint64_t q_time;	/* start of queue idle time */
-#ifdef NEW_AQM
-	void *aqm_status;	/* per-queue status variables*/
-#endif
-
-};
-
-/*
- * The kernel side of a scheduler. Contains the userland config,
- * a link, pointer to extra config arguments from command line,
- * kernel flags, and a pointer to the scheduler methods.
- * It is stored in a hash table, and holds a list of all
- * flowsets and scheduler instances.
- * XXX sch must be at the beginning, see schk_hash().
- */
-struct dn_schk {
-	struct dn_sch sch;
-	struct dn_alg *fp;	/* Pointer to scheduler functions */
-	struct dn_link link;	/* The link, embedded */
-	struct dn_profile *profile; /* delay profile, if any */
-	struct dn_id *cfg;	/* extra config arguments */
-
-	SLIST_ENTRY(dn_schk) schk_next;  /* hash chain for schedhash */
-
-	struct dn_fsk_head fsk_list;  /* all fsk linked to me */
-	struct dn_fsk *fs;	/* Flowset for !MULTIQUEUE */
-
-	/* bucket index used by the drain routine to drain the scheduler
-	 * instance for this flowset.
-	 */
-	int drain_bucket;
-
-	/* Hash table of all instances (through sch.sched_mask)
-	 * or single instance if no mask. Always valid.
-	 */
-	struct dn_ht	*siht;
-};
-
-
-/*
- * Scheduler instance.
- * Contains variables and all queues relative to a this instance.
- * This struct is created a runtime.
- */
-struct dn_sch_inst {
-	struct dn_flow	ni;	/* oid, flowid and stats */
-	SLIST_ENTRY(dn_sch_inst) si_next; /* hash chain for siht */
-	struct delay_line dline;
-	struct dn_schk *sched;	/* the template */
-	int		kflags;	/* DN_ACTIVE */
-
-	int64_t	credit;		/* bits I can transmit (more or less). */
-	uint64_t sched_time;	/* time link was scheduled in ready_heap */
-	uint64_t idle_time;	/* start of scheduler instance idle time */
-
-	/* q_count is the number of queues that this instance is using.
-	 * The counter is incremented or decremented when
-	 * a reference from the queue is created or deleted.
-	 * It is used to make sure that a scheduler instance can be safely
-	 * deleted by the drain routine. See notes below.
-	 */
-	int q_count;
-
-};
-
-/*
- * NOTE about object drain.
- * The system will automatically (XXX check when) drain queues and
- * scheduler instances when they are idle.
- * A queue is idle when it has no packets; an instance is idle when
- * it is not in the evheap heap, and the corresponding delay line is empty.
- * A queue can be safely deleted when it is idle because of the scheduler
- * function xxx_free_queue() will remove any references to it.
- * An instance can be only deleted when no queues reference it. To be sure
- * of that, a counter (q_count) stores the number of queues that are pointing
- * to the instance.
- *
- * XXX
- * Order of scan:
- * - take all flowset in a bucket for the flowset hash table
- * - take all queues in a bucket for the flowset
- * - increment the queue bucket
- * - scan next flowset bucket
- * Nothing is done if a bucket contains no entries.
- *
- * The same schema is used for sceduler instances
- */
-
-
-/* kernel-side flags. Linux has DN_DELETE in fcntl.h
- */
-enum {
-	/* 1 and 2 are reserved for the SCAN flags */
-	DN_DESTROY	= 0x0004, /* destroy */
-	DN_DELETE_FS	= 0x0008, /* destroy flowset */
-	DN_DETACH	= 0x0010,
-	DN_ACTIVE	= 0x0020, /* object is in evheap */
-	DN_F_DLINE	= 0x0040, /* object is a delay line */
-	DN_DEL_SAFE	= 0x0080, /* delete a queue only if no longer needed
-				   * by scheduler */
-	DN_QHT_IS_Q	= 0x0100, /* in flowset, qht is a single queue */
-};
-
-extern struct dn_parms dn_cfg;
-//VNET_DECLARE(struct dn_parms, _base_dn_cfg);
-//#define dn_cfg	VNET(_base_dn_cfg)
-
-int dummynet_io(struct mbuf **, int , struct ip_fw_args *);
-void dummynet_task(void *context, int pending);
-void dn_reschedule(void);
-
-struct dn_queue *ipdn_q_find(struct dn_fsk *, struct dn_sch_inst *,
-        struct ipfw_flow_id *);
-struct dn_sch_inst *ipdn_si_find(struct dn_schk *, struct ipfw_flow_id *);
-
-/*
- * copy_range is a template for requests for ranges of pipes/queues/scheds.
- * The number of ranges is variable and can be derived by o.len.
- * As a default, we use a small number of entries so that the struct
- * fits easily on the stack and is sufficient for most common requests.
- */
-#define DEFAULT_RANGES	5
-struct copy_range {
-        struct dn_id o;
-        uint32_t	r[ 2 * DEFAULT_RANGES ];
-};
-
-struct copy_args {
-	char **start;
-	char *end;
-	int flags;
-	int type;
-	struct copy_range *extra;	/* extra filtering */
-};
-
-struct sockopt;
-int ip_dummynet_compat(struct sockopt *sopt);
-int dummynet_get(struct sockopt *sopt, void **compat);
-int dn_c_copy_q (void *_ni, void *arg);
-int dn_c_copy_pipe(struct dn_schk *s, struct copy_args *a, int nq);
-int dn_c_copy_fs(struct dn_fsk *f, struct copy_args *a, int nq);
-int dn_compat_copy_queue(struct copy_args *a, void *_o);
-int dn_compat_copy_pipe(struct copy_args *a, void *_o);
-int copy_data_helper_compat(void *_o, void *_arg);
-int dn_compat_calc_size(void);
-int do_config(void *p, int l);
-
-/* function to drain idle object */
-void dn_drain_scheduler(void);
-void dn_drain_queue(void);
-
-#ifdef NEW_AQM
-int ecn_mark(struct mbuf* m);
-
-/* moved from ip_dn_io.c to here to be available for AQMs modules*/
-static inline void
-mq_append(struct mq *q, struct mbuf *m)
-{
-#ifdef USERSPACE
-	// buffers from netmap need to be copied
-	// XXX note that the routine is not expected to fail
-	ND("append %p to %p", m, q);
-	if (m->m_flags & M_STACK) {
-		struct mbuf *m_new;
-		void *p;
-		int l, ofs;
-
-		ofs = m->m_data - m->__m_extbuf;
-		// XXX allocate
-		MGETHDR(m_new, M_NOWAIT, MT_DATA);
-		ND("*** WARNING, volatile buf %p ext %p %d dofs %d m_new %p",
-			m, m->__m_extbuf, m->__m_extlen, ofs, m_new);
-		p = m_new->__m_extbuf;	/* new pointer */
-		l = m_new->__m_extlen;	/* new len */
-		if (l <= m->__m_extlen) {
-			panic("extlen too large");
-		}
-
-		*m_new = *m;	// copy
-		m_new->m_flags &= ~M_STACK;
-		m_new->__m_extbuf = p; // point to new buffer
-		_pkt_copy(m->__m_extbuf, p, m->__m_extlen);
-		m_new->m_data = p + ofs;
-		m = m_new;
-	}
-#endif /* USERSPACE */
-	if (q->head == NULL)
-		q->head = m;
-	else
-		q->tail->m_nextpkt = m;
-	q->count++;
-	q->tail = m;
-	m->m_nextpkt = NULL;
-}
-#endif /* NEW_AQM */
-
-#endif /* _IP_DN_PRIVATE_H */
Index: eebsd/sys/netpfil/ipfw/ip_fw2.c
===================================================================
--- freebsd/sys/netpfil/ipfw/ip_fw2.c	(revision f62c62d2fe57ec02c1350144f7739f8e866ee6d4)
+++ 	(revision )
@@ -1,3024 +1,0 @@
-#include <machine/rtems-bsd-kernel-space.h>
-
-/*-
- * Copyright (c) 2002-2009 Luigi Rizzo, Universita` di Pisa
- *
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-/*
- * The FreeBSD IP packet firewall, main file
- */
-
-#include <rtems/bsd/local/opt_ipfw.h>
-#include <rtems/bsd/local/opt_ipdivert.h>
-#include <rtems/bsd/local/opt_inet.h>
-#ifndef INET
-#error "IPFIREWALL requires INET"
-#endif /* INET */
-#include <rtems/bsd/local/opt_inet6.h>
-#include <rtems/bsd/local/opt_ipsec.h>
-
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/condvar.h>
-#include <sys/counter.h>
-#include <sys/eventhandler.h>
-#include <sys/malloc.h>
-#include <sys/mbuf.h>
-#include <sys/kernel.h>
-#include <sys/lock.h>
-#include <sys/jail.h>
-#include <sys/module.h>
-#include <sys/priv.h>
-#include <sys/proc.h>
-#include <sys/rwlock.h>
-#include <sys/rmlock.h>
-#include <sys/socket.h>
-#include <sys/socketvar.h>
-#include <sys/sysctl.h>
-#include <sys/syslog.h>
-#include <sys/ucred.h>
-#include <net/ethernet.h> /* for ETHERTYPE_IP */
-#include <net/if.h>
-#include <net/if_var.h>
-#include <net/route.h>
-#include <net/pfil.h>
-#include <net/vnet.h>
-
-#include <netpfil/pf/pf_mtag.h>
-
-#include <netinet/in.h>
-#include <netinet/in_var.h>
-#include <netinet/in_pcb.h>
-#include <netinet/ip.h>
-#include <netinet/ip_var.h>
-#include <netinet/ip_icmp.h>
-#include <netinet/ip_fw.h>
-#include <netinet/ip_carp.h>
-#include <netinet/pim.h>
-#include <netinet/tcp_var.h>
-#include <netinet/udp.h>
-#include <netinet/udp_var.h>
-#include <netinet/sctp.h>
-
-#include <netinet/ip6.h>
-#include <netinet/icmp6.h>
-#include <netinet/in_fib.h>
-#ifdef INET6
-#include <netinet6/in6_fib.h>
-#include <netinet6/in6_pcb.h>
-#include <netinet6/scope6_var.h>
-#include <netinet6/ip6_var.h>
-#endif
-
-#include <netpfil/ipfw/ip_fw_private.h>
-
-#include <machine/in_cksum.h>	/* XXX for in_cksum */
-
-#ifdef MAC
-#include <security/mac/mac_framework.h>
-#endif
-
-/*
- * static variables followed by global ones.
- * All ipfw global variables are here.
- */
-
-static VNET_DEFINE(int, fw_deny_unknown_exthdrs);
-#define	V_fw_deny_unknown_exthdrs	VNET(fw_deny_unknown_exthdrs)
-
-static VNET_DEFINE(int, fw_permit_single_frag6) = 1;
-#define	V_fw_permit_single_frag6	VNET(fw_permit_single_frag6)
-
-#ifdef IPFIREWALL_DEFAULT_TO_ACCEPT
-static int default_to_accept = 1;
-#else
-static int default_to_accept;
-#endif
-
-VNET_DEFINE(int, autoinc_step);
-VNET_DEFINE(int, fw_one_pass) = 1;
-
-VNET_DEFINE(unsigned int, fw_tables_max);
-VNET_DEFINE(unsigned int, fw_tables_sets) = 0;	/* Don't use set-aware tables */
-/* Use 128 tables by default */
-static unsigned int default_fw_tables = IPFW_TABLES_DEFAULT;
-
-#ifndef LINEAR_SKIPTO
-static int jump_fast(struct ip_fw_chain *chain, struct ip_fw *f, int num,
-    int tablearg, int jump_backwards);
-#define	JUMP(ch, f, num, targ, back)	jump_fast(ch, f, num, targ, back)
-#else
-static int jump_linear(struct ip_fw_chain *chain, struct ip_fw *f, int num,
-    int tablearg, int jump_backwards);
-#define	JUMP(ch, f, num, targ, back)	jump_linear(ch, f, num, targ, back)
-#endif
-
-/*
- * Each rule belongs to one of 32 different sets (0..31).
- * The variable set_disable contains one bit per set.
- * If the bit is set, all rules in the corresponding set
- * are disabled. Set RESVD_SET(31) is reserved for the default rule
- * and rules that are not deleted by the flush command,
- * and CANNOT be disabled.
- * Rules in set RESVD_SET can only be deleted individually.
- */
-VNET_DEFINE(u_int32_t, set_disable);
-#define	V_set_disable			VNET(set_disable)
-
-VNET_DEFINE(int, fw_verbose);
-/* counter for ipfw_log(NULL...) */
-VNET_DEFINE(u_int64_t, norule_counter);
-VNET_DEFINE(int, verbose_limit);
-
-/* layer3_chain contains the list of rules for layer 3 */
-VNET_DEFINE(struct ip_fw_chain, layer3_chain);
-
-/* ipfw_vnet_ready controls when we are open for business */
-VNET_DEFINE(int, ipfw_vnet_ready) = 0;
-
-VNET_DEFINE(int, ipfw_nat_ready) = 0;
-
-ipfw_nat_t *ipfw_nat_ptr = NULL;
-struct cfg_nat *(*lookup_nat_ptr)(struct nat_list *, int);
-ipfw_nat_cfg_t *ipfw_nat_cfg_ptr;
-ipfw_nat_cfg_t *ipfw_nat_del_ptr;
-ipfw_nat_cfg_t *ipfw_nat_get_cfg_ptr;
-ipfw_nat_cfg_t *ipfw_nat_get_log_ptr;
-
-#ifdef SYSCTL_NODE
-uint32_t dummy_def = IPFW_DEFAULT_RULE;
-static int sysctl_ipfw_table_num(SYSCTL_HANDLER_ARGS);
-static int sysctl_ipfw_tables_sets(SYSCTL_HANDLER_ARGS);
-
-SYSBEGIN(f3)
-
-SYSCTL_NODE(_net_inet_ip, OID_AUTO, fw, CTLFLAG_RW, 0, "Firewall");
-SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, one_pass,
-    CTLFLAG_VNET | CTLFLAG_RW | CTLFLAG_SECURE3, &VNET_NAME(fw_one_pass), 0,
-    "Only do a single pass through ipfw when using dummynet(4)");
-SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, autoinc_step,
-    CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(autoinc_step), 0,
-    "Rule number auto-increment step");
-SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, verbose,
-    CTLFLAG_VNET | CTLFLAG_RW | CTLFLAG_SECURE3, &VNET_NAME(fw_verbose), 0,
-    "Log matches to ipfw rules");
-SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, verbose_limit,
-    CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(verbose_limit), 0,
-    "Set upper limit of matches of ipfw rules logged");
-SYSCTL_UINT(_net_inet_ip_fw, OID_AUTO, default_rule, CTLFLAG_RD,
-    &dummy_def, 0,
-    "The default/max possible rule number.");
-SYSCTL_PROC(_net_inet_ip_fw, OID_AUTO, tables_max,
-    CTLFLAG_VNET | CTLTYPE_UINT | CTLFLAG_RW, 0, 0, sysctl_ipfw_table_num, "IU",
-    "Maximum number of concurrently used tables");
-SYSCTL_PROC(_net_inet_ip_fw, OID_AUTO, tables_sets,
-    CTLFLAG_VNET | CTLTYPE_UINT | CTLFLAG_RW,
-    0, 0, sysctl_ipfw_tables_sets, "IU",
-    "Use per-set namespace for tables");
-SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, default_to_accept, CTLFLAG_RDTUN,
-    &default_to_accept, 0,
-    "Make the default rule accept all packets.");
-TUNABLE_INT("net.inet.ip.fw.tables_max", (int *)&default_fw_tables);
-SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, static_count,
-    CTLFLAG_VNET | CTLFLAG_RD, &VNET_NAME(layer3_chain.n_rules), 0,
-    "Number of static rules");
-
-#ifdef INET6
-SYSCTL_DECL(_net_inet6_ip6);
-SYSCTL_NODE(_net_inet6_ip6, OID_AUTO, fw, CTLFLAG_RW, 0, "Firewall");
-SYSCTL_INT(_net_inet6_ip6_fw, OID_AUTO, deny_unknown_exthdrs,
-    CTLFLAG_VNET | CTLFLAG_RW | CTLFLAG_SECURE,
-    &VNET_NAME(fw_deny_unknown_exthdrs), 0,
-    "Deny packets with unknown IPv6 Extension Headers");
-SYSCTL_INT(_net_inet6_ip6_fw, OID_AUTO, permit_single_frag6,
-    CTLFLAG_VNET | CTLFLAG_RW | CTLFLAG_SECURE,
-    &VNET_NAME(fw_permit_single_frag6), 0,
-    "Permit single packet IPv6 fragments");
-#endif /* INET6 */
-
-SYSEND
-
-#endif /* SYSCTL_NODE */
-
-
-/*
- * Some macros used in the various matching options.
- * L3HDR maps an ipv4 pointer into a layer3 header pointer of type T
- * Other macros just cast void * into the appropriate type
- */
-#define	L3HDR(T, ip)	((T *)((u_int32_t *)(ip) + (ip)->ip_hl))
-#define	TCP(p)		((struct tcphdr *)(p))
-#define	SCTP(p)		((struct sctphdr *)(p))
-#define	UDP(p)		((struct udphdr *)(p))
-#define	ICMP(p)		((struct icmphdr *)(p))
-#define	ICMP6(p)	((struct icmp6_hdr *)(p))
-
-static __inline int
-icmptype_match(struct icmphdr *icmp, ipfw_insn_u32 *cmd)
-{
-	int type = icmp->icmp_type;
-
-	return (type <= ICMP_MAXTYPE && (cmd->d[0] & (1<<type)) );
-}
-
-#define TT	( (1 << ICMP_ECHO) | (1 << ICMP_ROUTERSOLICIT) | \
-    (1 << ICMP_TSTAMP) | (1 << ICMP_IREQ) | (1 << ICMP_MASKREQ) )
-
-static int
-is_icmp_query(struct icmphdr *icmp)
-{
-	int type = icmp->icmp_type;
-
-	return (type <= ICMP_MAXTYPE && (TT & (1<<type)) );
-}
-#undef TT
-
-/*
- * The following checks use two arrays of 8 or 16 bits to store the
- * bits that we want set or clear, respectively. They are in the
- * low and high half of cmd->arg1 or cmd->d[0].
- *
- * We scan options and store the bits we find set. We succeed if
- *
- *	(want_set & ~bits) == 0 && (want_clear & ~bits) == want_clear
- *
- * The code is sometimes optimized not to store additional variables.
- */
-
-static int
-flags_match(ipfw_insn *cmd, u_int8_t bits)
-{
-	u_char want_clear;
-	bits = ~bits;
-
-	if ( ((cmd->arg1 & 0xff) & bits) != 0)
-		return 0; /* some bits we want set were clear */
-	want_clear = (cmd->arg1 >> 8) & 0xff;
-	if ( (want_clear & bits) != want_clear)
-		return 0; /* some bits we want clear were set */
-	return 1;
-}
-
-static int
-ipopts_match(struct ip *ip, ipfw_insn *cmd)
-{
-	int optlen, bits = 0;
-	u_char *cp = (u_char *)(ip + 1);
-	int x = (ip->ip_hl << 2) - sizeof (struct ip);
-
-	for (; x > 0; x -= optlen, cp += optlen) {
-		int opt = cp[IPOPT_OPTVAL];
-
-		if (opt == IPOPT_EOL)
-			break;
-		if (opt == IPOPT_NOP)
-			optlen = 1;
-		else {
-			optlen = cp[IPOPT_OLEN];
-			if (optlen <= 0 || optlen > x)
-				return 0; /* invalid or truncated */
-		}
-		switch (opt) {
-
-		default:
-			break;
-
-		case IPOPT_LSRR:
-			bits |= IP_FW_IPOPT_LSRR;
-			break;
-
-		case IPOPT_SSRR:
-			bits |= IP_FW_IPOPT_SSRR;
-			break;
-
-		case IPOPT_RR:
-			bits |= IP_FW_IPOPT_RR;
-			break;
-
-		case IPOPT_TS:
-			bits |= IP_FW_IPOPT_TS;
-			break;
-		}
-	}
-	return (flags_match(cmd, bits));
-}
-
-static int
-tcpopts_match(struct tcphdr *tcp, ipfw_insn *cmd)
-{
-	int optlen, bits = 0;
-	u_char *cp = (u_char *)(tcp + 1);
-	int x = (tcp->th_off << 2) - sizeof(struct tcphdr);
-
-	for (; x > 0; x -= optlen, cp += optlen) {
-		int opt = cp[0];
-		if (opt == TCPOPT_EOL)
-			break;
-		if (opt == TCPOPT_NOP)
-			optlen = 1;
-		else {
-			optlen = cp[1];
-			if (optlen <= 0)
-				break;
-		}
-
-		switch (opt) {
-
-		default:
-			break;
-
-		case TCPOPT_MAXSEG:
-			bits |= IP_FW_TCPOPT_MSS;
-			break;
-
-		case TCPOPT_WINDOW:
-			bits |= IP_FW_TCPOPT_WINDOW;
-			break;
-
-		case TCPOPT_SACK_PERMITTED:
-		case TCPOPT_SACK:
-			bits |= IP_FW_TCPOPT_SACK;
-			break;
-
-		case TCPOPT_TIMESTAMP:
-			bits |= IP_FW_TCPOPT_TS;
-			break;
-
-		}
-	}
-	return (flags_match(cmd, bits));
-}
-
-static int
-iface_match(struct ifnet *ifp, ipfw_insn_if *cmd, struct ip_fw_chain *chain,
-    uint32_t *tablearg)
-{
-
-	if (ifp == NULL)	/* no iface with this packet, match fails */
-		return (0);
-
-	/* Check by name or by IP address */
-	if (cmd->name[0] != '\0') { /* match by name */
-		if (cmd->name[0] == '\1') /* use tablearg to match */
-			return ipfw_lookup_table(chain, cmd->p.kidx, 0,
-			    &ifp->if_index, tablearg);
-		/* Check name */
-		if (cmd->p.glob) {
-			if (fnmatch(cmd->name, ifp->if_xname, 0) == 0)
-				return(1);
-		} else {
-			if (strncmp(ifp->if_xname, cmd->name, IFNAMSIZ) == 0)
-				return(1);
-		}
-	} else {
-#if !defined(USERSPACE) && defined(__FreeBSD__)	/* and OSX too ? */
-		struct ifaddr *ia;
-
-		if_addr_rlock(ifp);
-		TAILQ_FOREACH(ia, &ifp->if_addrhead, ifa_link) {
-			if (ia->ifa_addr->sa_family != AF_INET)
-				continue;
-			if (cmd->p.ip.s_addr == ((struct sockaddr_in *)
-			    (ia->ifa_addr))->sin_addr.s_addr) {
-				if_addr_runlock(ifp);
-				return(1);	/* match */
-			}
-		}
-		if_addr_runlock(ifp);
-#endif /* __FreeBSD__ */
-	}
-	return(0);	/* no match, fail ... */
-}
-
-/*
- * The verify_path function checks if a route to the src exists and
- * if it is reachable via ifp (when provided).
- * 
- * The 'verrevpath' option checks that the interface that an IP packet
- * arrives on is the same interface that traffic destined for the
- * packet's source address would be routed out of.
- * The 'versrcreach' option just checks that the source address is
- * reachable via any route (except default) in the routing table.
- * These two are a measure to block forged packets. This is also
- * commonly known as "anti-spoofing" or Unicast Reverse Path
- * Forwarding (Unicast RFP) in Cisco-ese. The name of the knobs
- * is purposely reminiscent of the Cisco IOS command,
- *
- *   ip verify unicast reverse-path
- *   ip verify unicast source reachable-via any
- *
- * which implements the same functionality. But note that the syntax
- * is misleading, and the check may be performed on all IP packets
- * whether unicast, multicast, or broadcast.
- */
-static int
-verify_path(struct in_addr src, struct ifnet *ifp, u_int fib)
-{
-#if defined(USERSPACE) || !defined(__FreeBSD__)
-	return 0;
-#else
-	struct nhop4_basic nh4;
-
-	if (fib4_lookup_nh_basic(fib, src, NHR_IFAIF, 0, &nh4) != 0)
-		return (0);
-
-	/*
-	 * If ifp is provided, check for equality with rtentry.
-	 * We should use rt->rt_ifa->ifa_ifp, instead of rt->rt_ifp,
-	 * in order to pass packets injected back by if_simloop():
-	 * routing entry (via lo0) for our own address
-	 * may exist, so we need to handle routing assymetry.
-	 */
-	if (ifp != NULL && ifp != nh4.nh_ifp)
-		return (0);
-
-	/* if no ifp provided, check if rtentry is not default route */
-	if (ifp == NULL && (nh4.nh_flags & NHF_DEFAULT) != 0)
-		return (0);
-
-	/* or if this is a blackhole/reject route */
-	if (ifp == NULL && (nh4.nh_flags & (NHF_REJECT|NHF_BLACKHOLE)) != 0)
-		return (0);
-
-	/* found valid route */
-	return 1;
-#endif /* __FreeBSD__ */
-}
-
-#ifdef INET6
-/*
- * ipv6 specific rules here...
- */
-static __inline int
-icmp6type_match (int type, ipfw_insn_u32 *cmd)
-{
-	return (type <= ICMP6_MAXTYPE && (cmd->d[type/32] & (1<<(type%32)) ) );
-}
-
-static int
-flow6id_match( int curr_flow, ipfw_insn_u32 *cmd )
-{
-	int i;
-	for (i=0; i <= cmd->o.arg1; ++i )
-		if (curr_flow == cmd->d[i] )
-			return 1;
-	return 0;
-}
-
-/* support for IP6_*_ME opcodes */
-static const struct in6_addr lla_mask = {{{
-	0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
-	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
-}}};
-
-static int
-ipfw_localip6(struct in6_addr *in6)
-{
-	struct rm_priotracker in6_ifa_tracker;
-	struct in6_ifaddr *ia;
-
-	if (IN6_IS_ADDR_MULTICAST(in6))
-		return (0);
-
-	if (!IN6_IS_ADDR_LINKLOCAL(in6))
-		return (in6_localip(in6));
-
-	IN6_IFADDR_RLOCK(&in6_ifa_tracker);
-	TAILQ_FOREACH(ia, &V_in6_ifaddrhead, ia_link) {
-		if (!IN6_IS_ADDR_LINKLOCAL(&ia->ia_addr.sin6_addr))
-			continue;
-		if (IN6_ARE_MASKED_ADDR_EQUAL(&ia->ia_addr.sin6_addr,
-		    in6, &lla_mask)) {
-			IN6_IFADDR_RUNLOCK(&in6_ifa_tracker);
-			return (1);
-		}
-	}
-	IN6_IFADDR_RUNLOCK(&in6_ifa_tracker);
-	return (0);
-}
-
-static int
-verify_path6(struct in6_addr *src, struct ifnet *ifp, u_int fib)
-{
-	struct nhop6_basic nh6;
-
-	if (IN6_IS_SCOPE_LINKLOCAL(src))
-		return (1);
-
-	if (fib6_lookup_nh_basic(fib, src, 0, NHR_IFAIF, 0, &nh6) != 0)
-		return (0);
-
-	/* If ifp is provided, check for equality with route table. */
-	if (ifp != NULL && ifp != nh6.nh_ifp)
-		return (0);
-
-	/* if no ifp provided, check if rtentry is not default route */
-	if (ifp == NULL && (nh6.nh_flags & NHF_DEFAULT) != 0)
-		return (0);
-
-	/* or if this is a blackhole/reject route */
-	if (ifp == NULL && (nh6.nh_flags & (NHF_REJECT|NHF_BLACKHOLE)) != 0)
-		return (0);
-
-	/* found valid route */
-	return 1;
-}
-
-static int
-is_icmp6_query(int icmp6_type)
-{
-	if ((icmp6_type <= ICMP6_MAXTYPE) &&
-	    (icmp6_type == ICMP6_ECHO_REQUEST ||
-	    icmp6_type == ICMP6_MEMBERSHIP_QUERY ||
-	    icmp6_type == ICMP6_WRUREQUEST ||
-	    icmp6_type == ICMP6_FQDN_QUERY ||
-	    icmp6_type == ICMP6_NI_QUERY))
-		return (1);
-
-	return (0);
-}
-
-static void
-send_reject6(struct ip_fw_args *args, int code, u_int hlen, struct ip6_hdr *ip6)
-{
-	struct mbuf *m;
-
-	m = args->m;
-	if (code == ICMP6_UNREACH_RST && args->f_id.proto == IPPROTO_TCP) {
-		struct tcphdr *tcp;
-		tcp = (struct tcphdr *)((char *)ip6 + hlen);
-
-		if ((tcp->th_flags & TH_RST) == 0) {
-			struct mbuf *m0;
-			m0 = ipfw_send_pkt(args->m, &(args->f_id),
-			    ntohl(tcp->th_seq), ntohl(tcp->th_ack),
-			    tcp->th_flags | TH_RST);
-			if (m0 != NULL)
-				ip6_output(m0, NULL, NULL, 0, NULL, NULL,
-				    NULL);
-		}
-		FREE_PKT(m);
-	} else if (code != ICMP6_UNREACH_RST) { /* Send an ICMPv6 unreach. */
-#if 0
-		/*
-		 * Unlike above, the mbufs need to line up with the ip6 hdr,
-		 * as the contents are read. We need to m_adj() the
-		 * needed amount.
-		 * The mbuf will however be thrown away so we can adjust it.
-		 * Remember we did an m_pullup on it already so we
-		 * can make some assumptions about contiguousness.
-		 */
-		if (args->L3offset)
-			m_adj(m, args->L3offset);
-#endif
-		icmp6_error(m, ICMP6_DST_UNREACH, code, 0);
-	} else
-		FREE_PKT(m);
-
-	args->m = NULL;
-}
-
-#endif /* INET6 */
-
-
-/*
- * sends a reject message, consuming the mbuf passed as an argument.
- */
-static void
-send_reject(struct ip_fw_args *args, int code, int iplen, struct ip *ip)
-{
-
-#if 0
-	/* XXX When ip is not guaranteed to be at mtod() we will
-	 * need to account for this */
-	 * The mbuf will however be thrown away so we can adjust it.
-	 * Remember we did an m_pullup on it already so we
-	 * can make some assumptions about contiguousness.
-	 */
-	if (args->L3offset)
-		m_adj(m, args->L3offset);
-#endif
-	if (code != ICMP_REJECT_RST) { /* Send an ICMP unreach */
-		icmp_error(args->m, ICMP_UNREACH, code, 0L, 0);
-	} else if (args->f_id.proto == IPPROTO_TCP) {
-		struct tcphdr *const tcp =
-		    L3HDR(struct tcphdr, mtod(args->m, struct ip *));
-		if ( (tcp->th_flags & TH_RST) == 0) {
-			struct mbuf *m;
-			m = ipfw_send_pkt(args->m, &(args->f_id),
-				ntohl(tcp->th_seq), ntohl(tcp->th_ack),
-				tcp->th_flags | TH_RST);
-			if (m != NULL)
-				ip_output(m, NULL, NULL, 0, NULL, NULL);
-		}
-		FREE_PKT(args->m);
-	} else
-		FREE_PKT(args->m);
-	args->m = NULL;
-}
-
-/*
- * Support for uid/gid/jail lookup. These tests are expensive
- * (because we may need to look into the list of active sockets)
- * so we cache the results. ugid_lookupp is 0 if we have not
- * yet done a lookup, 1 if we succeeded, and -1 if we tried
- * and failed. The function always returns the match value.
- * We could actually spare the variable and use *uc, setting
- * it to '(void *)check_uidgid if we have no info, NULL if
- * we tried and failed, or any other value if successful.
- */
-static int
-check_uidgid(ipfw_insn_u32 *insn, struct ip_fw_args *args, int *ugid_lookupp,
-    struct ucred **uc)
-{
-#if defined(USERSPACE)
-	return 0;	// not supported in userspace
-#else
-#ifndef __FreeBSD__
-	/* XXX */
-	return cred_check(insn, proto, oif,
-	    dst_ip, dst_port, src_ip, src_port,
-	    (struct bsd_ucred *)uc, ugid_lookupp, ((struct mbuf *)inp)->m_skb);
-#else  /* FreeBSD */
-	struct in_addr src_ip, dst_ip;
-	struct inpcbinfo *pi;
-	struct ipfw_flow_id *id;
-	struct inpcb *pcb, *inp;
-	struct ifnet *oif;
-	int lookupflags;
-	int match;
-
-	id = &args->f_id;
-	inp = args->inp;
-	oif = args->oif;
-
-	/*
-	 * Check to see if the UDP or TCP stack supplied us with
-	 * the PCB. If so, rather then holding a lock and looking
-	 * up the PCB, we can use the one that was supplied.
-	 */
-	if (inp && *ugid_lookupp == 0) {
-		INP_LOCK_ASSERT(inp);
-		if (inp->inp_socket != NULL) {
-			*uc = crhold(inp->inp_cred);
-			*ugid_lookupp = 1;
-		} else
-			*ugid_lookupp = -1;
-	}
-	/*
-	 * If we have already been here and the packet has no
-	 * PCB entry associated with it, then we can safely
-	 * assume that this is a no match.
-	 */
-	if (*ugid_lookupp == -1)
-		return (0);
-	if (id->proto == IPPROTO_TCP) {
-		lookupflags = 0;
-		pi = &V_tcbinfo;
-	} else if (id->proto == IPPROTO_UDP) {
-		lookupflags = INPLOOKUP_WILDCARD;
-		pi = &V_udbinfo;
-	} else
-		return 0;
-	lookupflags |= INPLOOKUP_RLOCKPCB;
-	match = 0;
-	if (*ugid_lookupp == 0) {
-		if (id->addr_type == 6) {
-#ifdef INET6
-			if (oif == NULL)
-				pcb = in6_pcblookup_mbuf(pi,
-				    &id->src_ip6, htons(id->src_port),
-				    &id->dst_ip6, htons(id->dst_port),
-				    lookupflags, oif, args->m);
-			else
-				pcb = in6_pcblookup_mbuf(pi,
-				    &id->dst_ip6, htons(id->dst_port),
-				    &id->src_ip6, htons(id->src_port),
-				    lookupflags, oif, args->m);
-#else
-			*ugid_lookupp = -1;
-			return (0);
-#endif
-		} else {
-			src_ip.s_addr = htonl(id->src_ip);
-			dst_ip.s_addr = htonl(id->dst_ip);
-			if (oif == NULL)
-				pcb = in_pcblookup_mbuf(pi,
-				    src_ip, htons(id->src_port),
-				    dst_ip, htons(id->dst_port),
-				    lookupflags, oif, args->m);
-			else
-				pcb = in_pcblookup_mbuf(pi,
-				    dst_ip, htons(id->dst_port),
-				    src_ip, htons(id->src_port),
-				    lookupflags, oif, args->m);
-		}
-		if (pcb != NULL) {
-			INP_RLOCK_ASSERT(pcb);
-			*uc = crhold(pcb->inp_cred);
-			*ugid_lookupp = 1;
-			INP_RUNLOCK(pcb);
-		}
-		if (*ugid_lookupp == 0) {
-			/*
-			 * We tried and failed, set the variable to -1
-			 * so we will not try again on this packet.
-			 */
-			*ugid_lookupp = -1;
-			return (0);
-		}
-	}
-	if (insn->o.opcode == O_UID)
-#ifndef __rtems__
-		match = ((*uc)->cr_uid == (uid_t)insn->d[0]);
-#else /* __rtems__ */
-		match = (BSD_DEFAULT_UID == (uid_t)insn->d[0]);
-#endif /* __rtems__ */
-	else if (insn->o.opcode == O_GID)
-		match = groupmember((gid_t)insn->d[0], *uc);
-	else if (insn->o.opcode == O_JAIL)
-#ifndef __rtems__
-		match = ((*uc)->cr_prison->pr_id == (int)insn->d[0]);
-#else /* __rtems__ */
-		match = (BSD_DEFAULT_PRISON->pr_id == (int)insn->d[0]);
-#endif /* __rtems__ */
-	return (match);
-#endif /* __FreeBSD__ */
-#endif /* not supported in userspace */
-}
-
-/*
- * Helper function to set args with info on the rule after the matching
- * one. slot is precise, whereas we guess rule_id as they are
- * assigned sequentially.
- */
-static inline void
-set_match(struct ip_fw_args *args, int slot,
-	struct ip_fw_chain *chain)
-{
-	args->rule.chain_id = chain->id;
-	args->rule.slot = slot + 1; /* we use 0 as a marker */
-	args->rule.rule_id = 1 + chain->map[slot]->id;
-	args->rule.rulenum = chain->map[slot]->rulenum;
-}
-
-#ifndef LINEAR_SKIPTO
-/*
- * Helper function to enable cached rule lookups using
- * cached_id and cached_pos fields in ipfw rule.
- */
-static int
-jump_fast(struct ip_fw_chain *chain, struct ip_fw *f, int num,
-    int tablearg, int jump_backwards)
-{
-	int f_pos;
-
-	/* If possible use cached f_pos (in f->cached_pos),
-	 * whose version is written in f->cached_id
-	 * (horrible hacks to avoid changing the ABI).
-	 */
-	if (num != IP_FW_TARG && f->cached_id == chain->id)
-		f_pos = f->cached_pos;
-	else {
-		int i = IP_FW_ARG_TABLEARG(chain, num, skipto);
-		/* make sure we do not jump backward */
-		if (jump_backwards == 0 && i <= f->rulenum)
-			i = f->rulenum + 1;
-		if (chain->idxmap != NULL)
-			f_pos = chain->idxmap[i];
-		else
-			f_pos = ipfw_find_rule(chain, i, 0);
-		/* update the cache */
-		if (num != IP_FW_TARG) {
-			f->cached_id = chain->id;
-			f->cached_pos = f_pos;
-		}
-	}
-
-	return (f_pos);
-}
-#else
-/*
- * Helper function to enable real fast rule lookups.
- */
-static int
-jump_linear(struct ip_fw_chain *chain, struct ip_fw *f, int num,
-    int tablearg, int jump_backwards)
-{
-	int f_pos;
-
-	num = IP_FW_ARG_TABLEARG(chain, num, skipto);
-	/* make sure we do not jump backward */
-	if (jump_backwards == 0 && num <= f->rulenum)
-		num = f->rulenum + 1;
-	f_pos = chain->idxmap[num];
-
-	return (f_pos);
-}
-#endif
-
-#define	TARG(k, f)	IP_FW_ARG_TABLEARG(chain, k, f)
-/*
- * The main check routine for the firewall.
- *
- * All arguments are in args so we can modify them and return them
- * back to the caller.
- *
- * Parameters:
- *
- *	args->m	(in/out) The packet; we set to NULL when/if we nuke it.
- *		Starts with the IP header.
- *	args->eh (in)	Mac header if present, NULL for layer3 packet.
- *	args->L3offset	Number of bytes bypassed if we came from L2.
- *			e.g. often sizeof(eh)  ** NOTYET **
- *	args->oif	Outgoing interface, NULL if packet is incoming.
- *		The incoming interface is in the mbuf. (in)
- *	args->divert_rule (in/out)
- *		Skip up to the first rule past this rule number;
- *		upon return, non-zero port number for divert or tee.
- *
- *	args->rule	Pointer to the last matching rule (in/out)
- *	args->next_hop	Socket we are forwarding to (out).
- *	args->next_hop6	IPv6 next hop we are forwarding to (out).
- *	args->f_id	Addresses grabbed from the packet (out)
- * 	args->rule.info	a cookie depending on rule action
- *
- * Return value:
- *
- *	IP_FW_PASS	the packet must be accepted
- *	IP_FW_DENY	the packet must be dropped
- *	IP_FW_DIVERT	divert packet, port in m_tag
- *	IP_FW_TEE	tee packet, port in m_tag
- *	IP_FW_DUMMYNET	to dummynet, pipe in args->cookie
- *	IP_FW_NETGRAPH	into netgraph, cookie args->cookie
- *		args->rule contains the matching rule,
- *		args->rule.info has additional information.
- *
- */
-int
-ipfw_chk(struct ip_fw_args *args)
-{
-
-	/*
-	 * Local variables holding state while processing a packet:
-	 *
-	 * IMPORTANT NOTE: to speed up the processing of rules, there
-	 * are some assumption on the values of the variables, which
-	 * are documented here. Should you change them, please check
-	 * the implementation of the various instructions to make sure
-	 * that they still work.
-	 *
-	 * args->eh	The MAC header. It is non-null for a layer2
-	 *	packet, it is NULL for a layer-3 packet.
-	 * **notyet**
-	 * args->L3offset Offset in the packet to the L3 (IP or equiv.) header.
-	 *
-	 * m | args->m	Pointer to the mbuf, as received from the caller.
-	 *	It may change if ipfw_chk() does an m_pullup, or if it
-	 *	consumes the packet because it calls send_reject().
-	 *	XXX This has to change, so that ipfw_chk() never modifies
-	 *	or consumes the buffer.
-	 * ip	is the beginning of the ip(4 or 6) header.
-	 *	Calculated by adding the L3offset to the start of data.
-	 *	(Until we start using L3offset, the packet is
-	 *	supposed to start with the ip header).
-	 */
-	struct mbuf *m = args->m;
-	struct ip *ip = mtod(m, struct ip *);
-
-	/*
-	 * For rules which contain uid/gid or jail constraints, cache
-	 * a copy of the users credentials after the pcb lookup has been
-	 * executed. This will speed up the processing of rules with
-	 * these types of constraints, as well as decrease contention
-	 * on pcb related locks.
-	 */
-#ifndef __FreeBSD__
-	struct bsd_ucred ucred_cache;
-#else
-	struct ucred *ucred_cache = NULL;
-#endif
-	int ucred_lookup = 0;
-
-	/*
-	 * oif | args->oif	If NULL, ipfw_chk has been called on the
-	 *	inbound path (ether_input, ip_input).
-	 *	If non-NULL, ipfw_chk has been called on the outbound path
-	 *	(ether_output, ip_output).
-	 */
-	struct ifnet *oif = args->oif;
-
-	int f_pos = 0;		/* index of current rule in the array */
-	int retval = 0;
-
-	/*
-	 * hlen	The length of the IP header.
-	 */
-	u_int hlen = 0;		/* hlen >0 means we have an IP pkt */
-
-	/*
-	 * offset	The offset of a fragment. offset != 0 means that
-	 *	we have a fragment at this offset of an IPv4 packet.
-	 *	offset == 0 means that (if this is an IPv4 packet)
-	 *	this is the first or only fragment.
-	 *	For IPv6 offset|ip6f_mf == 0 means there is no Fragment Header
-	 *	or there is a single packet fragment (fragment header added
-	 *	without needed).  We will treat a single packet fragment as if
-	 *	there was no fragment header (or log/block depending on the
-	 *	V_fw_permit_single_frag6 sysctl setting).
-	 */
-	u_short offset = 0;
-	u_short ip6f_mf = 0;
-
-	/*
-	 * Local copies of addresses. They are only valid if we have
-	 * an IP packet.
-	 *
-	 * proto	The protocol. Set to 0 for non-ip packets,
-	 *	or to the protocol read from the packet otherwise.
-	 *	proto != 0 means that we have an IPv4 packet.
-	 *
-	 * src_port, dst_port	port numbers, in HOST format. Only
-	 *	valid for TCP and UDP packets.
-	 *
-	 * src_ip, dst_ip	ip addresses, in NETWORK format.
-	 *	Only valid for IPv4 packets.
-	 */
-	uint8_t proto;
-	uint16_t src_port = 0, dst_port = 0;	/* NOTE: host format	*/
-	struct in_addr src_ip, dst_ip;		/* NOTE: network format	*/
-	uint16_t iplen=0;
-	int pktlen;
-	uint16_t	etype = 0;	/* Host order stored ether type */
-
-	/*
-	 * dyn_dir = MATCH_UNKNOWN when rules unchecked,
-	 * 	MATCH_NONE when checked and not matched (q = NULL),
-	 *	MATCH_FORWARD or MATCH_REVERSE otherwise (q != NULL)
-	 */
-	int dyn_dir = MATCH_UNKNOWN;
-	uint16_t dyn_name = 0;
-	ipfw_dyn_rule *q = NULL;
-	struct ip_fw_chain *chain = &V_layer3_chain;
-
-	/*
-	 * We store in ulp a pointer to the upper layer protocol header.
-	 * In the ipv4 case this is easy to determine from the header,
-	 * but for ipv6 we might have some additional headers in the middle.
-	 * ulp is NULL if not found.
-	 */
-	void *ulp = NULL;		/* upper layer protocol pointer. */
-
-	/* XXX ipv6 variables */
-	int is_ipv6 = 0;
-	uint8_t	icmp6_type = 0;
-	uint16_t ext_hd = 0;	/* bits vector for extension header filtering */
-	/* end of ipv6 variables */
-
-	int is_ipv4 = 0;
-
-	int done = 0;		/* flag to exit the outer loop */
-
-	if (m->m_flags & M_SKIP_FIREWALL || (! V_ipfw_vnet_ready))
-		return (IP_FW_PASS);	/* accept */
-
-	dst_ip.s_addr = 0;		/* make sure it is initialized */
-	src_ip.s_addr = 0;		/* make sure it is initialized */
-	pktlen = m->m_pkthdr.len;
-	args->f_id.fib = M_GETFIB(m); /* note mbuf not altered) */
-	proto = args->f_id.proto = 0;	/* mark f_id invalid */
-		/* XXX 0 is a valid proto: IP/IPv6 Hop-by-Hop Option */
-
-/*
- * PULLUP_TO(len, p, T) makes sure that len + sizeof(T) is contiguous,
- * then it sets p to point at the offset "len" in the mbuf. WARNING: the
- * pointer might become stale after other pullups (but we never use it
- * this way).
- */
-#define PULLUP_TO(_len, p, T)	PULLUP_LEN(_len, p, sizeof(T))
-#define PULLUP_LEN(_len, p, T)					\
-do {								\
-	int x = (_len) + T;					\
-	if ((m)->m_len < x) {					\
-		args->m = m = m_pullup(m, x);			\
-		if (m == NULL)					\
-			goto pullup_failed;			\
-	}							\
-	p = (mtod(m, char *) + (_len));				\
-} while (0)
-
-	/*
-	 * if we have an ether header,
-	 */
-	if (args->eh)
-		etype = ntohs(args->eh->ether_type);
-
-	/* Identify IP packets and fill up variables. */
-	if (pktlen >= sizeof(struct ip6_hdr) &&
-	    (args->eh == NULL || etype == ETHERTYPE_IPV6) && ip->ip_v == 6) {
-		struct ip6_hdr *ip6 = (struct ip6_hdr *)ip;
-		is_ipv6 = 1;
-		args->f_id.addr_type = 6;
-		hlen = sizeof(struct ip6_hdr);
-		proto = ip6->ip6_nxt;
-
-		/* Search extension headers to find upper layer protocols */
-		while (ulp == NULL && offset == 0) {
-			switch (proto) {
-			case IPPROTO_ICMPV6:
-				PULLUP_TO(hlen, ulp, struct icmp6_hdr);
-				icmp6_type = ICMP6(ulp)->icmp6_type;
-				break;
-
-			case IPPROTO_TCP:
-				PULLUP_TO(hlen, ulp, struct tcphdr);
-				dst_port = TCP(ulp)->th_dport;
-				src_port = TCP(ulp)->th_sport;
-				/* save flags for dynamic rules */
-				args->f_id._flags = TCP(ulp)->th_flags;
-				break;
-
-			case IPPROTO_SCTP:
-				PULLUP_TO(hlen, ulp, struct sctphdr);
-				src_port = SCTP(ulp)->src_port;
-				dst_port = SCTP(ulp)->dest_port;
-				break;
-
-			case IPPROTO_UDP:
-				PULLUP_TO(hlen, ulp, struct udphdr);
-				dst_port = UDP(ulp)->uh_dport;
-				src_port = UDP(ulp)->uh_sport;
-				break;
-
-			case IPPROTO_HOPOPTS:	/* RFC 2460 */
-				PULLUP_TO(hlen, ulp, struct ip6_hbh);
-				ext_hd |= EXT_HOPOPTS;
-				hlen += (((struct ip6_hbh *)ulp)->ip6h_len + 1) << 3;
-				proto = ((struct ip6_hbh *)ulp)->ip6h_nxt;
-				ulp = NULL;
-				break;
-
-			case IPPROTO_ROUTING:	/* RFC 2460 */
-				PULLUP_TO(hlen, ulp, struct ip6_rthdr);
-				switch (((struct ip6_rthdr *)ulp)->ip6r_type) {
-				case 0:
-					ext_hd |= EXT_RTHDR0;
-					break;
-				case 2:
-					ext_hd |= EXT_RTHDR2;
-					break;
-				default:
-					if (V_fw_verbose)
-						printf("IPFW2: IPV6 - Unknown "
-						    "Routing Header type(%d)\n",
-						    ((struct ip6_rthdr *)
-						    ulp)->ip6r_type);
-					if (V_fw_deny_unknown_exthdrs)
-					    return (IP_FW_DENY);
-					break;
-				}
-				ext_hd |= EXT_ROUTING;
-				hlen += (((struct ip6_rthdr *)ulp)->ip6r_len + 1) << 3;
-				proto = ((struct ip6_rthdr *)ulp)->ip6r_nxt;
-				ulp = NULL;
-				break;
-
-			case IPPROTO_FRAGMENT:	/* RFC 2460 */
-				PULLUP_TO(hlen, ulp, struct ip6_frag);
-				ext_hd |= EXT_FRAGMENT;
-				hlen += sizeof (struct ip6_frag);
-				proto = ((struct ip6_frag *)ulp)->ip6f_nxt;
-				offset = ((struct ip6_frag *)ulp)->ip6f_offlg &
-					IP6F_OFF_MASK;
-				ip6f_mf = ((struct ip6_frag *)ulp)->ip6f_offlg &
-					IP6F_MORE_FRAG;
-				if (V_fw_permit_single_frag6 == 0 &&
-				    offset == 0 && ip6f_mf == 0) {
-					if (V_fw_verbose)
-						printf("IPFW2: IPV6 - Invalid "
-						    "Fragment Header\n");
-					if (V_fw_deny_unknown_exthdrs)
-					    return (IP_FW_DENY);
-					break;
-				}
-				args->f_id.extra =
-				    ntohl(((struct ip6_frag *)ulp)->ip6f_ident);
-				ulp = NULL;
-				break;
-
-			case IPPROTO_DSTOPTS:	/* RFC 2460 */
-				PULLUP_TO(hlen, ulp, struct ip6_hbh);
-				ext_hd |= EXT_DSTOPTS;
-				hlen += (((struct ip6_hbh *)ulp)->ip6h_len + 1) << 3;
-				proto = ((struct ip6_hbh *)ulp)->ip6h_nxt;
-				ulp = NULL;
-				break;
-
-			case IPPROTO_AH:	/* RFC 2402 */
-				PULLUP_TO(hlen, ulp, struct ip6_ext);
-				ext_hd |= EXT_AH;
-				hlen += (((struct ip6_ext *)ulp)->ip6e_len + 2) << 2;
-				proto = ((struct ip6_ext *)ulp)->ip6e_nxt;
-				ulp = NULL;
-				break;
-
-			case IPPROTO_ESP:	/* RFC 2406 */
-				PULLUP_TO(hlen, ulp, uint32_t);	/* SPI, Seq# */
-				/* Anything past Seq# is variable length and
-				 * data past this ext. header is encrypted. */
-				ext_hd |= EXT_ESP;
-				break;
-
-			case IPPROTO_NONE:	/* RFC 2460 */
-				/*
-				 * Packet ends here, and IPv6 header has
-				 * already been pulled up. If ip6e_len!=0
-				 * then octets must be ignored.
-				 */
-				ulp = ip; /* non-NULL to get out of loop. */
-				break;
-
-			case IPPROTO_OSPFIGP:
-				/* XXX OSPF header check? */
-				PULLUP_TO(hlen, ulp, struct ip6_ext);
-				break;
-
-			case IPPROTO_PIM:
-				/* XXX PIM header check? */
-				PULLUP_TO(hlen, ulp, struct pim);
-				break;
-
-			case IPPROTO_CARP:
-				PULLUP_TO(hlen, ulp, struct carp_header);
-				if (((struct carp_header *)ulp)->carp_version !=
-				    CARP_VERSION) 
-					return (IP_FW_DENY);
-				if (((struct carp_header *)ulp)->carp_type !=
-				    CARP_ADVERTISEMENT) 
-					return (IP_FW_DENY);
-				break;
-
-			case IPPROTO_IPV6:	/* RFC 2893 */
-				PULLUP_TO(hlen, ulp, struct ip6_hdr);
-				break;
-
-			case IPPROTO_IPV4:	/* RFC 2893 */
-				PULLUP_TO(hlen, ulp, struct ip);
-				break;
-
-			default:
-				if (V_fw_verbose)
-					printf("IPFW2: IPV6 - Unknown "
-					    "Extension Header(%d), ext_hd=%x\n",
-					     proto, ext_hd);
-				if (V_fw_deny_unknown_exthdrs)
-				    return (IP_FW_DENY);
-				PULLUP_TO(hlen, ulp, struct ip6_ext);
-				break;
-			} /*switch */
-		}
-		ip = mtod(m, struct ip *);
-		ip6 = (struct ip6_hdr *)ip;
-		args->f_id.src_ip6 = ip6->ip6_src;
-		args->f_id.dst_ip6 = ip6->ip6_dst;
-		args->f_id.src_ip = 0;
-		args->f_id.dst_ip = 0;
-		args->f_id.flow_id6 = ntohl(ip6->ip6_flow);
-	} else if (pktlen >= sizeof(struct ip) &&
-	    (args->eh == NULL || etype == ETHERTYPE_IP) && ip->ip_v == 4) {
-	    	is_ipv4 = 1;
-		hlen = ip->ip_hl << 2;
-		args->f_id.addr_type = 4;
-
-		/*
-		 * Collect parameters into local variables for faster matching.
-		 */
-		proto = ip->ip_p;
-		src_ip = ip->ip_src;
-		dst_ip = ip->ip_dst;
-		offset = ntohs(ip->ip_off) & IP_OFFMASK;
-		iplen = ntohs(ip->ip_len);
-		pktlen = iplen < pktlen ? iplen : pktlen;
-
-		if (offset == 0) {
-			switch (proto) {
-			case IPPROTO_TCP:
-				PULLUP_TO(hlen, ulp, struct tcphdr);
-				dst_port = TCP(ulp)->th_dport;
-				src_port = TCP(ulp)->th_sport;
-				/* save flags for dynamic rules */
-				args->f_id._flags = TCP(ulp)->th_flags;
-				break;
-
-			case IPPROTO_SCTP:
-				PULLUP_TO(hlen, ulp, struct sctphdr);
-				src_port = SCTP(ulp)->src_port;
-				dst_port = SCTP(ulp)->dest_port;
-				break;
-
-			case IPPROTO_UDP:
-				PULLUP_TO(hlen, ulp, struct udphdr);
-				dst_port = UDP(ulp)->uh_dport;
-				src_port = UDP(ulp)->uh_sport;
-				break;
-
-			case IPPROTO_ICMP:
-				PULLUP_TO(hlen, ulp, struct icmphdr);
-				//args->f_id.flags = ICMP(ulp)->icmp_type;
-				break;
-
-			default:
-				break;
-			}
-		}
-
-		ip = mtod(m, struct ip *);
-		args->f_id.src_ip = ntohl(src_ip.s_addr);
-		args->f_id.dst_ip = ntohl(dst_ip.s_addr);
-	}
-#undef PULLUP_TO
-	if (proto) { /* we may have port numbers, store them */
-		args->f_id.proto = proto;
-		args->f_id.src_port = src_port = ntohs(src_port);
-		args->f_id.dst_port = dst_port = ntohs(dst_port);
-	}
-
-	IPFW_PF_RLOCK(chain);
-	if (! V_ipfw_vnet_ready) { /* shutting down, leave NOW. */
-		IPFW_PF_RUNLOCK(chain);
-		return (IP_FW_PASS);	/* accept */
-	}
-	if (args->rule.slot) {
-		/*
-		 * Packet has already been tagged as a result of a previous
-		 * match on rule args->rule aka args->rule_id (PIPE, QUEUE,
-		 * REASS, NETGRAPH, DIVERT/TEE...)
-		 * Validate the slot and continue from the next one
-		 * if still present, otherwise do a lookup.
-		 */
-		f_pos = (args->rule.chain_id == chain->id) ?
-		    args->rule.slot :
-		    ipfw_find_rule(chain, args->rule.rulenum,
-			args->rule.rule_id);
-	} else {
-		f_pos = 0;
-	}
-
-	/*
-	 * Now scan the rules, and parse microinstructions for each rule.
-	 * We have two nested loops and an inner switch. Sometimes we
-	 * need to break out of one or both loops, or re-enter one of
-	 * the loops with updated variables. Loop variables are:
-	 *
-	 *	f_pos (outer loop) points to the current rule.
-	 *		On output it points to the matching rule.
-	 *	done (outer loop) is used as a flag to break the loop.
-	 *	l (inner loop)	residual length of current rule.
-	 *		cmd points to the current microinstruction.
-	 *
-	 * We break the inner loop by setting l=0 and possibly
-	 * cmdlen=0 if we don't want to advance cmd.
-	 * We break the outer loop by setting done=1
-	 * We can restart the inner loop by setting l>0 and f_pos, f, cmd
-	 * as needed.
-	 */
-	for (; f_pos < chain->n_rules; f_pos++) {
-		ipfw_insn *cmd;
-		uint32_t tablearg = 0;
-		int l, cmdlen, skip_or; /* skip rest of OR block */
-		struct ip_fw *f;
-
-		f = chain->map[f_pos];
-		if (V_set_disable & (1 << f->set) )
-			continue;
-
-		skip_or = 0;
-		for (l = f->cmd_len, cmd = f->cmd ; l > 0 ;
-		    l -= cmdlen, cmd += cmdlen) {
-			int match;
-
-			/*
-			 * check_body is a jump target used when we find a
-			 * CHECK_STATE, and need to jump to the body of
-			 * the target rule.
-			 */
-
-/* check_body: */
-			cmdlen = F_LEN(cmd);
-			/*
-			 * An OR block (insn_1 || .. || insn_n) has the
-			 * F_OR bit set in all but the last instruction.
-			 * The first match will set "skip_or", and cause
-			 * the following instructions to be skipped until
-			 * past the one with the F_OR bit clear.
-			 */
-			if (skip_or) {		/* skip this instruction */
-				if ((cmd->len & F_OR) == 0)
-					skip_or = 0;	/* next one is good */
-				continue;
-			}
-			match = 0; /* set to 1 if we succeed */
-
-			switch (cmd->opcode) {
-			/*
-			 * The first set of opcodes compares the packet's
-			 * fields with some pattern, setting 'match' if a
-			 * match is found. At the end of the loop there is
-			 * logic to deal with F_NOT and F_OR flags associated
-			 * with the opcode.
-			 */
-			case O_NOP:
-				match = 1;
-				break;
-
-			case O_FORWARD_MAC:
-				printf("ipfw: opcode %d unimplemented\n",
-				    cmd->opcode);
-				break;
-
-			case O_GID:
-			case O_UID:
-			case O_JAIL:
-				/*
-				 * We only check offset == 0 && proto != 0,
-				 * as this ensures that we have a
-				 * packet with the ports info.
-				 */
-				if (offset != 0)
-					break;
-				if (proto == IPPROTO_TCP ||
-				    proto == IPPROTO_UDP)
-					match = check_uidgid(
-						    (ipfw_insn_u32 *)cmd,
-						    args, &ucred_lookup,
-#ifdef __FreeBSD__
-						    &ucred_cache);
-#else
-						    (void *)&ucred_cache);
-#endif
-				break;
-
-			case O_RECV:
-				match = iface_match(m->m_pkthdr.rcvif,
-				    (ipfw_insn_if *)cmd, chain, &tablearg);
-				break;
-
-			case O_XMIT:
-				match = iface_match(oif, (ipfw_insn_if *)cmd,
-				    chain, &tablearg);
-				break;
-
-			case O_VIA:
-				match = iface_match(oif ? oif :
-				    m->m_pkthdr.rcvif, (ipfw_insn_if *)cmd,
-				    chain, &tablearg);
-				break;
-
-			case O_MACADDR2:
-				if (args->eh != NULL) {	/* have MAC header */
-					u_int32_t *want = (u_int32_t *)
-						((ipfw_insn_mac *)cmd)->addr;
-					u_int32_t *mask = (u_int32_t *)
-						((ipfw_insn_mac *)cmd)->mask;
-					u_int32_t *hdr = (u_int32_t *)args->eh;
-
-					match =
-					    ( want[0] == (hdr[0] & mask[0]) &&
-					      want[1] == (hdr[1] & mask[1]) &&
-					      want[2] == (hdr[2] & mask[2]) );
-				}
-				break;
-
-			case O_MAC_TYPE:
-				if (args->eh != NULL) {
-					u_int16_t *p =
-					    ((ipfw_insn_u16 *)cmd)->ports;
-					int i;
-
-					for (i = cmdlen - 1; !match && i>0;
-					    i--, p += 2)
-						match = (etype >= p[0] &&
-						    etype <= p[1]);
-				}
-				break;
-
-			case O_FRAG:
-				match = (offset != 0);
-				break;
-
-			case O_IN:	/* "out" is "not in" */
-				match = (oif == NULL);
-				break;
-
-			case O_LAYER2:
-				match = (args->eh != NULL);
-				break;
-
-			case O_DIVERTED:
-			    {
-				/* For diverted packets, args->rule.info
-				 * contains the divert port (in host format)
-				 * reason and direction.
-				 */
-				uint32_t i = args->rule.info;
-				match = (i&IPFW_IS_MASK) == IPFW_IS_DIVERT &&
-				    cmd->arg1 & ((i & IPFW_INFO_IN) ? 1 : 2);
-			    }
-				break;
-
-			case O_PROTO:
-				/*
-				 * We do not allow an arg of 0 so the
-				 * check of "proto" only suffices.
-				 */
-				match = (proto == cmd->arg1);
-				break;
-
-			case O_IP_SRC:
-				match = is_ipv4 &&
-				    (((ipfw_insn_ip *)cmd)->addr.s_addr ==
-				    src_ip.s_addr);
-				break;
-
-			case O_IP_DST_LOOKUP:
-			{
-				void *pkey;
-				uint32_t vidx, key;
-				uint16_t keylen;
-
-				if (cmdlen > F_INSN_SIZE(ipfw_insn_u32)) {
-					/* Determine lookup key type */
-					vidx = ((ipfw_insn_u32 *)cmd)->d[1];
-					if (vidx != 4 /* uid */ &&
-					    vidx != 5 /* jail */ &&
-					    is_ipv6 == 0 && is_ipv4 == 0)
-						break;
-					/* Determine key length */
-					if (vidx == 0 /* dst-ip */ ||
-					    vidx == 1 /* src-ip */)
-						keylen = is_ipv6 ?
-						    sizeof(struct in6_addr):
-						    sizeof(in_addr_t);
-					else {
-						keylen = sizeof(key);
-						pkey = &key;
-					}
-					if (vidx == 0 /* dst-ip */)
-						pkey = is_ipv4 ? (void *)&dst_ip:
-						    (void *)&args->f_id.dst_ip6;
-					else if (vidx == 1 /* src-ip */)
-						pkey = is_ipv4 ? (void *)&src_ip:
-						    (void *)&args->f_id.src_ip6;
-					else if (vidx == 6 /* dscp */) {
-						if (is_ipv4)
-							key = ip->ip_tos >> 2;
-						else {
-							key = args->f_id.flow_id6;
-							key = (key & 0x0f) << 2 |
-							    (key & 0xf000) >> 14;
-						}
-						key &= 0x3f;
-					} else if (vidx == 2 /* dst-port */ ||
-					    vidx == 3 /* src-port */) {
-						/* Skip fragments */
-						if (offset != 0)
-							break;
-						/* Skip proto without ports */
-						if (proto != IPPROTO_TCP &&
-						    proto != IPPROTO_UDP &&
-						    proto != IPPROTO_SCTP)
-							break;
-						if (vidx == 2 /* dst-port */)
-							key = dst_port;
-						else
-							key = src_port;
-					}
-#ifndef USERSPACE
-					else if (vidx == 4 /* uid */ ||
-					    vidx == 5 /* jail */) {
-						check_uidgid(
-						    (ipfw_insn_u32 *)cmd,
-						    args, &ucred_lookup,
-#ifdef __FreeBSD__
-						    &ucred_cache);
-						if (vidx == 4 /* uid */)
-#ifndef __rtems__
-							key = ucred_cache->cr_uid;
-#else /* __rtems__ */
-							key = BSD_DEFAULT_UID;
-#endif /* __rtems__ */
-						else if (vidx == 5 /* jail */)
-#ifndef __rtems__
-							key = ucred_cache->cr_prison->pr_id;
-#else /* __rtems__ */
-							key = BSD_DEFAULT_PRISON->pr_id;
-#endif /* __rtems__ */
-#else /* !__FreeBSD__ */
-						    (void *)&ucred_cache);
-						if (vidx == 4 /* uid */)
-							key = ucred_cache.uid;
-						else if (vidx == 5 /* jail */)
-							key = ucred_cache.xid;
-#endif /* !__FreeBSD__ */
-					}
-#endif /* !USERSPACE */
-					else
-						break;
-					match = ipfw_lookup_table(chain,
-					    cmd->arg1, keylen, pkey, &vidx);
-					if (!match)
-						break;
-					tablearg = vidx;
-					break;
-				}
-				/* cmdlen =< F_INSN_SIZE(ipfw_insn_u32) */
-				/* FALLTHROUGH */
-			}
-			case O_IP_SRC_LOOKUP:
-			{
-				void *pkey;
-				uint32_t vidx;
-				uint16_t keylen;
-
-				if (is_ipv4) {
-					keylen = sizeof(in_addr_t);
-					if (cmd->opcode == O_IP_DST_LOOKUP)
-						pkey = &dst_ip;
-					else
-						pkey = &src_ip;
-				} else if (is_ipv6) {
-					keylen = sizeof(struct in6_addr);
-					if (cmd->opcode == O_IP_DST_LOOKUP)
-						pkey = &args->f_id.dst_ip6;
-					else
-						pkey = &args->f_id.src_ip6;
-				} else
-					break;
-				match = ipfw_lookup_table(chain, cmd->arg1,
-				    keylen, pkey, &vidx);
-				if (!match)
-					break;
-				if (cmdlen == F_INSN_SIZE(ipfw_insn_u32)) {
-					match = ((ipfw_insn_u32 *)cmd)->d[0] ==
-					    TARG_VAL(chain, vidx, tag);
-					if (!match)
-						break;
-				}
-				tablearg = vidx;
-				break;
-			}
-
-			case O_IP_FLOW_LOOKUP:
-				{
-					uint32_t v = 0;
-					match = ipfw_lookup_table(chain,
-					    cmd->arg1, 0, &args->f_id, &v);
-					if (cmdlen == F_INSN_SIZE(ipfw_insn_u32))
-						match = ((ipfw_insn_u32 *)cmd)->d[0] ==
-						    TARG_VAL(chain, v, tag);
-					if (match)
-						tablearg = v;
-				}
-				break;
-			case O_IP_SRC_MASK:
-			case O_IP_DST_MASK:
-				if (is_ipv4) {
-				    uint32_t a =
-					(cmd->opcode == O_IP_DST_MASK) ?
-					    dst_ip.s_addr : src_ip.s_addr;
-				    uint32_t *p = ((ipfw_insn_u32 *)cmd)->d;
-				    int i = cmdlen-1;
-
-				    for (; !match && i>0; i-= 2, p+= 2)
-					match = (p[0] == (a & p[1]));
-				}
-				break;
-
-			case O_IP_SRC_ME:
-				if (is_ipv4) {
-					struct ifnet *tif;
-
-					INADDR_TO_IFP(src_ip, tif);
-					match = (tif != NULL);
-					break;
-				}
-#ifdef INET6
-				/* FALLTHROUGH */
-			case O_IP6_SRC_ME:
-				match= is_ipv6 && ipfw_localip6(&args->f_id.src_ip6);
-#endif
-				break;
-
-			case O_IP_DST_SET:
-			case O_IP_SRC_SET:
-				if (is_ipv4) {
-					u_int32_t *d = (u_int32_t *)(cmd+1);
-					u_int32_t addr =
-					    cmd->opcode == O_IP_DST_SET ?
-						args->f_id.dst_ip :
-						args->f_id.src_ip;
-
-					    if (addr < d[0])
-						    break;
-					    addr -= d[0]; /* subtract base */
-					    match = (addr < cmd->arg1) &&
-						( d[ 1 + (addr>>5)] &
-						  (1<<(addr & 0x1f)) );
-				}
-				break;
-
-			case O_IP_DST:
-				match = is_ipv4 &&
-				    (((ipfw_insn_ip *)cmd)->addr.s_addr ==
-				    dst_ip.s_addr);
-				break;
-
-			case O_IP_DST_ME:
-				if (is_ipv4) {
-					struct ifnet *tif;
-
-					INADDR_TO_IFP(dst_ip, tif);
-					match = (tif != NULL);
-					break;
-				}
-#ifdef INET6
-				/* FALLTHROUGH */
-			case O_IP6_DST_ME:
-				match= is_ipv6 && ipfw_localip6(&args->f_id.dst_ip6);
-#endif
-				break;
-
-
-			case O_IP_SRCPORT:
-			case O_IP_DSTPORT:
-				/*
-				 * offset == 0 && proto != 0 is enough
-				 * to guarantee that we have a
-				 * packet with port info.
-				 */
-				if ((proto==IPPROTO_UDP || proto==IPPROTO_TCP)
-				    && offset == 0) {
-					u_int16_t x =
-					    (cmd->opcode == O_IP_SRCPORT) ?
-						src_port : dst_port ;
-					u_int16_t *p =
-					    ((ipfw_insn_u16 *)cmd)->ports;
-					int i;
-
-					for (i = cmdlen - 1; !match && i>0;
-					    i--, p += 2)
-						match = (x>=p[0] && x<=p[1]);
-				}
-				break;
-
-			case O_ICMPTYPE:
-				match = (offset == 0 && proto==IPPROTO_ICMP &&
-				    icmptype_match(ICMP(ulp), (ipfw_insn_u32 *)cmd) );
-				break;
-
-#ifdef INET6
-			case O_ICMP6TYPE:
-				match = is_ipv6 && offset == 0 &&
-				    proto==IPPROTO_ICMPV6 &&
-				    icmp6type_match(
-					ICMP6(ulp)->icmp6_type,
-					(ipfw_insn_u32 *)cmd);
-				break;
-#endif /* INET6 */
-
-			case O_IPOPT:
-				match = (is_ipv4 &&
-				    ipopts_match(ip, cmd) );
-				break;
-
-			case O_IPVER:
-				match = (is_ipv4 &&
-				    cmd->arg1 == ip->ip_v);
-				break;
-
-			case O_IPID:
-			case O_IPLEN:
-			case O_IPTTL:
-				if (is_ipv4) {	/* only for IP packets */
-				    uint16_t x;
-				    uint16_t *p;
-				    int i;
-
-				    if (cmd->opcode == O_IPLEN)
-					x = iplen;
-				    else if (cmd->opcode == O_IPTTL)
-					x = ip->ip_ttl;
-				    else /* must be IPID */
-					x = ntohs(ip->ip_id);
-				    if (cmdlen == 1) {
-					match = (cmd->arg1 == x);
-					break;
-				    }
-				    /* otherwise we have ranges */
-				    p = ((ipfw_insn_u16 *)cmd)->ports;
-				    i = cmdlen - 1;
-				    for (; !match && i>0; i--, p += 2)
-					match = (x >= p[0] && x <= p[1]);
-				}
-				break;
-
-			case O_IPPRECEDENCE:
-				match = (is_ipv4 &&
-				    (cmd->arg1 == (ip->ip_tos & 0xe0)) );
-				break;
-
-			case O_IPTOS:
-				match = (is_ipv4 &&
-				    flags_match(cmd, ip->ip_tos));
-				break;
-
-			case O_DSCP:
-			    {
-				uint32_t *p;
-				uint16_t x;
-
-				p = ((ipfw_insn_u32 *)cmd)->d;
-
-				if (is_ipv4)
-					x = ip->ip_tos >> 2;
-				else if (is_ipv6) {
-					uint8_t *v;
-					v = &((struct ip6_hdr *)ip)->ip6_vfc;
-					x = (*v & 0x0F) << 2;
-					v++;
-					x |= *v >> 6;
-				} else
-					break;
-
-				/* DSCP bitmask is stored as low_u32 high_u32 */
-				if (x >= 32)
-					match = *(p + 1) & (1 << (x - 32));
-				else
-					match = *p & (1 << x);
-			    }
-				break;
-
-			case O_TCPDATALEN:
-				if (proto == IPPROTO_TCP && offset == 0) {
-				    struct tcphdr *tcp;
-				    uint16_t x;
-				    uint16_t *p;
-				    int i;
-
-				    tcp = TCP(ulp);
-				    x = iplen -
-					((ip->ip_hl + tcp->th_off) << 2);
-				    if (cmdlen == 1) {
-					match = (cmd->arg1 == x);
-					break;
-				    }
-				    /* otherwise we have ranges */
-				    p = ((ipfw_insn_u16 *)cmd)->ports;
-				    i = cmdlen - 1;
-				    for (; !match && i>0; i--, p += 2)
-					match = (x >= p[0] && x <= p[1]);
-				}
-				break;
-
-			case O_TCPFLAGS:
-				match = (proto == IPPROTO_TCP && offset == 0 &&
-				    flags_match(cmd, TCP(ulp)->th_flags));
-				break;
-
-			case O_TCPOPTS:
-				if (proto == IPPROTO_TCP && offset == 0 && ulp){
-					PULLUP_LEN(hlen, ulp,
-					    (TCP(ulp)->th_off << 2));
-					match = tcpopts_match(TCP(ulp), cmd);
-				}
-				break;
-
-			case O_TCPSEQ:
-				match = (proto == IPPROTO_TCP && offset == 0 &&
-				    ((ipfw_insn_u32 *)cmd)->d[0] ==
-					TCP(ulp)->th_seq);
-				break;
-
-			case O_TCPACK:
-				match = (proto == IPPROTO_TCP && offset == 0 &&
-				    ((ipfw_insn_u32 *)cmd)->d[0] ==
-					TCP(ulp)->th_ack);
-				break;
-
-			case O_TCPWIN:
-				if (proto == IPPROTO_TCP && offset == 0) {
-				    uint16_t x;
-				    uint16_t *p;
-				    int i;
-
-				    x = ntohs(TCP(ulp)->th_win);
-				    if (cmdlen == 1) {
-					match = (cmd->arg1 == x);
-					break;
-				    }
-				    /* Otherwise we have ranges. */
-				    p = ((ipfw_insn_u16 *)cmd)->ports;
-				    i = cmdlen - 1;
-				    for (; !match && i > 0; i--, p += 2)
-					match = (x >= p[0] && x <= p[1]);
-				}
-				break;
-
-			case O_ESTAB:
-				/* reject packets which have SYN only */
-				/* XXX should i also check for TH_ACK ? */
-				match = (proto == IPPROTO_TCP && offset == 0 &&
-				    (TCP(ulp)->th_flags &
-				     (TH_RST | TH_ACK | TH_SYN)) != TH_SYN);
-				break;
-
-			case O_ALTQ: {
-				struct pf_mtag *at;
-				struct m_tag *mtag;
-				ipfw_insn_altq *altq = (ipfw_insn_altq *)cmd;
-
-				/*
-				 * ALTQ uses mbuf tags from another
-				 * packet filtering system - pf(4).
-				 * We allocate a tag in its format
-				 * and fill it in, pretending to be pf(4).
-				 */
-				match = 1;
-				at = pf_find_mtag(m);
-				if (at != NULL && at->qid != 0)
-					break;
-				mtag = m_tag_get(PACKET_TAG_PF,
-				    sizeof(struct pf_mtag), M_NOWAIT | M_ZERO);
-				if (mtag == NULL) {
-					/*
-					 * Let the packet fall back to the
-					 * default ALTQ.
-					 */
-					break;
-				}
-				m_tag_prepend(m, mtag);
-				at = (struct pf_mtag *)(mtag + 1);
-				at->qid = altq->qid;
-				at->hdr = ip;
-				break;
-			}
-
-			case O_LOG:
-				ipfw_log(chain, f, hlen, args, m,
-				    oif, offset | ip6f_mf, tablearg, ip);
-				match = 1;
-				break;
-
-			case O_PROB:
-				match = (random()<((ipfw_insn_u32 *)cmd)->d[0]);
-				break;
-
-			case O_VERREVPATH:
-				/* Outgoing packets automatically pass/match */
-				match = ((oif != NULL) ||
-				    (m->m_pkthdr.rcvif == NULL) ||
-				    (
-#ifdef INET6
-				    is_ipv6 ?
-					verify_path6(&(args->f_id.src_ip6),
-					    m->m_pkthdr.rcvif, args->f_id.fib) :
-#endif
-				    verify_path(src_ip, m->m_pkthdr.rcvif,
-				        args->f_id.fib)));
-				break;
-
-			case O_VERSRCREACH:
-				/* Outgoing packets automatically pass/match */
-				match = (hlen > 0 && ((oif != NULL) ||
-#ifdef INET6
-				    is_ipv6 ?
-				        verify_path6(&(args->f_id.src_ip6),
-				            NULL, args->f_id.fib) :
-#endif
-				    verify_path(src_ip, NULL, args->f_id.fib)));
-				break;
-
-			case O_ANTISPOOF:
-				/* Outgoing packets automatically pass/match */
-				if (oif == NULL && hlen > 0 &&
-				    (  (is_ipv4 && in_localaddr(src_ip))
-#ifdef INET6
-				    || (is_ipv6 &&
-				        in6_localaddr(&(args->f_id.src_ip6)))
-#endif
-				    ))
-					match =
-#ifdef INET6
-					    is_ipv6 ? verify_path6(
-					        &(args->f_id.src_ip6),
-					        m->m_pkthdr.rcvif,
-						args->f_id.fib) :
-#endif
-					    verify_path(src_ip,
-					    	m->m_pkthdr.rcvif,
-					        args->f_id.fib);
-				else
-					match = 1;
-				break;
-
-			case O_IPSEC:
-#ifdef IPSEC
-				match = (m_tag_find(m,
-				    PACKET_TAG_IPSEC_IN_DONE, NULL) != NULL);
-#endif
-				/* otherwise no match */
-				break;
-
-#ifdef INET6
-			case O_IP6_SRC:
-				match = is_ipv6 &&
-				    IN6_ARE_ADDR_EQUAL(&args->f_id.src_ip6,
-				    &((ipfw_insn_ip6 *)cmd)->addr6);
-				break;
-
-			case O_IP6_DST:
-				match = is_ipv6 &&
-				IN6_ARE_ADDR_EQUAL(&args->f_id.dst_ip6,
-				    &((ipfw_insn_ip6 *)cmd)->addr6);
-				break;
-			case O_IP6_SRC_MASK:
-			case O_IP6_DST_MASK:
-				if (is_ipv6) {
-					int i = cmdlen - 1;
-					struct in6_addr p;
-					struct in6_addr *d =
-					    &((ipfw_insn_ip6 *)cmd)->addr6;
-
-					for (; !match && i > 0; d += 2,
-					    i -= F_INSN_SIZE(struct in6_addr)
-					    * 2) {
-						p = (cmd->opcode ==
-						    O_IP6_SRC_MASK) ?
-						    args->f_id.src_ip6:
-						    args->f_id.dst_ip6;
-						APPLY_MASK(&p, &d[1]);
-						match =
-						    IN6_ARE_ADDR_EQUAL(&d[0],
-						    &p);
-					}
-				}
-				break;
-
-			case O_FLOW6ID:
-				match = is_ipv6 &&
-				    flow6id_match(args->f_id.flow_id6,
-				    (ipfw_insn_u32 *) cmd);
-				break;
-
-			case O_EXT_HDR:
-				match = is_ipv6 &&
-				    (ext_hd & ((ipfw_insn *) cmd)->arg1);
-				break;
-
-			case O_IP6:
-				match = is_ipv6;
-				break;
-#endif
-
-			case O_IP4:
-				match = is_ipv4;
-				break;
-
-			case O_TAG: {
-				struct m_tag *mtag;
-				uint32_t tag = TARG(cmd->arg1, tag);
-
-				/* Packet is already tagged with this tag? */
-				mtag = m_tag_locate(m, MTAG_IPFW, tag, NULL);
-
-				/* We have `untag' action when F_NOT flag is
-				 * present. And we must remove this mtag from
-				 * mbuf and reset `match' to zero (`match' will
-				 * be inversed later).
-				 * Otherwise we should allocate new mtag and
-				 * push it into mbuf.
-				 */
-				if (cmd->len & F_NOT) { /* `untag' action */
-					if (mtag != NULL)
-						m_tag_delete(m, mtag);
-					match = 0;
-				} else {
-					if (mtag == NULL) {
-						mtag = m_tag_alloc( MTAG_IPFW,
-						    tag, 0, M_NOWAIT);
-						if (mtag != NULL)
-							m_tag_prepend(m, mtag);
-					}
-					match = 1;
-				}
-				break;
-			}
-
-			case O_FIB: /* try match the specified fib */
-				if (args->f_id.fib == cmd->arg1)
-					match = 1;
-				break;
-
-			case O_SOCKARG:	{
-#ifndef USERSPACE	/* not supported in userspace */
-				struct inpcb *inp = args->inp;
-				struct inpcbinfo *pi;
-				
-				if (is_ipv6) /* XXX can we remove this ? */
-					break;
-
-				if (proto == IPPROTO_TCP)
-					pi = &V_tcbinfo;
-				else if (proto == IPPROTO_UDP)
-					pi = &V_udbinfo;
-				else
-					break;
-
-				/*
-				 * XXXRW: so_user_cookie should almost
-				 * certainly be inp_user_cookie?
-				 */
-
-				/* For incoming packet, lookup up the 
-				inpcb using the src/dest ip/port tuple */
-				if (inp == NULL) {
-					inp = in_pcblookup(pi, 
-						src_ip, htons(src_port),
-						dst_ip, htons(dst_port),
-						INPLOOKUP_RLOCKPCB, NULL);
-					if (inp != NULL) {
-						tablearg =
-						    inp->inp_socket->so_user_cookie;
-						if (tablearg)
-							match = 1;
-						INP_RUNLOCK(inp);
-					}
-				} else {
-					if (inp->inp_socket) {
-						tablearg =
-						    inp->inp_socket->so_user_cookie;
-						if (tablearg)
-							match = 1;
-					}
-				}
-#endif /* !USERSPACE */
-				break;
-			}
-
-			case O_TAGGED: {
-				struct m_tag *mtag;
-				uint32_t tag = TARG(cmd->arg1, tag);
-
-				if (cmdlen == 1) {
-					match = m_tag_locate(m, MTAG_IPFW,
-					    tag, NULL) != NULL;
-					break;
-				}
-
-				/* we have ranges */
-				for (mtag = m_tag_first(m);
-				    mtag != NULL && !match;
-				    mtag = m_tag_next(m, mtag)) {
-					uint16_t *p;
-					int i;
-
-					if (mtag->m_tag_cookie != MTAG_IPFW)
-						continue;
-
-					p = ((ipfw_insn_u16 *)cmd)->ports;
-					i = cmdlen - 1;
-					for(; !match && i > 0; i--, p += 2)
-						match =
-						    mtag->m_tag_id >= p[0] &&
-						    mtag->m_tag_id <= p[1];
-				}
-				break;
-			}
-				
-			/*
-			 * The second set of opcodes represents 'actions',
-			 * i.e. the terminal part of a rule once the packet
-			 * matches all previous patterns.
-			 * Typically there is only one action for each rule,
-			 * and the opcode is stored at the end of the rule
-			 * (but there are exceptions -- see below).
-			 *
-			 * In general, here we set retval and terminate the
-			 * outer loop (would be a 'break 3' in some language,
-			 * but we need to set l=0, done=1)
-			 *
-			 * Exceptions:
-			 * O_COUNT and O_SKIPTO actions:
-			 *   instead of terminating, we jump to the next rule
-			 *   (setting l=0), or to the SKIPTO target (setting
-			 *   f/f_len, cmd and l as needed), respectively.
-			 *
-			 * O_TAG, O_LOG and O_ALTQ action parameters:
-			 *   perform some action and set match = 1;
-			 *
-			 * O_LIMIT and O_KEEP_STATE: these opcodes are
-			 *   not real 'actions', and are stored right
-			 *   before the 'action' part of the rule.
-			 *   These opcodes try to install an entry in the
-			 *   state tables; if successful, we continue with
-			 *   the next opcode (match=1; break;), otherwise
-			 *   the packet must be dropped (set retval,
-			 *   break loops with l=0, done=1)
-			 *
-			 * O_PROBE_STATE and O_CHECK_STATE: these opcodes
-			 *   cause a lookup of the state table, and a jump
-			 *   to the 'action' part of the parent rule
-			 *   if an entry is found, or
-			 *   (CHECK_STATE only) a jump to the next rule if
-			 *   the entry is not found.
-			 *   The result of the lookup is cached so that
-			 *   further instances of these opcodes become NOPs.
-			 *   The jump to the next rule is done by setting
-			 *   l=0, cmdlen=0.
-			 */
-			case O_LIMIT:
-			case O_KEEP_STATE:
-				if (ipfw_install_state(chain, f,
-				    (ipfw_insn_limit *)cmd, args, tablearg)) {
-					/* error or limit violation */
-					retval = IP_FW_DENY;
-					l = 0;	/* exit inner loop */
-					done = 1; /* exit outer loop */
-				}
-				match = 1;
-				break;
-
-			case O_PROBE_STATE:
-			case O_CHECK_STATE:
-				/*
-				 * dynamic rules are checked at the first
-				 * keep-state or check-state occurrence,
-				 * with the result being stored in dyn_dir
-				 * and dyn_name.
-				 * The compiler introduces a PROBE_STATE
-				 * instruction for us when we have a
-				 * KEEP_STATE (because PROBE_STATE needs
-				 * to be run first).
-				 *
-				 * (dyn_dir == MATCH_UNKNOWN) means this is
-				 * first lookup for such f_id. Do lookup.
-				 *
-				 * (dyn_dir != MATCH_UNKNOWN &&
-				 *  dyn_name != 0 && dyn_name != cmd->arg1)
-				 * means previous lookup didn't find dynamic
-				 * rule for specific state name and current
-				 * lookup will search rule with another state
-				 * name. Redo lookup.
-				 *
-				 * (dyn_dir != MATCH_UNKNOWN && dyn_name == 0)
-				 * means previous lookup was for `any' name
-				 * and it didn't find rule. No need to do
-				 * lookup again.
-				 */
-				if ((dyn_dir == MATCH_UNKNOWN ||
-				    (dyn_name != 0 &&
-				    dyn_name != cmd->arg1)) &&
-				    (q = ipfw_lookup_dyn_rule(&args->f_id,
-				     &dyn_dir, proto == IPPROTO_TCP ?
-				     TCP(ulp): NULL,
-				     (dyn_name = cmd->arg1))) != NULL) {
-					/*
-					 * Found dynamic entry, update stats
-					 * and jump to the 'action' part of
-					 * the parent rule by setting
-					 * f, cmd, l and clearing cmdlen.
-					 */
-					IPFW_INC_DYN_COUNTER(q, pktlen);
-					/* XXX we would like to have f_pos
-					 * readily accessible in the dynamic
-				         * rule, instead of having to
-					 * lookup q->rule.
-					 */
-					f = q->rule;
-					f_pos = ipfw_find_rule(chain,
-						f->rulenum, f->id);
-					cmd = ACTION_PTR(f);
-					l = f->cmd_len - f->act_ofs;
-					ipfw_dyn_unlock(q);
-					cmdlen = 0;
-					match = 1;
-					break;
-				}
-				/*
-				 * Dynamic entry not found. If CHECK_STATE,
-				 * skip to next rule, if PROBE_STATE just
-				 * ignore and continue with next opcode.
-				 */
-				if (cmd->opcode == O_CHECK_STATE)
-					l = 0;	/* exit inner loop */
-				match = 1;
-				break;
-
-			case O_ACCEPT:
-				retval = 0;	/* accept */
-				l = 0;		/* exit inner loop */
-				done = 1;	/* exit outer loop */
-				break;
-
-			case O_PIPE:
-			case O_QUEUE:
-				set_match(args, f_pos, chain);
-				args->rule.info = TARG(cmd->arg1, pipe);
-				if (cmd->opcode == O_PIPE)
-					args->rule.info |= IPFW_IS_PIPE;
-				if (V_fw_one_pass)
-					args->rule.info |= IPFW_ONEPASS;
-				retval = IP_FW_DUMMYNET;
-				l = 0;          /* exit inner loop */
-				done = 1;       /* exit outer loop */
-				break;
-
-			case O_DIVERT:
-			case O_TEE:
-				if (args->eh) /* not on layer 2 */
-				    break;
-				/* otherwise this is terminal */
-				l = 0;		/* exit inner loop */
-				done = 1;	/* exit outer loop */
-				retval = (cmd->opcode == O_DIVERT) ?
-					IP_FW_DIVERT : IP_FW_TEE;
-				set_match(args, f_pos, chain);
-				args->rule.info = TARG(cmd->arg1, divert);
-				break;
-
-			case O_COUNT:
-				IPFW_INC_RULE_COUNTER(f, pktlen);
-				l = 0;		/* exit inner loop */
-				break;
-
-			case O_SKIPTO:
-			    IPFW_INC_RULE_COUNTER(f, pktlen);
-			    f_pos = JUMP(chain, f, cmd->arg1, tablearg, 0);
-			    /*
-			     * Skip disabled rules, and re-enter
-			     * the inner loop with the correct
-			     * f_pos, f, l and cmd.
-			     * Also clear cmdlen and skip_or
-			     */
-			    for (; f_pos < chain->n_rules - 1 &&
-				    (V_set_disable &
-				     (1 << chain->map[f_pos]->set));
-				    f_pos++)
-				;
-			    /* Re-enter the inner loop at the skipto rule. */
-			    f = chain->map[f_pos];
-			    l = f->cmd_len;
-			    cmd = f->cmd;
-			    match = 1;
-			    cmdlen = 0;
-			    skip_or = 0;
-			    continue;
-			    break;	/* not reached */
-
-			case O_CALLRETURN: {
-				/*
-				 * Implementation of `subroutine' call/return,
-				 * in the stack carried in an mbuf tag. This
-				 * is different from `skipto' in that any call
-				 * address is possible (`skipto' must prevent
-				 * backward jumps to avoid endless loops).
-				 * We have `return' action when F_NOT flag is
-				 * present. The `m_tag_id' field is used as
-				 * stack pointer.
-				 */
-				struct m_tag *mtag;
-				uint16_t jmpto, *stack;
-
-#define	IS_CALL		((cmd->len & F_NOT) == 0)
-#define	IS_RETURN	((cmd->len & F_NOT) != 0)
-				/*
-				 * Hand-rolled version of m_tag_locate() with
-				 * wildcard `type'.
-				 * If not already tagged, allocate new tag.
-				 */
-				mtag = m_tag_first(m);
-				while (mtag != NULL) {
-					if (mtag->m_tag_cookie ==
-					    MTAG_IPFW_CALL)
-						break;
-					mtag = m_tag_next(m, mtag);
-				}
-				if (mtag == NULL && IS_CALL) {
-					mtag = m_tag_alloc(MTAG_IPFW_CALL, 0,
-					    IPFW_CALLSTACK_SIZE *
-					    sizeof(uint16_t), M_NOWAIT);
-					if (mtag != NULL)
-						m_tag_prepend(m, mtag);
-				}
-
-				/*
-				 * On error both `call' and `return' just
-				 * continue with next rule.
-				 */
-				if (IS_RETURN && (mtag == NULL ||
-				    mtag->m_tag_id == 0)) {
-					l = 0;		/* exit inner loop */
-					break;
-				}
-				if (IS_CALL && (mtag == NULL ||
-				    mtag->m_tag_id >= IPFW_CALLSTACK_SIZE)) {
-					printf("ipfw: call stack error, "
-					    "go to next rule\n");
-					l = 0;		/* exit inner loop */
-					break;
-				}
-
-				IPFW_INC_RULE_COUNTER(f, pktlen);
-				stack = (uint16_t *)(mtag + 1);
-
-				/*
-				 * The `call' action may use cached f_pos
-				 * (in f->next_rule), whose version is written
-				 * in f->next_rule.
-				 * The `return' action, however, doesn't have
-				 * fixed jump address in cmd->arg1 and can't use
-				 * cache.
-				 */
-				if (IS_CALL) {
-					stack[mtag->m_tag_id] = f->rulenum;
-					mtag->m_tag_id++;
-			    		f_pos = JUMP(chain, f, cmd->arg1,
-					    tablearg, 1);
-				} else {	/* `return' action */
-					mtag->m_tag_id--;
-					jmpto = stack[mtag->m_tag_id] + 1;
-					f_pos = ipfw_find_rule(chain, jmpto, 0);
-				}
-
-				/*
-				 * Skip disabled rules, and re-enter
-				 * the inner loop with the correct
-				 * f_pos, f, l and cmd.
-				 * Also clear cmdlen and skip_or
-				 */
-				for (; f_pos < chain->n_rules - 1 &&
-				    (V_set_disable &
-				    (1 << chain->map[f_pos]->set)); f_pos++)
-					;
-				/* Re-enter the inner loop at the dest rule. */
-				f = chain->map[f_pos];
-				l = f->cmd_len;
-				cmd = f->cmd;
-				cmdlen = 0;
-				skip_or = 0;
-				continue;
-				break;	/* NOTREACHED */
-			}
-#undef IS_CALL
-#undef IS_RETURN
-
-			case O_REJECT:
-				/*
-				 * Drop the packet and send a reject notice
-				 * if the packet is not ICMP (or is an ICMP
-				 * query), and it is not multicast/broadcast.
-				 */
-				if (hlen > 0 && is_ipv4 && offset == 0 &&
-				    (proto != IPPROTO_ICMP ||
-				     is_icmp_query(ICMP(ulp))) &&
-				    !(m->m_flags & (M_BCAST|M_MCAST)) &&
-				    !IN_MULTICAST(ntohl(dst_ip.s_addr))) {
-					send_reject(args, cmd->arg1, iplen, ip);
-					m = args->m;
-				}
-				/* FALLTHROUGH */
-#ifdef INET6
-			case O_UNREACH6:
-				if (hlen > 0 && is_ipv6 &&
-				    ((offset & IP6F_OFF_MASK) == 0) &&
-				    (proto != IPPROTO_ICMPV6 ||
-				     (is_icmp6_query(icmp6_type) == 1)) &&
-				    !(m->m_flags & (M_BCAST|M_MCAST)) &&
-				    !IN6_IS_ADDR_MULTICAST(&args->f_id.dst_ip6)) {
-					send_reject6(
-					    args, cmd->arg1, hlen,
-					    (struct ip6_hdr *)ip);
-					m = args->m;
-				}
-				/* FALLTHROUGH */
-#endif
-			case O_DENY:
-				retval = IP_FW_DENY;
-				l = 0;		/* exit inner loop */
-				done = 1;	/* exit outer loop */
-				break;
-
-			case O_FORWARD_IP:
-				if (args->eh)	/* not valid on layer2 pkts */
-					break;
-				if (q == NULL || q->rule != f ||
-				    dyn_dir == MATCH_FORWARD) {
-				    struct sockaddr_in *sa;
-
-				    sa = &(((ipfw_insn_sa *)cmd)->sa);
-				    if (sa->sin_addr.s_addr == INADDR_ANY) {
-#ifdef INET6
-					/*
-					 * We use O_FORWARD_IP opcode for
-					 * fwd rule with tablearg, but tables
-					 * now support IPv6 addresses. And
-					 * when we are inspecting IPv6 packet,
-					 * we can use nh6 field from
-					 * table_value as next_hop6 address.
-					 */
-					if (is_ipv6) {
-						struct sockaddr_in6 *sa6;
-
-						sa6 = args->next_hop6 =
-						    &args->hopstore6;
-						sa6->sin6_family = AF_INET6;
-						sa6->sin6_len = sizeof(*sa6);
-						sa6->sin6_addr = TARG_VAL(
-						    chain, tablearg, nh6);
-						/*
-						 * Set sin6_scope_id only for
-						 * link-local unicast addresses.
-						 */
-						if (IN6_IS_ADDR_LINKLOCAL(
-						    &sa6->sin6_addr))
-							sa6->sin6_scope_id =
-							    TARG_VAL(chain,
-								tablearg,
-								zoneid);
-					} else
-#endif
-					{
-						sa = args->next_hop =
-						    &args->hopstore;
-						sa->sin_family = AF_INET;
-						sa->sin_len = sizeof(*sa);
-						sa->sin_addr.s_addr = htonl(
-						    TARG_VAL(chain, tablearg,
-						    nh4));
-					}
-				    } else {
-					args->next_hop = sa;
-				    }
-				}
-				retval = IP_FW_PASS;
-				l = 0;          /* exit inner loop */
-				done = 1;       /* exit outer loop */
-				break;
-
-#ifdef INET6
-			case O_FORWARD_IP6:
-				if (args->eh)	/* not valid on layer2 pkts */
-					break;
-				if (q == NULL || q->rule != f ||
-				    dyn_dir == MATCH_FORWARD) {
-					struct sockaddr_in6 *sin6;
-
-					sin6 = &(((ipfw_insn_sa6 *)cmd)->sa);
-					args->next_hop6 = sin6;
-				}
-				retval = IP_FW_PASS;
-				l = 0;		/* exit inner loop */
-				done = 1;	/* exit outer loop */
-				break;
-#endif
-
-			case O_NETGRAPH:
-			case O_NGTEE:
-				set_match(args, f_pos, chain);
-				args->rule.info = TARG(cmd->arg1, netgraph);
-				if (V_fw_one_pass)
-					args->rule.info |= IPFW_ONEPASS;
-				retval = (cmd->opcode == O_NETGRAPH) ?
-				    IP_FW_NETGRAPH : IP_FW_NGTEE;
-				l = 0;          /* exit inner loop */
-				done = 1;       /* exit outer loop */
-				break;
-
-			case O_SETFIB: {
-				uint32_t fib;
-
-				IPFW_INC_RULE_COUNTER(f, pktlen);
-				fib = TARG(cmd->arg1, fib) & 0x7FFF;
-				if (fib >= rt_numfibs)
-					fib = 0;
-				M_SETFIB(m, fib);
-				args->f_id.fib = fib;
-				l = 0;		/* exit inner loop */
-				break;
-		        }
-
-			case O_SETDSCP: {
-				uint16_t code;
-
-				code = TARG(cmd->arg1, dscp) & 0x3F;
-				l = 0;		/* exit inner loop */
-				if (is_ipv4) {
-					uint16_t old;
-
-					old = *(uint16_t *)ip;
-					ip->ip_tos = (code << 2) |
-					    (ip->ip_tos & 0x03);
-					ip->ip_sum = cksum_adjust(ip->ip_sum,
-					    old, *(uint16_t *)ip);
-				} else if (is_ipv6) {
-					uint8_t *v;
-
-					v = &((struct ip6_hdr *)ip)->ip6_vfc;
-					*v = (*v & 0xF0) | (code >> 2);
-					v++;
-					*v = (*v & 0x3F) | ((code & 0x03) << 6);
-				} else
-					break;
-
-				IPFW_INC_RULE_COUNTER(f, pktlen);
-				break;
-			}
-
-			case O_NAT:
-				l = 0;          /* exit inner loop */
-				done = 1;       /* exit outer loop */
- 				if (!IPFW_NAT_LOADED) {
-				    retval = IP_FW_DENY;
-				    break;
-				}
-
-				struct cfg_nat *t;
-				int nat_id;
-
-				set_match(args, f_pos, chain);
-				/* Check if this is 'global' nat rule */
-				if (cmd->arg1 == IP_FW_NAT44_GLOBAL) {
-					retval = ipfw_nat_ptr(args, NULL, m);
-					break;
-				}
-				t = ((ipfw_insn_nat *)cmd)->nat;
-				if (t == NULL) {
-					nat_id = TARG(cmd->arg1, nat);
-					t = (*lookup_nat_ptr)(&chain->nat, nat_id);
-
-					if (t == NULL) {
-					    retval = IP_FW_DENY;
-					    break;
-					}
-					if (cmd->arg1 != IP_FW_TARG)
-					    ((ipfw_insn_nat *)cmd)->nat = t;
-				}
-				retval = ipfw_nat_ptr(args, t, m);
-				break;
-
-			case O_REASS: {
-				int ip_off;
-
-				IPFW_INC_RULE_COUNTER(f, pktlen);
-				l = 0;	/* in any case exit inner loop */
-				ip_off = ntohs(ip->ip_off);
-
-				/* if not fragmented, go to next rule */
-				if ((ip_off & (IP_MF | IP_OFFMASK)) == 0)
-				    break;
-
-				args->m = m = ip_reass(m);
-
-				/*
-				 * do IP header checksum fixup.
-				 */
-				if (m == NULL) { /* fragment got swallowed */
-				    retval = IP_FW_DENY;
-				} else { /* good, packet complete */
-				    int hlen;
-
-				    ip = mtod(m, struct ip *);
-				    hlen = ip->ip_hl << 2;
-				    ip->ip_sum = 0;
-				    if (hlen == sizeof(struct ip))
-					ip->ip_sum = in_cksum_hdr(ip);
-				    else
-					ip->ip_sum = in_cksum(m, hlen);
-				    retval = IP_FW_REASS;
-				    set_match(args, f_pos, chain);
-				}
-				done = 1;	/* exit outer loop */
-				break;
-			}
-			case O_EXTERNAL_ACTION:
-				l = 0; /* in any case exit inner loop */
-				retval = ipfw_run_eaction(chain, args,
-				    cmd, &done);
-				/*
-				 * If both @retval and @done are zero,
-				 * consider this as rule matching and
-				 * update counters.
-				 */
-				if (retval == 0 && done == 0) {
-					IPFW_INC_RULE_COUNTER(f, pktlen);
-					/*
-					 * Reset the result of the last
-					 * dynamic state lookup.
-					 * External action can change
-					 * @args content, and it may be
-					 * used for new state lookup later.
-					 */
-					dyn_dir = MATCH_UNKNOWN;
-				}
-				break;
-
-			default:
-				panic("-- unknown opcode %d\n", cmd->opcode);
-			} /* end of switch() on opcodes */
-			/*
-			 * if we get here with l=0, then match is irrelevant.
-			 */
-
-			if (cmd->len & F_NOT)
-				match = !match;
-
-			if (match) {
-				if (cmd->len & F_OR)
-					skip_or = 1;
-			} else {
-				if (!(cmd->len & F_OR)) /* not an OR block, */
-					break;		/* try next rule    */
-			}
-
-		}	/* end of inner loop, scan opcodes */
-#undef PULLUP_LEN
-
-		if (done)
-			break;
-
-/* next_rule:; */	/* try next rule		*/
-
-	}		/* end of outer for, scan rules */
-
-	if (done) {
-		struct ip_fw *rule = chain->map[f_pos];
-		/* Update statistics */
-		IPFW_INC_RULE_COUNTER(rule, pktlen);
-	} else {
-		retval = IP_FW_DENY;
-		printf("ipfw: ouch!, skip past end of rules, denying packet\n");
-	}
-	IPFW_PF_RUNLOCK(chain);
-#ifdef __FreeBSD__
-	if (ucred_cache != NULL)
-		crfree(ucred_cache);
-#endif
-	return (retval);
-
-pullup_failed:
-	if (V_fw_verbose)
-		printf("ipfw: pullup failed\n");
-	return (IP_FW_DENY);
-}
-
-/*
- * Set maximum number of tables that can be used in given VNET ipfw instance.
- */
-#ifdef SYSCTL_NODE
-static int
-sysctl_ipfw_table_num(SYSCTL_HANDLER_ARGS)
-{
-	int error;
-	unsigned int ntables;
-
-	ntables = V_fw_tables_max;
-
-	error = sysctl_handle_int(oidp, &ntables, 0, req);
-	/* Read operation or some error */
-	if ((error != 0) || (req->newptr == NULL))
-		return (error);
-
-	return (ipfw_resize_tables(&V_layer3_chain, ntables));
-}
-
-/*
- * Switches table namespace between global and per-set.
- */
-static int
-sysctl_ipfw_tables_sets(SYSCTL_HANDLER_ARGS)
-{
-	int error;
-	unsigned int sets;
-
-	sets = V_fw_tables_sets;
-
-	error = sysctl_handle_int(oidp, &sets, 0, req);
-	/* Read operation or some error */
-	if ((error != 0) || (req->newptr == NULL))
-		return (error);
-
-	return (ipfw_switch_tables_namespace(&V_layer3_chain, sets));
-}
-#endif
-
-/*
- * Module and VNET glue
- */
-
-/*
- * Stuff that must be initialised only on boot or module load
- */
-static int
-ipfw_init(void)
-{
-	int error = 0;
-
-	/*
- 	 * Only print out this stuff the first time around,
-	 * when called from the sysinit code.
-	 */
-	printf("ipfw2 "
-#ifdef INET6
-		"(+ipv6) "
-#endif
-		"initialized, divert %s, nat %s, "
-		"default to %s, logging ",
-#ifdef IPDIVERT
-		"enabled",
-#else
-		"loadable",
-#endif
-#ifdef IPFIREWALL_NAT
-		"enabled",
-#else
-		"loadable",
-#endif
-		default_to_accept ? "accept" : "deny");
-
-	/*
-	 * Note: V_xxx variables can be accessed here but the vnet specific
-	 * initializer may not have been called yet for the VIMAGE case.
-	 * Tuneables will have been processed. We will print out values for
-	 * the default vnet. 
-	 * XXX This should all be rationalized AFTER 8.0
-	 */
-	if (V_fw_verbose == 0)
-		printf("disabled\n");
-	else if (V_verbose_limit == 0)
-		printf("unlimited\n");
-	else
-		printf("limited to %d packets/entry by default\n",
-		    V_verbose_limit);
-
-	/* Check user-supplied table count for validness */
-	if (default_fw_tables > IPFW_TABLES_MAX)
-	  default_fw_tables = IPFW_TABLES_MAX;
-
-	ipfw_init_sopt_handler();
-	ipfw_init_obj_rewriter();
-	ipfw_iface_init();
-	return (error);
-}
-
-#ifndef __rtems__
-/*
- * Called for the removal of the last instance only on module unload.
- */
-static void
-ipfw_destroy(void)
-{
-
-	ipfw_iface_destroy();
-	ipfw_destroy_sopt_handler();
-	ipfw_destroy_obj_rewriter();
-	printf("IP firewall unloaded\n");
-}
-#endif /* __rtems__ */
-
-/*
- * Stuff that must be initialized for every instance
- * (including the first of course).
- */
-static int
-vnet_ipfw_init(const void *unused)
-{
-	int error, first;
-	struct ip_fw *rule = NULL;
-	struct ip_fw_chain *chain;
-
-	chain = &V_layer3_chain;
-
-	first = IS_DEFAULT_VNET(curvnet) ? 1 : 0;
-
-	/* First set up some values that are compile time options */
-	V_autoinc_step = 100;	/* bounded to 1..1000 in add_rule() */
-	V_fw_deny_unknown_exthdrs = 1;
-#ifdef IPFIREWALL_VERBOSE
-	V_fw_verbose = 1;
-#endif
-#ifdef IPFIREWALL_VERBOSE_LIMIT
-	V_verbose_limit = IPFIREWALL_VERBOSE_LIMIT;
-#endif
-#ifdef IPFIREWALL_NAT
-	LIST_INIT(&chain->nat);
-#endif
-
-	/* Init shared services hash table */
-	ipfw_init_srv(chain);
-
-	ipfw_init_counters();
-	/* insert the default rule and create the initial map */
-	chain->n_rules = 1;
-	chain->map = malloc(sizeof(struct ip_fw *), M_IPFW, M_WAITOK | M_ZERO);
-	rule = ipfw_alloc_rule(chain, sizeof(struct ip_fw));
-
-	/* Set initial number of tables */
-	V_fw_tables_max = default_fw_tables;
-	error = ipfw_init_tables(chain, first);
-	if (error) {
-		printf("ipfw2: setting up tables failed\n");
-		free(chain->map, M_IPFW);
-		free(rule, M_IPFW);
-		return (ENOSPC);
-	}
-
-	/* fill and insert the default rule */
-	rule->act_ofs = 0;
-	rule->rulenum = IPFW_DEFAULT_RULE;
-	rule->cmd_len = 1;
-	rule->set = RESVD_SET;
-	rule->cmd[0].len = 1;
-	rule->cmd[0].opcode = default_to_accept ? O_ACCEPT : O_DENY;
-	chain->default_rule = chain->map[0] = rule;
-	chain->id = rule->id = 1;
-	/* Pre-calculate rules length for legacy dump format */
-	chain->static_len = sizeof(struct ip_fw_rule0);
-
-	IPFW_LOCK_INIT(chain);
-	ipfw_dyn_init(chain);
-	ipfw_eaction_init(chain, first);
-#ifdef LINEAR_SKIPTO
-	ipfw_init_skipto_cache(chain);
-#endif
-	ipfw_bpf_init(first);
-
-	/* First set up some values that are compile time options */
-	V_ipfw_vnet_ready = 1;		/* Open for business */
-
-	/*
-	 * Hook the sockopt handler and pfil hooks for ipv4 and ipv6.
-	 * Even if the latter two fail we still keep the module alive
-	 * because the sockopt and layer2 paths are still useful.
-	 * ipfw[6]_hook return 0 on success, ENOENT on failure,
-	 * so we can ignore the exact return value and just set a flag.
-	 *
-	 * Note that V_fw[6]_enable are manipulated by a SYSCTL_PROC so
-	 * changes in the underlying (per-vnet) variables trigger
-	 * immediate hook()/unhook() calls.
-	 * In layer2 we have the same behaviour, except that V_ether_ipfw
-	 * is checked on each packet because there are no pfil hooks.
-	 */
-	V_ip_fw_ctl_ptr = ipfw_ctl3;
-	error = ipfw_attach_hooks(1);
-	return (error);
-}
-
-#ifndef __rtems__
-/*
- * Called for the removal of each instance.
- */
-static int
-vnet_ipfw_uninit(const void *unused)
-{
-	struct ip_fw *reap;
-	struct ip_fw_chain *chain = &V_layer3_chain;
-	int i, last;
-
-	V_ipfw_vnet_ready = 0; /* tell new callers to go away */
-	/*
-	 * disconnect from ipv4, ipv6, layer2 and sockopt.
-	 * Then grab, release and grab again the WLOCK so we make
-	 * sure the update is propagated and nobody will be in.
-	 */
-	(void)ipfw_attach_hooks(0 /* detach */);
-	V_ip_fw_ctl_ptr = NULL;
-
-	last = IS_DEFAULT_VNET(curvnet) ? 1 : 0;
-
-	IPFW_UH_WLOCK(chain);
-	IPFW_UH_WUNLOCK(chain);
-
-	ipfw_dyn_uninit(0);	/* run the callout_drain */
-
-	IPFW_UH_WLOCK(chain);
-
-	reap = NULL;
-	IPFW_WLOCK(chain);
-	for (i = 0; i < chain->n_rules; i++)
-		ipfw_reap_add(chain, &reap, chain->map[i]);
-	free(chain->map, M_IPFW);
-#ifdef LINEAR_SKIPTO
-	ipfw_destroy_skipto_cache(chain);
-#endif
-	IPFW_WUNLOCK(chain);
-	IPFW_UH_WUNLOCK(chain);
-	ipfw_destroy_tables(chain, last);
-	ipfw_eaction_uninit(chain, last);
-	if (reap != NULL)
-		ipfw_reap_rules(reap);
-	vnet_ipfw_iface_destroy(chain);
-	ipfw_destroy_srv(chain);
-	IPFW_LOCK_DESTROY(chain);
-	ipfw_dyn_uninit(1);	/* free the remaining parts */
-	ipfw_destroy_counters();
-	ipfw_bpf_uninit(last);
-	return (0);
-}
-#endif /* __rtems__ */
-
-/*
- * Module event handler.
- * In general we have the choice of handling most of these events by the
- * event handler or by the (VNET_)SYS(UN)INIT handlers. I have chosen to
- * use the SYSINIT handlers as they are more capable of expressing the
- * flow of control during module and vnet operations, so this is just
- * a skeleton. Note there is no SYSINIT equivalent of the module
- * SHUTDOWN handler, but we don't have anything to do in that case anyhow.
- */
-static int
-ipfw_modevent(module_t mod, int type, void *unused)
-{
-	int err = 0;
-
-	switch (type) {
-	case MOD_LOAD:
-		/* Called once at module load or
-	 	 * system boot if compiled in. */
-		break;
-	case MOD_QUIESCE:
-		/* Called before unload. May veto unloading. */
-		break;
-	case MOD_UNLOAD:
-		/* Called during unload. */
-		break;
-	case MOD_SHUTDOWN:
-		/* Called during system shutdown. */
-		break;
-	default:
-		err = EOPNOTSUPP;
-		break;
-	}
-	return err;
-}
-
-static moduledata_t ipfwmod = {
-	"ipfw",
-	ipfw_modevent,
-	0
-};
-
-/* Define startup order. */
-#define	IPFW_SI_SUB_FIREWALL	SI_SUB_PROTO_FIREWALL
-#define	IPFW_MODEVENT_ORDER	(SI_ORDER_ANY - 255) /* On boot slot in here. */
-#define	IPFW_MODULE_ORDER	(IPFW_MODEVENT_ORDER + 1) /* A little later. */
-#define	IPFW_VNET_ORDER		(IPFW_MODEVENT_ORDER + 2) /* Later still. */
-
-DECLARE_MODULE(ipfw, ipfwmod, IPFW_SI_SUB_FIREWALL, IPFW_MODEVENT_ORDER);
-FEATURE(ipfw_ctl3, "ipfw new sockopt calls");
-MODULE_VERSION(ipfw, 3);
-/* should declare some dependencies here */
-
-/*
- * Starting up. Done in order after ipfwmod() has been called.
- * VNET_SYSINIT is also called for each existing vnet and each new vnet.
- */
-SYSINIT(ipfw_init, IPFW_SI_SUB_FIREWALL, IPFW_MODULE_ORDER,
-	    ipfw_init, NULL);
-VNET_SYSINIT(vnet_ipfw_init, IPFW_SI_SUB_FIREWALL, IPFW_VNET_ORDER,
-	    vnet_ipfw_init, NULL);
- 
-/*
- * Closing up shop. These are done in REVERSE ORDER, but still
- * after ipfwmod() has been called. Not called on reboot.
- * VNET_SYSUNINIT is also called for each exiting vnet as it exits.
- * or when the module is unloaded.
- */
-SYSUNINIT(ipfw_destroy, IPFW_SI_SUB_FIREWALL, IPFW_MODULE_ORDER,
-	    ipfw_destroy, NULL);
-VNET_SYSUNINIT(vnet_ipfw_uninit, IPFW_SI_SUB_FIREWALL, IPFW_VNET_ORDER,
-	    vnet_ipfw_uninit, NULL);
-/* end of file */
Index: eebsd/sys/netpfil/ipfw/ip_fw_bpf.c
===================================================================
--- freebsd/sys/netpfil/ipfw/ip_fw_bpf.c	(revision f62c62d2fe57ec02c1350144f7739f8e866ee6d4)
+++ 	(revision )
@@ -1,211 +1,0 @@
-#include <machine/rtems-bsd-kernel-space.h>
-
-/*-
- * Copyright (c) 2016 Yandex LLC
- * Copyright (c) 2016 Andrey V. Elsukov <ae@FreeBSD.org>
- *
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/mbuf.h>
-#include <sys/kernel.h>
-#include <sys/lock.h>
-#include <sys/rmlock.h>
-#include <sys/socket.h>
-#include <net/ethernet.h>
-#include <net/if.h>
-#include <net/if_pflog.h>
-#include <net/if_var.h>
-#include <net/if_clone.h>
-#include <net/if_types.h>
-#include <net/vnet.h>
-#include <net/bpf.h>
-
-#include <netinet/in.h>
-#include <netinet/ip_fw.h>
-#include <netinet/ip_var.h>
-#include <netpfil/ipfw/ip_fw_private.h>
-
-static VNET_DEFINE(struct ifnet *, log_if);
-static VNET_DEFINE(struct ifnet *, pflog_if);
-static VNET_DEFINE(struct if_clone *, ipfw_cloner);
-static VNET_DEFINE(struct if_clone *, ipfwlog_cloner);
-#define	V_ipfw_cloner		VNET(ipfw_cloner)
-#define	V_ipfwlog_cloner	VNET(ipfwlog_cloner)
-#define	V_log_if		VNET(log_if)
-#define	V_pflog_if		VNET(pflog_if)
-
-static struct rmlock log_if_lock;
-#define	LOGIF_LOCK_INIT(x)	rm_init(&log_if_lock, "ipfw log_if lock")
-#define	LOGIF_LOCK_DESTROY(x)	rm_destroy(&log_if_lock)
-#define	LOGIF_RLOCK_TRACKER	struct rm_priotracker _log_tracker
-#define	LOGIF_RLOCK(x)		rm_rlock(&log_if_lock, &_log_tracker)
-#define	LOGIF_RUNLOCK(x)	rm_runlock(&log_if_lock, &_log_tracker)
-#define	LOGIF_WLOCK(x)		rm_wlock(&log_if_lock)
-#define	LOGIF_WUNLOCK(x)	rm_wunlock(&log_if_lock)
-
-static const char ipfwname[] = "ipfw";
-static const char ipfwlogname[] = "ipfwlog";
-
-static int
-ipfw_bpf_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr)
-{
-
-	return (EINVAL);
-}
-
-static int
-ipfw_bpf_output(struct ifnet *ifp, struct mbuf *m,
-	const struct sockaddr *dst, struct route *ro)
-{
-
-	if (m != NULL)
-		FREE_PKT(m);
-	return (0);
-}
-
-static void
-ipfw_clone_destroy(struct ifnet *ifp)
-{
-
-	LOGIF_WLOCK();
-	if (ifp->if_hdrlen == ETHER_HDR_LEN)
-		V_log_if = NULL;
-	else
-		V_pflog_if = NULL;
-	LOGIF_WUNLOCK();
-
-	bpfdetach(ifp);
-	if_detach(ifp);
-	if_free(ifp);
-}
-
-static int
-ipfw_clone_create(struct if_clone *ifc, int unit, caddr_t params)
-{
-	struct ifnet *ifp;
-
-	ifp = if_alloc(IFT_PFLOG);
-	if (ifp == NULL)
-		return (ENOSPC);
-	if_initname(ifp, ipfwname, unit);
-	ifp->if_flags = IFF_UP | IFF_SIMPLEX | IFF_MULTICAST;
-	ifp->if_mtu = 65536;
-	ifp->if_ioctl = ipfw_bpf_ioctl;
-	ifp->if_output = ipfw_bpf_output;
-	ifp->if_hdrlen = ETHER_HDR_LEN;
-	if_attach(ifp);
-	bpfattach(ifp, DLT_EN10MB, ETHER_HDR_LEN);
-	LOGIF_WLOCK();
-	if (V_log_if != NULL) {
-		LOGIF_WUNLOCK();
-		bpfdetach(ifp);
-		if_detach(ifp);
-		if_free(ifp);
-		return (EEXIST);
-	}
-	V_log_if = ifp;
-	LOGIF_WUNLOCK();
-	return (0);
-}
-
-static int
-ipfwlog_clone_create(struct if_clone *ifc, int unit, caddr_t params)
-{
-	struct ifnet *ifp;
-
-	ifp = if_alloc(IFT_PFLOG);
-	if (ifp == NULL)
-		return (ENOSPC);
-	if_initname(ifp, ipfwlogname, unit);
-	ifp->if_flags = IFF_UP | IFF_SIMPLEX | IFF_MULTICAST;
-	ifp->if_mtu = 65536;
-	ifp->if_ioctl = ipfw_bpf_ioctl;
-	ifp->if_output = ipfw_bpf_output;
-	ifp->if_hdrlen = PFLOG_HDRLEN;
-	if_attach(ifp);
-	bpfattach(ifp, DLT_PFLOG, PFLOG_HDRLEN);
-	LOGIF_WLOCK();
-	if (V_pflog_if != NULL) {
-		LOGIF_WUNLOCK();
-		bpfdetach(ifp);
-		if_detach(ifp);
-		if_free(ifp);
-		return (EEXIST);
-	}
-	V_pflog_if = ifp;
-	LOGIF_WUNLOCK();
-	return (0);
-}
-
-void
-ipfw_bpf_mtap2(void *data, u_int dlen, struct mbuf *m)
-{
-	LOGIF_RLOCK_TRACKER;
-
-	LOGIF_RLOCK();
-	if (dlen == ETHER_HDR_LEN) {
-		if (V_log_if == NULL) {
-			LOGIF_RUNLOCK();
-			return;
-		}
-		BPF_MTAP2(V_log_if, data, dlen, m);
-	} else if (dlen == PFLOG_HDRLEN) {
-		if (V_pflog_if == NULL) {
-			LOGIF_RUNLOCK();
-			return;
-		}
-		BPF_MTAP2(V_pflog_if, data, dlen, m);
-	}
-	LOGIF_RUNLOCK();
-}
-
-void
-ipfw_bpf_init(int first)
-{
-
-	if (first) {
-		LOGIF_LOCK_INIT();
-		V_log_if = NULL;
-		V_pflog_if = NULL;
-	}
-	V_ipfw_cloner = if_clone_simple(ipfwname, ipfw_clone_create,
-	    ipfw_clone_destroy, 0);
-	V_ipfwlog_cloner = if_clone_simple(ipfwlogname, ipfwlog_clone_create,
-	    ipfw_clone_destroy, 0);
-}
-
-void
-ipfw_bpf_uninit(int last)
-{
-
-	if_clone_detach(V_ipfw_cloner);
-	if_clone_detach(V_ipfwlog_cloner);
-	if (last)
-		LOGIF_LOCK_DESTROY();
-}
-
Index: eebsd/sys/netpfil/ipfw/ip_fw_dynamic.c
===================================================================
--- freebsd/sys/netpfil/ipfw/ip_fw_dynamic.c	(revision f62c62d2fe57ec02c1350144f7739f8e866ee6d4)
+++ 	(revision )
@@ -1,1822 +1,0 @@
-#include <machine/rtems-bsd-kernel-space.h>
-
-/*-
- * Copyright (c) 2002 Luigi Rizzo, Universita` di Pisa
- *
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#define        DEB(x)
-#define        DDB(x) x
-
-/*
- * Dynamic rule support for ipfw
- */
-
-#include <rtems/bsd/local/opt_ipfw.h>
-#include <rtems/bsd/local/opt_inet.h>
-#ifndef INET
-#error IPFIREWALL requires INET.
-#endif /* INET */
-#include <rtems/bsd/local/opt_inet6.h>
-
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/malloc.h>
-#include <sys/mbuf.h>
-#include <sys/kernel.h>
-#include <sys/ktr.h>
-#include <sys/lock.h>
-#include <sys/rmlock.h>
-#include <sys/socket.h>
-#include <sys/sysctl.h>
-#include <sys/syslog.h>
-#include <net/ethernet.h> /* for ETHERTYPE_IP */
-#include <net/if.h>
-#include <net/if_var.h>
-#include <net/pfil.h>
-#include <net/vnet.h>
-
-#include <netinet/in.h>
-#include <netinet/ip.h>
-#include <netinet/ip_var.h>	/* ip_defttl */
-#include <netinet/ip_fw.h>
-#include <netinet/tcp_var.h>
-#include <netinet/udp.h>
-
-#include <netinet/ip6.h>	/* IN6_ARE_ADDR_EQUAL */
-#ifdef INET6
-#include <netinet6/in6_var.h>
-#include <netinet6/ip6_var.h>
-#endif
-
-#include <netpfil/ipfw/ip_fw_private.h>
-
-#include <machine/in_cksum.h>	/* XXX for in_cksum */
-
-#ifdef MAC
-#include <security/mac/mac_framework.h>
-#endif
-
-/*
- * Description of dynamic rules.
- *
- * Dynamic rules are stored in lists accessed through a hash table
- * (ipfw_dyn_v) whose size is curr_dyn_buckets. This value can
- * be modified through the sysctl variable dyn_buckets which is
- * updated when the table becomes empty.
- *
- * XXX currently there is only one list, ipfw_dyn.
- *
- * When a packet is received, its address fields are first masked
- * with the mask defined for the rule, then hashed, then matched
- * against the entries in the corresponding list.
- * Dynamic rules can be used for different purposes:
- *  + stateful rules;
- *  + enforcing limits on the number of sessions;
- *  + in-kernel NAT (not implemented yet)
- *
- * The lifetime of dynamic rules is regulated by dyn_*_lifetime,
- * measured in seconds and depending on the flags.
- *
- * The total number of dynamic rules is equal to UMA zone items count.
- * The max number of dynamic rules is dyn_max. When we reach
- * the maximum number of rules we do not create anymore. This is
- * done to avoid consuming too much memory, but also too much
- * time when searching on each packet (ideally, we should try instead
- * to put a limit on the length of the list on each bucket...).
- *
- * Each dynamic rule holds a pointer to the parent ipfw rule so
- * we know what action to perform. Dynamic rules are removed when
- * the parent rule is deleted. This can be changed by dyn_keep_states
- * sysctl.
- *
- * There are some limitations with dynamic rules -- we do not
- * obey the 'randomized match', and we do not do multiple
- * passes through the firewall. XXX check the latter!!!
- */
-
-struct ipfw_dyn_bucket {
-	struct mtx	mtx;		/* Bucket protecting lock */
-	ipfw_dyn_rule	*head;		/* Pointer to first rule */
-};
-
-/*
- * Static variables followed by global ones
- */
-static VNET_DEFINE(struct ipfw_dyn_bucket *, ipfw_dyn_v);
-static VNET_DEFINE(u_int32_t, dyn_buckets_max);
-static VNET_DEFINE(u_int32_t, curr_dyn_buckets);
-static VNET_DEFINE(struct callout, ipfw_timeout);
-#define	V_ipfw_dyn_v			VNET(ipfw_dyn_v)
-#define	V_dyn_buckets_max		VNET(dyn_buckets_max)
-#define	V_curr_dyn_buckets		VNET(curr_dyn_buckets)
-#define V_ipfw_timeout                  VNET(ipfw_timeout)
-
-static VNET_DEFINE(uma_zone_t, ipfw_dyn_rule_zone);
-#define	V_ipfw_dyn_rule_zone		VNET(ipfw_dyn_rule_zone)
-
-#define	IPFW_BUCK_LOCK_INIT(b)	\
-	mtx_init(&(b)->mtx, "IPFW dynamic bucket", NULL, MTX_DEF)
-#define	IPFW_BUCK_LOCK_DESTROY(b)	\
-	mtx_destroy(&(b)->mtx)
-#define	IPFW_BUCK_LOCK(i)	mtx_lock(&V_ipfw_dyn_v[(i)].mtx)
-#define	IPFW_BUCK_UNLOCK(i)	mtx_unlock(&V_ipfw_dyn_v[(i)].mtx)
-#define	IPFW_BUCK_ASSERT(i)	mtx_assert(&V_ipfw_dyn_v[(i)].mtx, MA_OWNED)
-
-
-static VNET_DEFINE(int, dyn_keep_states);
-#define	V_dyn_keep_states		VNET(dyn_keep_states)
-
-/*
- * Timeouts for various events in handing dynamic rules.
- */
-static VNET_DEFINE(u_int32_t, dyn_ack_lifetime);
-static VNET_DEFINE(u_int32_t, dyn_syn_lifetime);
-static VNET_DEFINE(u_int32_t, dyn_fin_lifetime);
-static VNET_DEFINE(u_int32_t, dyn_rst_lifetime);
-static VNET_DEFINE(u_int32_t, dyn_udp_lifetime);
-static VNET_DEFINE(u_int32_t, dyn_short_lifetime);
-
-#define	V_dyn_ack_lifetime		VNET(dyn_ack_lifetime)
-#define	V_dyn_syn_lifetime		VNET(dyn_syn_lifetime)
-#define	V_dyn_fin_lifetime		VNET(dyn_fin_lifetime)
-#define	V_dyn_rst_lifetime		VNET(dyn_rst_lifetime)
-#define	V_dyn_udp_lifetime		VNET(dyn_udp_lifetime)
-#define	V_dyn_short_lifetime		VNET(dyn_short_lifetime)
-
-/*
- * Keepalives are sent if dyn_keepalive is set. They are sent every
- * dyn_keepalive_period seconds, in the last dyn_keepalive_interval
- * seconds of lifetime of a rule.
- * dyn_rst_lifetime and dyn_fin_lifetime should be strictly lower
- * than dyn_keepalive_period.
- */
-
-static VNET_DEFINE(u_int32_t, dyn_keepalive_interval);
-static VNET_DEFINE(u_int32_t, dyn_keepalive_period);
-static VNET_DEFINE(u_int32_t, dyn_keepalive);
-static VNET_DEFINE(time_t, dyn_keepalive_last);
-
-#define	V_dyn_keepalive_interval	VNET(dyn_keepalive_interval)
-#define	V_dyn_keepalive_period		VNET(dyn_keepalive_period)
-#define	V_dyn_keepalive			VNET(dyn_keepalive)
-#define	V_dyn_keepalive_last		VNET(dyn_keepalive_last)
-
-static VNET_DEFINE(u_int32_t, dyn_max);		/* max # of dynamic rules */
-
-#define	DYN_COUNT			uma_zone_get_cur(V_ipfw_dyn_rule_zone)
-#define	V_dyn_max			VNET(dyn_max)
-
-/* for userspace, we emulate the uma_zone_counter with ipfw_dyn_count */
-static int ipfw_dyn_count;	/* number of objects */
-
-#ifdef USERSPACE /* emulation of UMA object counters for userspace */
-#define uma_zone_get_cur(x)	ipfw_dyn_count
-#endif /* USERSPACE */
-
-static int last_log;	/* Log ratelimiting */
-
-static void ipfw_dyn_tick(void *vnetx);
-static void check_dyn_rules(struct ip_fw_chain *, ipfw_range_tlv *, int, int);
-#ifdef SYSCTL_NODE
-
-static int sysctl_ipfw_dyn_count(SYSCTL_HANDLER_ARGS);
-static int sysctl_ipfw_dyn_max(SYSCTL_HANDLER_ARGS);
-
-SYSBEGIN(f2)
-
-SYSCTL_DECL(_net_inet_ip_fw);
-SYSCTL_UINT(_net_inet_ip_fw, OID_AUTO, dyn_buckets,
-    CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(dyn_buckets_max), 0,
-    "Max number of dyn. buckets");
-SYSCTL_UINT(_net_inet_ip_fw, OID_AUTO, curr_dyn_buckets,
-    CTLFLAG_VNET | CTLFLAG_RD, &VNET_NAME(curr_dyn_buckets), 0,
-    "Current Number of dyn. buckets");
-SYSCTL_PROC(_net_inet_ip_fw, OID_AUTO, dyn_count,
-    CTLFLAG_VNET | CTLTYPE_UINT | CTLFLAG_RD, 0, 0, sysctl_ipfw_dyn_count, "IU",
-    "Number of dyn. rules");
-SYSCTL_PROC(_net_inet_ip_fw, OID_AUTO, dyn_max,
-    CTLFLAG_VNET | CTLTYPE_UINT | CTLFLAG_RW, 0, 0, sysctl_ipfw_dyn_max, "IU",
-    "Max number of dyn. rules");
-SYSCTL_UINT(_net_inet_ip_fw, OID_AUTO, dyn_ack_lifetime,
-    CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(dyn_ack_lifetime), 0,
-    "Lifetime of dyn. rules for acks");
-SYSCTL_UINT(_net_inet_ip_fw, OID_AUTO, dyn_syn_lifetime,
-    CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(dyn_syn_lifetime), 0,
-    "Lifetime of dyn. rules for syn");
-SYSCTL_UINT(_net_inet_ip_fw, OID_AUTO, dyn_fin_lifetime,
-    CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(dyn_fin_lifetime), 0,
-    "Lifetime of dyn. rules for fin");
-SYSCTL_UINT(_net_inet_ip_fw, OID_AUTO, dyn_rst_lifetime,
-    CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(dyn_rst_lifetime), 0,
-    "Lifetime of dyn. rules for rst");
-SYSCTL_UINT(_net_inet_ip_fw, OID_AUTO, dyn_udp_lifetime,
-    CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(dyn_udp_lifetime), 0,
-    "Lifetime of dyn. rules for UDP");
-SYSCTL_UINT(_net_inet_ip_fw, OID_AUTO, dyn_short_lifetime,
-    CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(dyn_short_lifetime), 0,
-    "Lifetime of dyn. rules for other situations");
-SYSCTL_UINT(_net_inet_ip_fw, OID_AUTO, dyn_keepalive,
-    CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(dyn_keepalive), 0,
-    "Enable keepalives for dyn. rules");
-SYSCTL_UINT(_net_inet_ip_fw, OID_AUTO, dyn_keep_states,
-    CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(dyn_keep_states), 0,
-    "Do not flush dynamic states on rule deletion");
-
-SYSEND
-
-#endif /* SYSCTL_NODE */
-
-
-#ifdef INET6
-static __inline int
-hash_packet6(struct ipfw_flow_id *id)
-{
-	u_int32_t i;
-	i = (id->dst_ip6.__u6_addr.__u6_addr32[2]) ^
-	    (id->dst_ip6.__u6_addr.__u6_addr32[3]) ^
-	    (id->src_ip6.__u6_addr.__u6_addr32[2]) ^
-	    (id->src_ip6.__u6_addr.__u6_addr32[3]);
-	return ntohl(i);
-}
-#endif
-
-/*
- * IMPORTANT: the hash function for dynamic rules must be commutative
- * in source and destination (ip,port), because rules are bidirectional
- * and we want to find both in the same bucket.
- */
-static __inline int
-hash_packet(struct ipfw_flow_id *id, int buckets)
-{
-	u_int32_t i;
-
-#ifdef INET6
-	if (IS_IP6_FLOW_ID(id)) 
-		i = hash_packet6(id);
-	else
-#endif /* INET6 */
-	i = (id->dst_ip) ^ (id->src_ip);
-	i ^= (id->dst_port) ^ (id->src_port);
-	return (i & (buckets - 1));
-}
-
-#if 0
-#define	DYN_DEBUG(fmt, ...)	do {			\
-	printf("%s: " fmt "\n", __func__, __VA_ARGS__);	\
-} while (0)
-#else
-#define	DYN_DEBUG(fmt, ...)
-#endif
-
-static char *default_state_name = "default";
-struct dyn_state_obj {
-	struct named_object	no;
-	char			name[64];
-};
-
-#define	DYN_STATE_OBJ(ch, cmd)	\
-    ((struct dyn_state_obj *)SRV_OBJECT(ch, (cmd)->arg1))
-/*
- * Classifier callback.
- * Return 0 if opcode contains object that should be referenced
- * or rewritten.
- */
-static int
-dyn_classify(ipfw_insn *cmd, uint16_t *puidx, uint8_t *ptype)
-{
-
-	DYN_DEBUG("opcode %d, arg1 %d", cmd->opcode, cmd->arg1);
-	/* Don't rewrite "check-state any" */
-	if (cmd->arg1 == 0 &&
-	    cmd->opcode == O_CHECK_STATE)
-		return (1);
-
-	*puidx = cmd->arg1;
-	*ptype = 0;
-	return (0);
-}
-
-static void
-dyn_update(ipfw_insn *cmd, uint16_t idx)
-{
-
-	cmd->arg1 = idx;
-	DYN_DEBUG("opcode %d, arg1 %d", cmd->opcode, cmd->arg1);
-}
-
-static int
-dyn_findbyname(struct ip_fw_chain *ch, struct tid_info *ti,
-    struct named_object **pno)
-{
-	ipfw_obj_ntlv *ntlv;
-	const char *name;
-
-	DYN_DEBUG("uidx %d", ti->uidx);
-	if (ti->uidx != 0) {
-		if (ti->tlvs == NULL)
-			return (EINVAL);
-		/* Search ntlv in the buffer provided by user */
-		ntlv = ipfw_find_name_tlv_type(ti->tlvs, ti->tlen, ti->uidx,
-		    IPFW_TLV_STATE_NAME);
-		if (ntlv == NULL)
-			return (EINVAL);
-		name = ntlv->name;
-	} else
-		name = default_state_name;
-	/*
-	 * Search named object with corresponding name.
-	 * Since states objects are global - ignore the set value
-	 * and use zero instead.
-	 */
-	*pno = ipfw_objhash_lookup_name_type(CHAIN_TO_SRV(ch), 0,
-	    IPFW_TLV_STATE_NAME, name);
-	/*
-	 * We always return success here.
-	 * The caller will check *pno and mark object as unresolved,
-	 * then it will automatically create "default" object.
-	 */
-	return (0);
-}
-
-static struct named_object *
-dyn_findbykidx(struct ip_fw_chain *ch, uint16_t idx)
-{
-
-	DYN_DEBUG("kidx %d", idx);
-	return (ipfw_objhash_lookup_kidx(CHAIN_TO_SRV(ch), idx));
-}
-
-static int
-dyn_create(struct ip_fw_chain *ch, struct tid_info *ti,
-    uint16_t *pkidx)
-{
-	struct namedobj_instance *ni;
-	struct dyn_state_obj *obj;
-	struct named_object *no;
-	ipfw_obj_ntlv *ntlv;
-	char *name;
-
-	DYN_DEBUG("uidx %d", ti->uidx);
-	if (ti->uidx != 0) {
-		if (ti->tlvs == NULL)
-			return (EINVAL);
-		ntlv = ipfw_find_name_tlv_type(ti->tlvs, ti->tlen, ti->uidx,
-		    IPFW_TLV_STATE_NAME);
-		if (ntlv == NULL)
-			return (EINVAL);
-		name = ntlv->name;
-	} else
-		name = default_state_name;
-
-	ni = CHAIN_TO_SRV(ch);
-	obj = malloc(sizeof(*obj), M_IPFW, M_WAITOK | M_ZERO);
-	obj->no.name = obj->name;
-	obj->no.etlv = IPFW_TLV_STATE_NAME;
-	strlcpy(obj->name, name, sizeof(obj->name));
-
-	IPFW_UH_WLOCK(ch);
-	no = ipfw_objhash_lookup_name_type(ni, 0,
-	    IPFW_TLV_STATE_NAME, name);
-	if (no != NULL) {
-		/*
-		 * Object is already created.
-		 * Just return its kidx and bump refcount.
-		 */
-		*pkidx = no->kidx;
-		no->refcnt++;
-		IPFW_UH_WUNLOCK(ch);
-		free(obj, M_IPFW);
-		DYN_DEBUG("\tfound kidx %d", *pkidx);
-		return (0);
-	}
-	if (ipfw_objhash_alloc_idx(ni, &obj->no.kidx) != 0) {
-		DYN_DEBUG("\talloc_idx failed for %s", name);
-		IPFW_UH_WUNLOCK(ch);
-		free(obj, M_IPFW);
-		return (ENOSPC);
-	}
-	ipfw_objhash_add(ni, &obj->no);
-	IPFW_WLOCK(ch);
-	SRV_OBJECT(ch, obj->no.kidx) = obj;
-	IPFW_WUNLOCK(ch);
-	obj->no.refcnt++;
-	*pkidx = obj->no.kidx;
-	IPFW_UH_WUNLOCK(ch);
-	DYN_DEBUG("\tcreated kidx %d", *pkidx);
-	return (0);
-}
-
-static void
-dyn_destroy(struct ip_fw_chain *ch, struct named_object *no)
-{
-	struct dyn_state_obj *obj;
-
-	IPFW_UH_WLOCK_ASSERT(ch);
-
-	KASSERT(no->refcnt == 1,
-	    ("Destroying object '%s' (type %u, idx %u) with refcnt %u",
-	    no->name, no->etlv, no->kidx, no->refcnt));
-
-	DYN_DEBUG("kidx %d", no->kidx);
-	IPFW_WLOCK(ch);
-	obj = SRV_OBJECT(ch, no->kidx);
-	SRV_OBJECT(ch, no->kidx) = NULL;
-	IPFW_WUNLOCK(ch);
-	ipfw_objhash_del(CHAIN_TO_SRV(ch), no);
-	ipfw_objhash_free_idx(CHAIN_TO_SRV(ch), no->kidx);
-
-	free(obj, M_IPFW);
-}
-
-static struct opcode_obj_rewrite dyn_opcodes[] = {
-	{
-		O_KEEP_STATE, IPFW_TLV_STATE_NAME,
-		dyn_classify, dyn_update,
-		dyn_findbyname, dyn_findbykidx,
-		dyn_create, dyn_destroy
-	},
-	{
-		O_CHECK_STATE, IPFW_TLV_STATE_NAME,
-		dyn_classify, dyn_update,
-		dyn_findbyname, dyn_findbykidx,
-		dyn_create, dyn_destroy
-	},
-	{
-		O_PROBE_STATE, IPFW_TLV_STATE_NAME,
-		dyn_classify, dyn_update,
-		dyn_findbyname, dyn_findbykidx,
-		dyn_create, dyn_destroy
-	},
-	{
-		O_LIMIT, IPFW_TLV_STATE_NAME,
-		dyn_classify, dyn_update,
-		dyn_findbyname, dyn_findbykidx,
-		dyn_create, dyn_destroy
-	},
-};
-/**
- * Print customizable flow id description via log(9) facility.
- */
-static void
-print_dyn_rule_flags(struct ipfw_flow_id *id, int dyn_type, int log_flags,
-    char *prefix, char *postfix)
-{
-	struct in_addr da;
-#ifdef INET6
-	char src[INET6_ADDRSTRLEN], dst[INET6_ADDRSTRLEN];
-#else
-	char src[INET_ADDRSTRLEN], dst[INET_ADDRSTRLEN];
-#endif
-
-#ifdef INET6
-	if (IS_IP6_FLOW_ID(id)) {
-		ip6_sprintf(src, &id->src_ip6);
-		ip6_sprintf(dst, &id->dst_ip6);
-	} else
-#endif
-	{
-		da.s_addr = htonl(id->src_ip);
-		inet_ntop(AF_INET, &da, src, sizeof(src));
-		da.s_addr = htonl(id->dst_ip);
-		inet_ntop(AF_INET, &da, dst, sizeof(dst));
-	}
-	log(log_flags, "ipfw: %s type %d %s %d -> %s %d, %d %s\n",
-	    prefix, dyn_type, src, id->src_port, dst,
-	    id->dst_port, DYN_COUNT, postfix);
-}
-
-#define	print_dyn_rule(id, dtype, prefix, postfix)	\
-	print_dyn_rule_flags(id, dtype, LOG_DEBUG, prefix, postfix)
-
-#define TIME_LEQ(a,b)       ((int)((a)-(b)) <= 0)
-#define TIME_LE(a,b)       ((int)((a)-(b)) < 0)
-
-static void
-dyn_update_proto_state(ipfw_dyn_rule *q, const struct ipfw_flow_id *id,
-    const struct tcphdr *tcp, int dir)
-{
-	uint32_t ack;
-	u_char flags;
-
-	if (id->proto == IPPROTO_TCP) {
-		flags = id->_flags & (TH_FIN | TH_SYN | TH_RST);
-#define BOTH_SYN	(TH_SYN | (TH_SYN << 8))
-#define BOTH_FIN	(TH_FIN | (TH_FIN << 8))
-#define	TCP_FLAGS	(TH_FLAGS | (TH_FLAGS << 8))
-#define	ACK_FWD		0x10000			/* fwd ack seen */
-#define	ACK_REV		0x20000			/* rev ack seen */
-
-		q->state |= (dir == MATCH_FORWARD) ? flags : (flags << 8);
-		switch (q->state & TCP_FLAGS) {
-		case TH_SYN:			/* opening */
-			q->expire = time_uptime + V_dyn_syn_lifetime;
-			break;
-
-		case BOTH_SYN:			/* move to established */
-		case BOTH_SYN | TH_FIN:		/* one side tries to close */
-		case BOTH_SYN | (TH_FIN << 8):
-#define _SEQ_GE(a,b) ((int)(a) - (int)(b) >= 0)
-			if (tcp == NULL)
-				break;
-
-			ack = ntohl(tcp->th_ack);
-			if (dir == MATCH_FORWARD) {
-				if (q->ack_fwd == 0 ||
-				    _SEQ_GE(ack, q->ack_fwd)) {
-					q->ack_fwd = ack;
-					q->state |= ACK_FWD;
-				}
-			} else {
-				if (q->ack_rev == 0 ||
-				    _SEQ_GE(ack, q->ack_rev)) {
-					q->ack_rev = ack;
-					q->state |= ACK_REV;
-				}
-			}
-			if ((q->state & (ACK_FWD | ACK_REV)) ==
-			    (ACK_FWD | ACK_REV)) {
-				q->expire = time_uptime + V_dyn_ack_lifetime;
-				q->state &= ~(ACK_FWD | ACK_REV);
-			}
-			break;
-
-		case BOTH_SYN | BOTH_FIN:	/* both sides closed */
-			if (V_dyn_fin_lifetime >= V_dyn_keepalive_period)
-				V_dyn_fin_lifetime =
-				    V_dyn_keepalive_period - 1;
-			q->expire = time_uptime + V_dyn_fin_lifetime;
-			break;
-
-		default:
-#if 0
-			/*
-			 * reset or some invalid combination, but can also
-			 * occur if we use keep-state the wrong way.
-			 */
-			if ( (q->state & ((TH_RST << 8)|TH_RST)) == 0)
-				printf("invalid state: 0x%x\n", q->state);
-#endif
-			if (V_dyn_rst_lifetime >= V_dyn_keepalive_period)
-				V_dyn_rst_lifetime =
-				    V_dyn_keepalive_period - 1;
-			q->expire = time_uptime + V_dyn_rst_lifetime;
-			break;
-		}
-	} else if (id->proto == IPPROTO_UDP) {
-		q->expire = time_uptime + V_dyn_udp_lifetime;
-	} else {
-		/* other protocols */
-		q->expire = time_uptime + V_dyn_short_lifetime;
-	}
-}
-
-/*
- * Lookup a dynamic rule, locked version.
- */
-static ipfw_dyn_rule *
-lookup_dyn_rule_locked(struct ipfw_flow_id *pkt, int i, int *match_direction,
-    struct tcphdr *tcp, uint16_t kidx)
-{
-	/*
-	 * Stateful ipfw extensions.
-	 * Lookup into dynamic session queue.
-	 */
-	ipfw_dyn_rule *prev, *q = NULL;
-	int dir;
-
-	IPFW_BUCK_ASSERT(i);
-
-	dir = MATCH_NONE;
-	for (prev = NULL, q = V_ipfw_dyn_v[i].head; q; prev = q, q = q->next) {
-		if (q->dyn_type == O_LIMIT_PARENT)
-			continue;
-
-		if (pkt->proto != q->id.proto)
-			continue;
-
-		if (kidx != 0 && kidx != q->kidx)
-			continue;
-
-		if (IS_IP6_FLOW_ID(pkt)) {
-			if (IN6_ARE_ADDR_EQUAL(&pkt->src_ip6, &q->id.src_ip6) &&
-			    IN6_ARE_ADDR_EQUAL(&pkt->dst_ip6, &q->id.dst_ip6) &&
-			    pkt->src_port == q->id.src_port &&
-			    pkt->dst_port == q->id.dst_port) {
-				dir = MATCH_FORWARD;
-				break;
-			}
-			if (IN6_ARE_ADDR_EQUAL(&pkt->src_ip6, &q->id.dst_ip6) &&
-			    IN6_ARE_ADDR_EQUAL(&pkt->dst_ip6, &q->id.src_ip6) &&
-			    pkt->src_port == q->id.dst_port &&
-			    pkt->dst_port == q->id.src_port) {
-				dir = MATCH_REVERSE;
-				break;
-			}
-		} else {
-			if (pkt->src_ip == q->id.src_ip &&
-			    pkt->dst_ip == q->id.dst_ip &&
-			    pkt->src_port == q->id.src_port &&
-			    pkt->dst_port == q->id.dst_port) {
-				dir = MATCH_FORWARD;
-				break;
-			}
-			if (pkt->src_ip == q->id.dst_ip &&
-			    pkt->dst_ip == q->id.src_ip &&
-			    pkt->src_port == q->id.dst_port &&
-			    pkt->dst_port == q->id.src_port) {
-				dir = MATCH_REVERSE;
-				break;
-			}
-		}
-	}
-	if (q == NULL)
-		goto done;	/* q = NULL, not found */
-
-	if (prev != NULL) {	/* found and not in front */
-		prev->next = q->next;
-		q->next = V_ipfw_dyn_v[i].head;
-		V_ipfw_dyn_v[i].head = q;
-	}
-
-	/* update state according to flags */
-	dyn_update_proto_state(q, pkt, tcp, dir);
-done:
-	if (match_direction != NULL)
-		*match_direction = dir;
-	return (q);
-}
-
-ipfw_dyn_rule *
-ipfw_lookup_dyn_rule(struct ipfw_flow_id *pkt, int *match_direction,
-    struct tcphdr *tcp, uint16_t kidx)
-{
-	ipfw_dyn_rule *q;
-	int i;
-
-	i = hash_packet(pkt, V_curr_dyn_buckets);
-
-	IPFW_BUCK_LOCK(i);
-	q = lookup_dyn_rule_locked(pkt, i, match_direction, tcp, kidx);
-	if (q == NULL)
-		IPFW_BUCK_UNLOCK(i);
-	/* NB: return table locked when q is not NULL */
-	return q;
-}
-
-/*
- * Unlock bucket mtx
- * @p - pointer to dynamic rule
- */
-void
-ipfw_dyn_unlock(ipfw_dyn_rule *q)
-{
-
-	IPFW_BUCK_UNLOCK(q->bucket);
-}
-
-static int
-resize_dynamic_table(struct ip_fw_chain *chain, int nbuckets)
-{
-	int i, k, nbuckets_old;
-	ipfw_dyn_rule *q;
-	struct ipfw_dyn_bucket *dyn_v, *dyn_v_old;
-
-	/* Check if given number is power of 2 and less than 64k */
-	if ((nbuckets > 65536) || (!powerof2(nbuckets)))
-		return 1;
-
-	CTR3(KTR_NET, "%s: resize dynamic hash: %d -> %d", __func__,
-	    V_curr_dyn_buckets, nbuckets);
-
-	/* Allocate and initialize new hash */
-	dyn_v = malloc(nbuckets * sizeof(*dyn_v), M_IPFW,
-	    M_WAITOK | M_ZERO);
-
-	for (i = 0 ; i < nbuckets; i++)
-		IPFW_BUCK_LOCK_INIT(&dyn_v[i]);
-
-	/*
-	 * Call upper half lock, as get_map() do to ease
-	 * read-only access to dynamic rules hash from sysctl
-	 */
-	IPFW_UH_WLOCK(chain);
-
-	/*
-	 * Acquire chain write lock to permit hash access
-	 * for main traffic path without additional locks
-	 */
-	IPFW_WLOCK(chain);
-
-	/* Save old values */
-	nbuckets_old = V_curr_dyn_buckets;
-	dyn_v_old = V_ipfw_dyn_v;
-
-	/* Skip relinking if array is not set up */
-	if (V_ipfw_dyn_v == NULL)
-		V_curr_dyn_buckets = 0;
-
-	/* Re-link all dynamic states */
-	for (i = 0 ; i < V_curr_dyn_buckets ; i++) {
-		while (V_ipfw_dyn_v[i].head != NULL) {
-			/* Remove from current chain */
-			q = V_ipfw_dyn_v[i].head;
-			V_ipfw_dyn_v[i].head = q->next;
-
-			/* Get new hash value */
-			k = hash_packet(&q->id, nbuckets);
-			q->bucket = k;
-			/* Add to the new head */
-			q->next = dyn_v[k].head;
-			dyn_v[k].head = q;
-             }
-	}
-
-	/* Update current pointers/buckets values */
-	V_curr_dyn_buckets = nbuckets;
-	V_ipfw_dyn_v = dyn_v;
-
-	IPFW_WUNLOCK(chain);
-
-	IPFW_UH_WUNLOCK(chain);
-
-	/* Start periodic callout on initial creation */
-	if (dyn_v_old == NULL) {
-        	callout_reset_on(&V_ipfw_timeout, hz, ipfw_dyn_tick, curvnet, 0);
-		return (0);
-	}
-
-	/* Destroy all mutexes */
-	for (i = 0 ; i < nbuckets_old ; i++)
-		IPFW_BUCK_LOCK_DESTROY(&dyn_v_old[i]);
-
-	/* Free old hash */
-	free(dyn_v_old, M_IPFW);
-
-	return 0;
-}
-
-/**
- * Install state of type 'type' for a dynamic session.
- * The hash table contains two type of rules:
- * - regular rules (O_KEEP_STATE)
- * - rules for sessions with limited number of sess per user
- *   (O_LIMIT). When they are created, the parent is
- *   increased by 1, and decreased on delete. In this case,
- *   the third parameter is the parent rule and not the chain.
- * - "parent" rules for the above (O_LIMIT_PARENT).
- */
-static ipfw_dyn_rule *
-add_dyn_rule(struct ipfw_flow_id *id, int i, uint8_t dyn_type,
-    struct ip_fw *rule, uint16_t kidx)
-{
-	ipfw_dyn_rule *r;
-
-	IPFW_BUCK_ASSERT(i);
-
-	r = uma_zalloc(V_ipfw_dyn_rule_zone, M_NOWAIT | M_ZERO);
-	if (r == NULL) {
-		if (last_log != time_uptime) {
-			last_log = time_uptime;
-			log(LOG_DEBUG,
-			    "ipfw: Cannot allocate dynamic state, "
-			    "consider increasing net.inet.ip.fw.dyn_max\n");
-		}
-		return NULL;
-	}
-	ipfw_dyn_count++;
-
-	/*
-	 * refcount on parent is already incremented, so
-	 * it is safe to use parent unlocked.
-	 */
-	if (dyn_type == O_LIMIT) {
-		ipfw_dyn_rule *parent = (ipfw_dyn_rule *)rule;
-		if ( parent->dyn_type != O_LIMIT_PARENT)
-			panic("invalid parent");
-		r->parent = parent;
-		rule = parent->rule;
-	}
-
-	r->id = *id;
-	r->expire = time_uptime + V_dyn_syn_lifetime;
-	r->rule = rule;
-	r->dyn_type = dyn_type;
-	IPFW_ZERO_DYN_COUNTER(r);
-	r->count = 0;
-	r->kidx = kidx;
-	r->bucket = i;
-	r->next = V_ipfw_dyn_v[i].head;
-	V_ipfw_dyn_v[i].head = r;
-	DEB(print_dyn_rule(id, dyn_type, "add dyn entry", "total");)
-	return r;
-}
-
-/**
- * lookup dynamic parent rule using pkt and rule as search keys.
- * If the lookup fails, then install one.
- */
-static ipfw_dyn_rule *
-lookup_dyn_parent(struct ipfw_flow_id *pkt, int *pindex, struct ip_fw *rule,
-    uint16_t kidx)
-{
-	ipfw_dyn_rule *q;
-	int i, is_v6;
-
-	is_v6 = IS_IP6_FLOW_ID(pkt);
-	i = hash_packet( pkt, V_curr_dyn_buckets );
-	*pindex = i;
-	IPFW_BUCK_LOCK(i);
-	for (q = V_ipfw_dyn_v[i].head ; q != NULL ; q=q->next)
-		if (q->dyn_type == O_LIMIT_PARENT &&
-		    kidx == q->kidx &&
-		    rule == q->rule &&
-		    pkt->proto == q->id.proto &&
-		    pkt->src_port == q->id.src_port &&
-		    pkt->dst_port == q->id.dst_port &&
-		    (
-			(is_v6 &&
-			 IN6_ARE_ADDR_EQUAL(&(pkt->src_ip6),
-				&(q->id.src_ip6)) &&
-			 IN6_ARE_ADDR_EQUAL(&(pkt->dst_ip6),
-				&(q->id.dst_ip6))) ||
-			(!is_v6 &&
-			 pkt->src_ip == q->id.src_ip &&
-			 pkt->dst_ip == q->id.dst_ip)
-		    )
-		) {
-			q->expire = time_uptime + V_dyn_short_lifetime;
-			DEB(print_dyn_rule(pkt, q->dyn_type,
-			    "lookup_dyn_parent found", "");)
-			return q;
-		}
-
-	/* Add virtual limiting rule */
-	return add_dyn_rule(pkt, i, O_LIMIT_PARENT, rule, kidx);
-}
-
-/**
- * Install dynamic state for rule type cmd->o.opcode
- *
- * Returns 1 (failure) if state is not installed because of errors or because
- * session limitations are enforced.
- */
-int
-ipfw_install_state(struct ip_fw_chain *chain, struct ip_fw *rule,
-    ipfw_insn_limit *cmd, struct ip_fw_args *args, uint32_t tablearg)
-{
-	ipfw_dyn_rule *q;
-	int i;
-
-	DEB(print_dyn_rule(&args->f_id, cmd->o.opcode, "install_state",
-	    (cmd->o.arg1 == 0 ? "": DYN_STATE_OBJ(chain, &cmd->o)->name));)
-
-	i = hash_packet(&args->f_id, V_curr_dyn_buckets);
-
-	IPFW_BUCK_LOCK(i);
-
-	q = lookup_dyn_rule_locked(&args->f_id, i, NULL, NULL, cmd->o.arg1);
-	if (q != NULL) {	/* should never occur */
-		DEB(
-		if (last_log != time_uptime) {
-			last_log = time_uptime;
-			printf("ipfw: %s: entry already present, done\n",
-			    __func__);
-		})
-		IPFW_BUCK_UNLOCK(i);
-		return (0);
-	}
-
-	/*
-	 * State limiting is done via uma(9) zone limiting.
-	 * Save pointer to newly-installed rule and reject
-	 * packet if add_dyn_rule() returned NULL.
-	 * Note q is currently set to NULL.
-	 */
-
-	switch (cmd->o.opcode) {
-	case O_KEEP_STATE:	/* bidir rule */
-		q = add_dyn_rule(&args->f_id, i, O_KEEP_STATE, rule,
-		    cmd->o.arg1);
-		break;
-
-	case O_LIMIT: {		/* limit number of sessions */
-		struct ipfw_flow_id id;
-		ipfw_dyn_rule *parent;
-		uint32_t conn_limit;
-		uint16_t limit_mask = cmd->limit_mask;
-		int pindex;
-
-		conn_limit = IP_FW_ARG_TABLEARG(chain, cmd->conn_limit, limit);
-		  
-		DEB(
-		if (cmd->conn_limit == IP_FW_TARG)
-			printf("ipfw: %s: O_LIMIT rule, conn_limit: %u "
-			    "(tablearg)\n", __func__, conn_limit);
-		else
-			printf("ipfw: %s: O_LIMIT rule, conn_limit: %u\n",
-			    __func__, conn_limit);
-		)
-
-		id.dst_ip = id.src_ip = id.dst_port = id.src_port = 0;
-		id.proto = args->f_id.proto;
-		id.addr_type = args->f_id.addr_type;
-		id.fib = M_GETFIB(args->m);
-
-		if (IS_IP6_FLOW_ID (&(args->f_id))) {
-			bzero(&id.src_ip6, sizeof(id.src_ip6));
-			bzero(&id.dst_ip6, sizeof(id.dst_ip6));
-
-			if (limit_mask & DYN_SRC_ADDR)
-				id.src_ip6 = args->f_id.src_ip6;
-			if (limit_mask & DYN_DST_ADDR)
-				id.dst_ip6 = args->f_id.dst_ip6;
-		} else {
-			if (limit_mask & DYN_SRC_ADDR)
-				id.src_ip = args->f_id.src_ip;
-			if (limit_mask & DYN_DST_ADDR)
-				id.dst_ip = args->f_id.dst_ip;
-		}
-		if (limit_mask & DYN_SRC_PORT)
-			id.src_port = args->f_id.src_port;
-		if (limit_mask & DYN_DST_PORT)
-			id.dst_port = args->f_id.dst_port;
-
-		/*
-		 * We have to release lock for previous bucket to
-		 * avoid possible deadlock
-		 */
-		IPFW_BUCK_UNLOCK(i);
-
-		parent = lookup_dyn_parent(&id, &pindex, rule, cmd->o.arg1);
-		if (parent == NULL) {
-			printf("ipfw: %s: add parent failed\n", __func__);
-			IPFW_BUCK_UNLOCK(pindex);
-			return (1);
-		}
-
-		if (parent->count >= conn_limit) {
-			if (V_fw_verbose && last_log != time_uptime) {
-				last_log = time_uptime;
-				char sbuf[24];
-				last_log = time_uptime;
-				snprintf(sbuf, sizeof(sbuf),
-				    "%d drop session",
-				    parent->rule->rulenum);
-				print_dyn_rule_flags(&args->f_id,
-				    cmd->o.opcode,
-				    LOG_SECURITY | LOG_DEBUG,
-				    sbuf, "too many entries");
-			}
-			IPFW_BUCK_UNLOCK(pindex);
-			return (1);
-		}
-		/* Increment counter on parent */
-		parent->count++;
-		IPFW_BUCK_UNLOCK(pindex);
-
-		IPFW_BUCK_LOCK(i);
-		q = add_dyn_rule(&args->f_id, i, O_LIMIT,
-		    (struct ip_fw *)parent, cmd->o.arg1);
-		if (q == NULL) {
-			/* Decrement index and notify caller */
-			IPFW_BUCK_UNLOCK(i);
-			IPFW_BUCK_LOCK(pindex);
-			parent->count--;
-			IPFW_BUCK_UNLOCK(pindex);
-			return (1);
-		}
-		break;
-	}
-	default:
-		printf("ipfw: %s: unknown dynamic rule type %u\n",
-		    __func__, cmd->o.opcode);
-	}
-
-	if (q == NULL) {
-		IPFW_BUCK_UNLOCK(i);
-		return (1);	/* Notify caller about failure */
-	}
-
-	dyn_update_proto_state(q, &args->f_id, NULL, MATCH_FORWARD);
-	IPFW_BUCK_UNLOCK(i);
-	return (0);
-}
-
-/*
- * Generate a TCP packet, containing either a RST or a keepalive.
- * When flags & TH_RST, we are sending a RST packet, because of a
- * "reset" action matched the packet.
- * Otherwise we are sending a keepalive, and flags & TH_
- * The 'replyto' mbuf is the mbuf being replied to, if any, and is required
- * so that MAC can label the reply appropriately.
- */
-struct mbuf *
-ipfw_send_pkt(struct mbuf *replyto, struct ipfw_flow_id *id, u_int32_t seq,
-    u_int32_t ack, int flags)
-{
-	struct mbuf *m = NULL;		/* stupid compiler */
-	int len, dir;
-	struct ip *h = NULL;		/* stupid compiler */
-#ifdef INET6
-	struct ip6_hdr *h6 = NULL;
-#endif
-	struct tcphdr *th = NULL;
-
-	MGETHDR(m, M_NOWAIT, MT_DATA);
-	if (m == NULL)
-		return (NULL);
-
-	M_SETFIB(m, id->fib);
-#ifdef MAC
-	if (replyto != NULL)
-		mac_netinet_firewall_reply(replyto, m);
-	else
-		mac_netinet_firewall_send(m);
-#else
-	(void)replyto;		/* don't warn about unused arg */
-#endif
-
-	switch (id->addr_type) {
-	case 4:
-		len = sizeof(struct ip) + sizeof(struct tcphdr);
-		break;
-#ifdef INET6
-	case 6:
-		len = sizeof(struct ip6_hdr) + sizeof(struct tcphdr);
-		break;
-#endif
-	default:
-		/* XXX: log me?!? */
-		FREE_PKT(m);
-		return (NULL);
-	}
-	dir = ((flags & (TH_SYN | TH_RST)) == TH_SYN);
-
-	m->m_data += max_linkhdr;
-	m->m_flags |= M_SKIP_FIREWALL;
-	m->m_pkthdr.len = m->m_len = len;
-	m->m_pkthdr.rcvif = NULL;
-	bzero(m->m_data, len);
-
-	switch (id->addr_type) {
-	case 4:
-		h = mtod(m, struct ip *);
-
-		/* prepare for checksum */
-		h->ip_p = IPPROTO_TCP;
-		h->ip_len = htons(sizeof(struct tcphdr));
-		if (dir) {
-			h->ip_src.s_addr = htonl(id->src_ip);
-			h->ip_dst.s_addr = htonl(id->dst_ip);
-		} else {
-			h->ip_src.s_addr = htonl(id->dst_ip);
-			h->ip_dst.s_addr = htonl(id->src_ip);
-		}
-
-		th = (struct tcphdr *)(h + 1);
-		break;
-#ifdef INET6
-	case 6:
-		h6 = mtod(m, struct ip6_hdr *);
-
-		/* prepare for checksum */
-		h6->ip6_nxt = IPPROTO_TCP;
-		h6->ip6_plen = htons(sizeof(struct tcphdr));
-		if (dir) {
-			h6->ip6_src = id->src_ip6;
-			h6->ip6_dst = id->dst_ip6;
-		} else {
-			h6->ip6_src = id->dst_ip6;
-			h6->ip6_dst = id->src_ip6;
-		}
-
-		th = (struct tcphdr *)(h6 + 1);
-		break;
-#endif
-	}
-
-	if (dir) {
-		th->th_sport = htons(id->src_port);
-		th->th_dport = htons(id->dst_port);
-	} else {
-		th->th_sport = htons(id->dst_port);
-		th->th_dport = htons(id->src_port);
-	}
-	th->th_off = sizeof(struct tcphdr) >> 2;
-
-	if (flags & TH_RST) {
-		if (flags & TH_ACK) {
-			th->th_seq = htonl(ack);
-			th->th_flags = TH_RST;
-		} else {
-			if (flags & TH_SYN)
-				seq++;
-			th->th_ack = htonl(seq);
-			th->th_flags = TH_RST | TH_ACK;
-		}
-	} else {
-		/*
-		 * Keepalive - use caller provided sequence numbers
-		 */
-		th->th_seq = htonl(seq);
-		th->th_ack = htonl(ack);
-		th->th_flags = TH_ACK;
-	}
-
-	switch (id->addr_type) {
-	case 4:
-		th->th_sum = in_cksum(m, len);
-
-		/* finish the ip header */
-		h->ip_v = 4;
-		h->ip_hl = sizeof(*h) >> 2;
-		h->ip_tos = IPTOS_LOWDELAY;
-		h->ip_off = htons(0);
-		h->ip_len = htons(len);
-		h->ip_ttl = V_ip_defttl;
-		h->ip_sum = 0;
-		break;
-#ifdef INET6
-	case 6:
-		th->th_sum = in6_cksum(m, IPPROTO_TCP, sizeof(*h6),
-		    sizeof(struct tcphdr));
-
-		/* finish the ip6 header */
-		h6->ip6_vfc |= IPV6_VERSION;
-		h6->ip6_hlim = IPV6_DEFHLIM;
-		break;
-#endif
-	}
-
-	return (m);
-}
-
-/*
- * Queue keepalive packets for given dynamic rule
- */
-static struct mbuf **
-ipfw_dyn_send_ka(struct mbuf **mtailp, ipfw_dyn_rule *q)
-{
-	struct mbuf *m_rev, *m_fwd;
-
-	m_rev = (q->state & ACK_REV) ? NULL :
-	    ipfw_send_pkt(NULL, &(q->id), q->ack_rev - 1, q->ack_fwd, TH_SYN);
-	m_fwd = (q->state & ACK_FWD) ? NULL :
-	    ipfw_send_pkt(NULL, &(q->id), q->ack_fwd - 1, q->ack_rev, 0);
-
-	if (m_rev != NULL) {
-		*mtailp = m_rev;
-		mtailp = &(*mtailp)->m_nextpkt;
-	}
-	if (m_fwd != NULL) {
-		*mtailp = m_fwd;
-		mtailp = &(*mtailp)->m_nextpkt;
-	}
-
-	return (mtailp);
-}
-
-/*
- * This procedure is used to perform various maintenance
- * on dynamic hash list. Currently it is called every second.
- */
-static void
-ipfw_dyn_tick(void * vnetx) 
-{
-	struct ip_fw_chain *chain;
-	int check_ka = 0;
-#ifdef VIMAGE
-	struct vnet *vp = vnetx;
-#endif
-
-	CURVNET_SET(vp);
-
-	chain = &V_layer3_chain;
-
-	/* Run keepalive checks every keepalive_period iff ka is enabled */
-	if ((V_dyn_keepalive_last + V_dyn_keepalive_period <= time_uptime) &&
-	    (V_dyn_keepalive != 0)) {
-		V_dyn_keepalive_last = time_uptime;
-		check_ka = 1;
-	}
-
-	check_dyn_rules(chain, NULL, check_ka, 1);
-
-	callout_reset_on(&V_ipfw_timeout, hz, ipfw_dyn_tick, vnetx, 0);
-
-	CURVNET_RESTORE();
-}
-
-
-/*
- * Walk through all dynamic states doing generic maintenance:
- * 1) free expired states
- * 2) free all states based on deleted rule / set
- * 3) send keepalives for states if needed
- *
- * @chain - pointer to current ipfw rules chain
- * @rule - delete all states originated by given rule if != NULL
- * @set - delete all states originated by any rule in set @set if != RESVD_SET
- * @check_ka - perform checking/sending keepalives
- * @timer - indicate call from timer routine.
- *
- * Timer routine must call this function unlocked to permit
- * sending keepalives/resizing table.
- *
- * Others has to call function with IPFW_UH_WLOCK held.
- * Additionally, function assume that dynamic rule/set is
- * ALREADY deleted so no new states can be generated by
- * 'deleted' rules.
- *
- * Write lock is needed to ensure that unused parent rules
- * are not freed by other instance (see stage 2, 3)
- */
-static void
-check_dyn_rules(struct ip_fw_chain *chain, ipfw_range_tlv *rt,
-    int check_ka, int timer)
-{
-	struct mbuf *m0, *m, *mnext, **mtailp;
-	struct ip *h;
-	int i, dyn_count, new_buckets = 0, max_buckets;
-	int expired = 0, expired_limits = 0, parents = 0, total = 0;
-	ipfw_dyn_rule *q, *q_prev, *q_next;
-	ipfw_dyn_rule *exp_head, **exptailp;
-	ipfw_dyn_rule *exp_lhead, **expltailp;
-
-	KASSERT(V_ipfw_dyn_v != NULL, ("%s: dynamic table not allocated",
-	    __func__));
-
-	/* Avoid possible LOR */
-	KASSERT(!check_ka || timer, ("%s: keepalive check with lock held",
-	    __func__));
-
-	/*
-	 * Do not perform any checks if we currently have no dynamic states
-	 */
-	if (DYN_COUNT == 0)
-		return;
-
-	/* Expired states */
-	exp_head = NULL;
-	exptailp = &exp_head;
-
-	/* Expired limit states */
-	exp_lhead = NULL;
-	expltailp = &exp_lhead;
-
-	/*
-	 * We make a chain of packets to go out here -- not deferring
-	 * until after we drop the IPFW dynamic rule lock would result
-	 * in a lock order reversal with the normal packet input -> ipfw
-	 * call stack.
-	 */
-	m0 = NULL;
-	mtailp = &m0;
-
-	/* Protect from hash resizing */
-	if (timer != 0)
-		IPFW_UH_WLOCK(chain);
-	else
-		IPFW_UH_WLOCK_ASSERT(chain);
-
-#define	NEXT_RULE()	{ q_prev = q; q = q->next ; continue; }
-
-	/* Stage 1: perform requested deletion */
-	for (i = 0 ; i < V_curr_dyn_buckets ; i++) {
-		IPFW_BUCK_LOCK(i);
-		for (q = V_ipfw_dyn_v[i].head, q_prev = q; q ; ) {
-			/* account every rule */
-			total++;
-
-			/* Skip parent rules at all */
-			if (q->dyn_type == O_LIMIT_PARENT) {
-				parents++;
-				NEXT_RULE();
-			}
-
-			/*
-			 * Remove rules which are:
-			 * 1) expired
-			 * 2) matches deletion range
-			 */
-			if ((TIME_LEQ(q->expire, time_uptime)) ||
-			    (rt != NULL && ipfw_match_range(q->rule, rt))) {
-				if (TIME_LE(time_uptime, q->expire) &&
-				    q->dyn_type == O_KEEP_STATE &&
-				    V_dyn_keep_states != 0) {
-					/*
-					 * Do not delete state if
-					 * it is not expired and
-					 * dyn_keep_states is ON.
-					 * However we need to re-link it
-					 * to any other stable rule
-					 */
-					q->rule = chain->default_rule;
-					NEXT_RULE();
-				}
-
-				/* Unlink q from current list */
-				q_next = q->next;
-				if (q == V_ipfw_dyn_v[i].head)
-					V_ipfw_dyn_v[i].head = q_next;
-				else
-					q_prev->next = q_next;
-
-				q->next = NULL;
-
-				/* queue q to expire list */
-				if (q->dyn_type != O_LIMIT) {
-					*exptailp = q;
-					exptailp = &(*exptailp)->next;
-					DEB(print_dyn_rule(&q->id, q->dyn_type,
-					    "unlink entry", "left");
-					)
-				} else {
-					/* Separate list for limit rules */
-					*expltailp = q;
-					expltailp = &(*expltailp)->next;
-					expired_limits++;
-					DEB(print_dyn_rule(&q->id, q->dyn_type,
-					    "unlink limit entry", "left");
-					)
-				}
-
-				q = q_next;
-				expired++;
-				continue;
-			}
-
-			/*
-			 * Check if we need to send keepalive:
-			 * we need to ensure if is time to do KA,
-			 * this is established TCP session, and
-			 * expire time is within keepalive interval
-			 */
-			if ((check_ka != 0) && (q->id.proto == IPPROTO_TCP) &&
-			    ((q->state & BOTH_SYN) == BOTH_SYN) &&
-			    (TIME_LEQ(q->expire, time_uptime +
-			      V_dyn_keepalive_interval)))
-				mtailp = ipfw_dyn_send_ka(mtailp, q);
-
-			NEXT_RULE();
-		}
-		IPFW_BUCK_UNLOCK(i);
-	}
-
-	/* Stage 2: decrement counters from O_LIMIT parents */
-	if (expired_limits != 0) {
-		/*
-		 * XXX: Note that deleting set with more than one
-		 * heavily-used LIMIT rules can result in overwhelming
-		 * locking due to lack of per-hash value sorting
-		 *
-		 * We should probably think about:
-		 * 1) pre-allocating hash of size, say,
-		 * MAX(16, V_curr_dyn_buckets / 1024)
-		 * 2) checking if expired_limits is large enough
-		 * 3) If yes, init hash (or its part), re-link
-		 * current list and start decrementing procedure in
-		 * each bucket separately
-		 */
-
-		/*
-		 * Small optimization: do not unlock bucket until
-		 * we see the next item resides in different bucket
-		 */
-		if (exp_lhead != NULL) {
-			i = exp_lhead->parent->bucket;
-			IPFW_BUCK_LOCK(i);
-		}
-		for (q = exp_lhead; q != NULL; q = q->next) {
-			if (i != q->parent->bucket) {
-				IPFW_BUCK_UNLOCK(i);
-				i = q->parent->bucket;
-				IPFW_BUCK_LOCK(i);
-			}
-
-			/* Decrease parent refcount */
-			q->parent->count--;
-		}
-		if (exp_lhead != NULL)
-			IPFW_BUCK_UNLOCK(i);
-	}
-
-	/*
-	 * We protectet ourselves from unused parent deletion
-	 * (from the timer function) by holding UH write lock.
-	 */
-
-	/* Stage 3: remove unused parent rules */
-	if ((parents != 0) && (expired != 0)) {
-		for (i = 0 ; i < V_curr_dyn_buckets ; i++) {
-			IPFW_BUCK_LOCK(i);
-			for (q = V_ipfw_dyn_v[i].head, q_prev = q ; q ; ) {
-				if (q->dyn_type != O_LIMIT_PARENT)
-					NEXT_RULE();
-
-				if (q->count != 0)
-					NEXT_RULE();
-
-				/* Parent rule without consumers */
-
-				/* Unlink q from current list */
-				q_next = q->next;
-				if (q == V_ipfw_dyn_v[i].head)
-					V_ipfw_dyn_v[i].head = q_next;
-				else
-					q_prev->next = q_next;
-
-				q->next = NULL;
-
-				/* Add to expired list */
-				*exptailp = q;
-				exptailp = &(*exptailp)->next;
-
-				DEB(print_dyn_rule(&q->id, q->dyn_type,
-				    "unlink parent entry", "left");
-				)
-
-				expired++;
-
-				q = q_next;
-			}
-			IPFW_BUCK_UNLOCK(i);
-		}
-	}
-
-#undef NEXT_RULE
-
-	if (timer != 0) {
-		/*
-		 * Check if we need to resize hash:
-		 * if current number of states exceeds number of buckes in hash,
-		 * grow hash size to the minimum power of 2 which is bigger than
-		 * current states count. Limit hash size by 64k.
-		 */
-		max_buckets = (V_dyn_buckets_max > 65536) ?
-		    65536 : V_dyn_buckets_max;
-	
-		dyn_count = DYN_COUNT;
-	
-		if ((dyn_count > V_curr_dyn_buckets * 2) &&
-		    (dyn_count < max_buckets)) {
-			new_buckets = V_curr_dyn_buckets;
-			while (new_buckets < dyn_count) {
-				new_buckets *= 2;
-	
-				if (new_buckets >= max_buckets)
-					break;
-			}
-		}
-
-		IPFW_UH_WUNLOCK(chain);
-	}
-
-	/* Finally delete old states ad limits if any */
-	for (q = exp_head; q != NULL; q = q_next) {
-		q_next = q->next;
-		uma_zfree(V_ipfw_dyn_rule_zone, q);
-		ipfw_dyn_count--;
-	}
-
-	for (q = exp_lhead; q != NULL; q = q_next) {
-		q_next = q->next;
-		uma_zfree(V_ipfw_dyn_rule_zone, q);
-		ipfw_dyn_count--;
-	}
-
-	/*
-	 * The rest code MUST be called from timer routine only
-	 * without holding any locks
-	 */
-	if (timer == 0)
-		return;
-
-	/* Send keepalive packets if any */
-	for (m = m0; m != NULL; m = mnext) {
-		mnext = m->m_nextpkt;
-		m->m_nextpkt = NULL;
-		h = mtod(m, struct ip *);
-		if (h->ip_v == 4)
-			ip_output(m, NULL, NULL, 0, NULL, NULL);
-#ifdef INET6
-		else
-			ip6_output(m, NULL, NULL, 0, NULL, NULL, NULL);
-#endif
-	}
-
-	/* Run table resize without holding any locks */
-	if (new_buckets != 0)
-		resize_dynamic_table(chain, new_buckets);
-}
-
-/*
- * Deletes all dynamic rules originated by given rule or all rules in
- * given set. Specify RESVD_SET to indicate set should not be used.
- * @chain - pointer to current ipfw rules chain
- * @rr - delete all states originated by rules in matched range.
- *
- * Function has to be called with IPFW_UH_WLOCK held.
- * Additionally, function assume that dynamic rule/set is
- * ALREADY deleted so no new states can be generated by
- * 'deleted' rules.
- */
-void
-ipfw_expire_dyn_rules(struct ip_fw_chain *chain, ipfw_range_tlv *rt)
-{
-
-	check_dyn_rules(chain, rt, 0, 0);
-}
-
-/*
- * Check if rule contains at least one dynamic opcode.
- *
- * Returns 1 if such opcode is found, 0 otherwise.
- */
-int
-ipfw_is_dyn_rule(struct ip_fw *rule)
-{
-	int cmdlen, l;
-	ipfw_insn *cmd;
-
-	l = rule->cmd_len;
-	cmd = rule->cmd;
-	cmdlen = 0;
-	for ( ;	l > 0 ; l -= cmdlen, cmd += cmdlen) {
-		cmdlen = F_LEN(cmd);
-
-		switch (cmd->opcode) {
-		case O_LIMIT:
-		case O_KEEP_STATE:
-		case O_PROBE_STATE:
-		case O_CHECK_STATE:
-			return (1);
-		}
-	}
-
-	return (0);
-}
-
-void
-ipfw_dyn_init(struct ip_fw_chain *chain)
-{
-
-        V_ipfw_dyn_v = NULL;
-        V_dyn_buckets_max = 256; /* must be power of 2 */
-        V_curr_dyn_buckets = 256; /* must be power of 2 */
- 
-        V_dyn_ack_lifetime = 300;
-        V_dyn_syn_lifetime = 20;
-        V_dyn_fin_lifetime = 1;
-        V_dyn_rst_lifetime = 1;
-        V_dyn_udp_lifetime = 10;
-        V_dyn_short_lifetime = 5;
-
-        V_dyn_keepalive_interval = 20;
-        V_dyn_keepalive_period = 5;
-        V_dyn_keepalive = 1;    /* do send keepalives */
-	V_dyn_keepalive_last = time_uptime;
-        
-        V_dyn_max = 16384; /* max # of dynamic rules */
-
-	V_ipfw_dyn_rule_zone = uma_zcreate("IPFW dynamic rule",
-	    sizeof(ipfw_dyn_rule), NULL, NULL, NULL, NULL,
-	    UMA_ALIGN_PTR, 0);
-
-	/* Enforce limit on dynamic rules */
-	uma_zone_set_max(V_ipfw_dyn_rule_zone, V_dyn_max);
-
-        callout_init(&V_ipfw_timeout, 1);
-
-	/*
-	 * This can potentially be done on first dynamic rule
-	 * being added to chain.
-	 */
-	resize_dynamic_table(chain, V_curr_dyn_buckets);
-	IPFW_ADD_OBJ_REWRITER(IS_DEFAULT_VNET(curvnet), dyn_opcodes);
-}
-
-void
-ipfw_dyn_uninit(int pass)
-{
-	int i;
-
-	if (pass == 0) {
-		callout_drain(&V_ipfw_timeout);
-		return;
-	}
-	IPFW_DEL_OBJ_REWRITER(IS_DEFAULT_VNET(curvnet), dyn_opcodes);
-
-	if (V_ipfw_dyn_v != NULL) {
-		/*
-		 * Skip deleting all dynamic states -
-		 * uma_zdestroy() does this more efficiently;
-		 */
-
-		/* Destroy all mutexes */
-		for (i = 0 ; i < V_curr_dyn_buckets ; i++)
-			IPFW_BUCK_LOCK_DESTROY(&V_ipfw_dyn_v[i]);
-		free(V_ipfw_dyn_v, M_IPFW);
-		V_ipfw_dyn_v = NULL;
-	}
-
-        uma_zdestroy(V_ipfw_dyn_rule_zone);
-}
-
-#ifdef SYSCTL_NODE
-/*
- * Get/set maximum number of dynamic states in given VNET instance.
- */
-static int
-sysctl_ipfw_dyn_max(SYSCTL_HANDLER_ARGS)
-{
-	int error;
-	unsigned int nstates;
-
-	nstates = V_dyn_max;
-
-	error = sysctl_handle_int(oidp, &nstates, 0, req);
-	/* Read operation or some error */
-	if ((error != 0) || (req->newptr == NULL))
-		return (error);
-
-	V_dyn_max = nstates;
-	uma_zone_set_max(V_ipfw_dyn_rule_zone, V_dyn_max);
-
-	return (0);
-}
-
-/*
- * Get current number of dynamic states in given VNET instance.
- */
-static int
-sysctl_ipfw_dyn_count(SYSCTL_HANDLER_ARGS)
-{
-	int error;
-	unsigned int nstates;
-
-	nstates = DYN_COUNT;
-
-	error = sysctl_handle_int(oidp, &nstates, 0, req);
-
-	return (error);
-}
-#endif
-
-/*
- * Returns size of dynamic states in legacy format
- */
-int
-ipfw_dyn_len(void)
-{
-
-	return (V_ipfw_dyn_v == NULL) ? 0 :
-		(DYN_COUNT * sizeof(ipfw_dyn_rule));
-}
-
-/*
- * Returns number of dynamic states.
- * Used by dump format v1 (current).
- */
-int
-ipfw_dyn_get_count(void)
-{
-
-	return (V_ipfw_dyn_v == NULL) ? 0 : DYN_COUNT;
-}
-
-static void
-export_dyn_rule(ipfw_dyn_rule *src, ipfw_dyn_rule *dst)
-{
-
-	memcpy(dst, src, sizeof(*src));
-	memcpy(&(dst->rule), &(src->rule->rulenum), sizeof(src->rule->rulenum));
-	/*
-	 * store set number into high word of
-	 * dst->rule pointer.
-	 */
-	memcpy((char *)&dst->rule + sizeof(src->rule->rulenum),
-	    &(src->rule->set), sizeof(src->rule->set));
-	/*
-	 * store a non-null value in "next".
-	 * The userland code will interpret a
-	 * NULL here as a marker
-	 * for the last dynamic rule.
-	 */
-	memcpy(&dst->next, &dst, sizeof(dst));
-	dst->expire =
-	    TIME_LEQ(dst->expire, time_uptime) ?  0 : dst->expire - time_uptime;
-}
-
-/*
- * Fills int buffer given by @sd with dynamic states.
- * Used by dump format v1 (current).
- *
- * Returns 0 on success.
- */
-int
-ipfw_dump_states(struct ip_fw_chain *chain, struct sockopt_data *sd)
-{
-	ipfw_dyn_rule *p;
-	ipfw_obj_dyntlv *dst, *last;
-	ipfw_obj_ctlv *ctlv;
-	int i;
-	size_t sz;
-
-	if (V_ipfw_dyn_v == NULL)
-		return (0);
-
-	IPFW_UH_RLOCK_ASSERT(chain);
-
-	ctlv = (ipfw_obj_ctlv *)ipfw_get_sopt_space(sd, sizeof(*ctlv));
-	if (ctlv == NULL)
-		return (ENOMEM);
-	sz = sizeof(ipfw_obj_dyntlv);
-	ctlv->head.type = IPFW_TLV_DYNSTATE_LIST;
-	ctlv->objsize = sz;
-	last = NULL;
-
-	for (i = 0 ; i < V_curr_dyn_buckets; i++) {
-		IPFW_BUCK_LOCK(i);
-		for (p = V_ipfw_dyn_v[i].head ; p != NULL; p = p->next) {
-			dst = (ipfw_obj_dyntlv *)ipfw_get_sopt_space(sd, sz);
-			if (dst == NULL) {
-				IPFW_BUCK_UNLOCK(i);
-				return (ENOMEM);
-			}
-
-			export_dyn_rule(p, &dst->state);
-			dst->head.length = sz;
-			dst->head.type = IPFW_TLV_DYN_ENT;
-			last = dst;
-		}
-		IPFW_BUCK_UNLOCK(i);
-	}
-
-	if (last != NULL) /* mark last dynamic rule */
-		last->head.flags = IPFW_DF_LAST;
-
-	return (0);
-}
-
-/*
- * Fill given buffer with dynamic states (legacy format).
- * IPFW_UH_RLOCK has to be held while calling.
- */
-void
-ipfw_get_dynamic(struct ip_fw_chain *chain, char **pbp, const char *ep)
-{
-	ipfw_dyn_rule *p, *last = NULL;
-	char *bp;
-	int i;
-
-	if (V_ipfw_dyn_v == NULL)
-		return;
-	bp = *pbp;
-
-	IPFW_UH_RLOCK_ASSERT(chain);
-
-	for (i = 0 ; i < V_curr_dyn_buckets; i++) {
-		IPFW_BUCK_LOCK(i);
-		for (p = V_ipfw_dyn_v[i].head ; p != NULL; p = p->next) {
-			if (bp + sizeof *p <= ep) {
-				ipfw_dyn_rule *dst =
-					(ipfw_dyn_rule *)bp;
-
-				export_dyn_rule(p, dst);
-				last = dst;
-				bp += sizeof(ipfw_dyn_rule);
-			}
-		}
-		IPFW_BUCK_UNLOCK(i);
-	}
-
-	if (last != NULL) /* mark last dynamic rule */
-		bzero(&last->next, sizeof(last));
-	*pbp = bp;
-}
-/* end of file */
Index: eebsd/sys/netpfil/ipfw/ip_fw_eaction.c
===================================================================
--- freebsd/sys/netpfil/ipfw/ip_fw_eaction.c	(revision f62c62d2fe57ec02c1350144f7739f8e866ee6d4)
+++ 	(revision )
@@ -1,388 +1,0 @@
-#include <machine/rtems-bsd-kernel-space.h>
-
-/*-
- * Copyright (c) 2016-2017 Yandex LLC
- * Copyright (c) 2016-2017 Andrey V. Elsukov <ae@FreeBSD.org>
- *
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/malloc.h>
-#include <sys/kernel.h>
-#include <sys/hash.h>
-#include <sys/lock.h>
-#include <sys/rwlock.h>
-#include <sys/rmlock.h>
-#include <sys/socket.h>
-#include <sys/socketvar.h>
-#include <sys/queue.h>
-#include <net/pfil.h>
-
-#include <net/if.h>	/* ip_fw.h requires IFNAMSIZ */
-#include <netinet/in.h>
-#include <netinet/ip_var.h>	/* struct ipfw_rule_ref */
-#include <netinet/ip_fw.h>
-
-#include <netpfil/ipfw/ip_fw_private.h>
-
-#include <rtems/bsd/local/opt_ipfw.h>
-
-/*
- * External actions support for ipfw.
- *
- * This code provides KPI for implementing loadable modules, that
- * can provide handlers for external action opcodes in the ipfw's
- * rules.
- * Module should implement opcode handler with type ipfw_eaction_t.
- * This handler will be called by ipfw_chk() function when
- * O_EXTERNAL_ACTION opcode is matched. The handler must return
- * value used as return value in ipfw_chk(), i.e. IP_FW_PASS,
- * IP_FW_DENY (see ip_fw_private.h).
- * Also the last argument must be set by handler. If it is zero,
- * the search continues to the next rule. If it has non zero value,
- * the search terminates.
- *
- * The module that implements external action should register its
- * handler and name with ipfw_add_eaction() function.
- * This function will return eaction_id, that can be used by module.
- *
- * It is possible to pass some additional information to external
- * action handler using O_EXTERNAL_INSTANCE and O_EXTERNAL_DATA opcodes.
- * Such opcodes should be next after the O_EXTERNAL_ACTION opcode.
- * For the O_EXTERNAL_INSTANCE opcode the cmd->arg1 contains index of named
- * object related to an instance of external action.
- * For the O_EXTERNAL_DATA opcode the cmd contains the data that can be used
- * by external action handler without needing to create named instance.
- *
- * In case when eaction module uses named instances, it should register
- * opcode rewriting routines for O_EXTERNAL_INSTANCE opcode. The
- * classifier callback can look back into O_EXTERNAL_ACTION opcode (it
- * must be in the (ipfw_insn *)(cmd - 1)). By arg1 from O_EXTERNAL_ACTION
- * it can deteremine eaction_id and compare it with its own.
- * The macro IPFW_TLV_EACTION_NAME(eaction_id) can be used to deteremine
- * the type of named_object related to external action instance.
- *
- * On module unload handler should be deregistered with ipfw_del_eaction()
- * function using known eaction_id.
- */
-
-struct eaction_obj {
-	struct named_object	no;
-	ipfw_eaction_t		*handler;
-	char			name[64];
-};
-
-#define	EACTION_OBJ(ch, cmd)			\
-    ((struct eaction_obj *)SRV_OBJECT((ch), (cmd)->arg1))
-
-#if 0
-#define	EACTION_DEBUG(fmt, ...)	do {			\
-	printf("%s: " fmt "\n", __func__, ## __VA_ARGS__);	\
-} while (0)
-#else
-#define	EACTION_DEBUG(fmt, ...)
-#endif
-
-const char *default_eaction_typename = "drop";
-static int
-default_eaction(struct ip_fw_chain *ch, struct ip_fw_args *args,
-    ipfw_insn *cmd, int *done)
-{
-
-	*done = 1; /* terminate the search */
-	return (IP_FW_DENY);
-}
-
-/*
- * Opcode rewriting callbacks.
- */
-static int
-eaction_classify(ipfw_insn *cmd, uint16_t *puidx, uint8_t *ptype)
-{
-
-	EACTION_DEBUG("opcode %d, arg1 %d", cmd->opcode, cmd->arg1);
-	*puidx = cmd->arg1;
-	*ptype = 0;
-	return (0);
-}
-
-static void
-eaction_update(ipfw_insn *cmd, uint16_t idx)
-{
-
-	cmd->arg1 = idx;
-	EACTION_DEBUG("opcode %d, arg1 -> %d", cmd->opcode, cmd->arg1);
-}
-
-static int
-eaction_findbyname(struct ip_fw_chain *ch, struct tid_info *ti,
-    struct named_object **pno)
-{
-	ipfw_obj_ntlv *ntlv;
-
-	if (ti->tlvs == NULL)
-		return (EINVAL);
-
-	/* Search ntlv in the buffer provided by user */
-	ntlv = ipfw_find_name_tlv_type(ti->tlvs, ti->tlen, ti->uidx,
-	    IPFW_TLV_EACTION);
-	if (ntlv == NULL)
-		return (EINVAL);
-	EACTION_DEBUG("name %s, uidx %u, type %u", ntlv->name,
-	    ti->uidx, ti->type);
-	/*
-	 * Search named object with corresponding name.
-	 * Since eaction objects are global - ignore the set value
-	 * and use zero instead.
-	 */
-	*pno = ipfw_objhash_lookup_name_type(CHAIN_TO_SRV(ch),
-	    0, IPFW_TLV_EACTION, ntlv->name);
-	if (*pno == NULL)
-		return (ESRCH);
-	return (0);
-}
-
-static struct named_object *
-eaction_findbykidx(struct ip_fw_chain *ch, uint16_t idx)
-{
-
-	EACTION_DEBUG("kidx %u", idx);
-	return (ipfw_objhash_lookup_kidx(CHAIN_TO_SRV(ch), idx));
-}
-
-static struct opcode_obj_rewrite eaction_opcodes[] = {
-	{
-		.opcode = O_EXTERNAL_ACTION,
-		.etlv = IPFW_TLV_EACTION,
-		.classifier = eaction_classify,
-		.update = eaction_update,
-		.find_byname = eaction_findbyname,
-		.find_bykidx = eaction_findbykidx,
-	},
-};
-
-static int
-create_eaction_obj(struct ip_fw_chain *ch, ipfw_eaction_t handler,
-    const char *name, uint16_t *eaction_id)
-{
-	struct namedobj_instance *ni;
-	struct eaction_obj *obj;
-
-	IPFW_UH_UNLOCK_ASSERT(ch);
-
-	ni = CHAIN_TO_SRV(ch);
-	obj = malloc(sizeof(*obj), M_IPFW, M_WAITOK | M_ZERO);
-	obj->no.name = obj->name;
-	obj->no.etlv = IPFW_TLV_EACTION;
-	obj->handler = handler;
-	strlcpy(obj->name, name, sizeof(obj->name));
-
-	IPFW_UH_WLOCK(ch);
-	if (ipfw_objhash_lookup_name_type(ni, 0, IPFW_TLV_EACTION,
-	    name) != NULL) {
-		/*
-		 * Object is already created.
-		 * We don't allow eactions with the same name.
-		 */
-		IPFW_UH_WUNLOCK(ch);
-		free(obj, M_IPFW);
-		EACTION_DEBUG("External action with typename "
-		    "'%s' already exists", name);
-		return (EEXIST);
-	}
-	if (ipfw_objhash_alloc_idx(ni, &obj->no.kidx) != 0) {
-		IPFW_UH_WUNLOCK(ch);
-		free(obj, M_IPFW);
-		EACTION_DEBUG("alloc_idx failed");
-		return (ENOSPC);
-	}
-	ipfw_objhash_add(ni, &obj->no);
-	IPFW_WLOCK(ch);
-	SRV_OBJECT(ch, obj->no.kidx) = obj;
-	IPFW_WUNLOCK(ch);
-	obj->no.refcnt++;
-	IPFW_UH_WUNLOCK(ch);
-
-	if (eaction_id != NULL)
-		*eaction_id = obj->no.kidx;
-	return (0);
-}
-
-static void
-destroy_eaction_obj(struct ip_fw_chain *ch, struct named_object *no)
-{
-	struct namedobj_instance *ni;
-	struct eaction_obj *obj;
-
-	IPFW_UH_WLOCK_ASSERT(ch);
-
-	ni = CHAIN_TO_SRV(ch);
-	IPFW_WLOCK(ch);
-	obj = SRV_OBJECT(ch, no->kidx);
-	SRV_OBJECT(ch, no->kidx) = NULL;
-	IPFW_WUNLOCK(ch);
-	ipfw_objhash_del(ni, no);
-	ipfw_objhash_free_idx(ni, no->kidx);
-	free(obj, M_IPFW);
-}
-
-/*
- * Resets all eaction opcodes to default handlers.
- */
-static void
-reset_eaction_obj(struct ip_fw_chain *ch, uint16_t eaction_id)
-{
-	struct named_object *no;
-	struct ip_fw *rule;
-	ipfw_insn *cmd;
-	int i;
-
-	IPFW_UH_WLOCK_ASSERT(ch);
-
-	no = ipfw_objhash_lookup_name_type(CHAIN_TO_SRV(ch), 0,
-	    IPFW_TLV_EACTION, default_eaction_typename);
-	if (no == NULL)
-		panic("Default external action handler is not found");
-	if (eaction_id == no->kidx)
-		panic("Wrong eaction_id");
-	EACTION_DEBUG("replace id %u with %u", eaction_id, no->kidx);
-	IPFW_WLOCK(ch);
-	for (i = 0; i < ch->n_rules; i++) {
-		rule = ch->map[i];
-		cmd = ACTION_PTR(rule);
-		if (cmd->opcode != O_EXTERNAL_ACTION)
-			continue;
-		if (cmd->arg1 != eaction_id)
-			continue;
-		cmd->arg1 = no->kidx; /* Set to default id */
-		/*
-		 * XXX: we only bump refcount on default_eaction.
-		 * Refcount on the original object will be just
-		 * ignored on destroy. But on default_eaction it
-		 * will be decremented on rule deletion.
-		 */
-		no->refcnt++;
-		/*
-		 * Since named_object related to this instance will be
-		 * also destroyed, truncate the chain of opcodes to
-		 * remove the rest of cmd chain just after O_EXTERNAL_ACTION
-		 * opcode.
-		 */
-		if (rule->act_ofs < rule->cmd_len - 1) {
-			EACTION_DEBUG("truncate rule %d: len %u -> %u",
-			    rule->rulenum, rule->cmd_len, rule->act_ofs + 1);
-			rule->cmd_len = rule->act_ofs + 1;
-		}
-	}
-	IPFW_WUNLOCK(ch);
-}
-
-/*
- * Initialize external actions framework.
- * Create object with default eaction handler "drop".
- */
-int
-ipfw_eaction_init(struct ip_fw_chain *ch, int first)
-{
-	int error;
-
-	error = create_eaction_obj(ch, default_eaction,
-	    default_eaction_typename, NULL);
-	if (error != 0)
-		return (error);
-	IPFW_ADD_OBJ_REWRITER(first, eaction_opcodes);
-	EACTION_DEBUG("External actions support initialized");
-	return (0);
-}
-
-void
-ipfw_eaction_uninit(struct ip_fw_chain *ch, int last)
-{
-	struct namedobj_instance *ni;
-	struct named_object *no;
-
-	ni = CHAIN_TO_SRV(ch);
-
-	IPFW_UH_WLOCK(ch);
-	no = ipfw_objhash_lookup_name_type(ni, 0, IPFW_TLV_EACTION,
-	    default_eaction_typename);
-	if (no != NULL)
-		destroy_eaction_obj(ch, no);
-	IPFW_UH_WUNLOCK(ch);
-	IPFW_DEL_OBJ_REWRITER(last, eaction_opcodes);
-	EACTION_DEBUG("External actions support uninitialized");
-}
-
-/*
- * Registers external action handler to the global array.
- * On success it returns eaction id, otherwise - zero.
- */
-uint16_t
-ipfw_add_eaction(struct ip_fw_chain *ch, ipfw_eaction_t handler,
-    const char *name)
-{
-	uint16_t eaction_id;
-
-	eaction_id = 0;
-	if (ipfw_check_object_name_generic(name) == 0) {
-		create_eaction_obj(ch, handler, name, &eaction_id);
-		EACTION_DEBUG("Registered external action '%s' with id %u",
-		    name, eaction_id);
-	}
-	return (eaction_id);
-}
-
-/*
- * Deregisters external action handler with id eaction_id.
- */
-int
-ipfw_del_eaction(struct ip_fw_chain *ch, uint16_t eaction_id)
-{
-	struct named_object *no;
-
-	IPFW_UH_WLOCK(ch);
-	no = ipfw_objhash_lookup_kidx(CHAIN_TO_SRV(ch), eaction_id);
-	if (no == NULL || no->etlv != IPFW_TLV_EACTION) {
-		IPFW_UH_WUNLOCK(ch);
-		return (EINVAL);
-	}
-	if (no->refcnt > 1)
-		reset_eaction_obj(ch, eaction_id);
-	EACTION_DEBUG("External action '%s' with id %u unregistered",
-	    no->name, eaction_id);
-	destroy_eaction_obj(ch, no);
-	IPFW_UH_WUNLOCK(ch);
-	return (0);
-}
-
-int
-ipfw_run_eaction(struct ip_fw_chain *ch, struct ip_fw_args *args,
-    ipfw_insn *cmd, int *done)
-{
-
-	return (EACTION_OBJ(ch, cmd)->handler(ch, args, cmd, done));
-}
Index: eebsd/sys/netpfil/ipfw/ip_fw_iface.c
===================================================================
--- freebsd/sys/netpfil/ipfw/ip_fw_iface.c	(revision f62c62d2fe57ec02c1350144f7739f8e866ee6d4)
+++ 	(revision )
@@ -1,542 +1,0 @@
-#include <machine/rtems-bsd-kernel-space.h>
-
-/*-
- * Copyright (c) 2014 Yandex LLC.
- *
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-/*
- * Kernel interface tracking API.
- *
- */
-
-#include <rtems/bsd/local/opt_ipfw.h>
-#include <rtems/bsd/local/opt_inet.h>
-#ifndef INET
-#error IPFIREWALL requires INET.
-#endif /* INET */
-#include <rtems/bsd/local/opt_inet6.h>
-
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/malloc.h>
-#include <sys/kernel.h>
-#include <sys/lock.h>
-#include <sys/rwlock.h>
-#include <sys/rmlock.h>
-#include <sys/socket.h>
-#include <sys/queue.h>
-#include <sys/eventhandler.h>
-#include <net/if.h>
-#include <net/if_var.h>
-#include <net/pfil.h>
-#include <net/vnet.h>
-
-#include <netinet/in.h>
-#include <netinet/ip_var.h>	/* struct ipfw_rule_ref */
-#include <netinet/ip_fw.h>
-
-#include <netpfil/ipfw/ip_fw_private.h>
-
-#define	CHAIN_TO_II(ch)		((struct namedobj_instance *)ch->ifcfg)
-
-#define	DEFAULT_IFACES	128
-
-static void handle_ifdetach(struct ip_fw_chain *ch, struct ipfw_iface *iif,
-    uint16_t ifindex);
-static void handle_ifattach(struct ip_fw_chain *ch, struct ipfw_iface *iif,
-    uint16_t ifindex);
-static int list_ifaces(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
-    struct sockopt_data *sd);
-
-static struct ipfw_sopt_handler	scodes[] = {
-	{ IP_FW_XIFLIST,	0,	HDIR_GET,	list_ifaces },
-};
-
-/*
- * FreeBSD Kernel interface.
- */
-static void ipfw_kifhandler(void *arg, struct ifnet *ifp);
-static int ipfw_kiflookup(char *name);
-static void iface_khandler_register(void);
-static void iface_khandler_deregister(void);
-
-static eventhandler_tag ipfw_ifdetach_event, ipfw_ifattach_event;
-static int num_vnets = 0;
-static struct mtx vnet_mtx;
-
-/*
- * Checks if kernel interface is contained in our tracked
- * interface list and calls attach/detach handler.
- */
-static void
-ipfw_kifhandler(void *arg, struct ifnet *ifp)
-{
-	struct ip_fw_chain *ch;
-	struct ipfw_iface *iif;
-	struct namedobj_instance *ii;
-	uintptr_t htype;
-
-	if (V_ipfw_vnet_ready == 0)
-		return;
-
-	ch = &V_layer3_chain;
-	htype = (uintptr_t)arg;
-
-	IPFW_UH_WLOCK(ch);
-	ii = CHAIN_TO_II(ch);
-	if (ii == NULL) {
-		IPFW_UH_WUNLOCK(ch);
-		return;
-	}
-	iif = (struct ipfw_iface*)ipfw_objhash_lookup_name(ii, 0,
-	    if_name(ifp));
-	if (iif != NULL) {
-		if (htype == 1)
-			handle_ifattach(ch, iif, ifp->if_index);
-		else
-			handle_ifdetach(ch, iif, ifp->if_index);
-	}
-	IPFW_UH_WUNLOCK(ch);
-}
-
-/*
- * Reference current VNET as iface tracking API user.
- * Registers interface tracking handlers for first VNET.
- */
-static void
-iface_khandler_register()
-{
-	int create;
-
-	create = 0;
-
-	mtx_lock(&vnet_mtx);
-	if (num_vnets == 0)
-		create = 1;
-	num_vnets++;
-	mtx_unlock(&vnet_mtx);
-
-	if (create == 0)
-		return;
-
-	printf("IPFW: starting up interface tracker\n");
-
-	ipfw_ifdetach_event = EVENTHANDLER_REGISTER(
-	    ifnet_departure_event, ipfw_kifhandler, NULL,
-	    EVENTHANDLER_PRI_ANY);
-	ipfw_ifattach_event = EVENTHANDLER_REGISTER(
-	    ifnet_arrival_event, ipfw_kifhandler, (void*)((uintptr_t)1),
-	    EVENTHANDLER_PRI_ANY);
-}
-
-/*
- *
- * Detach interface event handlers on last VNET instance
- * detach.
- */
-static void
-iface_khandler_deregister()
-{
-	int destroy;
-
-	destroy = 0;
-	mtx_lock(&vnet_mtx);
-	if (num_vnets == 1)
-		destroy = 1;
-	num_vnets--;
-	mtx_unlock(&vnet_mtx);
-
-	if (destroy == 0)
-		return;
-
-	EVENTHANDLER_DEREGISTER(ifnet_arrival_event,
-	    ipfw_ifattach_event);
-	EVENTHANDLER_DEREGISTER(ifnet_departure_event,
-	    ipfw_ifdetach_event);
-}
-
-/*
- * Retrieves ifindex for given @name.
- *
- * Returns ifindex or 0.
- */
-static int
-ipfw_kiflookup(char *name)
-{
-	struct ifnet *ifp;
-	int ifindex;
-
-	ifindex = 0;
-
-	if ((ifp = ifunit_ref(name)) != NULL) {
-		ifindex = ifp->if_index;
-		if_rele(ifp);
-	}
-
-	return (ifindex);
-}
-
-/*
- * Global ipfw startup hook.
- * Since we perform lazy initialization, do nothing except
- * mutex init.
- */
-int
-ipfw_iface_init()
-{
-
-	mtx_init(&vnet_mtx, "IPFW ifhandler mtx", NULL, MTX_DEF);
-	IPFW_ADD_SOPT_HANDLER(1, scodes);
-	return (0);
-}
-
-/*
- * Global ipfw destroy hook.
- * Unregister khandlers iff init has been done.
- */
-void
-ipfw_iface_destroy()
-{
-
-	IPFW_DEL_SOPT_HANDLER(1, scodes);
-	mtx_destroy(&vnet_mtx);
-}
-
-/*
- * Perform actual init on internal request.
- * Inits both namehash and global khandler.
- */
-static void
-vnet_ipfw_iface_init(struct ip_fw_chain *ch)
-{
-	struct namedobj_instance *ii;
-
-	ii = ipfw_objhash_create(DEFAULT_IFACES);
-	IPFW_UH_WLOCK(ch);
-	if (ch->ifcfg == NULL) {
-		ch->ifcfg = ii;
-		ii = NULL;
-	}
-	IPFW_UH_WUNLOCK(ch);
-
-	if (ii != NULL) {
-		/* Already initialized. Free namehash. */
-		ipfw_objhash_destroy(ii);
-	} else {
-		/* We're the first ones. Init kernel hooks. */
-		iface_khandler_register();
-	}
-}
-
-static int
-destroy_iface(struct namedobj_instance *ii, struct named_object *no,
-    void *arg)
-{
-
-	/* Assume all consumers have been already detached */
-	free(no, M_IPFW);
-	return (0);
-}
-
-/*
- * Per-VNET ipfw detach hook.
- *
- */
-void
-vnet_ipfw_iface_destroy(struct ip_fw_chain *ch)
-{
-	struct namedobj_instance *ii;
-
-	IPFW_UH_WLOCK(ch);
-	ii = CHAIN_TO_II(ch);
-	ch->ifcfg = NULL;
-	IPFW_UH_WUNLOCK(ch);
-
-	if (ii != NULL) {
-		ipfw_objhash_foreach(ii, destroy_iface, ch);
-		ipfw_objhash_destroy(ii);
-		iface_khandler_deregister();
-	}
-}
-
-/*
- * Notify the subsystem that we are interested in tracking
- * interface @name. This function has to be called without
- * holding any locks to permit allocating the necessary states
- * for proper interface tracking.
- *
- * Returns 0 on success.
- */
-int
-ipfw_iface_ref(struct ip_fw_chain *ch, char *name,
-    struct ipfw_ifc *ic)
-{
-	struct namedobj_instance *ii;
-	struct ipfw_iface *iif, *tmp;
-
-	if (strlen(name) >= sizeof(iif->ifname))
-		return (EINVAL);
-
-	IPFW_UH_WLOCK(ch);
-
-	ii = CHAIN_TO_II(ch);
-	if (ii == NULL) {
-
-		/*
-		 * First request to subsystem.
-		 * Let's perform init.
-		 */
-		IPFW_UH_WUNLOCK(ch);
-		vnet_ipfw_iface_init(ch);
-		IPFW_UH_WLOCK(ch);
-		ii = CHAIN_TO_II(ch);
-	}
-
-	iif = (struct ipfw_iface *)ipfw_objhash_lookup_name(ii, 0, name);
-
-	if (iif != NULL) {
-		iif->no.refcnt++;
-		ic->iface = iif;
-		IPFW_UH_WUNLOCK(ch);
-		return (0);
-	}
-
-	IPFW_UH_WUNLOCK(ch);
-
-	/* Not found. Let's create one */
-	iif = malloc(sizeof(struct ipfw_iface), M_IPFW, M_WAITOK | M_ZERO);
-	TAILQ_INIT(&iif->consumers);
-	iif->no.name = iif->ifname;
-	strlcpy(iif->ifname, name, sizeof(iif->ifname));
-
-	/*
-	 * Ref & link to the list.
-	 *
-	 * We assume  ifnet_arrival_event / ifnet_departure_event
-	 * are not holding any locks.
-	 */
-	iif->no.refcnt = 1;
-	IPFW_UH_WLOCK(ch);
-
-	tmp = (struct ipfw_iface *)ipfw_objhash_lookup_name(ii, 0, name);
-	if (tmp != NULL) {
-		/* Interface has been created since unlock. Ref and return */
-		tmp->no.refcnt++;
-		ic->iface = tmp;
-		IPFW_UH_WUNLOCK(ch);
-		free(iif, M_IPFW);
-		return (0);
-	}
-
-	iif->ifindex = ipfw_kiflookup(name);
-	if (iif->ifindex != 0)
-		iif->resolved = 1;
-
-	ipfw_objhash_add(ii, &iif->no);
-	ic->iface = iif;
-
-	IPFW_UH_WUNLOCK(ch);
-
-	return (0);
-}
-
-/*
- * Adds @ic to the list of iif interface consumers.
- * Must be called with holding both UH+WLOCK.
- * Callback may be immediately called (if interface exists).
- */
-void
-ipfw_iface_add_notify(struct ip_fw_chain *ch, struct ipfw_ifc *ic)
-{
-	struct ipfw_iface *iif;
-
-	IPFW_UH_WLOCK_ASSERT(ch);
-	IPFW_WLOCK_ASSERT(ch);
-
-	iif = ic->iface;
-	
-	TAILQ_INSERT_TAIL(&iif->consumers, ic, next);
-	if (iif->resolved != 0)
-		ic->cb(ch, ic->cbdata, iif->ifindex);
-}
-
-/*
- * Unlinks interface tracker object @ic from interface.
- * Must be called while holding UH lock.
- */
-void
-ipfw_iface_del_notify(struct ip_fw_chain *ch, struct ipfw_ifc *ic)
-{
-	struct ipfw_iface *iif;
-
-	IPFW_UH_WLOCK_ASSERT(ch);
-
-	iif = ic->iface;
-	TAILQ_REMOVE(&iif->consumers, ic, next);
-}
-
-/*
- * Unreference interface specified by @ic.
- * Must be called while holding UH lock.
- */
-void
-ipfw_iface_unref(struct ip_fw_chain *ch, struct ipfw_ifc *ic)
-{
-	struct ipfw_iface *iif;
-
-	IPFW_UH_WLOCK_ASSERT(ch);
-
-	iif = ic->iface;
-	ic->iface = NULL;
-
-	iif->no.refcnt--;
-	/* TODO: check for references & delete */
-}
-
-/*
- * Interface arrival handler.
- */
-static void
-handle_ifattach(struct ip_fw_chain *ch, struct ipfw_iface *iif,
-    uint16_t ifindex)
-{
-	struct ipfw_ifc *ic;
-
-	IPFW_UH_WLOCK_ASSERT(ch);
-
-	iif->gencnt++;
-	iif->resolved = 1;
-	iif->ifindex = ifindex;
-
-	IPFW_WLOCK(ch);
-	TAILQ_FOREACH(ic, &iif->consumers, next)
-		ic->cb(ch, ic->cbdata, iif->ifindex);
-	IPFW_WUNLOCK(ch);
-}
-
-/*
- * Interface departure handler.
- */
-static void
-handle_ifdetach(struct ip_fw_chain *ch, struct ipfw_iface *iif,
-    uint16_t ifindex)
-{
-	struct ipfw_ifc *ic;
-
-	IPFW_UH_WLOCK_ASSERT(ch);
-
-	IPFW_WLOCK(ch);
-	TAILQ_FOREACH(ic, &iif->consumers, next)
-		ic->cb(ch, ic->cbdata, 0);
-	IPFW_WUNLOCK(ch);
-
-	iif->gencnt++;
-	iif->resolved = 0;
-	iif->ifindex = 0;
-}
-
-struct dump_iface_args {
-	struct ip_fw_chain *ch;
-	struct sockopt_data *sd;
-};
-
-static int
-export_iface_internal(struct namedobj_instance *ii, struct named_object *no,
-    void *arg)
-{
-	ipfw_iface_info *i;
-	struct dump_iface_args *da;
-	struct ipfw_iface *iif;
-
-	da = (struct dump_iface_args *)arg;
-
-	i = (ipfw_iface_info *)ipfw_get_sopt_space(da->sd, sizeof(*i));
-	KASSERT(i != NULL, ("previously checked buffer is not enough"));
-
-	iif = (struct ipfw_iface *)no;
-
-	strlcpy(i->ifname, iif->ifname, sizeof(i->ifname));
-	if (iif->resolved)
-		i->flags |= IPFW_IFFLAG_RESOLVED;
-	i->ifindex = iif->ifindex;
-	i->refcnt = iif->no.refcnt;
-	i->gencnt = iif->gencnt;
-	return (0);
-}
-
-/*
- * Lists all interface currently tracked by ipfw.
- * Data layout (v0)(current):
- * Request: [ ipfw_obj_lheader ], size = ipfw_obj_lheader.size
- * Reply: [ ipfw_obj_lheader ipfw_iface_info x N ]
- *
- * Returns 0 on success
- */
-static int
-list_ifaces(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
-    struct sockopt_data *sd)
-{
-	struct namedobj_instance *ii;
-	struct _ipfw_obj_lheader *olh;
-	struct dump_iface_args da;
-	uint32_t count, size;
-
-	olh = (struct _ipfw_obj_lheader *)ipfw_get_sopt_header(sd,sizeof(*olh));
-	if (olh == NULL)
-		return (EINVAL);
-	if (sd->valsize < olh->size)
-		return (EINVAL);
-
-	IPFW_UH_RLOCK(ch);
-	ii = CHAIN_TO_II(ch);
-	if (ii != NULL)
-		count = ipfw_objhash_count(ii);
-	else
-		count = 0;
-	size = count * sizeof(ipfw_iface_info) + sizeof(ipfw_obj_lheader);
-
-	/* Fill in header regadless of buffer size */
-	olh->count = count;
-	olh->objsize = sizeof(ipfw_iface_info);
-
-	if (size > olh->size) {
-		olh->size = size;
-		IPFW_UH_RUNLOCK(ch);
-		return (ENOMEM);
-	}
-	olh->size = size;
-
-	da.ch = ch;
-	da.sd = sd;
-
-	if (ii != NULL)
-		ipfw_objhash_foreach(ii, export_iface_internal, &da);
-	IPFW_UH_RUNLOCK(ch);
-
-	return (0);
-}
-
Index: eebsd/sys/netpfil/ipfw/ip_fw_log.c
===================================================================
--- freebsd/sys/netpfil/ipfw/ip_fw_log.c	(revision f62c62d2fe57ec02c1350144f7739f8e866ee6d4)
+++ 	(revision )
@@ -1,419 +1,0 @@
-#include <machine/rtems-bsd-kernel-space.h>
-
-/*-
- * Copyright (c) 2002-2009 Luigi Rizzo, Universita` di Pisa
- *
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-/*
- * Logging support for ipfw
- */
-
-#include <rtems/bsd/local/opt_ipfw.h>
-#include <rtems/bsd/local/opt_inet.h>
-#ifndef INET
-#error IPFIREWALL requires INET.
-#endif /* INET */
-#include <rtems/bsd/local/opt_inet6.h>
-
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/kernel.h>
-#include <sys/mbuf.h>
-#include <sys/socket.h>
-#include <sys/sysctl.h>
-#include <sys/syslog.h>
-#include <net/ethernet.h> /* for ETHERTYPE_IP */
-#include <net/if.h>
-#include <net/if_var.h>
-#include <net/vnet.h>
-
-#include <netinet/in.h>
-#include <netinet/ip.h>
-#include <netinet/ip_icmp.h>
-#include <netinet/ip_var.h>
-#include <netinet/ip_fw.h>
-#include <netinet/tcp_var.h>
-#include <netinet/udp.h>
-
-#include <netinet/ip6.h>
-#include <netinet/icmp6.h>
-#ifdef INET6
-#include <netinet6/in6_var.h>	/* ip6_sprintf() */
-#endif
-
-#include <netpfil/ipfw/ip_fw_private.h>
-
-#ifdef MAC
-#include <security/mac/mac_framework.h>
-#endif
-
-/*
- * L3HDR maps an ipv4 pointer into a layer3 header pointer of type T
- * Other macros just cast void * into the appropriate type
- */
-#define	L3HDR(T, ip)	((T *)((u_int32_t *)(ip) + (ip)->ip_hl))
-#define	TCP(p)		((struct tcphdr *)(p))
-#define	SCTP(p)		((struct sctphdr *)(p))
-#define	UDP(p)		((struct udphdr *)(p))
-#define	ICMP(p)		((struct icmphdr *)(p))
-#define	ICMP6(p)	((struct icmp6_hdr *)(p))
-
-#ifdef __APPLE__
-#undef snprintf
-#define snprintf	sprintf
-#define SNPARGS(buf, len) buf + len
-#define SNP(buf) buf
-#else	/* !__APPLE__ */
-#define SNPARGS(buf, len) buf + len, sizeof(buf) > len ? sizeof(buf) - len : 0
-#define SNP(buf) buf, sizeof(buf)
-#endif /* !__APPLE__ */
-
-#define	TARG(k, f)	IP_FW_ARG_TABLEARG(chain, k, f)
-/*
- * We enter here when we have a rule with O_LOG.
- * XXX this function alone takes about 2Kbytes of code!
- */
-void
-ipfw_log(struct ip_fw_chain *chain, struct ip_fw *f, u_int hlen,
-    struct ip_fw_args *args, struct mbuf *m, struct ifnet *oif,
-    u_short offset, uint32_t tablearg, struct ip *ip)
-{
-	char *action;
-	int limit_reached = 0;
-	char action2[92], proto[128], fragment[32];
-
-	if (V_fw_verbose == 0) {
-		if (args->eh) /* layer2, use orig hdr */
-			ipfw_bpf_mtap2(args->eh, ETHER_HDR_LEN, m);
-		else {
-			/* Add fake header. Later we will store
-			 * more info in the header.
-			 */
-			if (ip->ip_v == 4)
-				ipfw_bpf_mtap2("DDDDDDSSSSSS\x08\x00",
-				    ETHER_HDR_LEN, m);
-			else if (ip->ip_v == 6)
-				ipfw_bpf_mtap2("DDDDDDSSSSSS\x86\xdd",
-				    ETHER_HDR_LEN, m);
-			else
-				/* Obviously bogus EtherType. */
-				ipfw_bpf_mtap2("DDDDDDSSSSSS\xff\xff",
-				    ETHER_HDR_LEN, m);
-		}
-		return;
-	}
-	/* the old 'log' function */
-	fragment[0] = '\0';
-	proto[0] = '\0';
-
-	if (f == NULL) {	/* bogus pkt */
-		if (V_verbose_limit != 0 && V_norule_counter >= V_verbose_limit)
-			return;
-		V_norule_counter++;
-		if (V_norule_counter == V_verbose_limit)
-			limit_reached = V_verbose_limit;
-		action = "Refuse";
-	} else {	/* O_LOG is the first action, find the real one */
-		ipfw_insn *cmd = ACTION_PTR(f);
-		ipfw_insn_log *l = (ipfw_insn_log *)cmd;
-
-		if (l->max_log != 0 && l->log_left == 0)
-			return;
-		l->log_left--;
-		if (l->log_left == 0)
-			limit_reached = l->max_log;
-		cmd += F_LEN(cmd);	/* point to first action */
-		if (cmd->opcode == O_ALTQ) {
-			ipfw_insn_altq *altq = (ipfw_insn_altq *)cmd;
-
-			snprintf(SNPARGS(action2, 0), "Altq %d",
-				altq->qid);
-			cmd += F_LEN(cmd);
-		}
-		if (cmd->opcode == O_PROB || cmd->opcode == O_TAG ||
-		    cmd->opcode == O_SETDSCP)
-			cmd += F_LEN(cmd);
-
-		action = action2;
-		switch (cmd->opcode) {
-		case O_DENY:
-			action = "Deny";
-			break;
-
-		case O_REJECT:
-			if (cmd->arg1==ICMP_REJECT_RST)
-				action = "Reset";
-			else if (cmd->arg1==ICMP_UNREACH_HOST)
-				action = "Reject";
-			else
-				snprintf(SNPARGS(action2, 0), "Unreach %d",
-					cmd->arg1);
-			break;
-
-		case O_UNREACH6:
-			if (cmd->arg1==ICMP6_UNREACH_RST)
-				action = "Reset";
-			else
-				snprintf(SNPARGS(action2, 0), "Unreach %d",
-					cmd->arg1);
-			break;
-
-		case O_ACCEPT:
-			action = "Accept";
-			break;
-		case O_COUNT:
-			action = "Count";
-			break;
-		case O_DIVERT:
-			snprintf(SNPARGS(action2, 0), "Divert %d",
-				TARG(cmd->arg1, divert));
-			break;
-		case O_TEE:
-			snprintf(SNPARGS(action2, 0), "Tee %d",
-				TARG(cmd->arg1, divert));
-			break;
-		case O_SETFIB:
-			snprintf(SNPARGS(action2, 0), "SetFib %d",
-				TARG(cmd->arg1, fib) & 0x7FFF);
-			break;
-		case O_SKIPTO:
-			snprintf(SNPARGS(action2, 0), "SkipTo %d",
-				TARG(cmd->arg1, skipto));
-			break;
-		case O_PIPE:
-			snprintf(SNPARGS(action2, 0), "Pipe %d",
-				TARG(cmd->arg1, pipe));
-			break;
-		case O_QUEUE:
-			snprintf(SNPARGS(action2, 0), "Queue %d",
-				TARG(cmd->arg1, pipe));
-			break;
-		case O_FORWARD_IP: {
-			char buf[INET_ADDRSTRLEN];
-			ipfw_insn_sa *sa = (ipfw_insn_sa *)cmd;
-			int len;
-			struct in_addr dummyaddr;
-			if (sa->sa.sin_addr.s_addr == INADDR_ANY)
-				dummyaddr.s_addr = htonl(tablearg);
-			else
-				dummyaddr.s_addr = sa->sa.sin_addr.s_addr;
-
-			len = snprintf(SNPARGS(action2, 0), "Forward to %s",
-				inet_ntoa_r(dummyaddr, buf));
-
-			if (sa->sa.sin_port)
-				snprintf(SNPARGS(action2, len), ":%d",
-				    sa->sa.sin_port);
-			}
-			break;
-#ifdef INET6
-		case O_FORWARD_IP6: {
-			char buf[INET6_ADDRSTRLEN];
-			ipfw_insn_sa6 *sa = (ipfw_insn_sa6 *)cmd;
-			int len;
-
-			len = snprintf(SNPARGS(action2, 0), "Forward to [%s]",
-			    ip6_sprintf(buf, &sa->sa.sin6_addr));
-
-			if (sa->sa.sin6_port)
-				snprintf(SNPARGS(action2, len), ":%u",
-				    sa->sa.sin6_port);
-			}
-			break;
-#endif
-		case O_NETGRAPH:
-			snprintf(SNPARGS(action2, 0), "Netgraph %d",
-				cmd->arg1);
-			break;
-		case O_NGTEE:
-			snprintf(SNPARGS(action2, 0), "Ngtee %d",
-				cmd->arg1);
-			break;
-		case O_NAT:
-			action = "Nat";
- 			break;
-		case O_REASS:
-			action = "Reass";
-			break;
-		case O_CALLRETURN:
-			if (cmd->len & F_NOT)
-				action = "Return";
-			else
-				snprintf(SNPARGS(action2, 0), "Call %d",
-				    cmd->arg1);
-			break;
-		case O_EXTERNAL_ACTION:
-			snprintf(SNPARGS(action2, 0), "Eaction %s",
-			    ((struct named_object *)SRV_OBJECT(chain,
-			    cmd->arg1))->name);
-			break;
-		default:
-			action = "UNKNOWN";
-			break;
-		}
-	}
-
-	if (hlen == 0) {	/* non-ip */
-		snprintf(SNPARGS(proto, 0), "MAC");
-
-	} else {
-		int len;
-#ifdef INET6
-		char src[INET6_ADDRSTRLEN + 2], dst[INET6_ADDRSTRLEN + 2];
-#else
-		char src[INET_ADDRSTRLEN], dst[INET_ADDRSTRLEN];
-#endif
-		struct icmphdr *icmp;
-		struct tcphdr *tcp;
-		struct udphdr *udp;
-#ifdef INET6
-		struct ip6_hdr *ip6 = NULL;
-		struct icmp6_hdr *icmp6;
-		u_short ip6f_mf;
-#endif
-		src[0] = '\0';
-		dst[0] = '\0';
-#ifdef INET6
-		ip6f_mf = offset & IP6F_MORE_FRAG;
-		offset &= IP6F_OFF_MASK;
-
-		if (IS_IP6_FLOW_ID(&(args->f_id))) {
-			char ip6buf[INET6_ADDRSTRLEN];
-			snprintf(src, sizeof(src), "[%s]",
-			    ip6_sprintf(ip6buf, &args->f_id.src_ip6));
-			snprintf(dst, sizeof(dst), "[%s]",
-			    ip6_sprintf(ip6buf, &args->f_id.dst_ip6));
-
-			ip6 = (struct ip6_hdr *)ip;
-			tcp = (struct tcphdr *)(((char *)ip) + hlen);
-			udp = (struct udphdr *)(((char *)ip) + hlen);
-		} else
-#endif
-		{
-			tcp = L3HDR(struct tcphdr, ip);
-			udp = L3HDR(struct udphdr, ip);
-
-			inet_ntop(AF_INET, &ip->ip_src, src, sizeof(src));
-			inet_ntop(AF_INET, &ip->ip_dst, dst, sizeof(dst));
-		}
-
-		switch (args->f_id.proto) {
-		case IPPROTO_TCP:
-			len = snprintf(SNPARGS(proto, 0), "TCP %s", src);
-			if (offset == 0)
-				snprintf(SNPARGS(proto, len), ":%d %s:%d",
-				    ntohs(tcp->th_sport),
-				    dst,
-				    ntohs(tcp->th_dport));
-			else
-				snprintf(SNPARGS(proto, len), " %s", dst);
-			break;
-
-		case IPPROTO_UDP:
-			len = snprintf(SNPARGS(proto, 0), "UDP %s", src);
-			if (offset == 0)
-				snprintf(SNPARGS(proto, len), ":%d %s:%d",
-				    ntohs(udp->uh_sport),
-				    dst,
-				    ntohs(udp->uh_dport));
-			else
-				snprintf(SNPARGS(proto, len), " %s", dst);
-			break;
-
-		case IPPROTO_ICMP:
-			icmp = L3HDR(struct icmphdr, ip);
-			if (offset == 0)
-				len = snprintf(SNPARGS(proto, 0),
-				    "ICMP:%u.%u ",
-				    icmp->icmp_type, icmp->icmp_code);
-			else
-				len = snprintf(SNPARGS(proto, 0), "ICMP ");
-			len += snprintf(SNPARGS(proto, len), "%s", src);
-			snprintf(SNPARGS(proto, len), " %s", dst);
-			break;
-#ifdef INET6
-		case IPPROTO_ICMPV6:
-			icmp6 = (struct icmp6_hdr *)(((char *)ip) + hlen);
-			if (offset == 0)
-				len = snprintf(SNPARGS(proto, 0),
-				    "ICMPv6:%u.%u ",
-				    icmp6->icmp6_type, icmp6->icmp6_code);
-			else
-				len = snprintf(SNPARGS(proto, 0), "ICMPv6 ");
-			len += snprintf(SNPARGS(proto, len), "%s", src);
-			snprintf(SNPARGS(proto, len), " %s", dst);
-			break;
-#endif
-		default:
-			len = snprintf(SNPARGS(proto, 0), "P:%d %s",
-			    args->f_id.proto, src);
-			snprintf(SNPARGS(proto, len), " %s", dst);
-			break;
-		}
-
-#ifdef INET6
-		if (IS_IP6_FLOW_ID(&(args->f_id))) {
-			if (offset || ip6f_mf)
-				snprintf(SNPARGS(fragment, 0),
-				    " (frag %08x:%d@%d%s)",
-				    args->f_id.extra,
-				    ntohs(ip6->ip6_plen) - hlen,
-				    ntohs(offset) << 3, ip6f_mf ? "+" : "");
-		} else
-#endif
-		{
-			int ipoff, iplen;
-			ipoff = ntohs(ip->ip_off);
-			iplen = ntohs(ip->ip_len);
-			if (ipoff & (IP_MF | IP_OFFMASK))
-				snprintf(SNPARGS(fragment, 0),
-				    " (frag %d:%d@%d%s)",
-				    ntohs(ip->ip_id), iplen - (ip->ip_hl << 2),
-				    offset << 3,
-				    (ipoff & IP_MF) ? "+" : "");
-		}
-	}
-#ifdef __FreeBSD__
-	if (oif || m->m_pkthdr.rcvif)
-		log(LOG_SECURITY | LOG_INFO,
-		    "ipfw: %d %s %s %s via %s%s\n",
-		    f ? f->rulenum : -1,
-		    action, proto, oif ? "out" : "in",
-		    oif ? oif->if_xname : m->m_pkthdr.rcvif->if_xname,
-		    fragment);
-	else
-#endif
-		log(LOG_SECURITY | LOG_INFO,
-		    "ipfw: %d %s %s [no if info]%s\n",
-		    f ? f->rulenum : -1,
-		    action, proto, fragment);
-	if (limit_reached)
-		log(LOG_SECURITY | LOG_NOTICE,
-		    "ipfw: limit %d reached on entry %d\n",
-		    limit_reached, f ? f->rulenum : -1);
-}
-/* end of file */
Index: eebsd/sys/netpfil/ipfw/ip_fw_nat.c
===================================================================
--- freebsd/sys/netpfil/ipfw/ip_fw_nat.c	(revision f62c62d2fe57ec02c1350144f7739f8e866ee6d4)
+++ 	(revision )
@@ -1,1243 +1,0 @@
-#include <machine/rtems-bsd-kernel-space.h>
-
-/*-
- * Copyright (c) 2008 Paolo Pisati
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/eventhandler.h>
-#include <sys/malloc.h>
-#include <sys/mbuf.h>
-#include <sys/kernel.h>
-#include <sys/lock.h>
-#include <sys/module.h>
-#include <sys/rwlock.h>
-#include <sys/rmlock.h>
-
-#include <netinet/libalias/alias.h>
-#include <netinet/libalias/alias_local.h>
-
-#include <net/if.h>
-#include <net/if_var.h>
-#include <net/pfil.h>
-#include <netinet/in.h>
-#include <netinet/ip.h>
-#include <netinet/ip_var.h>
-#include <netinet/ip_fw.h>
-#include <netinet/tcp.h>
-#include <netinet/udp.h>
-
-#include <netpfil/ipfw/ip_fw_private.h>
-
-#include <machine/in_cksum.h>	/* XXX for in_cksum */
-
-struct cfg_spool {
-	LIST_ENTRY(cfg_spool)   _next;          /* chain of spool instances */
-	struct in_addr          addr;
-	uint16_t		port;
-};
-
-/* Nat redirect configuration. */
-struct cfg_redir {
-	LIST_ENTRY(cfg_redir)	_next;	/* chain of redir instances */
-	uint16_t		mode;	/* type of redirect mode */
-	uint16_t		proto;	/* protocol: tcp/udp */
-	struct in_addr		laddr;	/* local ip address */
-	struct in_addr		paddr;	/* public ip address */
-	struct in_addr		raddr;	/* remote ip address */
-	uint16_t		lport;	/* local port */
-	uint16_t		pport;	/* public port */
-	uint16_t		rport;	/* remote port	*/
-	uint16_t		pport_cnt;	/* number of public ports */
-	uint16_t		rport_cnt;	/* number of remote ports */
-	struct alias_link	**alink;	
-	u_int16_t		spool_cnt; /* num of entry in spool chain */
-	/* chain of spool instances */
-	LIST_HEAD(spool_chain, cfg_spool) spool_chain;
-};
-
-/* Nat configuration data struct. */
-struct cfg_nat {
-	/* chain of nat instances */
-	LIST_ENTRY(cfg_nat)	_next;
-	int			id;		/* nat id  */
-	struct in_addr		ip;		/* nat ip address */
-	struct libalias		*lib;		/* libalias instance */
-	int			mode;		/* aliasing mode */
-	int			redir_cnt; /* number of entry in spool chain */
-	/* chain of redir instances */
-	LIST_HEAD(redir_chain, cfg_redir) redir_chain;  
-	char			if_name[IF_NAMESIZE];	/* interface name */
-};
-
-static eventhandler_tag ifaddr_event_tag;
-
-static void
-ifaddr_change(void *arg __unused, struct ifnet *ifp)
-{
-	struct cfg_nat *ptr;
-	struct ifaddr *ifa;
-	struct ip_fw_chain *chain;
-
-	KASSERT(curvnet == ifp->if_vnet,
-	    ("curvnet(%p) differs from iface vnet(%p)", curvnet, ifp->if_vnet));
-
-	if (V_ipfw_vnet_ready == 0 || V_ipfw_nat_ready == 0)
-		return;
-
-	chain = &V_layer3_chain;
-	IPFW_UH_WLOCK(chain);
-	/* Check every nat entry... */
-	LIST_FOREACH(ptr, &chain->nat, _next) {
-		/* ...using nic 'ifp->if_xname' as dynamic alias address. */
-		if (strncmp(ptr->if_name, ifp->if_xname, IF_NAMESIZE) != 0)
-			continue;
-		if_addr_rlock(ifp);
-		TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
-			if (ifa->ifa_addr == NULL)
-				continue;
-			if (ifa->ifa_addr->sa_family != AF_INET)
-				continue;
-			IPFW_WLOCK(chain);
-			ptr->ip = ((struct sockaddr_in *)
-			    (ifa->ifa_addr))->sin_addr;
-			LibAliasSetAddress(ptr->lib, ptr->ip);
-			IPFW_WUNLOCK(chain);
-		}
-		if_addr_runlock(ifp);
-	}
-	IPFW_UH_WUNLOCK(chain);
-}
-
-/*
- * delete the pointers for nat entry ix, or all of them if ix < 0
- */
-static void
-flush_nat_ptrs(struct ip_fw_chain *chain, const int ix)
-{
-	int i;
-	ipfw_insn_nat *cmd;
-
-	IPFW_WLOCK_ASSERT(chain);
-	for (i = 0; i < chain->n_rules; i++) {
-		cmd = (ipfw_insn_nat *)ACTION_PTR(chain->map[i]);
-		/* XXX skip log and the like ? */
-		if (cmd->o.opcode == O_NAT && cmd->nat != NULL &&
-			    (ix < 0 || cmd->nat->id == ix))
-			cmd->nat = NULL;
-	}
-}
-
-static void
-del_redir_spool_cfg(struct cfg_nat *n, struct redir_chain *head)
-{
-	struct cfg_redir *r, *tmp_r;
-	struct cfg_spool *s, *tmp_s;
-	int i, num;
-
-	LIST_FOREACH_SAFE(r, head, _next, tmp_r) {
-		num = 1; /* Number of alias_link to delete. */
-		switch (r->mode) {
-		case NAT44_REDIR_PORT:
-			num = r->pport_cnt;
-			/* FALLTHROUGH */
-		case NAT44_REDIR_ADDR:
-		case NAT44_REDIR_PROTO:
-			/* Delete all libalias redirect entry. */
-			for (i = 0; i < num; i++)
-				LibAliasRedirectDelete(n->lib, r->alink[i]);
-			/* Del spool cfg if any. */
-			LIST_FOREACH_SAFE(s, &r->spool_chain, _next, tmp_s) {
-				LIST_REMOVE(s, _next);
-				free(s, M_IPFW);
-			}
-			free(r->alink, M_IPFW);
-			LIST_REMOVE(r, _next);
-			free(r, M_IPFW);
-			break;
-		default:
-			printf("unknown redirect mode: %u\n", r->mode);
-			/* XXX - panic?!?!? */
-			break;
-		}
-	}
-}
-
-static int
-add_redir_spool_cfg(char *buf, struct cfg_nat *ptr)
-{
-	struct cfg_redir *r;
-	struct cfg_spool *s;
-	struct nat44_cfg_redir *ser_r;
-	struct nat44_cfg_spool *ser_s;
-
-	int cnt, off, i;
-
-	for (cnt = 0, off = 0; cnt < ptr->redir_cnt; cnt++) {
-		ser_r = (struct nat44_cfg_redir *)&buf[off];
-		r = malloc(sizeof(*r), M_IPFW, M_WAITOK | M_ZERO);
-		r->mode = ser_r->mode;
-		r->laddr = ser_r->laddr;
-		r->paddr = ser_r->paddr;
-		r->raddr = ser_r->raddr;
-		r->lport = ser_r->lport;
-		r->pport = ser_r->pport;
-		r->rport = ser_r->rport;
-		r->pport_cnt = ser_r->pport_cnt;
-		r->rport_cnt = ser_r->rport_cnt;
-		r->proto = ser_r->proto;
-		r->spool_cnt = ser_r->spool_cnt;
-		//memcpy(r, ser_r, SOF_REDIR);
-		LIST_INIT(&r->spool_chain);
-		off += sizeof(struct nat44_cfg_redir);
-		r->alink = malloc(sizeof(struct alias_link *) * r->pport_cnt,
-		    M_IPFW, M_WAITOK | M_ZERO);
-		switch (r->mode) {
-		case NAT44_REDIR_ADDR:
-			r->alink[0] = LibAliasRedirectAddr(ptr->lib, r->laddr,
-			    r->paddr);
-			break;
-		case NAT44_REDIR_PORT:
-			for (i = 0 ; i < r->pport_cnt; i++) {
-				/* If remotePort is all ports, set it to 0. */
-				u_short remotePortCopy = r->rport + i;
-				if (r->rport_cnt == 1 && r->rport == 0)
-					remotePortCopy = 0;
-				r->alink[i] = LibAliasRedirectPort(ptr->lib,
-				    r->laddr, htons(r->lport + i), r->raddr,
-				    htons(remotePortCopy), r->paddr,
-				    htons(r->pport + i), r->proto);
-				if (r->alink[i] == NULL) {
-					r->alink[0] = NULL;
-					break;
-				}
-			}
-			break;
-		case NAT44_REDIR_PROTO:
-			r->alink[0] = LibAliasRedirectProto(ptr->lib ,r->laddr,
-			    r->raddr, r->paddr, r->proto);
-			break;
-		default:
-			printf("unknown redirect mode: %u\n", r->mode);
-			break;
-		}
-		if (r->alink[0] == NULL) {
-			printf("LibAliasRedirect* returned NULL\n");
-			free(r->alink, M_IPFW);
-			free(r, M_IPFW);
-			return (EINVAL);
-		}
-		/* LSNAT handling. */
-		for (i = 0; i < r->spool_cnt; i++) {
-			ser_s = (struct nat44_cfg_spool *)&buf[off];
-			s = malloc(sizeof(*s), M_IPFW, M_WAITOK | M_ZERO);
-			s->addr = ser_s->addr;
-			s->port = ser_s->port;
-			LibAliasAddServer(ptr->lib, r->alink[0],
-			    s->addr, htons(s->port));
-			off += sizeof(struct nat44_cfg_spool);
-			/* Hook spool entry. */
-			LIST_INSERT_HEAD(&r->spool_chain, s, _next);
-		}
-		/* And finally hook this redir entry. */
-		LIST_INSERT_HEAD(&ptr->redir_chain, r, _next);
-	}
-
-	return (0);
-}
-
-static void
-free_nat_instance(struct cfg_nat *ptr)
-{
-
-	del_redir_spool_cfg(ptr, &ptr->redir_chain);
-	LibAliasUninit(ptr->lib);
-	free(ptr, M_IPFW);
-}
-
-
-/*
- * ipfw_nat - perform mbuf header translation.
- *
- * Note V_layer3_chain has to be locked while calling ipfw_nat() in
- * 'global' operation mode (t == NULL).
- *
- */
-static int
-ipfw_nat(struct ip_fw_args *args, struct cfg_nat *t, struct mbuf *m)
-{
-	struct mbuf *mcl;
-	struct ip *ip;
-	/* XXX - libalias duct tape */
-	int ldt, retval, found;
-	struct ip_fw_chain *chain;
-	char *c;
-
-	ldt = 0;
-	retval = 0;
-	mcl = m_megapullup(m, m->m_pkthdr.len);
-	if (mcl == NULL) {
-		args->m = NULL;
-		return (IP_FW_DENY);
-	}
-	ip = mtod(mcl, struct ip *);
-
-	/*
-	 * XXX - Libalias checksum offload 'duct tape':
-	 *
-	 * locally generated packets have only pseudo-header checksum
-	 * calculated and libalias will break it[1], so mark them for
-	 * later fix.  Moreover there are cases when libalias modifies
-	 * tcp packet data[2], mark them for later fix too.
-	 *
-	 * [1] libalias was never meant to run in kernel, so it does
-	 * not have any knowledge about checksum offloading, and
-	 * expects a packet with a full internet checksum.
-	 * Unfortunately, packets generated locally will have just the
-	 * pseudo header calculated, and when libalias tries to adjust
-	 * the checksum it will actually compute a wrong value.
-	 *
-	 * [2] when libalias modifies tcp's data content, full TCP
-	 * checksum has to be recomputed: the problem is that
-	 * libalias does not have any idea about checksum offloading.
-	 * To work around this, we do not do checksumming in LibAlias,
-	 * but only mark the packets in th_x2 field. If we receive a
-	 * marked packet, we calculate correct checksum for it
-	 * aware of offloading.  Why such a terrible hack instead of
-	 * recalculating checksum for each packet?
-	 * Because the previous checksum was not checked!
-	 * Recalculating checksums for EVERY packet will hide ALL
-	 * transmission errors. Yes, marked packets still suffer from
-	 * this problem. But, sigh, natd(8) has this problem, too.
-	 *
-	 * TODO: -make libalias mbuf aware (so
-	 * it can handle delayed checksum and tso)
-	 */
-
-	if (mcl->m_pkthdr.rcvif == NULL &&
-	    mcl->m_pkthdr.csum_flags & CSUM_DELAY_DATA)
-		ldt = 1;
-
-	c = mtod(mcl, char *);
-
-	/* Check if this is 'global' instance */
-	if (t == NULL) {
-		if (args->oif == NULL) {
-			/* Wrong direction, skip processing */
-			args->m = mcl;
-			return (IP_FW_NAT);
-		}
-
-		found = 0;
-		chain = &V_layer3_chain;
-		IPFW_RLOCK_ASSERT(chain);
-		/* Check every nat entry... */
-		LIST_FOREACH(t, &chain->nat, _next) {
-			if ((t->mode & PKT_ALIAS_SKIP_GLOBAL) != 0)
-				continue;
-			retval = LibAliasOutTry(t->lib, c,
-			    mcl->m_len + M_TRAILINGSPACE(mcl), 0);
-			if (retval == PKT_ALIAS_OK) {
-				/* Nat instance recognises state */
-				found = 1;
-				break;
-			}
-		}
-		if (found != 1) {
-			/* No instance found, return ignore */
-			args->m = mcl;
-			return (IP_FW_NAT);
-		}
-	} else {
-		if (args->oif == NULL)
-			retval = LibAliasIn(t->lib, c,
-				mcl->m_len + M_TRAILINGSPACE(mcl));
-		else
-			retval = LibAliasOut(t->lib, c,
-				mcl->m_len + M_TRAILINGSPACE(mcl));
-	}
-
-	/*
-	 * We drop packet when:
-	 * 1. libalias returns PKT_ALIAS_ERROR;
-	 * 2. For incoming packets:
-	 *	a) for unresolved fragments;
-	 *	b) libalias returns PKT_ALIAS_IGNORED and
-	 *		PKT_ALIAS_DENY_INCOMING flag is set.
-	 */
-	if (retval == PKT_ALIAS_ERROR ||
-	    (args->oif == NULL && (retval == PKT_ALIAS_UNRESOLVED_FRAGMENT ||
-	    (retval == PKT_ALIAS_IGNORED &&
-	    (t->mode & PKT_ALIAS_DENY_INCOMING) != 0)))) {
-		/* XXX - should i add some logging? */
-		m_free(mcl);
-		args->m = NULL;
-		return (IP_FW_DENY);
-	}
-
-	if (retval == PKT_ALIAS_RESPOND)
-		mcl->m_flags |= M_SKIP_FIREWALL;
-	mcl->m_pkthdr.len = mcl->m_len = ntohs(ip->ip_len);
-
-	/*
-	 * XXX - libalias checksum offload
-	 * 'duct tape' (see above)
-	 */
-
-	if ((ip->ip_off & htons(IP_OFFMASK)) == 0 &&
-	    ip->ip_p == IPPROTO_TCP) {
-		struct tcphdr 	*th;
-
-		th = (struct tcphdr *)(ip + 1);
-		if (th->th_x2)
-			ldt = 1;
-	}
-
-	if (ldt) {
-		struct tcphdr 	*th;
-		struct udphdr 	*uh;
-		uint16_t ip_len, cksum;
-
-		ip_len = ntohs(ip->ip_len);
-		cksum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr,
-		    htons(ip->ip_p + ip_len - (ip->ip_hl << 2)));
-
-		switch (ip->ip_p) {
-		case IPPROTO_TCP:
-			th = (struct tcphdr *)(ip + 1);
-			/*
-			 * Maybe it was set in
-			 * libalias...
-			 */
-			th->th_x2 = 0;
-			th->th_sum = cksum;
-			mcl->m_pkthdr.csum_data =
-			    offsetof(struct tcphdr, th_sum);
-			break;
-		case IPPROTO_UDP:
-			uh = (struct udphdr *)(ip + 1);
-			uh->uh_sum = cksum;
-			mcl->m_pkthdr.csum_data =
-			    offsetof(struct udphdr, uh_sum);
-			break;
-		}
-		/* No hw checksum offloading: do it ourselves */
-		if ((mcl->m_pkthdr.csum_flags & CSUM_DELAY_DATA) == 0) {
-			in_delayed_cksum(mcl);
-			mcl->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA;
-		}
-	}
-	args->m = mcl;
-	return (IP_FW_NAT);
-}
-
-static struct cfg_nat *
-lookup_nat(struct nat_list *l, int nat_id)
-{
-	struct cfg_nat *res;
-
-	LIST_FOREACH(res, l, _next) {
-		if (res->id == nat_id)
-			break;
-	}
-	return res;
-}
-
-static struct cfg_nat *
-lookup_nat_name(struct nat_list *l, char *name)
-{
-	struct cfg_nat *res;
-	int id;
-	char *errptr;
-
-	id = strtol(name, &errptr, 10);
-	if (id == 0 || *errptr != '\0')
-		return (NULL);
-
-	LIST_FOREACH(res, l, _next) {
-		if (res->id == id)
-			break;
-	}
-	return (res);
-}
-
-/* IP_FW3 configuration routines */
-
-static void
-nat44_config(struct ip_fw_chain *chain, struct nat44_cfg_nat *ucfg)
-{
-	struct cfg_nat *ptr, *tcfg;
-	int gencnt;
-
-	/*
-	 * Find/create nat rule.
-	 */
-	IPFW_UH_WLOCK(chain);
-	gencnt = chain->gencnt;
-	ptr = lookup_nat_name(&chain->nat, ucfg->name);
-	if (ptr == NULL) {
-		IPFW_UH_WUNLOCK(chain);
-		/* New rule: allocate and init new instance. */
-		ptr = malloc(sizeof(struct cfg_nat), M_IPFW, M_WAITOK | M_ZERO);
-		ptr->lib = LibAliasInit(NULL);
-		LIST_INIT(&ptr->redir_chain);
-	} else {
-		/* Entry already present: temporarily unhook it. */
-		IPFW_WLOCK(chain);
-		LIST_REMOVE(ptr, _next);
-		flush_nat_ptrs(chain, ptr->id);
-		IPFW_WUNLOCK(chain);
-		IPFW_UH_WUNLOCK(chain);
-	}
-
-	/*
-	 * Basic nat (re)configuration.
-	 */
-	ptr->id = strtol(ucfg->name, NULL, 10);
-	/*
-	 * XXX - what if this rule doesn't nat any ip and just
-	 * redirect?
-	 * do we set aliasaddress to 0.0.0.0?
-	 */
-	ptr->ip = ucfg->ip;
-	ptr->redir_cnt = ucfg->redir_cnt;
-	ptr->mode = ucfg->mode;
-	strlcpy(ptr->if_name, ucfg->if_name, sizeof(ptr->if_name));
-	LibAliasSetMode(ptr->lib, ptr->mode, ~0);
-	LibAliasSetAddress(ptr->lib, ptr->ip);
-
-	/*
-	 * Redir and LSNAT configuration.
-	 */
-	/* Delete old cfgs. */
-	del_redir_spool_cfg(ptr, &ptr->redir_chain);
-	/* Add new entries. */
-	add_redir_spool_cfg((char *)(ucfg + 1), ptr);
-	IPFW_UH_WLOCK(chain);
-
-	/* Extra check to avoid race with another ipfw_nat_cfg() */
-	tcfg = NULL;
-	if (gencnt != chain->gencnt)
-	    tcfg = lookup_nat_name(&chain->nat, ucfg->name);
-	IPFW_WLOCK(chain);
-	if (tcfg != NULL)
-		LIST_REMOVE(tcfg, _next);
-	LIST_INSERT_HEAD(&chain->nat, ptr, _next);
-	IPFW_WUNLOCK(chain);
-	chain->gencnt++;
-
-	IPFW_UH_WUNLOCK(chain);
-
-	if (tcfg != NULL)
-		free_nat_instance(ptr);
-}
-
-/*
- * Creates/configure nat44 instance
- * Data layout (v0)(current):
- * Request: [ ipfw_obj_header nat44_cfg_nat .. ]
- *
- * Returns 0 on success
- */
-static int
-nat44_cfg(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
-    struct sockopt_data *sd)
-{
-	ipfw_obj_header *oh;
-	struct nat44_cfg_nat *ucfg;
-	int id;
-	size_t read;
-	char *errptr;
-
-	/* Check minimum header size */
-	if (sd->valsize < (sizeof(*oh) + sizeof(*ucfg)))
-		return (EINVAL);
-
-	oh = (ipfw_obj_header *)sd->kbuf;
-
-	/* Basic length checks for TLVs */
-	if (oh->ntlv.head.length != sizeof(oh->ntlv))
-		return (EINVAL);
-
-	ucfg = (struct nat44_cfg_nat *)(oh + 1);
-
-	/* Check if name is properly terminated and looks like number */
-	if (strnlen(ucfg->name, sizeof(ucfg->name)) == sizeof(ucfg->name))
-		return (EINVAL);
-	id = strtol(ucfg->name, &errptr, 10);
-	if (id == 0 || *errptr != '\0')
-		return (EINVAL);
-
-	read = sizeof(*oh) + sizeof(*ucfg);
-	/* Check number of redirs */
-	if (sd->valsize < read + ucfg->redir_cnt*sizeof(struct nat44_cfg_redir))
-		return (EINVAL);
-
-	nat44_config(chain, ucfg);
-	return (0);
-}
-
-/*
- * Destroys given nat instances.
- * Data layout (v0)(current):
- * Request: [ ipfw_obj_header ]
- *
- * Returns 0 on success
- */
-static int
-nat44_destroy(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
-    struct sockopt_data *sd)
-{
-	ipfw_obj_header *oh;
-	struct cfg_nat *ptr;
-	ipfw_obj_ntlv *ntlv;
-
-	/* Check minimum header size */
-	if (sd->valsize < sizeof(*oh))
-		return (EINVAL);
-
-	oh = (ipfw_obj_header *)sd->kbuf;
-
-	/* Basic length checks for TLVs */
-	if (oh->ntlv.head.length != sizeof(oh->ntlv))
-		return (EINVAL);
-
-	ntlv = &oh->ntlv;
-	/* Check if name is properly terminated */
-	if (strnlen(ntlv->name, sizeof(ntlv->name)) == sizeof(ntlv->name))
-		return (EINVAL);
-
-	IPFW_UH_WLOCK(chain);
-	ptr = lookup_nat_name(&chain->nat, ntlv->name);
-	if (ptr == NULL) {
-		IPFW_UH_WUNLOCK(chain);
-		return (ESRCH);
-	}
-	IPFW_WLOCK(chain);
-	LIST_REMOVE(ptr, _next);
-	flush_nat_ptrs(chain, ptr->id);
-	IPFW_WUNLOCK(chain);
-	IPFW_UH_WUNLOCK(chain);
-
-	free_nat_instance(ptr);
-
-	return (0);
-}
-
-static void
-export_nat_cfg(struct cfg_nat *ptr, struct nat44_cfg_nat *ucfg)
-{
-
-	snprintf(ucfg->name, sizeof(ucfg->name), "%d", ptr->id);
-	ucfg->ip = ptr->ip;
-	ucfg->redir_cnt = ptr->redir_cnt;
-	ucfg->mode = ptr->mode;
-	strlcpy(ucfg->if_name, ptr->if_name, sizeof(ucfg->if_name));
-}
-
-/*
- * Gets config for given nat instance
- * Data layout (v0)(current):
- * Request: [ ipfw_obj_header nat44_cfg_nat .. ]
- *
- * Returns 0 on success
- */
-static int
-nat44_get_cfg(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
-    struct sockopt_data *sd)
-{
-	ipfw_obj_header *oh;
-	struct nat44_cfg_nat *ucfg;
-	struct cfg_nat *ptr;
-	struct cfg_redir *r;
-	struct cfg_spool *s;
-	struct nat44_cfg_redir *ser_r;
-	struct nat44_cfg_spool *ser_s;
-	size_t sz;
-
-	sz = sizeof(*oh) + sizeof(*ucfg);
-	/* Check minimum header size */
-	if (sd->valsize < sz)
-		return (EINVAL);
-
-	oh = (struct _ipfw_obj_header *)ipfw_get_sopt_header(sd, sz);
-
-	/* Basic length checks for TLVs */
-	if (oh->ntlv.head.length != sizeof(oh->ntlv))
-		return (EINVAL);
-
-	ucfg = (struct nat44_cfg_nat *)(oh + 1);
-
-	/* Check if name is properly terminated */
-	if (strnlen(ucfg->name, sizeof(ucfg->name)) == sizeof(ucfg->name))
-		return (EINVAL);
-
-	IPFW_UH_RLOCK(chain);
-	ptr = lookup_nat_name(&chain->nat, ucfg->name);
-	if (ptr == NULL) {
-		IPFW_UH_RUNLOCK(chain);
-		return (ESRCH);
-	}
-
-	export_nat_cfg(ptr, ucfg);
-	
-	/* Estimate memory amount */
-	sz = sizeof(ipfw_obj_header) + sizeof(struct nat44_cfg_nat);
-	LIST_FOREACH(r, &ptr->redir_chain, _next) {
-		sz += sizeof(struct nat44_cfg_redir);
-		LIST_FOREACH(s, &r->spool_chain, _next)
-			sz += sizeof(struct nat44_cfg_spool);
-	}
-
-	ucfg->size = sz;
-	if (sd->valsize < sz) {
-
-		/*
-		 * Submitted buffer size is not enough.
-		 * WE've already filled in @ucfg structure with
-		 * relevant info including size, so we
-		 * can return. Buffer will be flushed automatically.
-		 */
-		IPFW_UH_RUNLOCK(chain);
-		return (ENOMEM);
-	}
-
-	/* Size OK, let's copy data */
-	LIST_FOREACH(r, &ptr->redir_chain, _next) {
-		ser_r = (struct nat44_cfg_redir *)ipfw_get_sopt_space(sd,
-		    sizeof(*ser_r));
-		ser_r->mode = r->mode;
-		ser_r->laddr = r->laddr;
-		ser_r->paddr = r->paddr;
-		ser_r->raddr = r->raddr;
-		ser_r->lport = r->lport;
-		ser_r->pport = r->pport;
-		ser_r->rport = r->rport;
-		ser_r->pport_cnt = r->pport_cnt;
-		ser_r->rport_cnt = r->rport_cnt;
-		ser_r->proto = r->proto;
-		ser_r->spool_cnt = r->spool_cnt;
-
-		LIST_FOREACH(s, &r->spool_chain, _next) {
-			ser_s = (struct nat44_cfg_spool *)ipfw_get_sopt_space(
-			    sd, sizeof(*ser_s));
-
-			ser_s->addr = s->addr;
-			ser_s->port = s->port;
-		}
-	}
-
-	IPFW_UH_RUNLOCK(chain);
-
-	return (0);
-}
-
-/*
- * Lists all nat44 instances currently available in kernel.
- * Data layout (v0)(current):
- * Request: [ ipfw_obj_lheader ]
- * Reply: [ ipfw_obj_lheader nat44_cfg_nat x N ]
- *
- * Returns 0 on success
- */
-static int
-nat44_list_nat(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
-    struct sockopt_data *sd)
-{
-	ipfw_obj_lheader *olh;
-	struct nat44_cfg_nat *ucfg;
-	struct cfg_nat *ptr;
-	int nat_count;
-
-	/* Check minimum header size */
-	if (sd->valsize < sizeof(ipfw_obj_lheader))
-		return (EINVAL);
-
-	olh = (ipfw_obj_lheader *)ipfw_get_sopt_header(sd, sizeof(*olh));
-	IPFW_UH_RLOCK(chain);
-	nat_count = 0;
-	LIST_FOREACH(ptr, &chain->nat, _next)
-		nat_count++;
-
-	olh->count = nat_count;
-	olh->objsize = sizeof(struct nat44_cfg_nat);
-	olh->size = sizeof(*olh) + olh->count * olh->objsize;
-
-	if (sd->valsize < olh->size) {
-		IPFW_UH_RUNLOCK(chain);
-		return (ENOMEM);
-	}
-
-	LIST_FOREACH(ptr, &chain->nat, _next) {
-		ucfg = (struct nat44_cfg_nat *)ipfw_get_sopt_space(sd,
-		    sizeof(*ucfg));
-		export_nat_cfg(ptr, ucfg);
-	}
-
-	IPFW_UH_RUNLOCK(chain);
-
-	return (0);
-}
-
-/*
- * Gets log for given nat instance
- * Data layout (v0)(current):
- * Request: [ ipfw_obj_header nat44_cfg_nat ]
- * Reply: [ ipfw_obj_header nat44_cfg_nat LOGBUFFER ]
- *
- * Returns 0 on success
- */
-static int
-nat44_get_log(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
-    struct sockopt_data *sd)
-{
-	ipfw_obj_header *oh;
-	struct nat44_cfg_nat *ucfg;
-	struct cfg_nat *ptr;
-	void *pbuf;
-	size_t sz;
-
-	sz = sizeof(*oh) + sizeof(*ucfg);
-	/* Check minimum header size */
-	if (sd->valsize < sz)
-		return (EINVAL);
-
-	oh = (struct _ipfw_obj_header *)ipfw_get_sopt_header(sd, sz);
-
-	/* Basic length checks for TLVs */
-	if (oh->ntlv.head.length != sizeof(oh->ntlv))
-		return (EINVAL);
-
-	ucfg = (struct nat44_cfg_nat *)(oh + 1);
-
-	/* Check if name is properly terminated */
-	if (strnlen(ucfg->name, sizeof(ucfg->name)) == sizeof(ucfg->name))
-		return (EINVAL);
-
-	IPFW_UH_RLOCK(chain);
-	ptr = lookup_nat_name(&chain->nat, ucfg->name);
-	if (ptr == NULL) {
-		IPFW_UH_RUNLOCK(chain);
-		return (ESRCH);
-	}
-
-	if (ptr->lib->logDesc == NULL) {
-		IPFW_UH_RUNLOCK(chain);
-		return (ENOENT);
-	}
-
-	export_nat_cfg(ptr, ucfg);
-	
-	/* Estimate memory amount */
-	ucfg->size = sizeof(struct nat44_cfg_nat) + LIBALIAS_BUF_SIZE;
-	if (sd->valsize < sz + sizeof(*oh)) {
-
-		/*
-		 * Submitted buffer size is not enough.
-		 * WE've already filled in @ucfg structure with
-		 * relevant info including size, so we
-		 * can return. Buffer will be flushed automatically.
-		 */
-		IPFW_UH_RUNLOCK(chain);
-		return (ENOMEM);
-	}
-
-	pbuf = (void *)ipfw_get_sopt_space(sd, LIBALIAS_BUF_SIZE);
-	memcpy(pbuf, ptr->lib->logDesc, LIBALIAS_BUF_SIZE);
-	
-	IPFW_UH_RUNLOCK(chain);
-
-	return (0);
-}
-
-static struct ipfw_sopt_handler	scodes[] = {
-	{ IP_FW_NAT44_XCONFIG,	0,	HDIR_SET,	nat44_cfg },
-	{ IP_FW_NAT44_DESTROY,	0,	HDIR_SET,	nat44_destroy },
-	{ IP_FW_NAT44_XGETCONFIG,	0,	HDIR_GET,	nat44_get_cfg },
-	{ IP_FW_NAT44_LIST_NAT,	0,	HDIR_GET,	nat44_list_nat },
-	{ IP_FW_NAT44_XGETLOG,	0,	HDIR_GET,	nat44_get_log },
-};
-
-
-/*
- * Legacy configuration routines
- */
-
-struct cfg_spool_legacy {
-	LIST_ENTRY(cfg_spool_legacy)	_next;
-	struct in_addr			addr;
-	u_short				port;
-};
-
-struct cfg_redir_legacy {
-	LIST_ENTRY(cfg_redir)   _next;
-	u_int16_t               mode;
-	struct in_addr	        laddr;
-	struct in_addr	        paddr;
-	struct in_addr	        raddr;
-	u_short                 lport;
-	u_short                 pport;
-	u_short                 rport;
-	u_short                 pport_cnt;
-	u_short                 rport_cnt;
-	int                     proto;
-	struct alias_link       **alink;
-	u_int16_t               spool_cnt;
-	LIST_HEAD(, cfg_spool_legacy) spool_chain;
-};
-
-struct cfg_nat_legacy {
-	LIST_ENTRY(cfg_nat_legacy)	_next;
-	int				id;
-	struct in_addr			ip;
-	char				if_name[IF_NAMESIZE];
-	int				mode;
-	struct libalias			*lib;
-	int				redir_cnt;
-	LIST_HEAD(, cfg_redir_legacy)	redir_chain;
-};
-
-static int
-ipfw_nat_cfg(struct sockopt *sopt)
-{
-	struct cfg_nat_legacy *cfg;
-	struct nat44_cfg_nat *ucfg;
-	struct cfg_redir_legacy *rdir;
-	struct nat44_cfg_redir *urdir;
-	char *buf;
-	size_t len, len2;
-	int error, i;
-
-	len = sopt->sopt_valsize;
-	len2 = len + 128;
-
-	/*
-	 * Allocate 2x buffer to store converted structures.
-	 * new redir_cfg has shrunk, so we're sure that
-	 * new buffer size is enough.
-	 */
-	buf = malloc(roundup2(len, 8) + len2, M_TEMP, M_WAITOK | M_ZERO);
-	error = sooptcopyin(sopt, buf, len, sizeof(struct cfg_nat_legacy));
-	if (error != 0)
-		goto out;
-
-	cfg = (struct cfg_nat_legacy *)buf;
-	if (cfg->id < 0) {
-		error = EINVAL;
-		goto out;
-	}
-
-	ucfg = (struct nat44_cfg_nat *)&buf[roundup2(len, 8)];
-	snprintf(ucfg->name, sizeof(ucfg->name), "%d", cfg->id);
-	strlcpy(ucfg->if_name, cfg->if_name, sizeof(ucfg->if_name));
-	ucfg->ip = cfg->ip;
-	ucfg->mode = cfg->mode;
-	ucfg->redir_cnt = cfg->redir_cnt;
-
-	if (len < sizeof(*cfg) + cfg->redir_cnt * sizeof(*rdir)) {
-		error = EINVAL;
-		goto out;
-	}
-
-	urdir = (struct nat44_cfg_redir *)(ucfg + 1);
-	rdir = (struct cfg_redir_legacy *)(cfg + 1);
-	for (i = 0; i < cfg->redir_cnt; i++) {
-		urdir->mode = rdir->mode;
-		urdir->laddr = rdir->laddr;
-		urdir->paddr = rdir->paddr;
-		urdir->raddr = rdir->raddr;
-		urdir->lport = rdir->lport;
-		urdir->pport = rdir->pport;
-		urdir->rport = rdir->rport;
-		urdir->pport_cnt = rdir->pport_cnt;
-		urdir->rport_cnt = rdir->rport_cnt;
-		urdir->proto = rdir->proto;
-		urdir->spool_cnt = rdir->spool_cnt;
-
-		urdir++;
-		rdir++;
-	}
-
-	nat44_config(&V_layer3_chain, ucfg);
-
-out:
-	free(buf, M_TEMP);
-	return (error);
-}
-
-static int
-ipfw_nat_del(struct sockopt *sopt)
-{
-	struct cfg_nat *ptr;
-	struct ip_fw_chain *chain = &V_layer3_chain;
-	int i;
-
-	sooptcopyin(sopt, &i, sizeof i, sizeof i);
-	/* XXX validate i */
-	IPFW_UH_WLOCK(chain);
-	ptr = lookup_nat(&chain->nat, i);
-	if (ptr == NULL) {
-		IPFW_UH_WUNLOCK(chain);
-		return (EINVAL);
-	}
-	IPFW_WLOCK(chain);
-	LIST_REMOVE(ptr, _next);
-	flush_nat_ptrs(chain, i);
-	IPFW_WUNLOCK(chain);
-	IPFW_UH_WUNLOCK(chain);
-	free_nat_instance(ptr);
-	return (0);
-}
-
-static int
-ipfw_nat_get_cfg(struct sockopt *sopt)
-{
-	struct ip_fw_chain *chain = &V_layer3_chain;
-	struct cfg_nat *n;
-	struct cfg_nat_legacy *ucfg;
-	struct cfg_redir *r;
-	struct cfg_spool *s;
-	struct cfg_redir_legacy *ser_r;
-	struct cfg_spool_legacy *ser_s;
-	char *data;
-	int gencnt, nat_cnt, len, error;
-
-	nat_cnt = 0;
-	len = sizeof(nat_cnt);
-
-	IPFW_UH_RLOCK(chain);
-retry:
-	gencnt = chain->gencnt;
-	/* Estimate memory amount */
-	LIST_FOREACH(n, &chain->nat, _next) {
-		nat_cnt++;
-		len += sizeof(struct cfg_nat_legacy);
-		LIST_FOREACH(r, &n->redir_chain, _next) {
-			len += sizeof(struct cfg_redir_legacy);
-			LIST_FOREACH(s, &r->spool_chain, _next)
-				len += sizeof(struct cfg_spool_legacy);
-		}
-	}
-	IPFW_UH_RUNLOCK(chain);
-
-	data = malloc(len, M_TEMP, M_WAITOK | M_ZERO);
-	bcopy(&nat_cnt, data, sizeof(nat_cnt));
-
-	nat_cnt = 0;
-	len = sizeof(nat_cnt);
-
-	IPFW_UH_RLOCK(chain);
-	if (gencnt != chain->gencnt) {
-		free(data, M_TEMP);
-		goto retry;
-	}
-	/* Serialize all the data. */
-	LIST_FOREACH(n, &chain->nat, _next) {
-		ucfg = (struct cfg_nat_legacy *)&data[len];
-		ucfg->id = n->id;
-		ucfg->ip = n->ip;
-		ucfg->redir_cnt = n->redir_cnt;
-		ucfg->mode = n->mode;
-		strlcpy(ucfg->if_name, n->if_name, sizeof(ucfg->if_name));
-		len += sizeof(struct cfg_nat_legacy);
-		LIST_FOREACH(r, &n->redir_chain, _next) {
-			ser_r = (struct cfg_redir_legacy *)&data[len];
-			ser_r->mode = r->mode;
-			ser_r->laddr = r->laddr;
-			ser_r->paddr = r->paddr;
-			ser_r->raddr = r->raddr;
-			ser_r->lport = r->lport;
-			ser_r->pport = r->pport;
-			ser_r->rport = r->rport;
-			ser_r->pport_cnt = r->pport_cnt;
-			ser_r->rport_cnt = r->rport_cnt;
-			ser_r->proto = r->proto;
-			ser_r->spool_cnt = r->spool_cnt;
-			len += sizeof(struct cfg_redir_legacy);
-			LIST_FOREACH(s, &r->spool_chain, _next) {
-				ser_s = (struct cfg_spool_legacy *)&data[len];
-				ser_s->addr = s->addr;
-				ser_s->port = s->port;
-				len += sizeof(struct cfg_spool_legacy);
-			}
-		}
-	}
-	IPFW_UH_RUNLOCK(chain);
-
-	error = sooptcopyout(sopt, data, len);
-	free(data, M_TEMP);
-
-	return (error);
-}
-
-static int
-ipfw_nat_get_log(struct sockopt *sopt)
-{
-	uint8_t *data;
-	struct cfg_nat *ptr;
-	int i, size;
-	struct ip_fw_chain *chain;
-	IPFW_RLOCK_TRACKER;
-
-	chain = &V_layer3_chain;
-
-	IPFW_RLOCK(chain);
-	/* one pass to count, one to copy the data */
-	i = 0;
-	LIST_FOREACH(ptr, &chain->nat, _next) {
-		if (ptr->lib->logDesc == NULL)
-			continue;
-		i++;
-	}
-	size = i * (LIBALIAS_BUF_SIZE + sizeof(int));
-	data = malloc(size, M_IPFW, M_NOWAIT | M_ZERO);
-	if (data == NULL) {
-		IPFW_RUNLOCK(chain);
-		return (ENOSPC);
-	}
-	i = 0;
-	LIST_FOREACH(ptr, &chain->nat, _next) {
-		if (ptr->lib->logDesc == NULL)
-			continue;
-		bcopy(&ptr->id, &data[i], sizeof(int));
-		i += sizeof(int);
-		bcopy(ptr->lib->logDesc, &data[i], LIBALIAS_BUF_SIZE);
-		i += LIBALIAS_BUF_SIZE;
-	}
-	IPFW_RUNLOCK(chain);
-	sooptcopyout(sopt, data, size);
-	free(data, M_IPFW);
-	return(0);
-}
-
-static int
-vnet_ipfw_nat_init(const void *arg __unused)
-{
-
-	V_ipfw_nat_ready = 1;
-	return (0);
-}
-
-static int
-vnet_ipfw_nat_uninit(const void *arg __unused)
-{
-	struct cfg_nat *ptr, *ptr_temp;
-	struct ip_fw_chain *chain;
-
-	chain = &V_layer3_chain;
-	IPFW_WLOCK(chain);
-	V_ipfw_nat_ready = 0;
-	LIST_FOREACH_SAFE(ptr, &chain->nat, _next, ptr_temp) {
-		LIST_REMOVE(ptr, _next);
-		free_nat_instance(ptr);
-	}
-	flush_nat_ptrs(chain, -1 /* flush all */);
-	IPFW_WUNLOCK(chain);
-	return (0);
-}
-
-static void
-ipfw_nat_init(void)
-{
-
-	/* init ipfw hooks */
-	ipfw_nat_ptr = ipfw_nat;
-	lookup_nat_ptr = lookup_nat;
-	ipfw_nat_cfg_ptr = ipfw_nat_cfg;
-	ipfw_nat_del_ptr = ipfw_nat_del;
-	ipfw_nat_get_cfg_ptr = ipfw_nat_get_cfg;
-	ipfw_nat_get_log_ptr = ipfw_nat_get_log;
-	IPFW_ADD_SOPT_HANDLER(1, scodes);
-
-	ifaddr_event_tag = EVENTHANDLER_REGISTER(ifaddr_event, ifaddr_change,
-	    NULL, EVENTHANDLER_PRI_ANY);
-}
-
-static void
-ipfw_nat_destroy(void)
-{
-
-	EVENTHANDLER_DEREGISTER(ifaddr_event, ifaddr_event_tag);
-	/* deregister ipfw_nat */
-	IPFW_DEL_SOPT_HANDLER(1, scodes);
-	ipfw_nat_ptr = NULL;
-	lookup_nat_ptr = NULL;
-	ipfw_nat_cfg_ptr = NULL;
-	ipfw_nat_del_ptr = NULL;
-	ipfw_nat_get_cfg_ptr = NULL;
-	ipfw_nat_get_log_ptr = NULL;
-}
-
-static int
-ipfw_nat_modevent(module_t mod, int type, void *unused)
-{
-	int err = 0;
-
-	switch (type) {
-	case MOD_LOAD:
-		break;
-
-	case MOD_UNLOAD:
-		break;
-
-	default:
-		return EOPNOTSUPP;
-		break;
-	}
-	return err;
-}
-
-static moduledata_t ipfw_nat_mod = {
-	"ipfw_nat",
-	ipfw_nat_modevent,
-	0
-};
-
-/* Define startup order. */
-#define	IPFW_NAT_SI_SUB_FIREWALL	SI_SUB_PROTO_FIREWALL
-#define	IPFW_NAT_MODEVENT_ORDER		(SI_ORDER_ANY - 128) /* after ipfw */
-#define	IPFW_NAT_MODULE_ORDER		(IPFW_NAT_MODEVENT_ORDER + 1)
-#define	IPFW_NAT_VNET_ORDER		(IPFW_NAT_MODEVENT_ORDER + 2)
-
-DECLARE_MODULE(ipfw_nat, ipfw_nat_mod, IPFW_NAT_SI_SUB_FIREWALL, SI_ORDER_ANY);
-MODULE_DEPEND(ipfw_nat, libalias, 1, 1, 1);
-MODULE_DEPEND(ipfw_nat, ipfw, 3, 3, 3);
-MODULE_VERSION(ipfw_nat, 1);
-
-SYSINIT(ipfw_nat_init, IPFW_NAT_SI_SUB_FIREWALL, IPFW_NAT_MODULE_ORDER,
-    ipfw_nat_init, NULL);
-VNET_SYSINIT(vnet_ipfw_nat_init, IPFW_NAT_SI_SUB_FIREWALL, IPFW_NAT_VNET_ORDER,
-    vnet_ipfw_nat_init, NULL);
-
-SYSUNINIT(ipfw_nat_destroy, IPFW_NAT_SI_SUB_FIREWALL, IPFW_NAT_MODULE_ORDER,
-    ipfw_nat_destroy, NULL);
-VNET_SYSUNINIT(vnet_ipfw_nat_uninit, IPFW_NAT_SI_SUB_FIREWALL,
-    IPFW_NAT_VNET_ORDER, vnet_ipfw_nat_uninit, NULL);
-
-/* end of file */
Index: eebsd/sys/netpfil/ipfw/ip_fw_pfil.c
===================================================================
--- freebsd/sys/netpfil/ipfw/ip_fw_pfil.c	(revision f62c62d2fe57ec02c1350144f7739f8e866ee6d4)
+++ 	(revision )
@@ -1,582 +1,0 @@
-#include <machine/rtems-bsd-kernel-space.h>
-
-/*-
- * Copyright (c) 2004 Andre Oppermann, Internet Business Solutions AG
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include <rtems/bsd/local/opt_ipfw.h>
-#include <rtems/bsd/local/opt_inet.h>
-#include <rtems/bsd/local/opt_inet6.h>
-#ifndef INET
-#error IPFIREWALL requires INET.
-#endif /* INET */
-
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/malloc.h>
-#include <sys/mbuf.h>
-#include <sys/module.h>
-#include <sys/kernel.h>
-#include <sys/lock.h>
-#include <sys/rwlock.h>
-#include <sys/socket.h>
-#include <sys/sysctl.h>
-
-#include <net/if.h>
-#include <net/route.h>
-#include <net/ethernet.h>
-#include <net/pfil.h>
-#include <net/vnet.h>
-
-#include <netinet/in.h>
-#include <netinet/in_systm.h>
-#include <netinet/ip.h>
-#include <netinet/ip_var.h>
-#include <netinet/ip_fw.h>
-#ifdef INET6
-#include <netinet/ip6.h>
-#include <netinet6/ip6_var.h>
-#include <netinet6/scope6_var.h>
-#endif
-
-#include <netgraph/ng_ipfw.h>
-
-#include <netpfil/ipfw/ip_fw_private.h>
-
-#include <machine/in_cksum.h>
-
-static VNET_DEFINE(int, fw_enable) = 1;
-#define V_fw_enable	VNET(fw_enable)
-
-#ifdef INET6
-static VNET_DEFINE(int, fw6_enable) = 1;
-#define V_fw6_enable	VNET(fw6_enable)
-#endif
-
-static VNET_DEFINE(int, fwlink_enable) = 0;
-#define V_fwlink_enable	VNET(fwlink_enable)
-
-int ipfw_chg_hook(SYSCTL_HANDLER_ARGS);
-
-/* Forward declarations. */
-static int ipfw_divert(struct mbuf **, int, struct ipfw_rule_ref *, int);
-int ipfw_check_packet(void *, struct mbuf **, struct ifnet *, int,
-	struct inpcb *);
-int ipfw_check_frame(void *, struct mbuf **, struct ifnet *, int,
-	struct inpcb *);
-
-#ifdef SYSCTL_NODE
-
-SYSBEGIN(f1)
-
-SYSCTL_DECL(_net_inet_ip_fw);
-SYSCTL_PROC(_net_inet_ip_fw, OID_AUTO, enable,
-    CTLFLAG_VNET | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_SECURE3,
-    &VNET_NAME(fw_enable), 0, ipfw_chg_hook, "I", "Enable ipfw");
-#ifdef INET6
-SYSCTL_DECL(_net_inet6_ip6_fw);
-SYSCTL_PROC(_net_inet6_ip6_fw, OID_AUTO, enable,
-    CTLFLAG_VNET | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_SECURE3,
-    &VNET_NAME(fw6_enable), 0, ipfw_chg_hook, "I", "Enable ipfw+6");
-#endif /* INET6 */
-
-SYSCTL_DECL(_net_link_ether);
-SYSCTL_PROC(_net_link_ether, OID_AUTO, ipfw,
-    CTLFLAG_VNET | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_SECURE3,
-    &VNET_NAME(fwlink_enable), 0, ipfw_chg_hook, "I",
-    "Pass ether pkts through firewall");
-
-SYSEND
-
-#endif /* SYSCTL_NODE */
-
-/*
- * The pfilter hook to pass packets to ipfw_chk and then to
- * dummynet, divert, netgraph or other modules.
- * The packet may be consumed.
- */
-int
-ipfw_check_packet(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir,
-    struct inpcb *inp)
-{
-	struct ip_fw_args args;
-	struct m_tag *tag;
-	int ipfw;
-	int ret;
-
-	/* convert dir to IPFW values */
-	dir = (dir == PFIL_IN) ? DIR_IN : DIR_OUT;
-	bzero(&args, sizeof(args));
-
-again:
-	/*
-	 * extract and remove the tag if present. If we are left
-	 * with onepass, optimize the outgoing path.
-	 */
-	tag = m_tag_locate(*m0, MTAG_IPFW_RULE, 0, NULL);
-	if (tag != NULL) {
-		args.rule = *((struct ipfw_rule_ref *)(tag+1));
-		m_tag_delete(*m0, tag);
-		if (args.rule.info & IPFW_ONEPASS)
-			return (0);
-	}
-
-	args.m = *m0;
-	args.oif = dir == DIR_OUT ? ifp : NULL;
-	args.inp = inp;
-
-	ipfw = ipfw_chk(&args);
-	*m0 = args.m;
-
-	KASSERT(*m0 != NULL || ipfw == IP_FW_DENY, ("%s: m0 is NULL",
-	    __func__));
-
-	/* breaking out of the switch means drop */
-	ret = 0;	/* default return value for pass */
-	switch (ipfw) {
-	case IP_FW_PASS:
-		/* next_hop may be set by ipfw_chk */
-		if (args.next_hop == NULL && args.next_hop6 == NULL)
-			break; /* pass */
-#if (!defined(INET6) && !defined(INET))
-		ret = EACCES;
-#else
-	    {
-		struct m_tag *fwd_tag;
-		size_t len;
-
-		KASSERT(args.next_hop == NULL || args.next_hop6 == NULL,
-		    ("%s: both next_hop=%p and next_hop6=%p not NULL", __func__,
-		     args.next_hop, args.next_hop6));
-#ifdef INET6
-		if (args.next_hop6 != NULL)
-			len = sizeof(struct sockaddr_in6);
-#endif
-#ifdef INET
-		if (args.next_hop != NULL)
-			len = sizeof(struct sockaddr_in);
-#endif
-
-		/* Incoming packets should not be tagged so we do not
-		 * m_tag_find. Outgoing packets may be tagged, so we
-		 * reuse the tag if present.
-		 */
-		fwd_tag = (dir == DIR_IN) ? NULL :
-			m_tag_find(*m0, PACKET_TAG_IPFORWARD, NULL);
-		if (fwd_tag != NULL) {
-			m_tag_unlink(*m0, fwd_tag);
-		} else {
-			fwd_tag = m_tag_get(PACKET_TAG_IPFORWARD, len,
-			    M_NOWAIT);
-			if (fwd_tag == NULL) {
-				ret = EACCES;
-				break; /* i.e. drop */
-			}
-		}
-#ifdef INET6
-		if (args.next_hop6 != NULL) {
-			struct sockaddr_in6 *sa6;
-
-			sa6 = (struct sockaddr_in6 *)(fwd_tag + 1);
-			bcopy(args.next_hop6, sa6, len);
-			/*
-			 * If nh6 address is link-local we should convert
-			 * it to kernel internal form before doing any
-			 * comparisons.
-			 */
-			if (sa6_embedscope(sa6, V_ip6_use_defzone) != 0) {
-				ret = EACCES;
-				break;
-			}
-			if (in6_localip(&sa6->sin6_addr))
-				(*m0)->m_flags |= M_FASTFWD_OURS;
-			(*m0)->m_flags |= M_IP6_NEXTHOP;
-		}
-#endif
-#ifdef INET
-		if (args.next_hop != NULL) {
-			bcopy(args.next_hop, (fwd_tag+1), len);
-			if (in_localip(args.next_hop->sin_addr))
-				(*m0)->m_flags |= M_FASTFWD_OURS;
-			(*m0)->m_flags |= M_IP_NEXTHOP;
-		}
-#endif
-		m_tag_prepend(*m0, fwd_tag);
-	    }
-#endif /* INET || INET6 */
-		break;
-
-	case IP_FW_DENY:
-		ret = EACCES;
-		break; /* i.e. drop */
-
-	case IP_FW_DUMMYNET:
-		ret = EACCES;
-		if (ip_dn_io_ptr == NULL)
-			break; /* i.e. drop */
-		if (mtod(*m0, struct ip *)->ip_v == 4)
-			ret = ip_dn_io_ptr(m0, dir, &args);
-		else if (mtod(*m0, struct ip *)->ip_v == 6)
-			ret = ip_dn_io_ptr(m0, dir | PROTO_IPV6, &args);
-		else
-			break; /* drop it */
-		/*
-		 * XXX should read the return value.
-		 * dummynet normally eats the packet and sets *m0=NULL
-		 * unless the packet can be sent immediately. In this
-		 * case args is updated and we should re-run the
-		 * check without clearing args.
-		 */
-		if (*m0 != NULL)
-			goto again;
-		break;
-
-	case IP_FW_TEE:
-	case IP_FW_DIVERT:
-		if (ip_divert_ptr == NULL) {
-			ret = EACCES;
-			break; /* i.e. drop */
-		}
-		ret = ipfw_divert(m0, dir, &args.rule,
-			(ipfw == IP_FW_TEE) ? 1 : 0);
-		/* continue processing for the original packet (tee). */
-		if (*m0)
-			goto again;
-		break;
-
-	case IP_FW_NGTEE:
-	case IP_FW_NETGRAPH:
-		if (ng_ipfw_input_p == NULL) {
-			ret = EACCES;
-			break; /* i.e. drop */
-		}
-		ret = ng_ipfw_input_p(m0, dir, &args,
-			(ipfw == IP_FW_NGTEE) ? 1 : 0);
-		if (ipfw == IP_FW_NGTEE) /* ignore errors for NGTEE */
-			goto again;	/* continue with packet */
-		break;
-
-	case IP_FW_NAT:
-		/* honor one-pass in case of successful nat */
-		if (V_fw_one_pass)
-			break; /* ret is already 0 */
-		goto again;
-
-	case IP_FW_REASS:
-		goto again;		/* continue with packet */
-	
-	default:
-		KASSERT(0, ("%s: unknown retval", __func__));
-	}
-
-	if (ret != 0) {
-		if (*m0)
-			FREE_PKT(*m0);
-		*m0 = NULL;
-	}
-
-	return ret;
-}
-
-/*
- * ipfw processing for ethernet packets (in and out).
- */
-int
-ipfw_check_frame(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir,
-    struct inpcb *inp)
-{
-	struct ether_header *eh;
-	struct ether_header save_eh;
-	struct mbuf *m;
-	int i, ret;
-	struct ip_fw_args args;
-	struct m_tag *mtag;
-
-	/* fetch start point from rule, if any.  remove the tag if present. */
-	mtag = m_tag_locate(*m0, MTAG_IPFW_RULE, 0, NULL);
-	if (mtag == NULL) {
-		args.rule.slot = 0;
-	} else {
-		args.rule = *((struct ipfw_rule_ref *)(mtag+1));
-		m_tag_delete(*m0, mtag);
-		if (args.rule.info & IPFW_ONEPASS)
-			return (0);
-	}
-
-	/* I need some amt of data to be contiguous */
-	m = *m0;
-	i = min(m->m_pkthdr.len, max_protohdr);
-	if (m->m_len < i) {
-		m = m_pullup(m, i);
-		if (m == NULL) {
-			*m0 = m;
-			return (0);
-		}
-	}
-	eh = mtod(m, struct ether_header *);
-	save_eh = *eh;			/* save copy for restore below */
-	m_adj(m, ETHER_HDR_LEN);	/* strip ethernet header */
-
-	args.m = m;		/* the packet we are looking at		*/
-	args.oif = dir == PFIL_OUT ? ifp: NULL;	/* destination, if any	*/
-	args.next_hop = NULL;	/* we do not support forward yet	*/
-	args.next_hop6 = NULL;	/* we do not support forward yet	*/
-	args.eh = &save_eh;	/* MAC header for bridged/MAC packets	*/
-	args.inp = NULL;	/* used by ipfw uid/gid/jail rules	*/
-	i = ipfw_chk(&args);
-	m = args.m;
-	if (m != NULL) {
-		/*
-		 * Restore Ethernet header, as needed, in case the
-		 * mbuf chain was replaced by ipfw.
-		 */
-		M_PREPEND(m, ETHER_HDR_LEN, M_NOWAIT);
-		if (m == NULL) {
-			*m0 = NULL;
-			return (0);
-		}
-		if (eh != mtod(m, struct ether_header *))
-			bcopy(&save_eh, mtod(m, struct ether_header *),
-				ETHER_HDR_LEN);
-	}
-	*m0 = m;
-
-	ret = 0;
-	/* Check result of ipfw_chk() */
-	switch (i) {
-	case IP_FW_PASS:
-		break;
-
-	case IP_FW_DENY:
-		ret = EACCES;
-		break; /* i.e. drop */
-
-	case IP_FW_DUMMYNET:
-		ret = EACCES;
-
-		if (ip_dn_io_ptr == NULL)
-			break; /* i.e. drop */
-
-		*m0 = NULL;
-		dir = (dir == PFIL_IN) ? DIR_IN : DIR_OUT;
-		ip_dn_io_ptr(&m, dir | PROTO_LAYER2, &args);
-		return 0;
-
-	default:
-		KASSERT(0, ("%s: unknown retval", __func__));
-	}
-
-	if (ret != 0) {
-		if (*m0)
-			FREE_PKT(*m0);
-		*m0 = NULL;
-	}
-
-	return ret;
-}
-
-/* do the divert, return 1 on error 0 on success */
-static int
-ipfw_divert(struct mbuf **m0, int incoming, struct ipfw_rule_ref *rule,
-	int tee)
-{
-	/*
-	 * ipfw_chk() has already tagged the packet with the divert tag.
-	 * If tee is set, copy packet and return original.
-	 * If not tee, consume packet and send it to divert socket.
-	 */
-	struct mbuf *clone;
-	struct ip *ip = mtod(*m0, struct ip *);
-	struct m_tag *tag;
-
-	/* Cloning needed for tee? */
-	if (tee == 0) {
-		clone = *m0;	/* use the original mbuf */
-		*m0 = NULL;
-	} else {
-		clone = m_dup(*m0, M_NOWAIT);
-		/* If we cannot duplicate the mbuf, we sacrifice the divert
-		 * chain and continue with the tee-ed packet.
-		 */
-		if (clone == NULL)
-			return 1;
-	}
-
-	/*
-	 * Divert listeners can normally handle non-fragmented packets,
-	 * but we can only reass in the non-tee case.
-	 * This means that listeners on a tee rule may get fragments,
-	 * and have to live with that.
-	 * Note that we now have the 'reass' ipfw option so if we care
-	 * we can do it before a 'tee'.
-	 */
-	if (!tee) switch (ip->ip_v) {
-	case IPVERSION:
-	    if (ntohs(ip->ip_off) & (IP_MF | IP_OFFMASK)) {
-		int hlen;
-		struct mbuf *reass;
-
-		reass = ip_reass(clone); /* Reassemble packet. */
-		if (reass == NULL)
-			return 0; /* not an error */
-		/* if reass = NULL then it was consumed by ip_reass */
-		/*
-		 * IP header checksum fixup after reassembly and leave header
-		 * in network byte order.
-		 */
-		ip = mtod(reass, struct ip *);
-		hlen = ip->ip_hl << 2;
-		ip->ip_sum = 0;
-		if (hlen == sizeof(struct ip))
-			ip->ip_sum = in_cksum_hdr(ip);
-		else
-			ip->ip_sum = in_cksum(reass, hlen);
-		clone = reass;
-	    }
-	    break;
-#ifdef INET6
-	case IPV6_VERSION >> 4:
-	    {
-	    struct ip6_hdr *const ip6 = mtod(clone, struct ip6_hdr *);
-
-		if (ip6->ip6_nxt == IPPROTO_FRAGMENT) {
-			int nxt, off;
-
-			off = sizeof(struct ip6_hdr);
-			nxt = frag6_input(&clone, &off, 0);
-			if (nxt == IPPROTO_DONE)
-				return (0);
-		}
-		break;
-	    }
-#endif
-	}
-
-	/* attach a tag to the packet with the reinject info */
-	tag = m_tag_alloc(MTAG_IPFW_RULE, 0,
-		    sizeof(struct ipfw_rule_ref), M_NOWAIT);
-	if (tag == NULL) {
-		FREE_PKT(clone);
-		return 1;
-	}
-	*((struct ipfw_rule_ref *)(tag+1)) = *rule;
-	m_tag_prepend(clone, tag);
-
-	/* Do the dirty job... */
-	ip_divert_ptr(clone, incoming);
-	return 0;
-}
-
-/*
- * attach or detach hooks for a given protocol family
- */
-static int
-ipfw_hook(int onoff, int pf)
-{
-	struct pfil_head *pfh;
-	pfil_func_t hook_func;
-
-	pfh = pfil_head_get(PFIL_TYPE_AF, pf);
-	if (pfh == NULL)
-		return ENOENT;
-
-	hook_func = (pf == AF_LINK) ? ipfw_check_frame : ipfw_check_packet;
-
-	(void) (onoff ? pfil_add_hook : pfil_remove_hook)
-	    (hook_func, NULL, PFIL_IN | PFIL_OUT | PFIL_WAITOK, pfh);
-
-	return 0;
-}
-
-int
-ipfw_attach_hooks(int arg)
-{
-	int error = 0;
-
-	if (arg == 0) /* detach */
-		ipfw_hook(0, AF_INET);
-	else if (V_fw_enable && ipfw_hook(1, AF_INET) != 0) {
-                error = ENOENT; /* see ip_fw_pfil.c::ipfw_hook() */
-                printf("ipfw_hook() error\n");
-        }
-#ifdef INET6
-	if (arg == 0) /* detach */
-		ipfw_hook(0, AF_INET6);
-	else if (V_fw6_enable && ipfw_hook(1, AF_INET6) != 0) {
-                error = ENOENT;
-                printf("ipfw6_hook() error\n");
-        }
-#endif
-	if (arg == 0) /* detach */
-		ipfw_hook(0, AF_LINK);
-	else if (V_fwlink_enable && ipfw_hook(1, AF_LINK) != 0) {
-                error = ENOENT;
-                printf("ipfw_link_hook() error\n");
-        }
-	return error;
-}
-
-int
-ipfw_chg_hook(SYSCTL_HANDLER_ARGS)
-{
-	int newval;
-	int error;
-	int af;
-
-	if (arg1 == &V_fw_enable)
-		af = AF_INET;
-#ifdef INET6
-	else if (arg1 == &V_fw6_enable)
-		af = AF_INET6;
-#endif
-	else if (arg1 == &V_fwlink_enable)
-		af = AF_LINK;
-	else 
-		return (EINVAL);
-
-	newval = *(int *)arg1;
-	/* Handle sysctl change */
-	error = sysctl_handle_int(oidp, &newval, 0, req);
-
-	if (error)
-		return (error);
-
-	/* Formalize new value */
-	newval = (newval) ? 1 : 0;
-
-	if (*(int *)arg1 == newval)
-		return (0);
-
-	error = ipfw_hook(newval, af);
-	if (error)
-		return (error);
-	*(int *)arg1 = newval;
-
-	return (0);
-}
-/* end of file */
Index: eebsd/sys/netpfil/ipfw/ip_fw_sockopt.c
===================================================================
--- freebsd/sys/netpfil/ipfw/ip_fw_sockopt.c	(revision f62c62d2fe57ec02c1350144f7739f8e866ee6d4)
+++ 	(revision )
@@ -1,4630 +1,0 @@
-#include <machine/rtems-bsd-kernel-space.h>
-
-/*-
- * Copyright (c) 2002-2009 Luigi Rizzo, Universita` di Pisa
- * Copyright (c) 2014 Yandex LLC
- * Copyright (c) 2014 Alexander V. Chernikov
- *
- * Supported by: Valeria Paoli
- *
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-/*
- * Control socket and rule management routines for ipfw.
- * Control is currently implemented via IP_FW3 setsockopt() code.
- */
-
-#include <rtems/bsd/local/opt_ipfw.h>
-#include <rtems/bsd/local/opt_inet.h>
-#ifndef INET
-#error IPFIREWALL requires INET.
-#endif /* INET */
-#include <rtems/bsd/local/opt_inet6.h>
-
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/malloc.h>
-#include <sys/mbuf.h>	/* struct m_tag used by nested headers */
-#include <sys/kernel.h>
-#include <sys/lock.h>
-#include <sys/priv.h>
-#include <sys/proc.h>
-#include <sys/rwlock.h>
-#include <sys/rmlock.h>
-#include <sys/socket.h>
-#include <sys/socketvar.h>
-#include <sys/sysctl.h>
-#include <sys/syslog.h>
-#include <sys/fnv_hash.h>
-#include <net/if.h>
-#include <net/pfil.h>
-#include <net/route.h>
-#include <net/vnet.h>
-#include <vm/vm.h>
-#include <vm/vm_extern.h>
-
-#include <netinet/in.h>
-#include <netinet/ip_var.h> /* hooks */
-#include <netinet/ip_fw.h>
-
-#include <netpfil/ipfw/ip_fw_private.h>
-#include <netpfil/ipfw/ip_fw_table.h>
-
-#ifdef MAC
-#include <security/mac/mac_framework.h>
-#endif
-
-static int ipfw_ctl(struct sockopt *sopt);
-static int check_ipfw_rule_body(ipfw_insn *cmd, int cmd_len,
-    struct rule_check_info *ci);
-static int check_ipfw_rule1(struct ip_fw_rule *rule, int size,
-    struct rule_check_info *ci);
-static int check_ipfw_rule0(struct ip_fw_rule0 *rule, int size,
-    struct rule_check_info *ci);
-static int rewrite_rule_uidx(struct ip_fw_chain *chain,
-    struct rule_check_info *ci);
-
-#define	NAMEDOBJ_HASH_SIZE	32
-
-struct namedobj_instance {
-	struct namedobjects_head	*names;
-	struct namedobjects_head	*values;
-	uint32_t nn_size;		/* names hash size */
-	uint32_t nv_size;		/* number hash size */
-	u_long *idx_mask;		/* used items bitmask */
-	uint32_t max_blocks;		/* number of "long" blocks in bitmask */
-	uint32_t count;			/* number of items */
-	uint16_t free_off[IPFW_MAX_SETS];	/* first possible free offset */
-	objhash_hash_f	*hash_f;
-	objhash_cmp_f	*cmp_f;
-};
-#define	BLOCK_ITEMS	(8 * sizeof(u_long))	/* Number of items for ffsl() */
-
-static uint32_t objhash_hash_name(struct namedobj_instance *ni,
-    const void *key, uint32_t kopt);
-static uint32_t objhash_hash_idx(struct namedobj_instance *ni, uint32_t val);
-static int objhash_cmp_name(struct named_object *no, const void *name,
-    uint32_t set);
-
-MALLOC_DEFINE(M_IPFW, "IpFw/IpAcct", "IpFw/IpAcct chain's");
-
-static int dump_config(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
-    struct sockopt_data *sd);
-static int add_rules(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
-    struct sockopt_data *sd);
-static int del_rules(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
-    struct sockopt_data *sd);
-static int clear_rules(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
-    struct sockopt_data *sd);
-static int move_rules(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
-    struct sockopt_data *sd);
-static int manage_sets(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
-    struct sockopt_data *sd);
-static int dump_soptcodes(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
-    struct sockopt_data *sd);
-static int dump_srvobjects(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
-    struct sockopt_data *sd);
-
-/* ctl3 handler data */
-struct mtx ctl3_lock;
-#define	CTL3_LOCK_INIT()	mtx_init(&ctl3_lock, "ctl3_lock", NULL, MTX_DEF)
-#define	CTL3_LOCK_DESTROY()	mtx_destroy(&ctl3_lock)
-#define	CTL3_LOCK()		mtx_lock(&ctl3_lock)
-#define	CTL3_UNLOCK()		mtx_unlock(&ctl3_lock)
-
-static struct ipfw_sopt_handler *ctl3_handlers;
-static size_t ctl3_hsize;
-static uint64_t ctl3_refct, ctl3_gencnt;
-#define	CTL3_SMALLBUF	4096			/* small page-size write buffer */
-#define	CTL3_LARGEBUF	16 * 1024 * 1024	/* handle large rulesets */
-
-static int ipfw_flush_sopt_data(struct sockopt_data *sd);
-
-static struct ipfw_sopt_handler	scodes[] = {
-	{ IP_FW_XGET,		0,	HDIR_GET,	dump_config },
-	{ IP_FW_XADD,		0,	HDIR_BOTH,	add_rules },
-	{ IP_FW_XDEL,		0,	HDIR_BOTH,	del_rules },
-	{ IP_FW_XZERO,		0,	HDIR_SET,	clear_rules },
-	{ IP_FW_XRESETLOG,	0,	HDIR_SET,	clear_rules },
-	{ IP_FW_XMOVE,		0,	HDIR_SET,	move_rules },
-	{ IP_FW_SET_SWAP,	0,	HDIR_SET,	manage_sets },
-	{ IP_FW_SET_MOVE,	0,	HDIR_SET,	manage_sets },
-	{ IP_FW_SET_ENABLE,	0,	HDIR_SET,	manage_sets },
-	{ IP_FW_DUMP_SOPTCODES,	0,	HDIR_GET,	dump_soptcodes },
-	{ IP_FW_DUMP_SRVOBJECTS,0,	HDIR_GET,	dump_srvobjects },
-};
-
-static int
-set_legacy_obj_kidx(struct ip_fw_chain *ch, struct ip_fw_rule0 *rule);
-static struct opcode_obj_rewrite *find_op_rw(ipfw_insn *cmd,
-    uint16_t *puidx, uint8_t *ptype);
-static int mark_object_kidx(struct ip_fw_chain *ch, struct ip_fw *rule,
-    uint32_t *bmask);
-static int ref_rule_objects(struct ip_fw_chain *ch, struct ip_fw *rule,
-    struct rule_check_info *ci, struct obj_idx *oib, struct tid_info *ti);
-static int ref_opcode_object(struct ip_fw_chain *ch, ipfw_insn *cmd,
-    struct tid_info *ti, struct obj_idx *pidx, int *unresolved);
-static void unref_rule_objects(struct ip_fw_chain *chain, struct ip_fw *rule);
-static void unref_oib_objects(struct ip_fw_chain *ch, ipfw_insn *cmd,
-    struct obj_idx *oib, struct obj_idx *end);
-static int export_objhash_ntlv(struct namedobj_instance *ni, uint16_t kidx,
-    struct sockopt_data *sd);
-
-/*
- * Opcode object rewriter variables
- */
-struct opcode_obj_rewrite *ctl3_rewriters;
-static size_t ctl3_rsize;
-
-/*
- * static variables followed by global ones
- */
-
-static VNET_DEFINE(uma_zone_t, ipfw_cntr_zone);
-#define	V_ipfw_cntr_zone		VNET(ipfw_cntr_zone)
-
-void
-ipfw_init_counters()
-{
-
-	V_ipfw_cntr_zone = uma_zcreate("IPFW counters",
-	    IPFW_RULE_CNTR_SIZE, NULL, NULL, NULL, NULL,
-	    UMA_ALIGN_PTR, UMA_ZONE_PCPU);
-}
-
-void
-ipfw_destroy_counters()
-{
-	
-	uma_zdestroy(V_ipfw_cntr_zone);
-}
-
-struct ip_fw *
-ipfw_alloc_rule(struct ip_fw_chain *chain, size_t rulesize)
-{
-	struct ip_fw *rule;
-
-	rule = malloc(rulesize, M_IPFW, M_WAITOK | M_ZERO);
-	rule->cntr = uma_zalloc(V_ipfw_cntr_zone, M_WAITOK | M_ZERO);
-
-	return (rule);
-}
-
-static void
-free_rule(struct ip_fw *rule)
-{
-
-	uma_zfree(V_ipfw_cntr_zone, rule->cntr);
-	free(rule, M_IPFW);
-}
-
-
-/*
- * Find the smallest rule >= key, id.
- * We could use bsearch but it is so simple that we code it directly
- */
-int
-ipfw_find_rule(struct ip_fw_chain *chain, uint32_t key, uint32_t id)
-{
-	int i, lo, hi;
-	struct ip_fw *r;
-
-  	for (lo = 0, hi = chain->n_rules - 1; lo < hi;) {
-		i = (lo + hi) / 2;
-		r = chain->map[i];
-		if (r->rulenum < key)
-			lo = i + 1;	/* continue from the next one */
-		else if (r->rulenum > key)
-			hi = i;		/* this might be good */
-		else if (r->id < id)
-			lo = i + 1;	/* continue from the next one */
-		else /* r->id >= id */
-			hi = i;		/* this might be good */
-	}
-	return hi;
-}
-
-/*
- * Builds skipto cache on rule set @map.
- */
-static void
-update_skipto_cache(struct ip_fw_chain *chain, struct ip_fw **map)
-{
-	int *smap, rulenum;
-	int i, mi;
-
-	IPFW_UH_WLOCK_ASSERT(chain);
-
-	mi = 0;
-	rulenum = map[mi]->rulenum;
-	smap = chain->idxmap_back;
-
-	if (smap == NULL)
-		return;
-
-	for (i = 0; i < 65536; i++) {
-		smap[i] = mi;
-		/* Use the same rule index until i < rulenum */
-		if (i != rulenum || i == 65535)
-			continue;
-		/* Find next rule with num > i */
-		rulenum = map[++mi]->rulenum;
-		while (rulenum == i)
-			rulenum = map[++mi]->rulenum;
-	}
-}
-
-/*
- * Swaps prepared (backup) index with current one.
- */
-static void
-swap_skipto_cache(struct ip_fw_chain *chain)
-{
-	int *map;
-
-	IPFW_UH_WLOCK_ASSERT(chain);
-	IPFW_WLOCK_ASSERT(chain);
-
-	map = chain->idxmap;
-	chain->idxmap = chain->idxmap_back;
-	chain->idxmap_back = map;
-}
-
-/*
- * Allocate and initialize skipto cache.
- */
-void
-ipfw_init_skipto_cache(struct ip_fw_chain *chain)
-{
-	int *idxmap, *idxmap_back;
-
-	idxmap = malloc(65536 * sizeof(uint32_t *), M_IPFW,
-	    M_WAITOK | M_ZERO);
-	idxmap_back = malloc(65536 * sizeof(uint32_t *), M_IPFW,
-	    M_WAITOK | M_ZERO);
-
-	/*
-	 * Note we may be called at any time after initialization,
-	 * for example, on first skipto rule, so we need to
-	 * provide valid chain->idxmap on return
-	 */
-
-	IPFW_UH_WLOCK(chain);
-	if (chain->idxmap != NULL) {
-		IPFW_UH_WUNLOCK(chain);
-		free(idxmap, M_IPFW);
-		free(idxmap_back, M_IPFW);
-		return;
-	}
-
-	/* Set backup pointer first to permit building cache */
-	chain->idxmap_back = idxmap_back;
-	update_skipto_cache(chain, chain->map);
-	IPFW_WLOCK(chain);
-	/* It is now safe to set chain->idxmap ptr */
-	chain->idxmap = idxmap;
-	swap_skipto_cache(chain);
-	IPFW_WUNLOCK(chain);
-	IPFW_UH_WUNLOCK(chain);
-}
-
-/*
- * Destroys skipto cache.
- */
-void
-ipfw_destroy_skipto_cache(struct ip_fw_chain *chain)
-{
-
-	if (chain->idxmap != NULL)
-		free(chain->idxmap, M_IPFW);
-	if (chain->idxmap != NULL)
-		free(chain->idxmap_back, M_IPFW);
-}
-
-
-/*
- * allocate a new map, returns the chain locked. extra is the number
- * of entries to add or delete.
- */
-static struct ip_fw **
-get_map(struct ip_fw_chain *chain, int extra, int locked)
-{
-
-	for (;;) {
-		struct ip_fw **map;
-		int i, mflags;
-
-		mflags = M_ZERO | ((locked != 0) ? M_NOWAIT : M_WAITOK);
-
-		i = chain->n_rules + extra;
-		map = malloc(i * sizeof(struct ip_fw *), M_IPFW, mflags);
-		if (map == NULL) {
-			printf("%s: cannot allocate map\n", __FUNCTION__);
-			return NULL;
-		}
-		if (!locked)
-			IPFW_UH_WLOCK(chain);
-		if (i >= chain->n_rules + extra) /* good */
-			return map;
-		/* otherwise we lost the race, free and retry */
-		if (!locked)
-			IPFW_UH_WUNLOCK(chain);
-		free(map, M_IPFW);
-	}
-}
-
-/*
- * swap the maps. It is supposed to be called with IPFW_UH_WLOCK
- */
-static struct ip_fw **
-swap_map(struct ip_fw_chain *chain, struct ip_fw **new_map, int new_len)
-{
-	struct ip_fw **old_map;
-
-	IPFW_WLOCK(chain);
-	chain->id++;
-	chain->n_rules = new_len;
-	old_map = chain->map;
-	chain->map = new_map;
-	swap_skipto_cache(chain);
-	IPFW_WUNLOCK(chain);
-	return old_map;
-}
-
-
-static void
-export_cntr1_base(struct ip_fw *krule, struct ip_fw_bcounter *cntr)
-{
-	struct timeval boottime;
-
-	cntr->size = sizeof(*cntr);
-
-	if (krule->cntr != NULL) {
-		cntr->pcnt = counter_u64_fetch(krule->cntr);
-		cntr->bcnt = counter_u64_fetch(krule->cntr + 1);
-		cntr->timestamp = krule->timestamp;
-	}
-	if (cntr->timestamp > 0) {
-		getboottime(&boottime);
-		cntr->timestamp += boottime.tv_sec;
-	}
-}
-
-static void
-export_cntr0_base(struct ip_fw *krule, struct ip_fw_bcounter0 *cntr)
-{
-	struct timeval boottime;
-
-	if (krule->cntr != NULL) {
-		cntr->pcnt = counter_u64_fetch(krule->cntr);
-		cntr->bcnt = counter_u64_fetch(krule->cntr + 1);
-		cntr->timestamp = krule->timestamp;
-	}
-	if (cntr->timestamp > 0) {
-		getboottime(&boottime);
-		cntr->timestamp += boottime.tv_sec;
-	}
-}
-
-/*
- * Copies rule @urule from v1 userland format (current).
- * to kernel @krule.
- * Assume @krule is zeroed.
- */
-static void
-import_rule1(struct rule_check_info *ci)
-{
-	struct ip_fw_rule *urule;
-	struct ip_fw *krule;
-
-	urule = (struct ip_fw_rule *)ci->urule;
-	krule = (struct ip_fw *)ci->krule;
-
-	/* copy header */
-	krule->act_ofs = urule->act_ofs;
-	krule->cmd_len = urule->cmd_len;
-	krule->rulenum = urule->rulenum;
-	krule->set = urule->set;
-	krule->flags = urule->flags;
-
-	/* Save rulenum offset */
-	ci->urule_numoff = offsetof(struct ip_fw_rule, rulenum);
-
-	/* Copy opcodes */
-	memcpy(krule->cmd, urule->cmd, krule->cmd_len * sizeof(uint32_t));
-}
-
-/*
- * Export rule into v1 format (Current).
- * Layout:
- * [ ipfw_obj_tlv(IPFW_TLV_RULE_ENT)
- *     [ ip_fw_rule ] OR
- *     [ ip_fw_bcounter ip_fw_rule] (depends on rcntrs).
- * ]
- * Assume @data is zeroed.
- */
-static void
-export_rule1(struct ip_fw *krule, caddr_t data, int len, int rcntrs)
-{
-	struct ip_fw_bcounter *cntr;
-	struct ip_fw_rule *urule;
-	ipfw_obj_tlv *tlv;
-
-	/* Fill in TLV header */
-	tlv = (ipfw_obj_tlv *)data;
-	tlv->type = IPFW_TLV_RULE_ENT;
-	tlv->length = len;
-
-	if (rcntrs != 0) {
-		/* Copy counters */
-		cntr = (struct ip_fw_bcounter *)(tlv + 1);
-		urule = (struct ip_fw_rule *)(cntr + 1);
-		export_cntr1_base(krule, cntr);
-	} else
-		urule = (struct ip_fw_rule *)(tlv + 1);
-
-	/* copy header */
-	urule->act_ofs = krule->act_ofs;
-	urule->cmd_len = krule->cmd_len;
-	urule->rulenum = krule->rulenum;
-	urule->set = krule->set;
-	urule->flags = krule->flags;
-	urule->id = krule->id;
-
-	/* Copy opcodes */
-	memcpy(urule->cmd, krule->cmd, krule->cmd_len * sizeof(uint32_t));
-}
-
-
-/*
- * Copies rule @urule from FreeBSD8 userland format (v0)
- * to kernel @krule.
- * Assume @krule is zeroed.
- */
-static void
-import_rule0(struct rule_check_info *ci)
-{
-	struct ip_fw_rule0 *urule;
-	struct ip_fw *krule;
-	int cmdlen, l;
-	ipfw_insn *cmd;
-	ipfw_insn_limit *lcmd;
-	ipfw_insn_if *cmdif;
-
-	urule = (struct ip_fw_rule0 *)ci->urule;
-	krule = (struct ip_fw *)ci->krule;
-
-	/* copy header */
-	krule->act_ofs = urule->act_ofs;
-	krule->cmd_len = urule->cmd_len;
-	krule->rulenum = urule->rulenum;
-	krule->set = urule->set;
-	if ((urule->_pad & 1) != 0)
-		krule->flags |= IPFW_RULE_NOOPT;
-
-	/* Save rulenum offset */
-	ci->urule_numoff = offsetof(struct ip_fw_rule0, rulenum);
-
-	/* Copy opcodes */
-	memcpy(krule->cmd, urule->cmd, krule->cmd_len * sizeof(uint32_t));
-
-	/*
-	 * Alter opcodes:
-	 * 1) convert tablearg value from 65535 to 0
-	 * 2) Add high bit to O_SETFIB/O_SETDSCP values (to make room
-	 *    for targ).
-	 * 3) convert table number in iface opcodes to u16
-	 * 4) convert old `nat global` into new 65535
-	 */
-	l = krule->cmd_len;
-	cmd = krule->cmd;
-	cmdlen = 0;
-
-	for ( ;	l > 0 ; l -= cmdlen, cmd += cmdlen) {
-		cmdlen = F_LEN(cmd);
-
-		switch (cmd->opcode) {
-		/* Opcodes supporting tablearg */
-		case O_TAG:
-		case O_TAGGED:
-		case O_PIPE:
-		case O_QUEUE:
-		case O_DIVERT:
-		case O_TEE:
-		case O_SKIPTO:
-		case O_CALLRETURN:
-		case O_NETGRAPH:
-		case O_NGTEE:
-		case O_NAT:
-			if (cmd->arg1 == IP_FW_TABLEARG)
-				cmd->arg1 = IP_FW_TARG;
-			else if (cmd->arg1 == 0)
-				cmd->arg1 = IP_FW_NAT44_GLOBAL;
-			break;
-		case O_SETFIB:
-		case O_SETDSCP:
-			if (cmd->arg1 == IP_FW_TABLEARG)
-				cmd->arg1 = IP_FW_TARG;
-			else
-				cmd->arg1 |= 0x8000;
-			break;
-		case O_LIMIT:
-			lcmd = (ipfw_insn_limit *)cmd;
-			if (lcmd->conn_limit == IP_FW_TABLEARG)
-				lcmd->conn_limit = IP_FW_TARG;
-			break;
-		/* Interface tables */
-		case O_XMIT:
-		case O_RECV:
-		case O_VIA:
-			/* Interface table, possibly */
-			cmdif = (ipfw_insn_if *)cmd;
-			if (cmdif->name[0] != '\1')
-				break;
-
-			cmdif->p.kidx = (uint16_t)cmdif->p.glob;
-			break;
-		}
-	}
-}
-
-/*
- * Copies rule @krule from kernel to FreeBSD8 userland format (v0)
- */
-static void
-export_rule0(struct ip_fw *krule, struct ip_fw_rule0 *urule, int len)
-{
-	int cmdlen, l;
-	ipfw_insn *cmd;
-	ipfw_insn_limit *lcmd;
-	ipfw_insn_if *cmdif;
-
-	/* copy header */
-	memset(urule, 0, len);
-	urule->act_ofs = krule->act_ofs;
-	urule->cmd_len = krule->cmd_len;
-	urule->rulenum = krule->rulenum;
-	urule->set = krule->set;
-	if ((krule->flags & IPFW_RULE_NOOPT) != 0)
-		urule->_pad |= 1;
-
-	/* Copy opcodes */
-	memcpy(urule->cmd, krule->cmd, krule->cmd_len * sizeof(uint32_t));
-
-	/* Export counters */
-	export_cntr0_base(krule, (struct ip_fw_bcounter0 *)&urule->pcnt);
-
-	/*
-	 * Alter opcodes:
-	 * 1) convert tablearg value from 0 to 65535
-	 * 2) Remove highest bit from O_SETFIB/O_SETDSCP values.
-	 * 3) convert table number in iface opcodes to int
-	 */
-	l = urule->cmd_len;
-	cmd = urule->cmd;
-	cmdlen = 0;
-
-	for ( ;	l > 0 ; l -= cmdlen, cmd += cmdlen) {
-		cmdlen = F_LEN(cmd);
-
-		switch (cmd->opcode) {
-		/* Opcodes supporting tablearg */
-		case O_TAG:
-		case O_TAGGED:
-		case O_PIPE:
-		case O_QUEUE:
-		case O_DIVERT:
-		case O_TEE:
-		case O_SKIPTO:
-		case O_CALLRETURN:
-		case O_NETGRAPH:
-		case O_NGTEE:
-		case O_NAT:
-			if (cmd->arg1 == IP_FW_TARG)
-				cmd->arg1 = IP_FW_TABLEARG;
-			else if (cmd->arg1 == IP_FW_NAT44_GLOBAL)
-				cmd->arg1 = 0;
-			break;
-		case O_SETFIB:
-		case O_SETDSCP:
-			if (cmd->arg1 == IP_FW_TARG)
-				cmd->arg1 = IP_FW_TABLEARG;
-			else
-				cmd->arg1 &= ~0x8000;
-			break;
-		case O_LIMIT:
-			lcmd = (ipfw_insn_limit *)cmd;
-			if (lcmd->conn_limit == IP_FW_TARG)
-				lcmd->conn_limit = IP_FW_TABLEARG;
-			break;
-		/* Interface tables */
-		case O_XMIT:
-		case O_RECV:
-		case O_VIA:
-			/* Interface table, possibly */
-			cmdif = (ipfw_insn_if *)cmd;
-			if (cmdif->name[0] != '\1')
-				break;
-
-			cmdif->p.glob = cmdif->p.kidx;
-			break;
-		}
-	}
-}
-
-/*
- * Add new rule(s) to the list possibly creating rule number for each.
- * Update the rule_number in the input struct so the caller knows it as well.
- * Must be called without IPFW_UH held
- */
-static int
-commit_rules(struct ip_fw_chain *chain, struct rule_check_info *rci, int count)
-{
-	int error, i, insert_before, tcount;
-	uint16_t rulenum, *pnum;
-	struct rule_check_info *ci;
-	struct ip_fw *krule;
-	struct ip_fw **map;	/* the new array of pointers */
-
-	/* Check if we need to do table/obj index remap */
-	tcount = 0;
-	for (ci = rci, i = 0; i < count; ci++, i++) {
-		if (ci->object_opcodes == 0)
-			continue;
-
-		/*
-		 * Rule has some object opcodes.
-		 * We need to find (and create non-existing)
-		 * kernel objects, and reference existing ones.
-		 */
-		error = rewrite_rule_uidx(chain, ci);
-		if (error != 0) {
-
-			/*
-			 * rewrite failed, state for current rule
-			 * has been reverted. Check if we need to
-			 * revert more.
-			 */
-			if (tcount > 0) {
-
-				/*
-				 * We have some more table rules
-				 * we need to rollback.
-				 */
-
-				IPFW_UH_WLOCK(chain);
-				while (ci != rci) {
-					ci--;
-					if (ci->object_opcodes == 0)
-						continue;
-					unref_rule_objects(chain,ci->krule);
-
-				}
-				IPFW_UH_WUNLOCK(chain);
-
-			}
-
-			return (error);
-		}
-
-		tcount++;
-	}
-
-	/* get_map returns with IPFW_UH_WLOCK if successful */
-	map = get_map(chain, count, 0 /* not locked */);
-	if (map == NULL) {
-		if (tcount > 0) {
-			/* Unbind tables */
-			IPFW_UH_WLOCK(chain);
-			for (ci = rci, i = 0; i < count; ci++, i++) {
-				if (ci->object_opcodes == 0)
-					continue;
-
-				unref_rule_objects(chain, ci->krule);
-			}
-			IPFW_UH_WUNLOCK(chain);
-		}
-
-		return (ENOSPC);
-	}
-
-	if (V_autoinc_step < 1)
-		V_autoinc_step = 1;
-	else if (V_autoinc_step > 1000)
-		V_autoinc_step = 1000;
-
-	/* FIXME: Handle count > 1 */
-	ci = rci;
-	krule = ci->krule;
-	rulenum = krule->rulenum;
-
-	/* find the insertion point, we will insert before */
-	insert_before = rulenum ? rulenum + 1 : IPFW_DEFAULT_RULE;
-	i = ipfw_find_rule(chain, insert_before, 0);
-	/* duplicate first part */
-	if (i > 0)
-		bcopy(chain->map, map, i * sizeof(struct ip_fw *));
-	map[i] = krule;
-	/* duplicate remaining part, we always have the default rule */
-	bcopy(chain->map + i, map + i + 1,
-		sizeof(struct ip_fw *) *(chain->n_rules - i));
-	if (rulenum == 0) {
-		/* Compute rule number and write it back */
-		rulenum = i > 0 ? map[i-1]->rulenum : 0;
-		if (rulenum < IPFW_DEFAULT_RULE - V_autoinc_step)
-			rulenum += V_autoinc_step;
-		krule->rulenum = rulenum;
-		/* Save number to userland rule */
-		pnum = (uint16_t *)((caddr_t)ci->urule + ci->urule_numoff);
-		*pnum = rulenum;
-	}
-
-	krule->id = chain->id + 1;
-	update_skipto_cache(chain, map);
-	map = swap_map(chain, map, chain->n_rules + 1);
-	chain->static_len += RULEUSIZE0(krule);
-	IPFW_UH_WUNLOCK(chain);
-	if (map)
-		free(map, M_IPFW);
-	return (0);
-}
-
-/*
- * Adds @rule to the list of rules to reap
- */
-void
-ipfw_reap_add(struct ip_fw_chain *chain, struct ip_fw **head,
-    struct ip_fw *rule)
-{
-
-	IPFW_UH_WLOCK_ASSERT(chain);
-
-	/* Unlink rule from everywhere */
-	unref_rule_objects(chain, rule);
-
-	*((struct ip_fw **)rule) = *head;
-	*head = rule;
-}
-
-/*
- * Reclaim storage associated with a list of rules.  This is
- * typically the list created using remove_rule.
- * A NULL pointer on input is handled correctly.
- */
-void
-ipfw_reap_rules(struct ip_fw *head)
-{
-	struct ip_fw *rule;
-
-	while ((rule = head) != NULL) {
-		head = *((struct ip_fw **)head);
-		free_rule(rule);
-	}
-}
-
-/*
- * Rules to keep are
- *	(default || reserved || !match_set || !match_number)
- * where
- *   default ::= (rule->rulenum == IPFW_DEFAULT_RULE)
- *	// the default rule is always protected
- *
- *   reserved ::= (cmd == 0 && n == 0 && rule->set == RESVD_SET)
- *	// RESVD_SET is protected only if cmd == 0 and n == 0 ("ipfw flush")
- *
- *   match_set ::= (cmd == 0 || rule->set == set)
- *	// set number is ignored for cmd == 0
- *
- *   match_number ::= (cmd == 1 || n == 0 || n == rule->rulenum)
- *	// number is ignored for cmd == 1 or n == 0
- *
- */
-int
-ipfw_match_range(struct ip_fw *rule, ipfw_range_tlv *rt)
-{
-
-	/* Don't match default rule for modification queries */
-	if (rule->rulenum == IPFW_DEFAULT_RULE &&
-	    (rt->flags & IPFW_RCFLAG_DEFAULT) == 0)
-		return (0);
-
-	/* Don't match rules in reserved set for flush requests */
-	if ((rt->flags & IPFW_RCFLAG_ALL) != 0 && rule->set == RESVD_SET)
-		return (0);
-
-	/* If we're filtering by set, don't match other sets */
-	if ((rt->flags & IPFW_RCFLAG_SET) != 0 && rule->set != rt->set)
-		return (0);
-
-	if ((rt->flags & IPFW_RCFLAG_RANGE) != 0 &&
-	    (rule->rulenum < rt->start_rule || rule->rulenum > rt->end_rule))
-		return (0);
-
-	return (1);
-}
-
-struct manage_sets_args {
-	uint16_t	set;
-	uint8_t		new_set;
-};
-
-static int
-swap_sets_cb(struct namedobj_instance *ni, struct named_object *no,
-    void *arg)
-{
-	struct manage_sets_args *args;
-
-	args = (struct manage_sets_args *)arg;
-	if (no->set == (uint8_t)args->set)
-		no->set = args->new_set;
-	else if (no->set == args->new_set)
-		no->set = (uint8_t)args->set;
-	return (0);
-}
-
-static int
-move_sets_cb(struct namedobj_instance *ni, struct named_object *no,
-    void *arg)
-{
-	struct manage_sets_args *args;
-
-	args = (struct manage_sets_args *)arg;
-	if (no->set == (uint8_t)args->set)
-		no->set = args->new_set;
-	return (0);
-}
-
-static int
-test_sets_cb(struct namedobj_instance *ni, struct named_object *no,
-    void *arg)
-{
-	struct manage_sets_args *args;
-
-	args = (struct manage_sets_args *)arg;
-	if (no->set != (uint8_t)args->set)
-		return (0);
-	if (ipfw_objhash_lookup_name_type(ni, args->new_set,
-	    no->etlv, no->name) != NULL)
-		return (EEXIST);
-	return (0);
-}
-
-/*
- * Generic function to handler moving and swapping sets.
- */
-int
-ipfw_obj_manage_sets(struct namedobj_instance *ni, uint16_t type,
-    uint16_t set, uint8_t new_set, enum ipfw_sets_cmd cmd)
-{
-	struct manage_sets_args args;
-	struct named_object *no;
-
-	args.set = set;
-	args.new_set = new_set;
-	switch (cmd) {
-	case SWAP_ALL:
-		return (ipfw_objhash_foreach_type(ni, swap_sets_cb,
-		    &args, type));
-	case TEST_ALL:
-		return (ipfw_objhash_foreach_type(ni, test_sets_cb,
-		    &args, type));
-	case MOVE_ALL:
-		return (ipfw_objhash_foreach_type(ni, move_sets_cb,
-		    &args, type));
-	case COUNT_ONE:
-		/*
-		 * @set used to pass kidx.
-		 * When @new_set is zero - reset object counter,
-		 * otherwise increment it.
-		 */
-		no = ipfw_objhash_lookup_kidx(ni, set);
-		if (new_set != 0)
-			no->ocnt++;
-		else
-			no->ocnt = 0;
-		return (0);
-	case TEST_ONE:
-		/* @set used to pass kidx */
-		no = ipfw_objhash_lookup_kidx(ni, set);
-		/*
-		 * First check number of references:
-		 * when it differs, this mean other rules are holding
-		 * reference to given object, so it is not possible to
-		 * change its set. Note that refcnt may account references
-		 * to some going-to-be-added rules. Since we don't know
-		 * their numbers (and even if they will be added) it is
-		 * perfectly OK to return error here.
-		 */
-		if (no->ocnt != no->refcnt)
-			return (EBUSY);
-		if (ipfw_objhash_lookup_name_type(ni, new_set, type,
-		    no->name) != NULL)
-			return (EEXIST);
-		return (0);
-	case MOVE_ONE:
-		/* @set used to pass kidx */
-		no = ipfw_objhash_lookup_kidx(ni, set);
-		no->set = new_set;
-		return (0);
-	}
-	return (EINVAL);
-}
-
-/*
- * Delete rules matching range @rt.
- * Saves number of deleted rules in @ndel.
- *
- * Returns 0 on success.
- */
-static int
-delete_range(struct ip_fw_chain *chain, ipfw_range_tlv *rt, int *ndel)
-{
-	struct ip_fw *reap, *rule, **map;
-	int end, start;
-	int i, n, ndyn, ofs;
-
-	reap = NULL;
-	IPFW_UH_WLOCK(chain);	/* arbitrate writers */
-
-	/*
-	 * Stage 1: Determine range to inspect.
-	 * Range is half-inclusive, e.g [start, end).
-	 */
-	start = 0;
-	end = chain->n_rules - 1;
-
-	if ((rt->flags & IPFW_RCFLAG_RANGE) != 0) {
-		start = ipfw_find_rule(chain, rt->start_rule, 0);
-
-		end = ipfw_find_rule(chain, rt->end_rule, 0);
-		if (rt->end_rule != IPFW_DEFAULT_RULE)
-			while (chain->map[end]->rulenum == rt->end_rule)
-				end++;
-	}
-
-	/* Allocate new map of the same size */
-	map = get_map(chain, 0, 1 /* locked */);
-	if (map == NULL) {
-		IPFW_UH_WUNLOCK(chain);
-		return (ENOMEM);
-	}
-
-	n = 0;
-	ndyn = 0;
-	ofs = start;
-	/* 1. bcopy the initial part of the map */
-	if (start > 0)
-		bcopy(chain->map, map, start * sizeof(struct ip_fw *));
-	/* 2. copy active rules between start and end */
-	for (i = start; i < end; i++) {
-		rule = chain->map[i];
-		if (ipfw_match_range(rule, rt) == 0) {
-			map[ofs++] = rule;
-			continue;
-		}
-
-		n++;
-		if (ipfw_is_dyn_rule(rule) != 0)
-			ndyn++;
-	}
-	/* 3. copy the final part of the map */
-	bcopy(chain->map + end, map + ofs,
-		(chain->n_rules - end) * sizeof(struct ip_fw *));
-	/* 4. recalculate skipto cache */
-	update_skipto_cache(chain, map);
-	/* 5. swap the maps (under UH_WLOCK + WHLOCK) */
-	map = swap_map(chain, map, chain->n_rules - n);
-	/* 6. Remove all dynamic states originated by deleted rules */
-	if (ndyn > 0)
-		ipfw_expire_dyn_rules(chain, rt);
-	/* 7. now remove the rules deleted from the old map */
-	for (i = start; i < end; i++) {
-		rule = map[i];
-		if (ipfw_match_range(rule, rt) == 0)
-			continue;
-		chain->static_len -= RULEUSIZE0(rule);
-		ipfw_reap_add(chain, &reap, rule);
-	}
-	IPFW_UH_WUNLOCK(chain);
-
-	ipfw_reap_rules(reap);
-	if (map != NULL)
-		free(map, M_IPFW);
-	*ndel = n;
-	return (0);
-}
-
-static int
-move_objects(struct ip_fw_chain *ch, ipfw_range_tlv *rt)
-{
-	struct opcode_obj_rewrite *rw;
-	struct ip_fw *rule;
-	ipfw_insn *cmd;
-	int cmdlen, i, l, c;
-	uint16_t kidx;
-
-	IPFW_UH_WLOCK_ASSERT(ch);
-
-	/* Stage 1: count number of references by given rules */
-	for (c = 0, i = 0; i < ch->n_rules - 1; i++) {
-		rule = ch->map[i];
-		if (ipfw_match_range(rule, rt) == 0)
-			continue;
-		if (rule->set == rt->new_set) /* nothing to do */
-			continue;
-		/* Search opcodes with named objects */
-		for (l = rule->cmd_len, cmdlen = 0, cmd = rule->cmd;
-		    l > 0; l -= cmdlen, cmd += cmdlen) {
-			cmdlen = F_LEN(cmd);
-			rw = find_op_rw(cmd, &kidx, NULL);
-			if (rw == NULL || rw->manage_sets == NULL)
-				continue;
-			/*
-			 * When manage_sets() returns non-zero value to
-			 * COUNT_ONE command, consider this as an object
-			 * doesn't support sets (e.g. disabled with sysctl).
-			 * So, skip checks for this object.
-			 */
-			if (rw->manage_sets(ch, kidx, 1, COUNT_ONE) != 0)
-				continue;
-			c++;
-		}
-	}
-	if (c == 0) /* No objects found */
-		return (0);
-	/* Stage 2: verify "ownership" */
-	for (c = 0, i = 0; (i < ch->n_rules - 1) && c == 0; i++) {
-		rule = ch->map[i];
-		if (ipfw_match_range(rule, rt) == 0)
-			continue;
-		if (rule->set == rt->new_set) /* nothing to do */
-			continue;
-		/* Search opcodes with named objects */
-		for (l = rule->cmd_len, cmdlen = 0, cmd = rule->cmd;
-		    l > 0 && c == 0; l -= cmdlen, cmd += cmdlen) {
-			cmdlen = F_LEN(cmd);
-			rw = find_op_rw(cmd, &kidx, NULL);
-			if (rw == NULL || rw->manage_sets == NULL)
-				continue;
-			/* Test for ownership and conflicting names */
-			c = rw->manage_sets(ch, kidx,
-			    (uint8_t)rt->new_set, TEST_ONE);
-		}
-	}
-	/* Stage 3: change set and cleanup */
-	for (i = 0; i < ch->n_rules - 1; i++) {
-		rule = ch->map[i];
-		if (ipfw_match_range(rule, rt) == 0)
-			continue;
-		if (rule->set == rt->new_set) /* nothing to do */
-			continue;
-		/* Search opcodes with named objects */
-		for (l = rule->cmd_len, cmdlen = 0, cmd = rule->cmd;
-		    l > 0; l -= cmdlen, cmd += cmdlen) {
-			cmdlen = F_LEN(cmd);
-			rw = find_op_rw(cmd, &kidx, NULL);
-			if (rw == NULL || rw->manage_sets == NULL)
-				continue;
-			/* cleanup object counter */
-			rw->manage_sets(ch, kidx,
-			    0 /* reset counter */, COUNT_ONE);
-			if (c != 0)
-				continue;
-			/* change set */
-			rw->manage_sets(ch, kidx,
-			    (uint8_t)rt->new_set, MOVE_ONE);
-		}
-	}
-	return (c);
-}/*
- * Changes set of given rule rannge @rt
- * with each other.
- *
- * Returns 0 on success.
- */
-static int
-move_range(struct ip_fw_chain *chain, ipfw_range_tlv *rt)
-{
-	struct ip_fw *rule;
-	int i;
-
-	IPFW_UH_WLOCK(chain);
-
-	/*
-	 * Move rules with matching paramenerts to a new set.
-	 * This one is much more complex. We have to ensure
-	 * that all referenced tables (if any) are referenced
-	 * by given rule subset only. Otherwise, we can't move
-	 * them to new set and have to return error.
-	 */
-	if ((i = move_objects(chain, rt)) != 0) {
-		IPFW_UH_WUNLOCK(chain);
-		return (i);
-	}
-
-	/* XXX: We have to do swap holding WLOCK */
-	for (i = 0; i < chain->n_rules; i++) {
-		rule = chain->map[i];
-		if (ipfw_match_range(rule, rt) == 0)
-			continue;
-		rule->set = rt->new_set;
-	}
-
-	IPFW_UH_WUNLOCK(chain);
-
-	return (0);
-}
-
-/*
- * Clear counters for a specific rule.
- * Normally run under IPFW_UH_RLOCK, but these are idempotent ops
- * so we only care that rules do not disappear.
- */
-static void
-clear_counters(struct ip_fw *rule, int log_only)
-{
-	ipfw_insn_log *l = (ipfw_insn_log *)ACTION_PTR(rule);
-
-	if (log_only == 0)
-		IPFW_ZERO_RULE_COUNTER(rule);
-	if (l->o.opcode == O_LOG)
-		l->log_left = l->max_log;
-}
-
-/*
- * Flushes rules counters and/or log values on matching range.
- *
- * Returns number of items cleared.
- */
-static int
-clear_range(struct ip_fw_chain *chain, ipfw_range_tlv *rt, int log_only)
-{
-	struct ip_fw *rule;
-	int num;
-	int i;
-
-	num = 0;
-	rt->flags |= IPFW_RCFLAG_DEFAULT;
-
-	IPFW_UH_WLOCK(chain);	/* arbitrate writers */
-	for (i = 0; i < chain->n_rules; i++) {
-		rule = chain->map[i];
-		if (ipfw_match_range(rule, rt) == 0)
-			continue;
-		clear_counters(rule, log_only);
-		num++;
-	}
-	IPFW_UH_WUNLOCK(chain);
-
-	return (num);
-}
-
-static int
-check_range_tlv(ipfw_range_tlv *rt)
-{
-
-	if (rt->head.length != sizeof(*rt))
-		return (1);
-	if (rt->start_rule > rt->end_rule)
-		return (1);
-	if (rt->set >= IPFW_MAX_SETS || rt->new_set >= IPFW_MAX_SETS)
-		return (1);
-
-	if ((rt->flags & IPFW_RCFLAG_USER) != rt->flags)
-		return (1);
-
-	return (0);
-}
-
-/*
- * Delete rules matching specified parameters
- * Data layout (v0)(current):
- * Request: [ ipfw_obj_header ipfw_range_tlv ]
- * Reply: [ ipfw_obj_header ipfw_range_tlv ]
- *
- * Saves number of deleted rules in ipfw_range_tlv->new_set.
- *
- * Returns 0 on success.
- */
-static int
-del_rules(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
-    struct sockopt_data *sd)
-{
-	ipfw_range_header *rh;
-	int error, ndel;
-
-	if (sd->valsize != sizeof(*rh))
-		return (EINVAL);
-
-	rh = (ipfw_range_header *)ipfw_get_sopt_space(sd, sd->valsize);
-
-	if (check_range_tlv(&rh->range) != 0)
-		return (EINVAL);
-
-	ndel = 0;
-	if ((error = delete_range(chain, &rh->range, &ndel)) != 0)
-		return (error);
-
-	/* Save number of rules deleted */
-	rh->range.new_set = ndel;
-	return (0);
-}
-
-/*
- * Move rules/sets matching specified parameters
- * Data layout (v0)(current):
- * Request: [ ipfw_obj_header ipfw_range_tlv ]
- *
- * Returns 0 on success.
- */
-static int
-move_rules(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
-    struct sockopt_data *sd)
-{
-	ipfw_range_header *rh;
-
-	if (sd->valsize != sizeof(*rh))
-		return (EINVAL);
-
-	rh = (ipfw_range_header *)ipfw_get_sopt_space(sd, sd->valsize);
-
-	if (check_range_tlv(&rh->range) != 0)
-		return (EINVAL);
-
-	return (move_range(chain, &rh->range));
-}
-
-/*
- * Clear rule accounting data matching specified parameters
- * Data layout (v0)(current):
- * Request: [ ipfw_obj_header ipfw_range_tlv ]
- * Reply: [ ipfw_obj_header ipfw_range_tlv ]
- *
- * Saves number of cleared rules in ipfw_range_tlv->new_set.
- *
- * Returns 0 on success.
- */
-static int
-clear_rules(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
-    struct sockopt_data *sd)
-{
-	ipfw_range_header *rh;
-	int log_only, num;
-	char *msg;
-
-	if (sd->valsize != sizeof(*rh))
-		return (EINVAL);
-
-	rh = (ipfw_range_header *)ipfw_get_sopt_space(sd, sd->valsize);
-
-	if (check_range_tlv(&rh->range) != 0)
-		return (EINVAL);
-
-	log_only = (op3->opcode == IP_FW_XRESETLOG);
-
-	num = clear_range(chain, &rh->range, log_only);
-
-	if (rh->range.flags & IPFW_RCFLAG_ALL)
-		msg = log_only ? "All logging counts reset" :
-		    "Accounting cleared";
-	else
-		msg = log_only ? "logging count reset" : "cleared";
-
-	if (V_fw_verbose) {
-		int lev = LOG_SECURITY | LOG_NOTICE;
-		log(lev, "ipfw: %s.\n", msg);
-	}
-
-	/* Save number of rules cleared */
-	rh->range.new_set = num;
-	return (0);
-}
-
-static void
-enable_sets(struct ip_fw_chain *chain, ipfw_range_tlv *rt)
-{
-	uint32_t v_set;
-
-	IPFW_UH_WLOCK_ASSERT(chain);
-
-	/* Change enabled/disabled sets mask */
-	v_set = (V_set_disable | rt->set) & ~rt->new_set;
-	v_set &= ~(1 << RESVD_SET); /* set RESVD_SET always enabled */
-	IPFW_WLOCK(chain);
-	V_set_disable = v_set;
-	IPFW_WUNLOCK(chain);
-}
-
-static int
-swap_sets(struct ip_fw_chain *chain, ipfw_range_tlv *rt, int mv)
-{
-	struct opcode_obj_rewrite *rw;
-	struct ip_fw *rule;
-	int i;
-
-	IPFW_UH_WLOCK_ASSERT(chain);
-
-	if (rt->set == rt->new_set) /* nothing to do */
-		return (0);
-
-	if (mv != 0) {
-		/*
-		 * Berfore moving the rules we need to check that
-		 * there aren't any conflicting named objects.
-		 */
-		for (rw = ctl3_rewriters;
-		    rw < ctl3_rewriters + ctl3_rsize; rw++) {
-			if (rw->manage_sets == NULL)
-				continue;
-			i = rw->manage_sets(chain, (uint8_t)rt->set,
-			    (uint8_t)rt->new_set, TEST_ALL);
-			if (i != 0)
-				return (EEXIST);
-		}
-	}
-	/* Swap or move two sets */
-	for (i = 0; i < chain->n_rules - 1; i++) {
-		rule = chain->map[i];
-		if (rule->set == (uint8_t)rt->set)
-			rule->set = (uint8_t)rt->new_set;
-		else if (rule->set == (uint8_t)rt->new_set && mv == 0)
-			rule->set = (uint8_t)rt->set;
-	}
-	for (rw = ctl3_rewriters; rw < ctl3_rewriters + ctl3_rsize; rw++) {
-		if (rw->manage_sets == NULL)
-			continue;
-		rw->manage_sets(chain, (uint8_t)rt->set,
-		    (uint8_t)rt->new_set, mv != 0 ? MOVE_ALL: SWAP_ALL);
-	}
-	return (0);
-}
-
-/*
- * Swaps or moves set
- * Data layout (v0)(current):
- * Request: [ ipfw_obj_header ipfw_range_tlv ]
- *
- * Returns 0 on success.
- */
-static int
-manage_sets(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
-    struct sockopt_data *sd)
-{
-	ipfw_range_header *rh;
-	int ret;
-
-	if (sd->valsize != sizeof(*rh))
-		return (EINVAL);
-
-	rh = (ipfw_range_header *)ipfw_get_sopt_space(sd, sd->valsize);
-
-	if (rh->range.head.length != sizeof(ipfw_range_tlv))
-		return (1);
-	/* enable_sets() expects bitmasks. */
-	if (op3->opcode != IP_FW_SET_ENABLE &&
-	    (rh->range.set >= IPFW_MAX_SETS ||
-	    rh->range.new_set >= IPFW_MAX_SETS))
-		return (EINVAL);
-
-	ret = 0;
-	IPFW_UH_WLOCK(chain);
-	switch (op3->opcode) {
-	case IP_FW_SET_SWAP:
-	case IP_FW_SET_MOVE:
-		ret = swap_sets(chain, &rh->range,
-		    op3->opcode == IP_FW_SET_MOVE);
-		break;
-	case IP_FW_SET_ENABLE:
-		enable_sets(chain, &rh->range);
-		break;
-	}
-	IPFW_UH_WUNLOCK(chain);
-
-	return (ret);
-}
-
-/**
- * Remove all rules with given number, or do set manipulation.
- * Assumes chain != NULL && *chain != NULL.
- *
- * The argument is an uint32_t. The low 16 bit are the rule or set number;
- * the next 8 bits are the new set; the top 8 bits indicate the command:
- *
- *	0	delete rules numbered "rulenum"
- *	1	delete rules in set "rulenum"
- *	2	move rules "rulenum" to set "new_set"
- *	3	move rules from set "rulenum" to set "new_set"
- *	4	swap sets "rulenum" and "new_set"
- *	5	delete rules "rulenum" and set "new_set"
- */
-static int
-del_entry(struct ip_fw_chain *chain, uint32_t arg)
-{
-	uint32_t num;	/* rule number or old_set */
-	uint8_t cmd, new_set;
-	int do_del, ndel;
-	int error = 0;
-	ipfw_range_tlv rt;
-
-	num = arg & 0xffff;
-	cmd = (arg >> 24) & 0xff;
-	new_set = (arg >> 16) & 0xff;
-
-	if (cmd > 5 || new_set > RESVD_SET)
-		return EINVAL;
-	if (cmd == 0 || cmd == 2 || cmd == 5) {
-		if (num >= IPFW_DEFAULT_RULE)
-			return EINVAL;
-	} else {
-		if (num > RESVD_SET)	/* old_set */
-			return EINVAL;
-	}
-
-	/* Convert old requests into new representation */
-	memset(&rt, 0, sizeof(rt));
-	rt.start_rule = num;
-	rt.end_rule = num;
-	rt.set = num;
-	rt.new_set = new_set;
-	do_del = 0;
-
-	switch (cmd) {
-	case 0: /* delete rules numbered "rulenum" */
-		if (num == 0)
-			rt.flags |= IPFW_RCFLAG_ALL;
-		else
-			rt.flags |= IPFW_RCFLAG_RANGE;
-		do_del = 1;
-		break;
-	case 1: /* delete rules in set "rulenum" */
-		rt.flags |= IPFW_RCFLAG_SET;
-		do_del = 1;
-		break;
-	case 5: /* delete rules "rulenum" and set "new_set" */
-		rt.flags |= IPFW_RCFLAG_RANGE | IPFW_RCFLAG_SET;
-		rt.set = new_set;
-		rt.new_set = 0;
-		do_del = 1;
-		break;
-	case 2: /* move rules "rulenum" to set "new_set" */
-		rt.flags |= IPFW_RCFLAG_RANGE;
-		break;
-	case 3: /* move rules from set "rulenum" to set "new_set" */
-		IPFW_UH_WLOCK(chain);
-		error = swap_sets(chain, &rt, 1);
-		IPFW_UH_WUNLOCK(chain);
-		return (error);
-	case 4: /* swap sets "rulenum" and "new_set" */
-		IPFW_UH_WLOCK(chain);
-		error = swap_sets(chain, &rt, 0);
-		IPFW_UH_WUNLOCK(chain);
-		return (error);
-	default:
-		return (ENOTSUP);
-	}
-
-	if (do_del != 0) {
-		if ((error = delete_range(chain, &rt, &ndel)) != 0)
-			return (error);
-
-		if (ndel == 0 && (cmd != 1 && num != 0))
-			return (EINVAL);
-
-		return (0);
-	}
-
-	return (move_range(chain, &rt));
-}
-
-/**
- * Reset some or all counters on firewall rules.
- * The argument `arg' is an u_int32_t. The low 16 bit are the rule number,
- * the next 8 bits are the set number, the top 8 bits are the command:
- *	0	work with rules from all set's;
- *	1	work with rules only from specified set.
- * Specified rule number is zero if we want to clear all entries.
- * log_only is 1 if we only want to reset logs, zero otherwise.
- */
-static int
-zero_entry(struct ip_fw_chain *chain, u_int32_t arg, int log_only)
-{
-	struct ip_fw *rule;
-	char *msg;
-	int i;
-
-	uint16_t rulenum = arg & 0xffff;
-	uint8_t set = (arg >> 16) & 0xff;
-	uint8_t cmd = (arg >> 24) & 0xff;
-
-	if (cmd > 1)
-		return (EINVAL);
-	if (cmd == 1 && set > RESVD_SET)
-		return (EINVAL);
-
-	IPFW_UH_RLOCK(chain);
-	if (rulenum == 0) {
-		V_norule_counter = 0;
-		for (i = 0; i < chain->n_rules; i++) {
-			rule = chain->map[i];
-			/* Skip rules not in our set. */
-			if (cmd == 1 && rule->set != set)
-				continue;
-			clear_counters(rule, log_only);
-		}
-		msg = log_only ? "All logging counts reset" :
-		    "Accounting cleared";
-	} else {
-		int cleared = 0;
-		for (i = 0; i < chain->n_rules; i++) {
-			rule = chain->map[i];
-			if (rule->rulenum == rulenum) {
-				if (cmd == 0 || rule->set == set)
-					clear_counters(rule, log_only);
-				cleared = 1;
-			}
-			if (rule->rulenum > rulenum)
-				break;
-		}
-		if (!cleared) {	/* we did not find any matching rules */
-			IPFW_UH_RUNLOCK(chain);
-			return (EINVAL);
-		}
-		msg = log_only ? "logging count reset" : "cleared";
-	}
-	IPFW_UH_RUNLOCK(chain);
-
-	if (V_fw_verbose) {
-		int lev = LOG_SECURITY | LOG_NOTICE;
-
-		if (rulenum)
-			log(lev, "ipfw: Entry %d %s.\n", rulenum, msg);
-		else
-			log(lev, "ipfw: %s.\n", msg);
-	}
-	return (0);
-}
-
-
-/*
- * Check rule head in FreeBSD11 format
- *
- */
-static int
-check_ipfw_rule1(struct ip_fw_rule *rule, int size,
-    struct rule_check_info *ci)
-{
-	int l;
-
-	if (size < sizeof(*rule)) {
-		printf("ipfw: rule too short\n");
-		return (EINVAL);
-	}
-
-	/* Check for valid cmd_len */
-	l = roundup2(RULESIZE(rule), sizeof(uint64_t));
-	if (l != size) {
-		printf("ipfw: size mismatch (have %d want %d)\n", size, l);
-		return (EINVAL);
-	}
-	if (rule->act_ofs >= rule->cmd_len) {
-		printf("ipfw: bogus action offset (%u > %u)\n",
-		    rule->act_ofs, rule->cmd_len - 1);
-		return (EINVAL);
-	}
-
-	if (rule->rulenum > IPFW_DEFAULT_RULE - 1)
-		return (EINVAL);
-
-	return (check_ipfw_rule_body(rule->cmd, rule->cmd_len, ci));
-}
-
-/*
- * Check rule head in FreeBSD8 format
- *
- */
-static int
-check_ipfw_rule0(struct ip_fw_rule0 *rule, int size,
-    struct rule_check_info *ci)
-{
-	int l;
-
-	if (size < sizeof(*rule)) {
-		printf("ipfw: rule too short\n");
-		return (EINVAL);
-	}
-
-	/* Check for valid cmd_len */
-	l = sizeof(*rule) + rule->cmd_len * 4 - 4;
-	if (l != size) {
-		printf("ipfw: size mismatch (have %d want %d)\n", size, l);
-		return (EINVAL);
-	}
-	if (rule->act_ofs >= rule->cmd_len) {
-		printf("ipfw: bogus action offset (%u > %u)\n",
-		    rule->act_ofs, rule->cmd_len - 1);
-		return (EINVAL);
-	}
-
-	if (rule->rulenum > IPFW_DEFAULT_RULE - 1)
-		return (EINVAL);
-
-	return (check_ipfw_rule_body(rule->cmd, rule->cmd_len, ci));
-}
-
-static int
-check_ipfw_rule_body(ipfw_insn *cmd, int cmd_len, struct rule_check_info *ci)
-{
-	int cmdlen, l;
-	int have_action;
-
-	have_action = 0;
-
-	/*
-	 * Now go for the individual checks. Very simple ones, basically only
-	 * instruction sizes.
-	 */
-	for (l = cmd_len; l > 0 ; l -= cmdlen, cmd += cmdlen) {
-		cmdlen = F_LEN(cmd);
-		if (cmdlen > l) {
-			printf("ipfw: opcode %d size truncated\n",
-			    cmd->opcode);
-			return EINVAL;
-		}
-		switch (cmd->opcode) {
-		case O_PROBE_STATE:
-		case O_KEEP_STATE:
-			if (cmdlen != F_INSN_SIZE(ipfw_insn))
-				goto bad_size;
-			ci->object_opcodes++;
-			break;
-		case O_PROTO:
-		case O_IP_SRC_ME:
-		case O_IP_DST_ME:
-		case O_LAYER2:
-		case O_IN:
-		case O_FRAG:
-		case O_DIVERTED:
-		case O_IPOPT:
-		case O_IPTOS:
-		case O_IPPRECEDENCE:
-		case O_IPVER:
-		case O_SOCKARG:
-		case O_TCPFLAGS:
-		case O_TCPOPTS:
-		case O_ESTAB:
-		case O_VERREVPATH:
-		case O_VERSRCREACH:
-		case O_ANTISPOOF:
-		case O_IPSEC:
-#ifdef INET6
-		case O_IP6_SRC_ME:
-		case O_IP6_DST_ME:
-		case O_EXT_HDR:
-		case O_IP6:
-#endif
-		case O_IP4:
-		case O_TAG:
-			if (cmdlen != F_INSN_SIZE(ipfw_insn))
-				goto bad_size;
-			break;
-
-		case O_EXTERNAL_ACTION:
-			if (cmd->arg1 == 0 ||
-			    cmdlen != F_INSN_SIZE(ipfw_insn)) {
-				printf("ipfw: invalid external "
-				    "action opcode\n");
-				return (EINVAL);
-			}
-			ci->object_opcodes++;
-			/*
-			 * Do we have O_EXTERNAL_INSTANCE or O_EXTERNAL_DATA
-			 * opcode?
-			 */
-			if (l != cmdlen) {
-				l -= cmdlen;
-				cmd += cmdlen;
-				cmdlen = F_LEN(cmd);
-				if (cmd->opcode == O_EXTERNAL_DATA)
-					goto check_action;
-				if (cmd->opcode != O_EXTERNAL_INSTANCE) {
-					printf("ipfw: invalid opcode "
-					    "next to external action %u\n",
-					    cmd->opcode);
-					return (EINVAL);
-				}
-				if (cmd->arg1 == 0 ||
-				    cmdlen != F_INSN_SIZE(ipfw_insn)) {
-					printf("ipfw: invalid external "
-					    "action instance opcode\n");
-					return (EINVAL);
-				}
-				ci->object_opcodes++;
-			}
-			goto check_action;
-
-		case O_FIB:
-			if (cmdlen != F_INSN_SIZE(ipfw_insn))
-				goto bad_size;
-			if (cmd->arg1 >= rt_numfibs) {
-				printf("ipfw: invalid fib number %d\n",
-					cmd->arg1);
-				return EINVAL;
-			}
-			break;
-
-		case O_SETFIB:
-			if (cmdlen != F_INSN_SIZE(ipfw_insn))
-				goto bad_size;
-			if ((cmd->arg1 != IP_FW_TARG) &&
-			    ((cmd->arg1 & 0x7FFF) >= rt_numfibs)) {
-				printf("ipfw: invalid fib number %d\n",
-					cmd->arg1 & 0x7FFF);
-				return EINVAL;
-			}
-			goto check_action;
-
-		case O_UID:
-		case O_GID:
-		case O_JAIL:
-		case O_IP_SRC:
-		case O_IP_DST:
-		case O_TCPSEQ:
-		case O_TCPACK:
-		case O_PROB:
-		case O_ICMPTYPE:
-			if (cmdlen != F_INSN_SIZE(ipfw_insn_u32))
-				goto bad_size;
-			break;
-
-		case O_LIMIT:
-			if (cmdlen != F_INSN_SIZE(ipfw_insn_limit))
-				goto bad_size;
-			ci->object_opcodes++;
-			break;
-
-		case O_LOG:
-			if (cmdlen != F_INSN_SIZE(ipfw_insn_log))
-				goto bad_size;
-
-			((ipfw_insn_log *)cmd)->log_left =
-			    ((ipfw_insn_log *)cmd)->max_log;
-
-			break;
-
-		case O_IP_SRC_MASK:
-		case O_IP_DST_MASK:
-			/* only odd command lengths */
-			if ((cmdlen & 1) == 0)
-				goto bad_size;
-			break;
-
-		case O_IP_SRC_SET:
-		case O_IP_DST_SET:
-			if (cmd->arg1 == 0 || cmd->arg1 > 256) {
-				printf("ipfw: invalid set size %d\n",
-					cmd->arg1);
-				return EINVAL;
-			}
-			if (cmdlen != F_INSN_SIZE(ipfw_insn_u32) +
-			    (cmd->arg1+31)/32 )
-				goto bad_size;
-			break;
-
-		case O_IP_SRC_LOOKUP:
-			if (cmdlen > F_INSN_SIZE(ipfw_insn_u32))
-				goto bad_size;
-		case O_IP_DST_LOOKUP:
-			if (cmd->arg1 >= V_fw_tables_max) {
-				printf("ipfw: invalid table number %d\n",
-				    cmd->arg1);
-				return (EINVAL);
-			}
-			if (cmdlen != F_INSN_SIZE(ipfw_insn) &&
-			    cmdlen != F_INSN_SIZE(ipfw_insn_u32) + 1 &&
-			    cmdlen != F_INSN_SIZE(ipfw_insn_u32))
-				goto bad_size;
-			ci->object_opcodes++;
-			break;
-		case O_IP_FLOW_LOOKUP:
-			if (cmd->arg1 >= V_fw_tables_max) {
-				printf("ipfw: invalid table number %d\n",
-				    cmd->arg1);
-				return (EINVAL);
-			}
-			if (cmdlen != F_INSN_SIZE(ipfw_insn) &&
-			    cmdlen != F_INSN_SIZE(ipfw_insn_u32))
-				goto bad_size;
-			ci->object_opcodes++;
-			break;
-		case O_MACADDR2:
-			if (cmdlen != F_INSN_SIZE(ipfw_insn_mac))
-				goto bad_size;
-			break;
-
-		case O_NOP:
-		case O_IPID:
-		case O_IPTTL:
-		case O_IPLEN:
-		case O_TCPDATALEN:
-		case O_TCPWIN:
-		case O_TAGGED:
-			if (cmdlen < 1 || cmdlen > 31)
-				goto bad_size;
-			break;
-
-		case O_DSCP:
-			if (cmdlen != F_INSN_SIZE(ipfw_insn_u32) + 1)
-				goto bad_size;
-			break;
-
-		case O_MAC_TYPE:
-		case O_IP_SRCPORT:
-		case O_IP_DSTPORT: /* XXX artificial limit, 30 port pairs */
-			if (cmdlen < 2 || cmdlen > 31)
-				goto bad_size;
-			break;
-
-		case O_RECV:
-		case O_XMIT:
-		case O_VIA:
-			if (cmdlen != F_INSN_SIZE(ipfw_insn_if))
-				goto bad_size;
-			ci->object_opcodes++;
-			break;
-
-		case O_ALTQ:
-			if (cmdlen != F_INSN_SIZE(ipfw_insn_altq))
-				goto bad_size;
-			break;
-
-		case O_PIPE:
-		case O_QUEUE:
-			if (cmdlen != F_INSN_SIZE(ipfw_insn))
-				goto bad_size;
-			goto check_action;
-
-		case O_FORWARD_IP:
-			if (cmdlen != F_INSN_SIZE(ipfw_insn_sa))
-				goto bad_size;
-			goto check_action;
-#ifdef INET6
-		case O_FORWARD_IP6:
-			if (cmdlen != F_INSN_SIZE(ipfw_insn_sa6))
-				goto bad_size;
-			goto check_action;
-#endif /* INET6 */
-
-		case O_DIVERT:
-		case O_TEE:
-			if (ip_divert_ptr == NULL)
-				return EINVAL;
-			else
-				goto check_size;
-		case O_NETGRAPH:
-		case O_NGTEE:
-			if (ng_ipfw_input_p == NULL)
-				return EINVAL;
-			else
-				goto check_size;
-		case O_NAT:
-			if (!IPFW_NAT_LOADED)
-				return EINVAL;
-			if (cmdlen != F_INSN_SIZE(ipfw_insn_nat))
- 				goto bad_size;		
- 			goto check_action;
-		case O_CHECK_STATE:
-			ci->object_opcodes++;
-			/* FALLTHROUGH */
-		case O_FORWARD_MAC: /* XXX not implemented yet */
-		case O_COUNT:
-		case O_ACCEPT:
-		case O_DENY:
-		case O_REJECT:
-		case O_SETDSCP:
-#ifdef INET6
-		case O_UNREACH6:
-#endif
-		case O_SKIPTO:
-		case O_REASS:
-		case O_CALLRETURN:
-check_size:
-			if (cmdlen != F_INSN_SIZE(ipfw_insn))
-				goto bad_size;
-check_action:
-			if (have_action) {
-				printf("ipfw: opcode %d, multiple actions"
-					" not allowed\n",
-					cmd->opcode);
-				return (EINVAL);
-			}
-			have_action = 1;
-			if (l != cmdlen) {
-				printf("ipfw: opcode %d, action must be"
-					" last opcode\n",
-					cmd->opcode);
-				return (EINVAL);
-			}
-			break;
-#ifdef INET6
-		case O_IP6_SRC:
-		case O_IP6_DST:
-			if (cmdlen != F_INSN_SIZE(struct in6_addr) +
-			    F_INSN_SIZE(ipfw_insn))
-				goto bad_size;
-			break;
-
-		case O_FLOW6ID:
-			if (cmdlen != F_INSN_SIZE(ipfw_insn_u32) +
-			    ((ipfw_insn_u32 *)cmd)->o.arg1)
-				goto bad_size;
-			break;
-
-		case O_IP6_SRC_MASK:
-		case O_IP6_DST_MASK:
-			if ( !(cmdlen & 1) || cmdlen > 127)
-				goto bad_size;
-			break;
-		case O_ICMP6TYPE:
-			if( cmdlen != F_INSN_SIZE( ipfw_insn_icmp6 ) )
-				goto bad_size;
-			break;
-#endif
-
-		default:
-			switch (cmd->opcode) {
-#ifndef INET6
-			case O_IP6_SRC_ME:
-			case O_IP6_DST_ME:
-			case O_EXT_HDR:
-			case O_IP6:
-			case O_UNREACH6:
-			case O_IP6_SRC:
-			case O_IP6_DST:
-			case O_FLOW6ID:
-			case O_IP6_SRC_MASK:
-			case O_IP6_DST_MASK:
-			case O_ICMP6TYPE:
-				printf("ipfw: no IPv6 support in kernel\n");
-				return (EPROTONOSUPPORT);
-#endif
-			default:
-				printf("ipfw: opcode %d, unknown opcode\n",
-					cmd->opcode);
-				return (EINVAL);
-			}
-		}
-	}
-	if (have_action == 0) {
-		printf("ipfw: missing action\n");
-		return (EINVAL);
-	}
-	return 0;
-
-bad_size:
-	printf("ipfw: opcode %d size %d wrong\n",
-		cmd->opcode, cmdlen);
-	return (EINVAL);
-}
-
-
-/*
- * Translation of requests for compatibility with FreeBSD 7.2/8.
- * a static variable tells us if we have an old client from userland,
- * and if necessary we translate requests and responses between the
- * two formats.
- */
-static int is7 = 0;
-
-struct ip_fw7 {
-	struct ip_fw7	*next;		/* linked list of rules     */
-	struct ip_fw7	*next_rule;	/* ptr to next [skipto] rule    */
-	/* 'next_rule' is used to pass up 'set_disable' status      */
-
-	uint16_t	act_ofs;	/* offset of action in 32-bit units */
-	uint16_t	cmd_len;	/* # of 32-bit words in cmd */
-	uint16_t	rulenum;	/* rule number          */
-	uint8_t		set;		/* rule set (0..31)     */
-	// #define RESVD_SET   31  /* set for default and persistent rules */
-	uint8_t		_pad;		/* padding          */
-	// uint32_t        id;             /* rule id, only in v.8 */
-	/* These fields are present in all rules.           */
-	uint64_t	pcnt;		/* Packet counter       */
-	uint64_t	bcnt;		/* Byte counter         */
-	uint32_t	timestamp;	/* tv_sec of last match     */
-
-	ipfw_insn	cmd[1];		/* storage for commands     */
-};
-
-static int convert_rule_to_7(struct ip_fw_rule0 *rule);
-static int convert_rule_to_8(struct ip_fw_rule0 *rule);
-
-#ifndef RULESIZE7
-#define RULESIZE7(rule)  (sizeof(struct ip_fw7) + \
-	((struct ip_fw7 *)(rule))->cmd_len * 4 - 4)
-#endif
-
-
-/*
- * Copy the static and dynamic rules to the supplied buffer
- * and return the amount of space actually used.
- * Must be run under IPFW_UH_RLOCK
- */
-static size_t
-ipfw_getrules(struct ip_fw_chain *chain, void *buf, size_t space)
-{
-	char *bp = buf;
-	char *ep = bp + space;
-	struct ip_fw *rule;
-	struct ip_fw_rule0 *dst;
-	struct timeval boottime;
-	int error, i, l, warnflag;
-	time_t	boot_seconds;
-
-	warnflag = 0;
-
-	getboottime(&boottime);
-        boot_seconds = boottime.tv_sec;
-	for (i = 0; i < chain->n_rules; i++) {
-		rule = chain->map[i];
-
-		if (is7) {
-		    /* Convert rule to FreeBSd 7.2 format */
-		    l = RULESIZE7(rule);
-		    if (bp + l + sizeof(uint32_t) <= ep) {
-			bcopy(rule, bp, l + sizeof(uint32_t));
-			error = set_legacy_obj_kidx(chain,
-			    (struct ip_fw_rule0 *)bp);
-			if (error != 0)
-				return (0);
-			error = convert_rule_to_7((struct ip_fw_rule0 *) bp);
-			if (error)
-				return 0; /*XXX correct? */
-			/*
-			 * XXX HACK. Store the disable mask in the "next"
-			 * pointer in a wild attempt to keep the ABI the same.
-			 * Why do we do this on EVERY rule?
-			 */
-			bcopy(&V_set_disable,
-				&(((struct ip_fw7 *)bp)->next_rule),
-				sizeof(V_set_disable));
-			if (((struct ip_fw7 *)bp)->timestamp)
-			    ((struct ip_fw7 *)bp)->timestamp += boot_seconds;
-			bp += l;
-		    }
-		    continue; /* go to next rule */
-		}
-
-		l = RULEUSIZE0(rule);
-		if (bp + l > ep) { /* should not happen */
-			printf("overflow dumping static rules\n");
-			break;
-		}
-		dst = (struct ip_fw_rule0 *)bp;
-		export_rule0(rule, dst, l);
-		error = set_legacy_obj_kidx(chain, dst);
-
-		/*
-		 * XXX HACK. Store the disable mask in the "next"
-		 * pointer in a wild attempt to keep the ABI the same.
-		 * Why do we do this on EVERY rule?
-		 *
-		 * XXX: "ipfw set show" (ab)uses IP_FW_GET to read disabled mask
-		 * so we need to fail _after_ saving at least one mask.
-		 */
-		bcopy(&V_set_disable, &dst->next_rule, sizeof(V_set_disable));
-		if (dst->timestamp)
-			dst->timestamp += boot_seconds;
-		bp += l;
-
-		if (error != 0) {
-			if (error == 2) {
-				/* Non-fatal table rewrite error. */
-				warnflag = 1;
-				continue;
-			}
-			printf("Stop on rule %d. Fail to convert table\n",
-			    rule->rulenum);
-			break;
-		}
-	}
-	if (warnflag != 0)
-		printf("ipfw: process %s is using legacy interfaces,"
-		    " consider rebuilding\n", "");
-	ipfw_get_dynamic(chain, &bp, ep); /* protected by the dynamic lock */
-	return (bp - (char *)buf);
-}
-
-
-struct dump_args {
-	uint32_t	b;	/* start rule */
-	uint32_t	e;	/* end rule */
-	uint32_t	rcount;	/* number of rules */
-	uint32_t	rsize;	/* rules size */
-	uint32_t	tcount;	/* number of tables */
-	int		rcounters;	/* counters */
-};
-
-void
-ipfw_export_obj_ntlv(struct named_object *no, ipfw_obj_ntlv *ntlv)
-{
-
-	ntlv->head.type = no->etlv;
-	ntlv->head.length = sizeof(*ntlv);
-	ntlv->idx = no->kidx;
-	strlcpy(ntlv->name, no->name, sizeof(ntlv->name));
-}
-
-/*
- * Export named object info in instance @ni, identified by @kidx
- * to ipfw_obj_ntlv. TLV is allocated from @sd space.
- *
- * Returns 0 on success.
- */
-static int
-export_objhash_ntlv(struct namedobj_instance *ni, uint16_t kidx,
-    struct sockopt_data *sd)
-{
-	struct named_object *no;
-	ipfw_obj_ntlv *ntlv;
-
-	no = ipfw_objhash_lookup_kidx(ni, kidx);
-	KASSERT(no != NULL, ("invalid object kernel index passed"));
-
-	ntlv = (ipfw_obj_ntlv *)ipfw_get_sopt_space(sd, sizeof(*ntlv));
-	if (ntlv == NULL)
-		return (ENOMEM);
-
-	ipfw_export_obj_ntlv(no, ntlv);
-	return (0);
-}
-
-/*
- * Dumps static rules with table TLVs in buffer @sd.
- *
- * Returns 0 on success.
- */
-static int
-dump_static_rules(struct ip_fw_chain *chain, struct dump_args *da,
-    uint32_t *bmask, struct sockopt_data *sd)
-{
-	int error;
-	int i, l;
-	uint32_t tcount;
-	ipfw_obj_ctlv *ctlv;
-	struct ip_fw *krule;
-	struct namedobj_instance *ni;
-	caddr_t dst;
-
-	/* Dump table names first (if any) */
-	if (da->tcount > 0) {
-		/* Header first */
-		ctlv = (ipfw_obj_ctlv *)ipfw_get_sopt_space(sd, sizeof(*ctlv));
-		if (ctlv == NULL)
-			return (ENOMEM);
-		ctlv->head.type = IPFW_TLV_TBLNAME_LIST;
-		ctlv->head.length = da->tcount * sizeof(ipfw_obj_ntlv) + 
-		    sizeof(*ctlv);
-		ctlv->count = da->tcount;
-		ctlv->objsize = sizeof(ipfw_obj_ntlv);
-	}
-
-	i = 0;
-	tcount = da->tcount;
-	ni = ipfw_get_table_objhash(chain);
-	while (tcount > 0) {
-		if ((bmask[i / 32] & (1 << (i % 32))) == 0) {
-			i++;
-			continue;
-		}
-
-		/* Jump to shared named object bitmask */
-		if (i >= IPFW_TABLES_MAX) {
-			ni = CHAIN_TO_SRV(chain);
-			i -= IPFW_TABLES_MAX;
-			bmask += IPFW_TABLES_MAX / 32;
-		}
-
-		if ((error = export_objhash_ntlv(ni, i, sd)) != 0)
-			return (error);
-
-		i++;
-		tcount--;
-	}
-
-	/* Dump rules */
-	ctlv = (ipfw_obj_ctlv *)ipfw_get_sopt_space(sd, sizeof(*ctlv));
-	if (ctlv == NULL)
-		return (ENOMEM);
-	ctlv->head.type = IPFW_TLV_RULE_LIST;
-	ctlv->head.length = da->rsize + sizeof(*ctlv);
-	ctlv->count = da->rcount;
-
-	for (i = da->b; i < da->e; i++) {
-		krule = chain->map[i];
-
-		l = RULEUSIZE1(krule) + sizeof(ipfw_obj_tlv);
-		if (da->rcounters != 0)
-			l += sizeof(struct ip_fw_bcounter);
-		dst = (caddr_t)ipfw_get_sopt_space(sd, l);
-		if (dst == NULL)
-			return (ENOMEM);
-
-		export_rule1(krule, dst, l, da->rcounters);
-	}
-
-	return (0);
-}
-
-/*
- * Marks every object index used in @rule with bit in @bmask.
- * Used to generate bitmask of referenced tables/objects for given ruleset
- * or its part.
- *
- * Returns number of newly-referenced objects.
- */
-static int
-mark_object_kidx(struct ip_fw_chain *ch, struct ip_fw *rule,
-    uint32_t *bmask)
-{
-	struct opcode_obj_rewrite *rw;
-	ipfw_insn *cmd;
-	int bidx, cmdlen, l, count;
-	uint16_t kidx;
-	uint8_t subtype;
-
-	l = rule->cmd_len;
-	cmd = rule->cmd;
-	cmdlen = 0;
-	count = 0;
-	for ( ;	l > 0 ; l -= cmdlen, cmd += cmdlen) {
-		cmdlen = F_LEN(cmd);
-
-		rw = find_op_rw(cmd, &kidx, &subtype);
-		if (rw == NULL)
-			continue;
-
-		bidx = kidx / 32;
-		/*
-		 * Maintain separate bitmasks for table and
-		 * non-table objects.
-		 */
-		if (rw->etlv != IPFW_TLV_TBL_NAME)
-			bidx += IPFW_TABLES_MAX / 32;
-
-		if ((bmask[bidx] & (1 << (kidx % 32))) == 0)
-			count++;
-
-		bmask[bidx] |= 1 << (kidx % 32);
-	}
-
-	return (count);
-}
-
-/*
- * Dumps requested objects data
- * Data layout (version 0)(current):
- * Request: [ ipfw_cfg_lheader ] + IPFW_CFG_GET_* flags
- *   size = ipfw_cfg_lheader.size
- * Reply: [ ipfw_cfg_lheader 
- *   [ ipfw_obj_ctlv(IPFW_TLV_TBL_LIST) ipfw_obj_ntlv x N ] (optional)
- *   [ ipfw_obj_ctlv(IPFW_TLV_RULE_LIST)
- *     ipfw_obj_tlv(IPFW_TLV_RULE_ENT) [ ip_fw_bcounter (optional) ip_fw_rule ]
- *   ] (optional)
- *   [ ipfw_obj_ctlv(IPFW_TLV_STATE_LIST) ipfw_obj_dyntlv x N ] (optional)
- * ]
- * * NOTE IPFW_TLV_STATE_LIST has the single valid field: objsize.
- * The rest (size, count) are set to zero and needs to be ignored.
- *
- * Returns 0 on success.
- */
-static int
-dump_config(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
-    struct sockopt_data *sd)
-{
-	ipfw_cfg_lheader *hdr;
-	struct ip_fw *rule;
-	size_t sz, rnum;
-	uint32_t hdr_flags;
-	int error, i;
-	struct dump_args da;
-	uint32_t *bmask;
-
-	hdr = (ipfw_cfg_lheader *)ipfw_get_sopt_header(sd, sizeof(*hdr));
-	if (hdr == NULL)
-		return (EINVAL);
-
-	error = 0;
-	bmask = NULL;
-	/* Allocate needed state. Note we allocate 2xspace mask, for table&srv  */
-	if (hdr->flags & IPFW_CFG_GET_STATIC)
-		bmask = malloc(IPFW_TABLES_MAX / 4, M_TEMP, M_WAITOK | M_ZERO);
-
-	IPFW_UH_RLOCK(chain);
-
-	/*
-	 * STAGE 1: Determine size/count for objects in range.
-	 * Prepare used tables bitmask.
-	 */
-	sz = sizeof(ipfw_cfg_lheader);
-	memset(&da, 0, sizeof(da));
-
-	da.b = 0;
-	da.e = chain->n_rules;
-
-	if (hdr->end_rule != 0) {
-		/* Handle custom range */
-		if ((rnum = hdr->start_rule) > IPFW_DEFAULT_RULE)
-			rnum = IPFW_DEFAULT_RULE;
-		da.b = ipfw_find_rule(chain, rnum, 0);
-		rnum = hdr->end_rule;
-		rnum = (rnum < IPFW_DEFAULT_RULE) ? rnum+1 : IPFW_DEFAULT_RULE;
-		da.e = ipfw_find_rule(chain, rnum, 0) + 1;
-	}
-
-	if (hdr->flags & IPFW_CFG_GET_STATIC) {
-		for (i = da.b; i < da.e; i++) {
-			rule = chain->map[i];
-			da.rsize += RULEUSIZE1(rule) + sizeof(ipfw_obj_tlv);
-			da.rcount++;
-			/* Update bitmask of used objects for given range */
-			da.tcount += mark_object_kidx(chain, rule, bmask);
-		}
-		/* Add counters if requested */
-		if (hdr->flags & IPFW_CFG_GET_COUNTERS) {
-			da.rsize += sizeof(struct ip_fw_bcounter) * da.rcount;
-			da.rcounters = 1;
-		}
-
-		if (da.tcount > 0)
-			sz += da.tcount * sizeof(ipfw_obj_ntlv) +
-			    sizeof(ipfw_obj_ctlv);
-		sz += da.rsize + sizeof(ipfw_obj_ctlv);
-	}
-
-	if (hdr->flags & IPFW_CFG_GET_STATES)
-		sz += ipfw_dyn_get_count() * sizeof(ipfw_obj_dyntlv) +
-		     sizeof(ipfw_obj_ctlv);
-
-
-	/*
-	 * Fill header anyway.
-	 * Note we have to save header fields to stable storage
-	 * buffer inside @sd can be flushed after dumping rules
-	 */
-	hdr->size = sz;
-	hdr->set_mask = ~V_set_disable;
-	hdr_flags = hdr->flags;
-	hdr = NULL;
-
-	if (sd->valsize < sz) {
-		error = ENOMEM;
-		goto cleanup;
-	}
-
-	/* STAGE2: Store actual data */
-	if (hdr_flags & IPFW_CFG_GET_STATIC) {
-		error = dump_static_rules(chain, &da, bmask, sd);
-		if (error != 0)
-			goto cleanup;
-	}
-
-	if (hdr_flags & IPFW_CFG_GET_STATES)
-		error = ipfw_dump_states(chain, sd);
-
-cleanup:
-	IPFW_UH_RUNLOCK(chain);
-
-	if (bmask != NULL)
-		free(bmask, M_TEMP);
-
-	return (error);
-}
-
-int
-ipfw_check_object_name_generic(const char *name)
-{
-	int nsize;
-
-	nsize = sizeof(((ipfw_obj_ntlv *)0)->name);
-	if (strnlen(name, nsize) == nsize)
-		return (EINVAL);
-	if (name[0] == '\0')
-		return (EINVAL);
-	return (0);
-}
-
-/*
- * Creates non-existent objects referenced by rule.
- *
- * Return 0 on success.
- */
-int
-create_objects_compat(struct ip_fw_chain *ch, ipfw_insn *cmd,
-    struct obj_idx *oib, struct obj_idx *pidx, struct tid_info *ti)
-{
-	struct opcode_obj_rewrite *rw;
-	struct obj_idx *p;
-	uint16_t kidx;
-	int error;
-
-	/*
-	 * Compatibility stuff: do actual creation for non-existing,
-	 * but referenced objects.
-	 */
-	for (p = oib; p < pidx; p++) {
-		if (p->kidx != 0)
-			continue;
-
-		ti->uidx = p->uidx;
-		ti->type = p->type;
-		ti->atype = 0;
-
-		rw = find_op_rw(cmd + p->off, NULL, NULL);
-		KASSERT(rw != NULL, ("Unable to find handler for op %d",
-		    (cmd + p->off)->opcode));
-
-		if (rw->create_object == NULL)
-			error = EOPNOTSUPP;
-		else
-			error = rw->create_object(ch, ti, &kidx);
-		if (error == 0) {
-			p->kidx = kidx;
-			continue;
-		}
-
-		/*
-		 * Error happened. We have to rollback everything.
-		 * Drop all already acquired references.
-		 */
-		IPFW_UH_WLOCK(ch);
-		unref_oib_objects(ch, cmd, oib, pidx);
-		IPFW_UH_WUNLOCK(ch);
-
-		return (error);
-	}
-
-	return (0);
-}
-
-/*
- * Compatibility function for old ipfw(8) binaries.
- * Rewrites table/nat kernel indices with userland ones.
- * Convert tables matching '/^\d+$/' to their atoi() value.
- * Use number 65535 for other tables.
- *
- * Returns 0 on success.
- */
-static int
-set_legacy_obj_kidx(struct ip_fw_chain *ch, struct ip_fw_rule0 *rule)
-{
-	struct opcode_obj_rewrite *rw;
-	struct named_object *no;
-	ipfw_insn *cmd;
-	char *end;
-	long val;
-	int cmdlen, error, l;
-	uint16_t kidx, uidx;
-	uint8_t subtype;
-
-	error = 0;
-
-	l = rule->cmd_len;
-	cmd = rule->cmd;
-	cmdlen = 0;
-	for ( ;	l > 0 ; l -= cmdlen, cmd += cmdlen) {
-		cmdlen = F_LEN(cmd);
-
-		/* Check if is index in given opcode */
-		rw = find_op_rw(cmd, &kidx, &subtype);
-		if (rw == NULL)
-			continue;
-
-		/* Try to find referenced kernel object */
-		no = rw->find_bykidx(ch, kidx);
-		if (no == NULL)
-			continue;
-
-		val = strtol(no->name, &end, 10);
-		if (*end == '\0' && val < 65535) {
-			uidx = val;
-		} else {
-
-			/*
-			 * We are called via legacy opcode.
-			 * Save error and show table as fake number
-			 * not to make ipfw(8) hang.
-			 */
-			uidx = 65535;
-			error = 2;
-		}
-
-		rw->update(cmd, uidx);
-	}
-
-	return (error);
-}
-
-
-/*
- * Unreferences all already-referenced objects in given @cmd rule,
- * using information in @oib.
- *
- * Used to rollback partially converted rule on error.
- */
-static void
-unref_oib_objects(struct ip_fw_chain *ch, ipfw_insn *cmd, struct obj_idx *oib,
-    struct obj_idx *end)
-{
-	struct opcode_obj_rewrite *rw;
-	struct named_object *no;
-	struct obj_idx *p;
-
-	IPFW_UH_WLOCK_ASSERT(ch);
-
-	for (p = oib; p < end; p++) {
-		if (p->kidx == 0)
-			continue;
-
-		rw = find_op_rw(cmd + p->off, NULL, NULL);
-		KASSERT(rw != NULL, ("Unable to find handler for op %d",
-		    (cmd + p->off)->opcode));
-
-		/* Find & unref by existing idx */
-		no = rw->find_bykidx(ch, p->kidx);
-		KASSERT(no != NULL, ("Ref'd object %d disappeared", p->kidx));
-		no->refcnt--;
-	}
-}
-
-/*
- * Remove references from every object used in @rule.
- * Used at rule removal code.
- */
-static void
-unref_rule_objects(struct ip_fw_chain *ch, struct ip_fw *rule)
-{
-	struct opcode_obj_rewrite *rw;
-	struct named_object *no;
-	ipfw_insn *cmd;
-	int cmdlen, l;
-	uint16_t kidx;
-	uint8_t subtype;
-
-	IPFW_UH_WLOCK_ASSERT(ch);
-
-	l = rule->cmd_len;
-	cmd = rule->cmd;
-	cmdlen = 0;
-	for ( ;	l > 0 ; l -= cmdlen, cmd += cmdlen) {
-		cmdlen = F_LEN(cmd);
-
-		rw = find_op_rw(cmd, &kidx, &subtype);
-		if (rw == NULL)
-			continue;
-		no = rw->find_bykidx(ch, kidx);
-
-		KASSERT(no != NULL, ("object id %d not found", kidx));
-		KASSERT(no->subtype == subtype,
-		    ("wrong type %d (%d) for object id %d",
-		    no->subtype, subtype, kidx));
-		KASSERT(no->refcnt > 0, ("refcount for object %d is %d",
-		    kidx, no->refcnt));
-
-		if (no->refcnt == 1 && rw->destroy_object != NULL)
-			rw->destroy_object(ch, no);
-		else
-			no->refcnt--;
-	}
-}
-
-
-/*
- * Find and reference object (if any) stored in instruction @cmd.
- *
- * Saves object info in @pidx, sets
- *  - @unresolved to 1 if object should exists but not found
- *
- * Returns non-zero value in case of error.
- */
-static int
-ref_opcode_object(struct ip_fw_chain *ch, ipfw_insn *cmd, struct tid_info *ti,
-    struct obj_idx *pidx, int *unresolved)
-{
-	struct named_object *no;
-	struct opcode_obj_rewrite *rw;
-	int error;
-
-	/* Check if this opcode is candidate for rewrite */
-	rw = find_op_rw(cmd, &ti->uidx, &ti->type);
-	if (rw == NULL)
-		return (0);
-
-	/* Need to rewrite. Save necessary fields */
-	pidx->uidx = ti->uidx;
-	pidx->type = ti->type;
-
-	/* Try to find referenced kernel object */
-	error = rw->find_byname(ch, ti, &no);
-	if (error != 0)
-		return (error);
-	if (no == NULL) {
-		/*
-		 * Report about unresolved object for automaic
-		 * creation.
-		 */
-		*unresolved = 1;
-		return (0);
-	}
-
-	/*
-	 * Object is already exist.
-	 * Its subtype should match with expected value.
-	 */
-	if (ti->type != no->subtype)
-		return (EINVAL);
-
-	/* Bump refcount and update kidx. */
-	no->refcnt++;
-	rw->update(cmd, no->kidx);
-	return (0);
-}
-
-/*
- * Finds and bumps refcount for objects referenced by given @rule.
- * Auto-creates non-existing tables.
- * Fills in @oib array with userland/kernel indexes.
- *
- * Returns 0 on success.
- */
-static int
-ref_rule_objects(struct ip_fw_chain *ch, struct ip_fw *rule,
-    struct rule_check_info *ci, struct obj_idx *oib, struct tid_info *ti)
-{
-	struct obj_idx *pidx;
-	ipfw_insn *cmd;
-	int cmdlen, error, l, unresolved;
-
-	pidx = oib;
-	l = rule->cmd_len;
-	cmd = rule->cmd;
-	cmdlen = 0;
-	error = 0;
-
-	IPFW_UH_WLOCK(ch);
-
-	/* Increase refcount on each existing referenced table. */
-	for ( ;	l > 0 ; l -= cmdlen, cmd += cmdlen) {
-		cmdlen = F_LEN(cmd);
-		unresolved = 0;
-
-		error = ref_opcode_object(ch, cmd, ti, pidx, &unresolved);
-		if (error != 0)
-			break;
-		/*
-		 * Compatibility stuff for old clients:
-		 * prepare to automaitcally create non-existing objects.
-		 */
-		if (unresolved != 0) {
-			pidx->off = rule->cmd_len - l;
-			pidx++;
-		}
-	}
-
-	if (error != 0) {
-		/* Unref everything we have already done */
-		unref_oib_objects(ch, rule->cmd, oib, pidx);
-		IPFW_UH_WUNLOCK(ch);
-		return (error);
-	}
-	IPFW_UH_WUNLOCK(ch);
-
-	/* Perform auto-creation for non-existing objects */
-	if (pidx != oib)
-		error = create_objects_compat(ch, rule->cmd, oib, pidx, ti);
-
-	/* Calculate real number of dynamic objects */
-	ci->object_opcodes = (uint16_t)(pidx - oib);
-
-	return (error);
-}
-
-/*
- * Checks is opcode is referencing table of appropriate type.
- * Adds reference count for found table if true.
- * Rewrites user-supplied opcode values with kernel ones.
- *
- * Returns 0 on success and appropriate error code otherwise.
- */
-static int
-rewrite_rule_uidx(struct ip_fw_chain *chain, struct rule_check_info *ci)
-{
-	int error;
-	ipfw_insn *cmd;
-	uint8_t type;
-	struct obj_idx *p, *pidx_first, *pidx_last;
-	struct tid_info ti;
-
-	/*
-	 * Prepare an array for storing opcode indices.
-	 * Use stack allocation by default.
-	 */
-	if (ci->object_opcodes <= (sizeof(ci->obuf)/sizeof(ci->obuf[0]))) {
-		/* Stack */
-		pidx_first = ci->obuf;
-	} else
-		pidx_first = malloc(
-		    ci->object_opcodes * sizeof(struct obj_idx),
-		    M_IPFW, M_WAITOK | M_ZERO);
-
-	error = 0;
-	type = 0;
-	memset(&ti, 0, sizeof(ti));
-
-	/* Use set rule is assigned to. */
-	ti.set = ci->krule->set;
-	if (ci->ctlv != NULL) {
-		ti.tlvs = (void *)(ci->ctlv + 1);
-		ti.tlen = ci->ctlv->head.length - sizeof(ipfw_obj_ctlv);
-	}
-
-	/* Reference all used tables and other objects */
-	error = ref_rule_objects(chain, ci->krule, ci, pidx_first, &ti);
-	if (error != 0)
-		goto free;
-	/*
-	 * Note that ref_rule_objects() might have updated ci->object_opcodes
-	 * to reflect actual number of object opcodes.
-	 */
-
-	/* Perform rewrite of remaining opcodes */
-	p = pidx_first;
-	pidx_last = pidx_first + ci->object_opcodes;
-	for (p = pidx_first; p < pidx_last; p++) {
-		cmd = ci->krule->cmd + p->off;
-		update_opcode_kidx(cmd, p->kidx);
-	}
-
-free:
-	if (pidx_first != ci->obuf)
-		free(pidx_first, M_IPFW);
-
-	return (error);
-}
-
-/*
- * Adds one or more rules to ipfw @chain.
- * Data layout (version 0)(current):
- * Request:
- * [
- *   ip_fw3_opheader
- *   [ ipfw_obj_ctlv(IPFW_TLV_TBL_LIST) ipfw_obj_ntlv x N ] (optional *1)
- *   [ ipfw_obj_ctlv(IPFW_TLV_RULE_LIST) ip_fw x N ] (*2) (*3)
- * ]
- * Reply:
- * [
- *   ip_fw3_opheader
- *   [ ipfw_obj_ctlv(IPFW_TLV_TBL_LIST) ipfw_obj_ntlv x N ] (optional)
- *   [ ipfw_obj_ctlv(IPFW_TLV_RULE_LIST) ip_fw x N ]
- * ]
- *
- * Rules in reply are modified to store their actual ruleset number.
- *
- * (*1) TLVs inside IPFW_TLV_TBL_LIST needs to be sorted ascending
- * according to their idx field and there has to be no duplicates.
- * (*2) Numbered rules inside IPFW_TLV_RULE_LIST needs to be sorted ascending.
- * (*3) Each ip_fw structure needs to be aligned to u64 boundary.
- *
- * Returns 0 on success.
- */
-static int
-add_rules(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
-    struct sockopt_data *sd)
-{
-	ipfw_obj_ctlv *ctlv, *rtlv, *tstate;
-	ipfw_obj_ntlv *ntlv;
-	int clen, error, idx;
-	uint32_t count, read;
-	struct ip_fw_rule *r;
-	struct rule_check_info rci, *ci, *cbuf;
-	int i, rsize;
-
-	op3 = (ip_fw3_opheader *)ipfw_get_sopt_space(sd, sd->valsize);
-	ctlv = (ipfw_obj_ctlv *)(op3 + 1);
-
-	read = sizeof(ip_fw3_opheader);
-	rtlv = NULL;
-	tstate = NULL;
-	cbuf = NULL;
-	memset(&rci, 0, sizeof(struct rule_check_info));
-
-	if (read + sizeof(*ctlv) > sd->valsize)
-		return (EINVAL);
-
-	if (ctlv->head.type == IPFW_TLV_TBLNAME_LIST) {
-		clen = ctlv->head.length;
-		/* Check size and alignment */
-		if (clen > sd->valsize || clen < sizeof(*ctlv))
-			return (EINVAL);
-		if ((clen % sizeof(uint64_t)) != 0)
-			return (EINVAL);
-
-		/*
-		 * Some table names or other named objects.
-		 * Check for validness.
-		 */
-		count = (ctlv->head.length - sizeof(*ctlv)) / sizeof(*ntlv);
-		if (ctlv->count != count || ctlv->objsize != sizeof(*ntlv))
-			return (EINVAL);
-
-		/*
-		 * Check each TLV.
-		 * Ensure TLVs are sorted ascending and
-		 * there are no duplicates.
-		 */
-		idx = -1;
-		ntlv = (ipfw_obj_ntlv *)(ctlv + 1);
-		while (count > 0) {
-			if (ntlv->head.length != sizeof(ipfw_obj_ntlv))
-				return (EINVAL);
-
-			error = ipfw_check_object_name_generic(ntlv->name);
-			if (error != 0)
-				return (error);
-
-			if (ntlv->idx <= idx)
-				return (EINVAL);
-
-			idx = ntlv->idx;
-			count--;
-			ntlv++;
-		}
-
-		tstate = ctlv;
-		read += ctlv->head.length;
-		ctlv = (ipfw_obj_ctlv *)((caddr_t)ctlv + ctlv->head.length);
-	}
-
-	if (read + sizeof(*ctlv) > sd->valsize)
-		return (EINVAL);
-
-	if (ctlv->head.type == IPFW_TLV_RULE_LIST) {
-		clen = ctlv->head.length;
-		if (clen + read > sd->valsize || clen < sizeof(*ctlv))
-			return (EINVAL);
-		if ((clen % sizeof(uint64_t)) != 0)
-			return (EINVAL);
-
-		/*
-		 * TODO: Permit adding multiple rules at once
-		 */
-		if (ctlv->count != 1)
-			return (ENOTSUP);
-
-		clen -= sizeof(*ctlv);
-
-		if (ctlv->count > clen / sizeof(struct ip_fw_rule))
-			return (EINVAL);
-
-		/* Allocate state for each rule or use stack */
-		if (ctlv->count == 1) {
-			memset(&rci, 0, sizeof(struct rule_check_info));
-			cbuf = &rci;
-		} else
-			cbuf = malloc(ctlv->count * sizeof(*ci), M_TEMP,
-			    M_WAITOK | M_ZERO);
-		ci = cbuf;
-
-		/*
-		 * Check each rule for validness.
-		 * Ensure numbered rules are sorted ascending
-		 * and properly aligned
-		 */
-		idx = 0;
-		r = (struct ip_fw_rule *)(ctlv + 1);
-		count = 0;
-		error = 0;
-		while (clen > 0) {
-			rsize = roundup2(RULESIZE(r), sizeof(uint64_t));
-			if (rsize > clen || ctlv->count <= count) {
-				error = EINVAL;
-				break;
-			}
-
-			ci->ctlv = tstate;
-			error = check_ipfw_rule1(r, rsize, ci);
-			if (error != 0)
-				break;
-
-			/* Check sorting */
-			if (r->rulenum != 0 && r->rulenum < idx) {
-				printf("rulenum %d idx %d\n", r->rulenum, idx);
-				error = EINVAL;
-				break;
-			}
-			idx = r->rulenum;
-
-			ci->urule = (caddr_t)r;
-
-			rsize = roundup2(rsize, sizeof(uint64_t));
-			clen -= rsize;
-			r = (struct ip_fw_rule *)((caddr_t)r + rsize);
-			count++;
-			ci++;
-		}
-
-		if (ctlv->count != count || error != 0) {
-			if (cbuf != &rci)
-				free(cbuf, M_TEMP);
-			return (EINVAL);
-		}
-
-		rtlv = ctlv;
-		read += ctlv->head.length;
-		ctlv = (ipfw_obj_ctlv *)((caddr_t)ctlv + ctlv->head.length);
-	}
-
-	if (read != sd->valsize || rtlv == NULL || rtlv->count == 0) {
-		if (cbuf != NULL && cbuf != &rci)
-			free(cbuf, M_TEMP);
-		return (EINVAL);
-	}
-
-	/*
-	 * Passed rules seems to be valid.
-	 * Allocate storage and try to add them to chain.
-	 */
-	for (i = 0, ci = cbuf; i < rtlv->count; i++, ci++) {
-		clen = RULEKSIZE1((struct ip_fw_rule *)ci->urule);
-		ci->krule = ipfw_alloc_rule(chain, clen);
-		import_rule1(ci);
-	}
-
-	if ((error = commit_rules(chain, cbuf, rtlv->count)) != 0) {
-		/* Free allocate krules */
-		for (i = 0, ci = cbuf; i < rtlv->count; i++, ci++)
-			free_rule(ci->krule);
-	}
-
-	if (cbuf != NULL && cbuf != &rci)
-		free(cbuf, M_TEMP);
-
-	return (error);
-}
-
-/*
- * Lists all sopts currently registered.
- * Data layout (v0)(current):
- * Request: [ ipfw_obj_lheader ], size = ipfw_obj_lheader.size
- * Reply: [ ipfw_obj_lheader ipfw_sopt_info x N ]
- *
- * Returns 0 on success
- */
-static int
-dump_soptcodes(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
-    struct sockopt_data *sd)
-{
-	struct _ipfw_obj_lheader *olh;
-	ipfw_sopt_info *i;
-	struct ipfw_sopt_handler *sh;
-	uint32_t count, n, size;
-
-	olh = (struct _ipfw_obj_lheader *)ipfw_get_sopt_header(sd,sizeof(*olh));
-	if (olh == NULL)
-		return (EINVAL);
-	if (sd->valsize < olh->size)
-		return (EINVAL);
-
-	CTL3_LOCK();
-	count = ctl3_hsize;
-	size = count * sizeof(ipfw_sopt_info) + sizeof(ipfw_obj_lheader);
-
-	/* Fill in header regadless of buffer size */
-	olh->count = count;
-	olh->objsize = sizeof(ipfw_sopt_info);
-
-	if (size > olh->size) {
-		olh->size = size;
-		CTL3_UNLOCK();
-		return (ENOMEM);
-	}
-	olh->size = size;
-
-	for (n = 1; n <= count; n++) {
-		i = (ipfw_sopt_info *)ipfw_get_sopt_space(sd, sizeof(*i));
-		KASSERT(i != NULL, ("previously checked buffer is not enough"));
-		sh = &ctl3_handlers[n];
-		i->opcode = sh->opcode;
-		i->version = sh->version;
-		i->refcnt = sh->refcnt;
-	}
-	CTL3_UNLOCK();
-
-	return (0);
-}
-
-/*
- * Compares two opcodes.
- * Used both in qsort() and bsearch().
- *
- * Returns 0 if match is found.
- */
-static int
-compare_opcodes(const void *_a, const void *_b)
-{
-	const struct opcode_obj_rewrite *a, *b;
-
-	a = (const struct opcode_obj_rewrite *)_a;
-	b = (const struct opcode_obj_rewrite *)_b;
-
-	if (a->opcode < b->opcode)
-		return (-1);
-	else if (a->opcode > b->opcode)
-		return (1);
-
-	return (0);
-}
-
-/*
- * XXX: Rewrite bsearch()
- */
-static int
-find_op_rw_range(uint16_t op, struct opcode_obj_rewrite **plo,
-    struct opcode_obj_rewrite **phi)
-{
-	struct opcode_obj_rewrite *ctl3_max, *lo, *hi, h, *rw;
-
-	memset(&h, 0, sizeof(h));
-	h.opcode = op;
-
-	rw = (struct opcode_obj_rewrite *)bsearch(&h, ctl3_rewriters,
-	    ctl3_rsize, sizeof(h), compare_opcodes);
-	if (rw == NULL)
-		return (1);
-
-	/* Find the first element matching the same opcode */
-	lo = rw;
-	for ( ; lo > ctl3_rewriters && (lo - 1)->opcode == op; lo--)
-		;
-
-	/* Find the last element matching the same opcode */
-	hi = rw;
-	ctl3_max = ctl3_rewriters + ctl3_rsize;
-	for ( ; (hi + 1) < ctl3_max && (hi + 1)->opcode == op; hi++)
-		;
-
-	*plo = lo;
-	*phi = hi;
-
-	return (0);
-}
-
-/*
- * Finds opcode object rewriter based on @code.
- *
- * Returns pointer to handler or NULL.
- */
-static struct opcode_obj_rewrite *
-find_op_rw(ipfw_insn *cmd, uint16_t *puidx, uint8_t *ptype)
-{
-	struct opcode_obj_rewrite *rw, *lo, *hi;
-	uint16_t uidx;
-	uint8_t subtype;
-
-	if (find_op_rw_range(cmd->opcode, &lo, &hi) != 0)
-		return (NULL);
-
-	for (rw = lo; rw <= hi; rw++) {
-		if (rw->classifier(cmd, &uidx, &subtype) == 0) {
-			if (puidx != NULL)
-				*puidx = uidx;
-			if (ptype != NULL)
-				*ptype = subtype;
-			return (rw);
-		}
-	}
-
-	return (NULL);
-}
-int
-classify_opcode_kidx(ipfw_insn *cmd, uint16_t *puidx)
-{
-
-	if (find_op_rw(cmd, puidx, NULL) == NULL)
-		return (1);
-	return (0);
-}
-
-void
-update_opcode_kidx(ipfw_insn *cmd, uint16_t idx)
-{
-	struct opcode_obj_rewrite *rw;
-
-	rw = find_op_rw(cmd, NULL, NULL);
-	KASSERT(rw != NULL, ("No handler to update opcode %d", cmd->opcode));
-	rw->update(cmd, idx);
-}
-
-void
-ipfw_init_obj_rewriter()
-{
-
-	ctl3_rewriters = NULL;
-	ctl3_rsize = 0;
-}
-
-void
-ipfw_destroy_obj_rewriter()
-{
-
-	if (ctl3_rewriters != NULL)
-		free(ctl3_rewriters, M_IPFW);
-	ctl3_rewriters = NULL;
-	ctl3_rsize = 0;
-}
-
-/*
- * Adds one or more opcode object rewrite handlers to the global array.
- * Function may sleep.
- */
-void
-ipfw_add_obj_rewriter(struct opcode_obj_rewrite *rw, size_t count)
-{
-	size_t sz;
-	struct opcode_obj_rewrite *tmp;
-
-	CTL3_LOCK();
-
-	for (;;) {
-		sz = ctl3_rsize + count;
-		CTL3_UNLOCK();
-		tmp = malloc(sizeof(*rw) * sz, M_IPFW, M_WAITOK | M_ZERO);
-		CTL3_LOCK();
-		if (ctl3_rsize + count <= sz)
-			break;
-
-		/* Retry */
-		free(tmp, M_IPFW);
-	}
-
-	/* Merge old & new arrays */
-	sz = ctl3_rsize + count;
-	memcpy(tmp, ctl3_rewriters, ctl3_rsize * sizeof(*rw));
-	memcpy(&tmp[ctl3_rsize], rw, count * sizeof(*rw));
-	qsort(tmp, sz, sizeof(*rw), compare_opcodes);
-	/* Switch new and free old */
-	if (ctl3_rewriters != NULL)
-		free(ctl3_rewriters, M_IPFW);
-	ctl3_rewriters = tmp;
-	ctl3_rsize = sz;
-
-	CTL3_UNLOCK();
-}
-
-/*
- * Removes one or more object rewrite handlers from the global array.
- */
-int
-ipfw_del_obj_rewriter(struct opcode_obj_rewrite *rw, size_t count)
-{
-	size_t sz;
-	struct opcode_obj_rewrite *ctl3_max, *ktmp, *lo, *hi;
-	int i;
-
-	CTL3_LOCK();
-
-	for (i = 0; i < count; i++) {
-		if (find_op_rw_range(rw[i].opcode, &lo, &hi) != 0)
-			continue;
-
-		for (ktmp = lo; ktmp <= hi; ktmp++) {
-			if (ktmp->classifier != rw[i].classifier)
-				continue;
-
-			ctl3_max = ctl3_rewriters + ctl3_rsize;
-			sz = (ctl3_max - (ktmp + 1)) * sizeof(*ktmp);
-			memmove(ktmp, ktmp + 1, sz);
-			ctl3_rsize--;
-			break;
-		}
-
-	}
-
-	if (ctl3_rsize == 0) {
-		if (ctl3_rewriters != NULL)
-			free(ctl3_rewriters, M_IPFW);
-		ctl3_rewriters = NULL;
-	}
-
-	CTL3_UNLOCK();
-
-	return (0);
-}
-
-static int
-export_objhash_ntlv_internal(struct namedobj_instance *ni,
-    struct named_object *no, void *arg)
-{
-	struct sockopt_data *sd;
-	ipfw_obj_ntlv *ntlv;
-
-	sd = (struct sockopt_data *)arg;
-	ntlv = (ipfw_obj_ntlv *)ipfw_get_sopt_space(sd, sizeof(*ntlv));
-	if (ntlv == NULL)
-		return (ENOMEM);
-	ipfw_export_obj_ntlv(no, ntlv);
-	return (0);
-}
-
-/*
- * Lists all service objects.
- * Data layout (v0)(current):
- * Request: [ ipfw_obj_lheader ] size = ipfw_obj_lheader.size
- * Reply: [ ipfw_obj_lheader [ ipfw_obj_ntlv x N ] (optional) ]
- * Returns 0 on success
- */
-static int
-dump_srvobjects(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
-    struct sockopt_data *sd)
-{
-	ipfw_obj_lheader *hdr;
-	int count;
-
-	hdr = (ipfw_obj_lheader *)ipfw_get_sopt_header(sd, sizeof(*hdr));
-	if (hdr == NULL)
-		return (EINVAL);
-
-	IPFW_UH_RLOCK(chain);
-	count = ipfw_objhash_count(CHAIN_TO_SRV(chain));
-	hdr->size = sizeof(ipfw_obj_lheader) + count * sizeof(ipfw_obj_ntlv);
-	if (sd->valsize < hdr->size) {
-		IPFW_UH_RUNLOCK(chain);
-		return (ENOMEM);
-	}
-	hdr->count = count;
-	hdr->objsize = sizeof(ipfw_obj_ntlv);
-	if (count > 0)
-		ipfw_objhash_foreach(CHAIN_TO_SRV(chain),
-		    export_objhash_ntlv_internal, sd);
-	IPFW_UH_RUNLOCK(chain);
-	return (0);
-}
-
-/*
- * Compares two sopt handlers (code, version and handler ptr).
- * Used both as qsort() and bsearch().
- * Does not compare handler for latter case.
- *
- * Returns 0 if match is found.
- */
-static int
-compare_sh(const void *_a, const void *_b)
-{
-	const struct ipfw_sopt_handler *a, *b;
-
-	a = (const struct ipfw_sopt_handler *)_a;
-	b = (const struct ipfw_sopt_handler *)_b;
-
-	if (a->opcode < b->opcode)
-		return (-1);
-	else if (a->opcode > b->opcode)
-		return (1);
-
-	if (a->version < b->version)
-		return (-1);
-	else if (a->version > b->version)
-		return (1);
-
-	/* bsearch helper */
-	if (a->handler == NULL)
-		return (0);
-
-	if ((uintptr_t)a->handler < (uintptr_t)b->handler)
-		return (-1);
-	else if ((uintptr_t)a->handler > (uintptr_t)b->handler)
-		return (1);
-
-	return (0);
-}
-
-/*
- * Finds sopt handler based on @code and @version.
- *
- * Returns pointer to handler or NULL.
- */
-static struct ipfw_sopt_handler *
-find_sh(uint16_t code, uint8_t version, sopt_handler_f *handler)
-{
-	struct ipfw_sopt_handler *sh, h;
-
-	memset(&h, 0, sizeof(h));
-	h.opcode = code;
-	h.version = version;
-	h.handler = handler;
-
-	sh = (struct ipfw_sopt_handler *)bsearch(&h, ctl3_handlers,
-	    ctl3_hsize, sizeof(h), compare_sh);
-
-	return (sh);
-}
-
-static int
-find_ref_sh(uint16_t opcode, uint8_t version, struct ipfw_sopt_handler *psh)
-{
-	struct ipfw_sopt_handler *sh;
-
-	CTL3_LOCK();
-	if ((sh = find_sh(opcode, version, NULL)) == NULL) {
-		CTL3_UNLOCK();
-		printf("ipfw: ipfw_ctl3 invalid option %d""v""%d\n",
-		    opcode, version);
-		return (EINVAL);
-	}
-	sh->refcnt++;
-	ctl3_refct++;
-	/* Copy handler data to requested buffer */
-	*psh = *sh; 
-	CTL3_UNLOCK();
-
-	return (0);
-}
-
-static void
-find_unref_sh(struct ipfw_sopt_handler *psh)
-{
-	struct ipfw_sopt_handler *sh;
-
-	CTL3_LOCK();
-	sh = find_sh(psh->opcode, psh->version, NULL);
-	KASSERT(sh != NULL, ("ctl3 handler disappeared"));
-	sh->refcnt--;
-	ctl3_refct--;
-	CTL3_UNLOCK();
-}
-
-void
-ipfw_init_sopt_handler()
-{
-
-	CTL3_LOCK_INIT();
-	IPFW_ADD_SOPT_HANDLER(1, scodes);
-}
-
-void
-ipfw_destroy_sopt_handler()
-{
-
-	IPFW_DEL_SOPT_HANDLER(1, scodes);
-	CTL3_LOCK_DESTROY();
-}
-
-/*
- * Adds one or more sockopt handlers to the global array.
- * Function may sleep.
- */
-void
-ipfw_add_sopt_handler(struct ipfw_sopt_handler *sh, size_t count)
-{
-	size_t sz;
-	struct ipfw_sopt_handler *tmp;
-
-	CTL3_LOCK();
-
-	for (;;) {
-		sz = ctl3_hsize + count;
-		CTL3_UNLOCK();
-		tmp = malloc(sizeof(*sh) * sz, M_IPFW, M_WAITOK | M_ZERO);
-		CTL3_LOCK();
-		if (ctl3_hsize + count <= sz)
-			break;
-
-		/* Retry */
-		free(tmp, M_IPFW);
-	}
-
-	/* Merge old & new arrays */
-	sz = ctl3_hsize + count;
-	memcpy(tmp, ctl3_handlers, ctl3_hsize * sizeof(*sh));
-	memcpy(&tmp[ctl3_hsize], sh, count * sizeof(*sh));
-	qsort(tmp, sz, sizeof(*sh), compare_sh);
-	/* Switch new and free old */
-	if (ctl3_handlers != NULL)
-		free(ctl3_handlers, M_IPFW);
-	ctl3_handlers = tmp;
-	ctl3_hsize = sz;
-	ctl3_gencnt++;
-
-	CTL3_UNLOCK();
-}
-
-/*
- * Removes one or more sockopt handlers from the global array.
- */
-int
-ipfw_del_sopt_handler(struct ipfw_sopt_handler *sh, size_t count)
-{
-	size_t sz;
-	struct ipfw_sopt_handler *tmp, *h;
-	int i;
-
-	CTL3_LOCK();
-
-	for (i = 0; i < count; i++) {
-		tmp = &sh[i];
-		h = find_sh(tmp->opcode, tmp->version, tmp->handler);
-		if (h == NULL)
-			continue;
-
-		sz = (ctl3_handlers + ctl3_hsize - (h + 1)) * sizeof(*h);
-		memmove(h, h + 1, sz);
-		ctl3_hsize--;
-	}
-
-	if (ctl3_hsize == 0) {
-		if (ctl3_handlers != NULL)
-			free(ctl3_handlers, M_IPFW);
-		ctl3_handlers = NULL;
-	}
-
-	ctl3_gencnt++;
-
-	CTL3_UNLOCK();
-
-	return (0);
-}
-
-/*
- * Writes data accumulated in @sd to sockopt buffer.
- * Zeroes internal @sd buffer.
- */
-static int
-ipfw_flush_sopt_data(struct sockopt_data *sd)
-{
-	struct sockopt *sopt;
-	int error;
-	size_t sz;
-
-	sz = sd->koff;
-	if (sz == 0)
-		return (0);
-
-	sopt = sd->sopt;
-
-	if (sopt->sopt_dir == SOPT_GET) {
-		error = copyout(sd->kbuf, sopt->sopt_val, sz);
-		if (error != 0)
-			return (error);
-	}
-
-	memset(sd->kbuf, 0, sd->ksize);
-	sd->ktotal += sz;
-	sd->koff = 0;
-	if (sd->ktotal + sd->ksize < sd->valsize)
-		sd->kavail = sd->ksize;
-	else
-		sd->kavail = sd->valsize - sd->ktotal;
-
-	/* Update sopt buffer data */
-	sopt->sopt_valsize = sd->ktotal;
-	sopt->sopt_val = sd->sopt_val + sd->ktotal;
-
-	return (0);
-}
-
-/*
- * Ensures that @sd buffer has contiguous @neeeded number of
- * bytes.
- *
- * Returns pointer to requested space or NULL.
- */
-caddr_t
-ipfw_get_sopt_space(struct sockopt_data *sd, size_t needed)
-{
-	int error;
-	caddr_t addr;
-
-	if (sd->kavail < needed) {
-		/*
-		 * Flush data and try another time.
-		 */
-		error = ipfw_flush_sopt_data(sd);
-
-		if (sd->kavail < needed || error != 0)
-			return (NULL);
-	}
-
-	addr = sd->kbuf + sd->koff;
-	sd->koff += needed;
-	sd->kavail -= needed;
-	return (addr);
-}
-
-/*
- * Requests @needed contiguous bytes from @sd buffer.
- * Function is used to notify subsystem that we are
- * interesed in first @needed bytes (request header)
- * and the rest buffer can be safely zeroed.
- *
- * Returns pointer to requested space or NULL.
- */
-caddr_t
-ipfw_get_sopt_header(struct sockopt_data *sd, size_t needed)
-{
-	caddr_t addr;
-
-	if ((addr = ipfw_get_sopt_space(sd, needed)) == NULL)
-		return (NULL);
-
-	if (sd->kavail > 0)
-		memset(sd->kbuf + sd->koff, 0, sd->kavail);
-	
-	return (addr);
-}
-
-/*
- * New sockopt handler.
- */
-int
-ipfw_ctl3(struct sockopt *sopt)
-{
-	int error, locked;
-	size_t size, valsize;
-	struct ip_fw_chain *chain;
-	char xbuf[256];
-	struct sockopt_data sdata;
-	struct ipfw_sopt_handler h;
-	ip_fw3_opheader *op3 = NULL;
-
-	error = priv_check(sopt->sopt_td, PRIV_NETINET_IPFW);
-	if (error != 0)
-		return (error);
-
-	if (sopt->sopt_name != IP_FW3)
-		return (ipfw_ctl(sopt));
-
-	chain = &V_layer3_chain;
-	error = 0;
-
-	/* Save original valsize before it is altered via sooptcopyin() */
-	valsize = sopt->sopt_valsize;
-	memset(&sdata, 0, sizeof(sdata));
-	/* Read op3 header first to determine actual operation */
-	op3 = (ip_fw3_opheader *)xbuf;
-	error = sooptcopyin(sopt, op3, sizeof(*op3), sizeof(*op3));
-	if (error != 0)
-		return (error);
-	sopt->sopt_valsize = valsize;
-
-	/*
-	 * Find and reference command.
-	 */
-	error = find_ref_sh(op3->opcode, op3->version, &h);
-	if (error != 0)
-		return (error);
-
-	/*
-	 * Disallow modifications in really-really secure mode, but still allow
-	 * the logging counters to be reset.
-	 */
-	if ((h.dir & HDIR_SET) != 0 && h.opcode != IP_FW_XRESETLOG) {
-		error = securelevel_ge(sopt->sopt_td->td_ucred, 3);
-		if (error != 0) {
-			find_unref_sh(&h);
-			return (error);
-		}
-	}
-
-	/*
-	 * Fill in sockopt_data structure that may be useful for
-	 * IP_FW3 get requests.
-	 */
-	locked = 0;
-	if (valsize <= sizeof(xbuf)) {
-		/* use on-stack buffer */
-		sdata.kbuf = xbuf;
-		sdata.ksize = sizeof(xbuf);
-		sdata.kavail = valsize;
-	} else {
-
-		/*
-		 * Determine opcode type/buffer size:
-		 * allocate sliding-window buf for data export or
-		 * contiguous buffer for special ops.
-		 */
-		if ((h.dir & HDIR_SET) != 0) {
-			/* Set request. Allocate contigous buffer. */
-			if (valsize > CTL3_LARGEBUF) {
-				find_unref_sh(&h);
-				return (EFBIG);
-			}
-
-			size = valsize;
-		} else {
-			/* Get request. Allocate sliding window buffer */
-			size = (valsize<CTL3_SMALLBUF) ? valsize:CTL3_SMALLBUF;
-
-			if (size < valsize) {
-				/* We have to wire user buffer */
-				error = vslock(sopt->sopt_val, valsize);
-				if (error != 0)
-					return (error);
-				locked = 1;
-			}
-		}
-
-		sdata.kbuf = malloc(size, M_TEMP, M_WAITOK | M_ZERO);
-		sdata.ksize = size;
-		sdata.kavail = size;
-	}
-
-	sdata.sopt = sopt;
-	sdata.sopt_val = sopt->sopt_val;
-	sdata.valsize = valsize;
-
-	/*
-	 * Copy either all request (if valsize < bsize_max)
-	 * or first bsize_max bytes to guarantee most consumers
-	 * that all necessary data has been copied).
-	 * Anyway, copy not less than sizeof(ip_fw3_opheader).
-	 */
-	if ((error = sooptcopyin(sopt, sdata.kbuf, sdata.ksize,
-	    sizeof(ip_fw3_opheader))) != 0)
-		return (error);
-	op3 = (ip_fw3_opheader *)sdata.kbuf;
-
-	/* Finally, run handler */
-	error = h.handler(chain, op3, &sdata);
-	find_unref_sh(&h);
-
-	/* Flush state and free buffers */
-	if (error == 0)
-		error = ipfw_flush_sopt_data(&sdata);
-	else
-		ipfw_flush_sopt_data(&sdata);
-
-	if (locked != 0)
-		vsunlock(sdata.sopt_val, valsize);
-
-	/* Restore original pointer and set number of bytes written */
-	sopt->sopt_val = sdata.sopt_val;
-	sopt->sopt_valsize = sdata.ktotal;
-	if (sdata.kbuf != xbuf)
-		free(sdata.kbuf, M_TEMP);
-
-	return (error);
-}
-
-/**
- * {set|get}sockopt parser.
- */
-int
-ipfw_ctl(struct sockopt *sopt)
-{
-#define	RULE_MAXSIZE	(512*sizeof(u_int32_t))
-	int error;
-	size_t size, valsize;
-	struct ip_fw *buf;
-	struct ip_fw_rule0 *rule;
-	struct ip_fw_chain *chain;
-	u_int32_t rulenum[2];
-	uint32_t opt;
-	struct rule_check_info ci;
-	IPFW_RLOCK_TRACKER;
-
-	chain = &V_layer3_chain;
-	error = 0;
-
-	/* Save original valsize before it is altered via sooptcopyin() */
-	valsize = sopt->sopt_valsize;
-	opt = sopt->sopt_name;
-
-	/*
-	 * Disallow modifications in really-really secure mode, but still allow
-	 * the logging counters to be reset.
-	 */
-	if (opt == IP_FW_ADD ||
-	    (sopt->sopt_dir == SOPT_SET && opt != IP_FW_RESETLOG)) {
-		error = securelevel_ge(sopt->sopt_td->td_ucred, 3);
-		if (error != 0)
-			return (error);
-	}
-
-	switch (opt) {
-	case IP_FW_GET:
-		/*
-		 * pass up a copy of the current rules. Static rules
-		 * come first (the last of which has number IPFW_DEFAULT_RULE),
-		 * followed by a possibly empty list of dynamic rule.
-		 * The last dynamic rule has NULL in the "next" field.
-		 *
-		 * Note that the calculated size is used to bound the
-		 * amount of data returned to the user.  The rule set may
-		 * change between calculating the size and returning the
-		 * data in which case we'll just return what fits.
-		 */
-		for (;;) {
-			int len = 0, want;
-
-			size = chain->static_len;
-			size += ipfw_dyn_len();
-			if (size >= sopt->sopt_valsize)
-				break;
-			buf = malloc(size, M_TEMP, M_WAITOK | M_ZERO);
-			IPFW_UH_RLOCK(chain);
-			/* check again how much space we need */
-			want = chain->static_len + ipfw_dyn_len();
-			if (size >= want)
-				len = ipfw_getrules(chain, buf, size);
-			IPFW_UH_RUNLOCK(chain);
-			if (size >= want)
-				error = sooptcopyout(sopt, buf, len);
-			free(buf, M_TEMP);
-			if (size >= want)
-				break;
-		}
-		break;
-
-	case IP_FW_FLUSH:
-		/* locking is done within del_entry() */
-		error = del_entry(chain, 0); /* special case, rule=0, cmd=0 means all */
-		break;
-
-	case IP_FW_ADD:
-		rule = malloc(RULE_MAXSIZE, M_TEMP, M_WAITOK);
-		error = sooptcopyin(sopt, rule, RULE_MAXSIZE,
-			sizeof(struct ip_fw7) );
-
-		memset(&ci, 0, sizeof(struct rule_check_info));
-
-		/*
-		 * If the size of commands equals RULESIZE7 then we assume
-		 * a FreeBSD7.2 binary is talking to us (set is7=1).
-		 * is7 is persistent so the next 'ipfw list' command
-		 * will use this format.
-		 * NOTE: If wrong version is guessed (this can happen if
-		 *       the first ipfw command is 'ipfw [pipe] list')
-		 *       the ipfw binary may crash or loop infinitly...
-		 */
-		size = sopt->sopt_valsize;
-		if (size == RULESIZE7(rule)) {
-		    is7 = 1;
-		    error = convert_rule_to_8(rule);
-		    if (error) {
-			free(rule, M_TEMP);
-			return error;
-		    }
-		    size = RULESIZE(rule);
-		} else
-		    is7 = 0;
-		if (error == 0)
-			error = check_ipfw_rule0(rule, size, &ci);
-		if (error == 0) {
-			/* locking is done within add_rule() */
-			struct ip_fw *krule;
-			krule = ipfw_alloc_rule(chain, RULEKSIZE0(rule));
-			ci.urule = (caddr_t)rule;
-			ci.krule = krule;
-			import_rule0(&ci);
-			error = commit_rules(chain, &ci, 1);
-			if (error != 0)
-				free_rule(ci.krule);
-			else if (sopt->sopt_dir == SOPT_GET) {
-				if (is7) {
-					error = convert_rule_to_7(rule);
-					size = RULESIZE7(rule);
-					if (error) {
-						free(rule, M_TEMP);
-						return error;
-					}
-				}
-				error = sooptcopyout(sopt, rule, size);
-			}
-		}
-		free(rule, M_TEMP);
-		break;
-
-	case IP_FW_DEL:
-		/*
-		 * IP_FW_DEL is used for deleting single rules or sets,
-		 * and (ab)used to atomically manipulate sets. Argument size
-		 * is used to distinguish between the two:
-		 *    sizeof(u_int32_t)
-		 *	delete single rule or set of rules,
-		 *	or reassign rules (or sets) to a different set.
-		 *    2*sizeof(u_int32_t)
-		 *	atomic disable/enable sets.
-		 *	first u_int32_t contains sets to be disabled,
-		 *	second u_int32_t contains sets to be enabled.
-		 */
-		error = sooptcopyin(sopt, rulenum,
-			2*sizeof(u_int32_t), sizeof(u_int32_t));
-		if (error)
-			break;
-		size = sopt->sopt_valsize;
-		if (size == sizeof(u_int32_t) && rulenum[0] != 0) {
-			/* delete or reassign, locking done in del_entry() */
-			error = del_entry(chain, rulenum[0]);
-		} else if (size == 2*sizeof(u_int32_t)) { /* set enable/disable */
-			IPFW_UH_WLOCK(chain);
-			V_set_disable =
-			    (V_set_disable | rulenum[0]) & ~rulenum[1] &
-			    ~(1<<RESVD_SET); /* set RESVD_SET always enabled */
-			IPFW_UH_WUNLOCK(chain);
-		} else
-			error = EINVAL;
-		break;
-
-	case IP_FW_ZERO:
-	case IP_FW_RESETLOG: /* argument is an u_int_32, the rule number */
-		rulenum[0] = 0;
-		if (sopt->sopt_val != 0) {
-		    error = sooptcopyin(sopt, rulenum,
-			    sizeof(u_int32_t), sizeof(u_int32_t));
-		    if (error)
-			break;
-		}
-		error = zero_entry(chain, rulenum[0],
-			sopt->sopt_name == IP_FW_RESETLOG);
-		break;
-
-	/*--- TABLE opcodes ---*/
-	case IP_FW_TABLE_ADD:
-	case IP_FW_TABLE_DEL:
-		{
-			ipfw_table_entry ent;
-			struct tentry_info tei;
-			struct tid_info ti;
-			struct table_value v;
-
-			error = sooptcopyin(sopt, &ent,
-			    sizeof(ent), sizeof(ent));
-			if (error)
-				break;
-
-			memset(&tei, 0, sizeof(tei));
-			tei.paddr = &ent.addr;
-			tei.subtype = AF_INET;
-			tei.masklen = ent.masklen;
-			ipfw_import_table_value_legacy(ent.value, &v);
-			tei.pvalue = &v;
-			memset(&ti, 0, sizeof(ti));
-			ti.uidx = ent.tbl;
-			ti.type = IPFW_TABLE_CIDR;
-
-			error = (opt == IP_FW_TABLE_ADD) ?
-			    add_table_entry(chain, &ti, &tei, 0, 1) :
-			    del_table_entry(chain, &ti, &tei, 0, 1);
-		}
-		break;
-
-
-	case IP_FW_TABLE_FLUSH:
-		{
-			u_int16_t tbl;
-			struct tid_info ti;
-
-			error = sooptcopyin(sopt, &tbl,
-			    sizeof(tbl), sizeof(tbl));
-			if (error)
-				break;
-			memset(&ti, 0, sizeof(ti));
-			ti.uidx = tbl;
-			error = flush_table(chain, &ti);
-		}
-		break;
-
-	case IP_FW_TABLE_GETSIZE:
-		{
-			u_int32_t tbl, cnt;
-			struct tid_info ti;
-
-			if ((error = sooptcopyin(sopt, &tbl, sizeof(tbl),
-			    sizeof(tbl))))
-				break;
-			memset(&ti, 0, sizeof(ti));
-			ti.uidx = tbl;
-			IPFW_RLOCK(chain);
-			error = ipfw_count_table(chain, &ti, &cnt);
-			IPFW_RUNLOCK(chain);
-			if (error)
-				break;
-			error = sooptcopyout(sopt, &cnt, sizeof(cnt));
-		}
-		break;
-
-	case IP_FW_TABLE_LIST:
-		{
-			ipfw_table *tbl;
-			struct tid_info ti;
-
-			if (sopt->sopt_valsize < sizeof(*tbl)) {
-				error = EINVAL;
-				break;
-			}
-			size = sopt->sopt_valsize;
-			tbl = malloc(size, M_TEMP, M_WAITOK);
-			error = sooptcopyin(sopt, tbl, size, sizeof(*tbl));
-			if (error) {
-				free(tbl, M_TEMP);
-				break;
-			}
-			tbl->size = (size - sizeof(*tbl)) /
-			    sizeof(ipfw_table_entry);
-			memset(&ti, 0, sizeof(ti));
-			ti.uidx = tbl->tbl;
-			IPFW_RLOCK(chain);
-			error = ipfw_dump_table_legacy(chain, &ti, tbl);
-			IPFW_RUNLOCK(chain);
-			if (error) {
-				free(tbl, M_TEMP);
-				break;
-			}
-			error = sooptcopyout(sopt, tbl, size);
-			free(tbl, M_TEMP);
-		}
-		break;
-
-	/*--- NAT operations are protected by the IPFW_LOCK ---*/
-	case IP_FW_NAT_CFG:
-		if (IPFW_NAT_LOADED)
-			error = ipfw_nat_cfg_ptr(sopt);
-		else {
-			printf("IP_FW_NAT_CFG: %s\n",
-			    "ipfw_nat not present, please load it");
-			error = EINVAL;
-		}
-		break;
-
-	case IP_FW_NAT_DEL:
-		if (IPFW_NAT_LOADED)
-			error = ipfw_nat_del_ptr(sopt);
-		else {
-			printf("IP_FW_NAT_DEL: %s\n",
-			    "ipfw_nat not present, please load it");
-			error = EINVAL;
-		}
-		break;
-
-	case IP_FW_NAT_GET_CONFIG:
-		if (IPFW_NAT_LOADED)
-			error = ipfw_nat_get_cfg_ptr(sopt);
-		else {
-			printf("IP_FW_NAT_GET_CFG: %s\n",
-			    "ipfw_nat not present, please load it");
-			error = EINVAL;
-		}
-		break;
-
-	case IP_FW_NAT_GET_LOG:
-		if (IPFW_NAT_LOADED)
-			error = ipfw_nat_get_log_ptr(sopt);
-		else {
-			printf("IP_FW_NAT_GET_LOG: %s\n",
-			    "ipfw_nat not present, please load it");
-			error = EINVAL;
-		}
-		break;
-
-	default:
-		printf("ipfw: ipfw_ctl invalid option %d\n", sopt->sopt_name);
-		error = EINVAL;
-	}
-
-	return (error);
-#undef RULE_MAXSIZE
-}
-#define	RULE_MAXSIZE	(256*sizeof(u_int32_t))
-
-/* Functions to convert rules 7.2 <==> 8.0 */
-static int
-convert_rule_to_7(struct ip_fw_rule0 *rule)
-{
-	/* Used to modify original rule */
-	struct ip_fw7 *rule7 = (struct ip_fw7 *)rule;
-	/* copy of original rule, version 8 */
-	struct ip_fw_rule0 *tmp;
-
-	/* Used to copy commands */
-	ipfw_insn *ccmd, *dst;
-	int ll = 0, ccmdlen = 0;
-
-	tmp = malloc(RULE_MAXSIZE, M_TEMP, M_NOWAIT | M_ZERO);
-	if (tmp == NULL) {
-		return 1; //XXX error
-	}
-	bcopy(rule, tmp, RULE_MAXSIZE);
-
-	/* Copy fields */
-	//rule7->_pad = tmp->_pad;
-	rule7->set = tmp->set;
-	rule7->rulenum = tmp->rulenum;
-	rule7->cmd_len = tmp->cmd_len;
-	rule7->act_ofs = tmp->act_ofs;
-	rule7->next_rule = (struct ip_fw7 *)tmp->next_rule;
-	rule7->cmd_len = tmp->cmd_len;
-	rule7->pcnt = tmp->pcnt;
-	rule7->bcnt = tmp->bcnt;
-	rule7->timestamp = tmp->timestamp;
-
-	/* Copy commands */
-	for (ll = tmp->cmd_len, ccmd = tmp->cmd, dst = rule7->cmd ;
-			ll > 0 ; ll -= ccmdlen, ccmd += ccmdlen, dst += ccmdlen) {
-		ccmdlen = F_LEN(ccmd);
-
-		bcopy(ccmd, dst, F_LEN(ccmd)*sizeof(uint32_t));
-
-		if (dst->opcode > O_NAT)
-			/* O_REASS doesn't exists in 7.2 version, so
-			 * decrement opcode if it is after O_REASS
-			 */
-			dst->opcode--;
-
-		if (ccmdlen > ll) {
-			printf("ipfw: opcode %d size truncated\n",
-				ccmd->opcode);
-			return EINVAL;
-		}
-	}
-	free(tmp, M_TEMP);
-
-	return 0;
-}
-
-static int
-convert_rule_to_8(struct ip_fw_rule0 *rule)
-{
-	/* Used to modify original rule */
-	struct ip_fw7 *rule7 = (struct ip_fw7 *) rule;
-
-	/* Used to copy commands */
-	ipfw_insn *ccmd, *dst;
-	int ll = 0, ccmdlen = 0;
-
-	/* Copy of original rule */
-	struct ip_fw7 *tmp = malloc(RULE_MAXSIZE, M_TEMP, M_NOWAIT | M_ZERO);
-	if (tmp == NULL) {
-		return 1; //XXX error
-	}
-
-	bcopy(rule7, tmp, RULE_MAXSIZE);
-
-	for (ll = tmp->cmd_len, ccmd = tmp->cmd, dst = rule->cmd ;
-			ll > 0 ; ll -= ccmdlen, ccmd += ccmdlen, dst += ccmdlen) {
-		ccmdlen = F_LEN(ccmd);
-		
-		bcopy(ccmd, dst, F_LEN(ccmd)*sizeof(uint32_t));
-
-		if (dst->opcode > O_NAT)
-			/* O_REASS doesn't exists in 7.2 version, so
-			 * increment opcode if it is after O_REASS
-			 */
-			dst->opcode++;
-
-		if (ccmdlen > ll) {
-			printf("ipfw: opcode %d size truncated\n",
-			    ccmd->opcode);
-			return EINVAL;
-		}
-	}
-
-	rule->_pad = tmp->_pad;
-	rule->set = tmp->set;
-	rule->rulenum = tmp->rulenum;
-	rule->cmd_len = tmp->cmd_len;
-	rule->act_ofs = tmp->act_ofs;
-	rule->next_rule = (struct ip_fw *)tmp->next_rule;
-	rule->cmd_len = tmp->cmd_len;
-	rule->id = 0; /* XXX see if is ok = 0 */
-	rule->pcnt = tmp->pcnt;
-	rule->bcnt = tmp->bcnt;
-	rule->timestamp = tmp->timestamp;
-
-	free (tmp, M_TEMP);
-	return 0;
-}
-
-/*
- * Named object api
- *
- */
-
-void
-ipfw_init_srv(struct ip_fw_chain *ch)
-{
-
-	ch->srvmap = ipfw_objhash_create(IPFW_OBJECTS_DEFAULT);
-	ch->srvstate = malloc(sizeof(void *) * IPFW_OBJECTS_DEFAULT,
-	    M_IPFW, M_WAITOK | M_ZERO);
-}
-
-void
-ipfw_destroy_srv(struct ip_fw_chain *ch)
-{
-
-	free(ch->srvstate, M_IPFW);
-	ipfw_objhash_destroy(ch->srvmap);
-}
-
-/*
- * Allocate new bitmask which can be used to enlarge/shrink
- * named instance index.
- */
-void
-ipfw_objhash_bitmap_alloc(uint32_t items, void **idx, int *pblocks)
-{
-	size_t size;
-	int max_blocks;
-	u_long *idx_mask;
-
-	KASSERT((items % BLOCK_ITEMS) == 0,
-	   ("bitmask size needs to power of 2 and greater or equal to %zu",
-	    BLOCK_ITEMS));
-
-	max_blocks = items / BLOCK_ITEMS;
-	size = items / 8;
-	idx_mask = malloc(size * IPFW_MAX_SETS, M_IPFW, M_WAITOK);
-	/* Mark all as free */
-	memset(idx_mask, 0xFF, size * IPFW_MAX_SETS);
-	*idx_mask &= ~(u_long)1; /* Skip index 0 */
-
-	*idx = idx_mask;
-	*pblocks = max_blocks;
-}
-
-/*
- * Copy current bitmask index to new one.
- */
-void
-ipfw_objhash_bitmap_merge(struct namedobj_instance *ni, void **idx, int *blocks)
-{
-	int old_blocks, new_blocks;
-	u_long *old_idx, *new_idx;
-	int i;
-
-	old_idx = ni->idx_mask;
-	old_blocks = ni->max_blocks;
-	new_idx = *idx;
-	new_blocks = *blocks;
-
-	for (i = 0; i < IPFW_MAX_SETS; i++) {
-		memcpy(&new_idx[new_blocks * i], &old_idx[old_blocks * i],
-		    old_blocks * sizeof(u_long));
-	}
-}
-
-/*
- * Swaps current @ni index with new one.
- */
-void
-ipfw_objhash_bitmap_swap(struct namedobj_instance *ni, void **idx, int *blocks)
-{
-	int old_blocks;
-	u_long *old_idx;
-
-	old_idx = ni->idx_mask;
-	old_blocks = ni->max_blocks;
-
-	ni->idx_mask = *idx;
-	ni->max_blocks = *blocks;
-
-	/* Save old values */
-	*idx = old_idx;
-	*blocks = old_blocks;
-}
-
-void
-ipfw_objhash_bitmap_free(void *idx, int blocks)
-{
-
-	free(idx, M_IPFW);
-}
-
-/*
- * Creates named hash instance.
- * Must be called without holding any locks.
- * Return pointer to new instance.
- */
-struct namedobj_instance *
-ipfw_objhash_create(uint32_t items)
-{
-	struct namedobj_instance *ni;
-	int i;
-	size_t size;
-
-	size = sizeof(struct namedobj_instance) +
-	    sizeof(struct namedobjects_head) * NAMEDOBJ_HASH_SIZE +
-	    sizeof(struct namedobjects_head) * NAMEDOBJ_HASH_SIZE;
-
-	ni = malloc(size, M_IPFW, M_WAITOK | M_ZERO);
-	ni->nn_size = NAMEDOBJ_HASH_SIZE;
-	ni->nv_size = NAMEDOBJ_HASH_SIZE;
-
-	ni->names = (struct namedobjects_head *)(ni +1);
-	ni->values = &ni->names[ni->nn_size];
-
-	for (i = 0; i < ni->nn_size; i++)
-		TAILQ_INIT(&ni->names[i]);
-
-	for (i = 0; i < ni->nv_size; i++)
-		TAILQ_INIT(&ni->values[i]);
-
-	/* Set default hashing/comparison functions */
-	ni->hash_f = objhash_hash_name;
-	ni->cmp_f = objhash_cmp_name;
-
-	/* Allocate bitmask separately due to possible resize */
-	ipfw_objhash_bitmap_alloc(items, (void*)&ni->idx_mask, &ni->max_blocks);
-
-	return (ni);
-}
-
-void
-ipfw_objhash_destroy(struct namedobj_instance *ni)
-{
-
-	free(ni->idx_mask, M_IPFW);
-	free(ni, M_IPFW);
-}
-
-void
-ipfw_objhash_set_funcs(struct namedobj_instance *ni, objhash_hash_f *hash_f,
-    objhash_cmp_f *cmp_f)
-{
-
-	ni->hash_f = hash_f;
-	ni->cmp_f = cmp_f;
-}
-
-static uint32_t
-objhash_hash_name(struct namedobj_instance *ni, const void *name, uint32_t set)
-{
-
-	return (fnv_32_str((const char *)name, FNV1_32_INIT));
-}
-
-static int
-objhash_cmp_name(struct named_object *no, const void *name, uint32_t set)
-{
-
-	if ((strcmp(no->name, (const char *)name) == 0) && (no->set == set))
-		return (0);
-
-	return (1);
-}
-
-static uint32_t
-objhash_hash_idx(struct namedobj_instance *ni, uint32_t val)
-{
-	uint32_t v;
-
-	v = val % (ni->nv_size - 1);
-
-	return (v);
-}
-
-struct named_object *
-ipfw_objhash_lookup_name(struct namedobj_instance *ni, uint32_t set, char *name)
-{
-	struct named_object *no;
-	uint32_t hash;
-
-	hash = ni->hash_f(ni, name, set) % ni->nn_size;
-	
-	TAILQ_FOREACH(no, &ni->names[hash], nn_next) {
-		if (ni->cmp_f(no, name, set) == 0)
-			return (no);
-	}
-
-	return (NULL);
-}
-
-/*
- * Find named object by @uid.
- * Check @tlvs for valid data inside.
- *
- * Returns pointer to found TLV or NULL.
- */
-ipfw_obj_ntlv *
-ipfw_find_name_tlv_type(void *tlvs, int len, uint16_t uidx, uint32_t etlv)
-{
-	ipfw_obj_ntlv *ntlv;
-	uintptr_t pa, pe;
-	int l;
-
-	pa = (uintptr_t)tlvs;
-	pe = pa + len;
-	l = 0;
-	for (; pa < pe; pa += l) {
-		ntlv = (ipfw_obj_ntlv *)pa;
-		l = ntlv->head.length;
-
-		if (l != sizeof(*ntlv))
-			return (NULL);
-
-		if (ntlv->idx != uidx)
-			continue;
-		/*
-		 * When userland has specified zero TLV type, do
-		 * not compare it with eltv. In some cases userland
-		 * doesn't know what type should it have. Use only
-		 * uidx and name for search named_object.
-		 */
-		if (ntlv->head.type != 0 &&
-		    ntlv->head.type != (uint16_t)etlv)
-			continue;
-
-		if (ipfw_check_object_name_generic(ntlv->name) != 0)
-			return (NULL);
-
-		return (ntlv);
-	}
-
-	return (NULL);
-}
-
-/*
- * Finds object config based on either legacy index
- * or name in ntlv.
- * Note @ti structure contains unchecked data from userland.
- *
- * Returns 0 in success and fills in @pno with found config
- */
-int
-ipfw_objhash_find_type(struct namedobj_instance *ni, struct tid_info *ti,
-    uint32_t etlv, struct named_object **pno)
-{
-	char *name;
-	ipfw_obj_ntlv *ntlv;
-	uint32_t set;
-
-	if (ti->tlvs == NULL)
-		return (EINVAL);
-
-	ntlv = ipfw_find_name_tlv_type(ti->tlvs, ti->tlen, ti->uidx, etlv);
-	if (ntlv == NULL)
-		return (EINVAL);
-	name = ntlv->name;
-
-	/*
-	 * Use set provided by @ti instead of @ntlv one.
-	 * This is needed due to different sets behavior
-	 * controlled by V_fw_tables_sets.
-	 */
-	set = ti->set;
-	*pno = ipfw_objhash_lookup_name(ni, set, name);
-	if (*pno == NULL)
-		return (ESRCH);
-	return (0);
-}
-
-/*
- * Find named object by name, considering also its TLV type.
- */
-struct named_object *
-ipfw_objhash_lookup_name_type(struct namedobj_instance *ni, uint32_t set,
-    uint32_t type, const char *name)
-{
-	struct named_object *no;
-	uint32_t hash;
-
-	hash = ni->hash_f(ni, name, set) % ni->nn_size;
-
-	TAILQ_FOREACH(no, &ni->names[hash], nn_next) {
-		if (ni->cmp_f(no, name, set) == 0 &&
-		    no->etlv == (uint16_t)type)
-			return (no);
-	}
-
-	return (NULL);
-}
-
-struct named_object *
-ipfw_objhash_lookup_kidx(struct namedobj_instance *ni, uint16_t kidx)
-{
-	struct named_object *no;
-	uint32_t hash;
-
-	hash = objhash_hash_idx(ni, kidx);
-	
-	TAILQ_FOREACH(no, &ni->values[hash], nv_next) {
-		if (no->kidx == kidx)
-			return (no);
-	}
-
-	return (NULL);
-}
-
-int
-ipfw_objhash_same_name(struct namedobj_instance *ni, struct named_object *a,
-    struct named_object *b)
-{
-
-	if ((strcmp(a->name, b->name) == 0) && a->set == b->set)
-		return (1);
-
-	return (0);
-}
-
-void
-ipfw_objhash_add(struct namedobj_instance *ni, struct named_object *no)
-{
-	uint32_t hash;
-
-	hash = ni->hash_f(ni, no->name, no->set) % ni->nn_size;
-	TAILQ_INSERT_HEAD(&ni->names[hash], no, nn_next);
-
-	hash = objhash_hash_idx(ni, no->kidx);
-	TAILQ_INSERT_HEAD(&ni->values[hash], no, nv_next);
-
-	ni->count++;
-}
-
-void
-ipfw_objhash_del(struct namedobj_instance *ni, struct named_object *no)
-{
-	uint32_t hash;
-
-	hash = ni->hash_f(ni, no->name, no->set) % ni->nn_size;
-	TAILQ_REMOVE(&ni->names[hash], no, nn_next);
-
-	hash = objhash_hash_idx(ni, no->kidx);
-	TAILQ_REMOVE(&ni->values[hash], no, nv_next);
-
-	ni->count--;
-}
-
-uint32_t
-ipfw_objhash_count(struct namedobj_instance *ni)
-{
-
-	return (ni->count);
-}
-
-uint32_t
-ipfw_objhash_count_type(struct namedobj_instance *ni, uint16_t type)
-{
-	struct named_object *no;
-	uint32_t count;
-	int i;
-
-	count = 0;
-	for (i = 0; i < ni->nn_size; i++) {
-		TAILQ_FOREACH(no, &ni->names[i], nn_next) {
-			if (no->etlv == type)
-				count++;
-		}
-	}
-	return (count);
-}
-
-/*
- * Runs @func for each found named object.
- * It is safe to delete objects from callback
- */
-int
-ipfw_objhash_foreach(struct namedobj_instance *ni, objhash_cb_t *f, void *arg)
-{
-	struct named_object *no, *no_tmp;
-	int i, ret;
-
-	for (i = 0; i < ni->nn_size; i++) {
-		TAILQ_FOREACH_SAFE(no, &ni->names[i], nn_next, no_tmp) {
-			ret = f(ni, no, arg);
-			if (ret != 0)
-				return (ret);
-		}
-	}
-	return (0);
-}
-
-/*
- * Runs @f for each found named object with type @type.
- * It is safe to delete objects from callback
- */
-int
-ipfw_objhash_foreach_type(struct namedobj_instance *ni, objhash_cb_t *f,
-    void *arg, uint16_t type)
-{
-	struct named_object *no, *no_tmp;
-	int i, ret;
-
-	for (i = 0; i < ni->nn_size; i++) {
-		TAILQ_FOREACH_SAFE(no, &ni->names[i], nn_next, no_tmp) {
-			if (no->etlv != type)
-				continue;
-			ret = f(ni, no, arg);
-			if (ret != 0)
-				return (ret);
-		}
-	}
-	return (0);
-}
-
-/*
- * Removes index from given set.
- * Returns 0 on success.
- */
-int
-ipfw_objhash_free_idx(struct namedobj_instance *ni, uint16_t idx)
-{
-	u_long *mask;
-	int i, v;
-
-	i = idx / BLOCK_ITEMS;
-	v = idx % BLOCK_ITEMS;
-
-	if (i >= ni->max_blocks)
-		return (1);
-
-	mask = &ni->idx_mask[i];
-
-	if ((*mask & ((u_long)1 << v)) != 0)
-		return (1);
-
-	/* Mark as free */
-	*mask |= (u_long)1 << v;
-
-	/* Update free offset */
-	if (ni->free_off[0] > i)
-		ni->free_off[0] = i;
-	
-	return (0);
-}
-
-/*
- * Allocate new index in given instance and stores in in @pidx.
- * Returns 0 on success.
- */
-int
-ipfw_objhash_alloc_idx(void *n, uint16_t *pidx)
-{
-	struct namedobj_instance *ni;
-	u_long *mask;
-	int i, off, v;
-
-	ni = (struct namedobj_instance *)n;
-
-	off = ni->free_off[0];
-	mask = &ni->idx_mask[off];
-
-	for (i = off; i < ni->max_blocks; i++, mask++) {
-		if ((v = ffsl(*mask)) == 0)
-			continue;
-
-		/* Mark as busy */
-		*mask &= ~ ((u_long)1 << (v - 1));
-
-		ni->free_off[0] = i;
-		
-		v = BLOCK_ITEMS * i + v - 1;
-
-		*pidx = v;
-		return (0);
-	}
-
-	return (1);
-}
-
-/* end of file */
Index: eebsd/sys/netpfil/ipfw/ip_fw_table.c
===================================================================
--- freebsd/sys/netpfil/ipfw/ip_fw_table.c	(revision f62c62d2fe57ec02c1350144f7739f8e866ee6d4)
+++ 	(revision )
@@ -1,3365 +1,0 @@
-#include <machine/rtems-bsd-kernel-space.h>
-
-/*-
- * Copyright (c) 2004 Ruslan Ermilov and Vsevolod Lobko.
- * Copyright (c) 2014 Yandex LLC
- * Copyright (c) 2014 Alexander V. Chernikov
- *
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-/*
- * Lookup table support for ipfw.
- *
- * This file contains handlers for all generic tables' operations:
- * add/del/flush entries, list/dump tables etc..
- *
- * Table data modification is protected by both UH and runtime lock
- * while reading configuration/data is protected by UH lock.
- *
- * Lookup algorithms for all table types are located in ip_fw_table_algo.c
- */
-
-#include <rtems/bsd/local/opt_ipfw.h>
-
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/malloc.h>
-#include <sys/kernel.h>
-#include <sys/lock.h>
-#include <sys/rwlock.h>
-#include <sys/rmlock.h>
-#include <sys/socket.h>
-#include <sys/socketvar.h>
-#include <sys/queue.h>
-#include <net/if.h>	/* ip_fw.h requires IFNAMSIZ */
-#include <net/pfil.h>
-
-#include <netinet/in.h>
-#include <netinet/ip_var.h>	/* struct ipfw_rule_ref */
-#include <netinet/ip_fw.h>
-
-#include <netpfil/ipfw/ip_fw_private.h>
-#include <netpfil/ipfw/ip_fw_table.h>
-
- /*
- * Table has the following `type` concepts:
- *
- * `no.type` represents lookup key type (addr, ifp, uid, etc..)
- * vmask represents bitmask of table values which are present at the moment.
- * Special IPFW_VTYPE_LEGACY ( (uint32_t)-1 ) represents old
- * single-value-for-all approach.
- */
-struct table_config {
-	struct named_object	no;
-	uint8_t		tflags;		/* type flags */
-	uint8_t		locked;		/* 1 if locked from changes */
-	uint8_t		linked;		/* 1 if already linked */
-	uint8_t		ochanged;	/* used by set swapping */
-	uint8_t		vshared;	/* 1 if using shared value array */
-	uint8_t		spare[3];
-	uint32_t	count;		/* Number of records */
-	uint32_t	limit;		/* Max number of records */
-	uint32_t	vmask;		/* bitmask with supported values */
-	uint32_t	ocount;		/* used by set swapping */
-	uint64_t	gencnt;		/* generation count */
-	char		tablename[64];	/* table name */
-	struct table_algo	*ta;	/* Callbacks for given algo */
-	void		*astate;	/* algorithm state */
-	struct table_info	ti_copy;	/* data to put to table_info */
-	struct namedobj_instance	*vi;
-};
-
-static int find_table_err(struct namedobj_instance *ni, struct tid_info *ti,
-    struct table_config **tc);
-static struct table_config *find_table(struct namedobj_instance *ni,
-    struct tid_info *ti);
-static struct table_config *alloc_table_config(struct ip_fw_chain *ch,
-    struct tid_info *ti, struct table_algo *ta, char *adata, uint8_t tflags);
-static void free_table_config(struct namedobj_instance *ni,
-    struct table_config *tc);
-static int create_table_internal(struct ip_fw_chain *ch, struct tid_info *ti,
-    char *aname, ipfw_xtable_info *i, uint16_t *pkidx, int ref);
-static void link_table(struct ip_fw_chain *ch, struct table_config *tc);
-static void unlink_table(struct ip_fw_chain *ch, struct table_config *tc);
-static int find_ref_table(struct ip_fw_chain *ch, struct tid_info *ti,
-    struct tentry_info *tei, uint32_t count, int op, struct table_config **ptc);
-#define	OP_ADD	1
-#define	OP_DEL	0
-static int export_tables(struct ip_fw_chain *ch, ipfw_obj_lheader *olh,
-    struct sockopt_data *sd);
-static void export_table_info(struct ip_fw_chain *ch, struct table_config *tc,
-    ipfw_xtable_info *i);
-static int dump_table_tentry(void *e, void *arg);
-static int dump_table_xentry(void *e, void *arg);
-
-static int swap_tables(struct ip_fw_chain *ch, struct tid_info *a,
-    struct tid_info *b);
-
-static int check_table_name(const char *name);
-static int check_table_space(struct ip_fw_chain *ch, struct tableop_state *ts,
-    struct table_config *tc, struct table_info *ti, uint32_t count);
-static int destroy_table(struct ip_fw_chain *ch, struct tid_info *ti);
-
-static struct table_algo *find_table_algo(struct tables_config *tableconf,
-    struct tid_info *ti, char *name);
-
-static void objheader_to_ti(struct _ipfw_obj_header *oh, struct tid_info *ti);
-static void ntlv_to_ti(struct _ipfw_obj_ntlv *ntlv, struct tid_info *ti);
-
-#define	CHAIN_TO_NI(chain)	(CHAIN_TO_TCFG(chain)->namehash)
-#define	KIDX_TO_TI(ch, k)	(&(((struct table_info *)(ch)->tablestate)[k]))
-
-#define	TA_BUF_SZ	128	/* On-stack buffer for add/delete state */
-
-void
-rollback_toperation_state(struct ip_fw_chain *ch, void *object)
-{
-	struct tables_config *tcfg;
-	struct op_state *os;
-
-	tcfg = CHAIN_TO_TCFG(ch);
-	TAILQ_FOREACH(os, &tcfg->state_list, next)
-		os->func(object, os);
-}
-
-void
-add_toperation_state(struct ip_fw_chain *ch, struct tableop_state *ts)
-{
-	struct tables_config *tcfg;
-
-	tcfg = CHAIN_TO_TCFG(ch);
-	TAILQ_INSERT_HEAD(&tcfg->state_list, &ts->opstate, next);
-}
-
-void
-del_toperation_state(struct ip_fw_chain *ch, struct tableop_state *ts)
-{
-	struct tables_config *tcfg;
-
-	tcfg = CHAIN_TO_TCFG(ch);
-	TAILQ_REMOVE(&tcfg->state_list, &ts->opstate, next);
-}
-
-void
-tc_ref(struct table_config *tc)
-{
-
-	tc->no.refcnt++;
-}
-
-void
-tc_unref(struct table_config *tc)
-{
-
-	tc->no.refcnt--;
-}
-
-static struct table_value *
-get_table_value(struct ip_fw_chain *ch, struct table_config *tc, uint32_t kidx)
-{
-	struct table_value *pval;
-
-	pval = (struct table_value *)ch->valuestate;
-
-	return (&pval[kidx]);
-}
-
-
-/*
- * Checks if we're able to insert/update entry @tei into table
- * w.r.t @tc limits.
- * May alter @tei to indicate insertion error / insert
- * options.
- *
- * Returns 0 if operation can be performed/
- */
-static int
-check_table_limit(struct table_config *tc, struct tentry_info *tei)
-{
-
-	if (tc->limit == 0 || tc->count < tc->limit)
-		return (0);
-
-	if ((tei->flags & TEI_FLAGS_UPDATE) == 0) {
-		/* Notify userland on error cause */
-		tei->flags |= TEI_FLAGS_LIMIT;
-		return (EFBIG);
-	}
-
-	/*
-	 * We have UPDATE flag set.
-	 * Permit updating record (if found),
-	 * but restrict adding new one since we've
-	 * already hit the limit.
-	 */
-	tei->flags |= TEI_FLAGS_DONTADD;
-
-	return (0);
-}
-
-/*
- * Convert algorithm callback return code into
- * one of pre-defined states known by userland.
- */
-static void
-store_tei_result(struct tentry_info *tei, int op, int error, uint32_t num)
-{
-	int flag;
-
-	flag = 0;
-
-	switch (error) {
-	case 0:
-		if (op == OP_ADD && num != 0)
-			flag = TEI_FLAGS_ADDED;
-		if (op == OP_DEL)
-			flag = TEI_FLAGS_DELETED;
-		break;
-	case ENOENT:
-		flag = TEI_FLAGS_NOTFOUND;
-		break;
-	case EEXIST:
-		flag = TEI_FLAGS_EXISTS;
-		break;
-	default:
-		flag = TEI_FLAGS_ERROR;
-	}
-
-	tei->flags |= flag;
-}
-
-/*
- * Creates and references table with default parameters.
- * Saves table config, algo and allocated kidx info @ptc, @pta and
- * @pkidx if non-zero.
- * Used for table auto-creation to support old binaries.
- *
- * Returns 0 on success.
- */
-static int
-create_table_compat(struct ip_fw_chain *ch, struct tid_info *ti,
-    uint16_t *pkidx)
-{
-	ipfw_xtable_info xi;
-	int error;
-
-	memset(&xi, 0, sizeof(xi));
-	/* Set default value mask for legacy clients */
-	xi.vmask = IPFW_VTYPE_LEGACY;
-
-	error = create_table_internal(ch, ti, NULL, &xi, pkidx, 1);
-	if (error != 0)
-		return (error);
-
-	return (0);
-}
-
-/*
- * Find and reference existing table optionally
- * creating new one.
- *
- * Saves found table config into @ptc.
- * Note function may drop/acquire UH_WLOCK.
- * Returns 0 if table was found/created and referenced
- * or non-zero return code.
- */
-static int
-find_ref_table(struct ip_fw_chain *ch, struct tid_info *ti,
-    struct tentry_info *tei, uint32_t count, int op,
-    struct table_config **ptc)
-{
-	struct namedobj_instance *ni;
-	struct table_config *tc;
-	uint16_t kidx;
-	int error;
-
-	IPFW_UH_WLOCK_ASSERT(ch);
-
-	ni = CHAIN_TO_NI(ch);
-	tc = NULL;
-	if ((tc = find_table(ni, ti)) != NULL) {
-		/* check table type */
-		if (tc->no.subtype != ti->type)
-			return (EINVAL);
-
-		if (tc->locked != 0)
-			return (EACCES);
-
-		/* Try to exit early on limit hit */
-		if (op == OP_ADD && count == 1 &&
-		    check_table_limit(tc, tei) != 0)
-			return (EFBIG);
-
-		/* Reference and return */
-		tc->no.refcnt++;
-		*ptc = tc;
-		return (0);
-	}
-
-	if (op == OP_DEL)
-		return (ESRCH);
-
-	/* Compatibility mode: create new table for old clients */
-	if ((tei->flags & TEI_FLAGS_COMPAT) == 0)
-		return (ESRCH);
-
-	IPFW_UH_WUNLOCK(ch);
-	error = create_table_compat(ch, ti, &kidx);
-	IPFW_UH_WLOCK(ch);
-	
-	if (error != 0)
-		return (error);
-
-	tc = (struct table_config *)ipfw_objhash_lookup_kidx(ni, kidx);
-	KASSERT(tc != NULL, ("create_table_compat returned bad idx %d", kidx));
-
-	/* OK, now we've got referenced table. */
-	*ptc = tc;
-	return (0);
-}
-
-/*
- * Rolls back already @added to @tc entries using state array @ta_buf_m.
- * Assume the following layout:
- * 1) ADD state (ta_buf_m[0] ... t_buf_m[added - 1]) for handling update cases
- * 2) DEL state (ta_buf_m[count[ ... t_buf_m[count + added - 1])
- *   for storing deleted state
- */
-static void
-rollback_added_entries(struct ip_fw_chain *ch, struct table_config *tc,
-    struct table_info *tinfo, struct tentry_info *tei, caddr_t ta_buf_m,
-    uint32_t count, uint32_t added)
-{
-	struct table_algo *ta;
-	struct tentry_info *ptei;
-	caddr_t v, vv;
-	size_t ta_buf_sz;
-	int error, i;
-	uint32_t num;
-
-	IPFW_UH_WLOCK_ASSERT(ch);
-
-	ta = tc->ta;
-	ta_buf_sz = ta->ta_buf_size;
-	v = ta_buf_m;
-	vv = v + count * ta_buf_sz;
-	for (i = 0; i < added; i++, v += ta_buf_sz, vv += ta_buf_sz) {
-		ptei = &tei[i];
-		if ((ptei->flags & TEI_FLAGS_UPDATED) != 0) {
-
-			/*
-			 * We have old value stored by previous
-			 * call in @ptei->value. Do add once again
-			 * to restore it.
-			 */
-			error = ta->add(tc->astate, tinfo, ptei, v, &num);
-			KASSERT(error == 0, ("rollback UPDATE fail"));
-			KASSERT(num == 0, ("rollback UPDATE fail2"));
-			continue;
-		}
-
-		error = ta->prepare_del(ch, ptei, vv);
-		KASSERT(error == 0, ("pre-rollback INSERT failed"));
-		error = ta->del(tc->astate, tinfo, ptei, vv, &num);
-		KASSERT(error == 0, ("rollback INSERT failed"));
-		tc->count -= num;
-	}
-}
-
-/*
- * Prepares add/del state for all @count entries in @tei.
- * Uses either stack buffer (@ta_buf) or allocates a new one.
- * Stores pointer to allocated buffer back to @ta_buf.
- *
- * Returns 0 on success.
- */
-static int
-prepare_batch_buffer(struct ip_fw_chain *ch, struct table_algo *ta,
-    struct tentry_info *tei, uint32_t count, int op, caddr_t *ta_buf)
-{
-	caddr_t ta_buf_m, v;
-	size_t ta_buf_sz, sz;
-	struct tentry_info *ptei;
-	int error, i;
-
-	error = 0;
-	ta_buf_sz = ta->ta_buf_size;
-	if (count == 1) {
-		/* Single add/delete, use on-stack buffer */
-		memset(*ta_buf, 0, TA_BUF_SZ);
-		ta_buf_m = *ta_buf;
-	} else {
-
-		/*
-		 * Multiple adds/deletes, allocate larger buffer
-		 *
-		 * Note we need 2xcount buffer for add case:
-		 * we have hold both ADD state
-		 * and DELETE state (this may be needed
-		 * if we need to rollback all changes)
-		 */
-		sz = count * ta_buf_sz;
-		ta_buf_m = malloc((op == OP_ADD) ? sz * 2 : sz, M_TEMP,
-		    M_WAITOK | M_ZERO);
-	}
-
-	v = ta_buf_m;
-	for (i = 0; i < count; i++, v += ta_buf_sz) {
-		ptei = &tei[i];
-		error = (op == OP_ADD) ?
-		    ta->prepare_add(ch, ptei, v) : ta->prepare_del(ch, ptei, v);
-
-		/*
-		 * Some syntax error (incorrect mask, or address, or
-		 * anything). Return error regardless of atomicity
-		 * settings.
-		 */
-		if (error != 0)
-			break;
-	}
-
-	*ta_buf = ta_buf_m;
-	return (error);
-}
-
-/*
- * Flushes allocated state for each @count entries in @tei.
- * Frees @ta_buf_m if differs from stack buffer @ta_buf.
- */
-static void
-flush_batch_buffer(struct ip_fw_chain *ch, struct table_algo *ta,
-    struct tentry_info *tei, uint32_t count, int rollback,
-    caddr_t ta_buf_m, caddr_t ta_buf)
-{
-	caddr_t v;
-	struct tentry_info *ptei;
-	size_t ta_buf_sz;
-	int i;
-
-	ta_buf_sz = ta->ta_buf_size;
-
-	/* Run cleaning callback anyway */
-	v = ta_buf_m;
-	for (i = 0; i < count; i++, v += ta_buf_sz) {
-		ptei = &tei[i];
-		ta->flush_entry(ch, ptei, v);
-		if (ptei->ptv != NULL) {
-			free(ptei->ptv, M_IPFW);
-			ptei->ptv = NULL;
-		}
-	}
-
-	/* Clean up "deleted" state in case of rollback */
-	if (rollback != 0) {
-		v = ta_buf_m + count * ta_buf_sz;
-		for (i = 0; i < count; i++, v += ta_buf_sz)
-			ta->flush_entry(ch, &tei[i], v);
-	}
-
-	if (ta_buf_m != ta_buf)
-		free(ta_buf_m, M_TEMP);
-}
-
-
-static void
-rollback_add_entry(void *object, struct op_state *_state)
-{
-	struct ip_fw_chain *ch;
-	struct tableop_state *ts;
-
-	ts = (struct tableop_state *)_state;
-
-	if (ts->tc != object && ts->ch != object)
-		return;
-
-	ch = ts->ch;
-
-	IPFW_UH_WLOCK_ASSERT(ch);
-
-	/* Call specifid unlockers */
-	rollback_table_values(ts);
-
-	/* Indicate we've called */
-	ts->modified = 1;
-}
-
-/*
- * Adds/updates one or more entries in table @ti.
- *
- * Function may drop/reacquire UH wlock multiple times due to
- * items alloc, algorithm callbacks (check_space), value linkage
- * (new values, value storage realloc), etc..
- * Other processes like other adds (which may involve storage resize),
- * table swaps (which changes table data and may change algo type),
- * table modify (which may change value mask) may be executed
- * simultaneously so we need to deal with it.
- *
- * The following approach was implemented:
- * we have per-chain linked list, protected with UH lock.
- * add_table_entry prepares special on-stack structure wthich is passed
- * to its descendants. Users add this structure to this list before unlock.
- * After performing needed operations and acquiring UH lock back, each user
- * checks if structure has changed. If true, it rolls local state back and
- * returns without error to the caller.
- * add_table_entry() on its own checks if structure has changed and restarts
- * its operation from the beginning (goto restart).
- *
- * Functions which are modifying fields of interest (currently
- *   resize_shared_value_storage() and swap_tables() )
- * traverses given list while holding UH lock immediately before
- * performing their operations calling function provided be list entry
- * ( currently rollback_add_entry  ) which performs rollback for all necessary
- * state and sets appropriate values in structure indicating rollback
- * has happened.
- *
- * Algo interaction:
- * Function references @ti first to ensure table won't
- * disappear or change its type.
- * After that, prepare_add callback is called for each @tei entry.
- * Next, we try to add each entry under UH+WHLOCK
- * using add() callback.
- * Finally, we free all state by calling flush_entry callback
- * for each @tei.
- *
- * Returns 0 on success.
- */
-int
-add_table_entry(struct ip_fw_chain *ch, struct tid_info *ti,
-    struct tentry_info *tei, uint8_t flags, uint32_t count)
-{
-	struct table_config *tc;
-	struct table_algo *ta;
-	uint16_t kidx;
-	int error, first_error, i, rollback;
-	uint32_t num, numadd;
-	struct tentry_info *ptei;
-	struct tableop_state ts;
-	char ta_buf[TA_BUF_SZ];
-	caddr_t ta_buf_m, v;
-
-	memset(&ts, 0, sizeof(ts));
-	ta = NULL;
-	IPFW_UH_WLOCK(ch);
-
-	/*
-	 * Find and reference existing table.
-	 */
-restart:
-	if (ts.modified != 0) {
-		IPFW_UH_WUNLOCK(ch);
-		flush_batch_buffer(ch, ta, tei, count, rollback,
-		    ta_buf_m, ta_buf);
-		memset(&ts, 0, sizeof(ts));
-		ta = NULL;
-		IPFW_UH_WLOCK(ch);
-	}
-
-	error = find_ref_table(ch, ti, tei, count, OP_ADD, &tc);
-	if (error != 0) {
-		IPFW_UH_WUNLOCK(ch);
-		return (error);
-	}
-	ta = tc->ta;
-
-	/* Fill in tablestate */
-	ts.ch = ch;
-	ts.opstate.func = rollback_add_entry;
-	ts.tc = tc;
-	ts.vshared = tc->vshared;
-	ts.vmask = tc->vmask;
-	ts.ta = ta;
-	ts.tei = tei;
-	ts.count = count;
-	rollback = 0;
-	add_toperation_state(ch, &ts);
-	IPFW_UH_WUNLOCK(ch);
-
-	/* Allocate memory and prepare record(s) */
-	/* Pass stack buffer by default */
-	ta_buf_m = ta_buf;
-	error = prepare_batch_buffer(ch, ta, tei, count, OP_ADD, &ta_buf_m);
-
-	IPFW_UH_WLOCK(ch);
-	del_toperation_state(ch, &ts);
-	/* Drop reference we've used in first search */
-	tc->no.refcnt--;
-
-	/* Check prepare_batch_buffer() error */
-	if (error != 0)
-		goto cleanup;
-
-	/*
-	 * Check if table swap has happened.
-	 * (so table algo might be changed).
-	 * Restart operation to achieve consistent behavior.
-	 */
-	if (ts.modified != 0)
-		goto restart;
-
-	/*
-	 * Link all values values to shared/per-table value array.
-	 *
-	 * May release/reacquire UH_WLOCK.
-	 */
-	error = ipfw_link_table_values(ch, &ts);
-	if (error != 0)
-		goto cleanup;
-	if (ts.modified != 0)
-		goto restart;
-
-	/*
-	 * Ensure we are able to add all entries without additional
-	 * memory allocations. May release/reacquire UH_WLOCK.
-	 */
-	kidx = tc->no.kidx;
-	error = check_table_space(ch, &ts, tc, KIDX_TO_TI(ch, kidx), count);
-	if (error != 0)
-		goto cleanup;
-	if (ts.modified != 0)
-		goto restart;
-
-	/* We've got valid table in @tc. Let's try to add data */
-	kidx = tc->no.kidx;
-	ta = tc->ta;
-	numadd = 0;
-	first_error = 0;
-
-	IPFW_WLOCK(ch);
-
-	v = ta_buf_m;
-	for (i = 0; i < count; i++, v += ta->ta_buf_size) {
-		ptei = &tei[i];
-		num = 0;
-		/* check limit before adding */
-		if ((error = check_table_limit(tc, ptei)) == 0) {
-			error = ta->add(tc->astate, KIDX_TO_TI(ch, kidx),
-			    ptei, v, &num);
-			/* Set status flag to inform userland */
-			store_tei_result(ptei, OP_ADD, error, num);
-		}
-		if (error == 0) {
-			/* Update number of records to ease limit checking */
-			tc->count += num;
-			numadd += num;
-			continue;
-		}
-
-		if (first_error == 0)
-			first_error = error;
-
-		/*
-		 * Some error have happened. Check our atomicity
-		 * settings: continue if atomicity is not required,
-		 * rollback changes otherwise.
-		 */
-		if ((flags & IPFW_CTF_ATOMIC) == 0)
-			continue;
-
-		rollback_added_entries(ch, tc, KIDX_TO_TI(ch, kidx),
-		    tei, ta_buf_m, count, i);
-
-		rollback = 1;
-		break;
-	}
-
-	IPFW_WUNLOCK(ch);
-
-	ipfw_garbage_table_values(ch, tc, tei, count, rollback);
-
-	/* Permit post-add algorithm grow/rehash. */
-	if (numadd != 0)
-		check_table_space(ch, NULL, tc, KIDX_TO_TI(ch, kidx), 0);
-
-	/* Return first error to user, if any */
-	error = first_error;
-
-cleanup:
-	IPFW_UH_WUNLOCK(ch);
-
-	flush_batch_buffer(ch, ta, tei, count, rollback, ta_buf_m, ta_buf);
-	
-	return (error);
-}
-
-/*
- * Deletes one or more entries in table @ti.
- *
- * Returns 0 on success.
- */
-int
-del_table_entry(struct ip_fw_chain *ch, struct tid_info *ti,
-    struct tentry_info *tei, uint8_t flags, uint32_t count)
-{
-	struct table_config *tc;
-	struct table_algo *ta;
-	struct tentry_info *ptei;
-	uint16_t kidx;
-	int error, first_error, i;
-	uint32_t num, numdel;
-	char ta_buf[TA_BUF_SZ];
-	caddr_t ta_buf_m, v;
-
-	/*
-	 * Find and reference existing table.
-	 */
-	IPFW_UH_WLOCK(ch);
-	error = find_ref_table(ch, ti, tei, count, OP_DEL, &tc);
-	if (error != 0) {
-		IPFW_UH_WUNLOCK(ch);
-		return (error);
-	}
-	ta = tc->ta;
-	IPFW_UH_WUNLOCK(ch);
-
-	/* Allocate memory and prepare record(s) */
-	/* Pass stack buffer by default */
-	ta_buf_m = ta_buf;
-	error = prepare_batch_buffer(ch, ta, tei, count, OP_DEL, &ta_buf_m);
-	if (error != 0)
-		goto cleanup;
-
-	IPFW_UH_WLOCK(ch);
-
-	/* Drop reference we've used in first search */
-	tc->no.refcnt--;
-
-	/*
-	 * Check if table algo is still the same.
-	 * (changed ta may be the result of table swap).
-	 */
-	if (ta != tc->ta) {
-		IPFW_UH_WUNLOCK(ch);
-		error = EINVAL;
-		goto cleanup;
-	}
-
-	kidx = tc->no.kidx;
-	numdel = 0;
-	first_error = 0;
-
-	IPFW_WLOCK(ch);
-	v = ta_buf_m;
-	for (i = 0; i < count; i++, v += ta->ta_buf_size) {
-		ptei = &tei[i];
-		num = 0;
-		error = ta->del(tc->astate, KIDX_TO_TI(ch, kidx), ptei, v,
-		    &num);
-		/* Save state for userland */
-		store_tei_result(ptei, OP_DEL, error, num);
-		if (error != 0 && first_error == 0)
-			first_error = error;
-		tc->count -= num;
-		numdel += num;
-	}
-	IPFW_WUNLOCK(ch);
-
-	/* Unlink non-used values */
-	ipfw_garbage_table_values(ch, tc, tei, count, 0);
-
-	if (numdel != 0) {
-		/* Run post-del hook to permit shrinking */
-		check_table_space(ch, NULL, tc, KIDX_TO_TI(ch, kidx), 0);
-	}
-
-	IPFW_UH_WUNLOCK(ch);
-
-	/* Return first error to user, if any */
-	error = first_error;
-
-cleanup:
-	flush_batch_buffer(ch, ta, tei, count, 0, ta_buf_m, ta_buf);
-
-	return (error);
-}
-
-/*
- * Ensure that table @tc has enough space to add @count entries without
- * need for reallocation.
- *
- * Callbacks order:
- * 0) need_modify() (UH_WLOCK) - checks if @count items can be added w/o resize.
- *
- * 1) alloc_modify (no locks, M_WAITOK) - alloc new state based on @pflags.
- * 2) prepare_modifyt (UH_WLOCK) - copy old data into new storage
- * 3) modify (UH_WLOCK + WLOCK) - switch pointers
- * 4) flush_modify (UH_WLOCK) - free state, if needed
- *
- * Returns 0 on success.
- */
-static int
-check_table_space(struct ip_fw_chain *ch, struct tableop_state *ts,
-    struct table_config *tc, struct table_info *ti, uint32_t count)
-{
-	struct table_algo *ta;
-	uint64_t pflags;
-	char ta_buf[TA_BUF_SZ];
-	int error;
-
-	IPFW_UH_WLOCK_ASSERT(ch);
-
-	error = 0;
-	ta = tc->ta;
-	if (ta->need_modify == NULL)
-		return (0);
-
-	/* Acquire reference not to loose @tc between locks/unlocks */
-	tc->no.refcnt++;
-
-	/*
-	 * TODO: think about avoiding race between large add/large delete
-	 * operation on algorithm which implements shrinking along with
-	 * growing.
-	 */
-	while (true) {
-		pflags = 0;
-		if (ta->need_modify(tc->astate, ti, count, &pflags) == 0) {
-			error = 0;
-			break;
-		}
-
-		/* We have to shrink/grow table */
-		if (ts != NULL)
-			add_toperation_state(ch, ts);
-		IPFW_UH_WUNLOCK(ch);
-
-		memset(&ta_buf, 0, sizeof(ta_buf));
-		error = ta->prepare_mod(ta_buf, &pflags);
-
-		IPFW_UH_WLOCK(ch);
-		if (ts != NULL)
-			del_toperation_state(ch, ts);
-
-		if (error != 0)
-			break;
-
-		if (ts != NULL && ts->modified != 0) {
-
-			/*
-			 * Swap operation has happened
-			 * so we're currently operating on other
-			 * table data. Stop doing this.
-			 */
-			ta->flush_mod(ta_buf);
-			break;
-		}
-
-		/* Check if we still need to alter table */
-		ti = KIDX_TO_TI(ch, tc->no.kidx);
-		if (ta->need_modify(tc->astate, ti, count, &pflags) == 0) {
-			IPFW_UH_WUNLOCK(ch);
-
-			/*
-			 * Other thread has already performed resize.
-			 * Flush our state and return.
-			 */
-			ta->flush_mod(ta_buf);
-			break;
-		}
-	
-		error = ta->fill_mod(tc->astate, ti, ta_buf, &pflags);
-		if (error == 0) {
-			/* Do actual modification */
-			IPFW_WLOCK(ch);
-			ta->modify(tc->astate, ti, ta_buf, pflags);
-			IPFW_WUNLOCK(ch);
-		}
-
-		/* Anyway, flush data and retry */
-		ta->flush_mod(ta_buf);
-	}
-
-	tc->no.refcnt--;
-	return (error);
-}
-
-/*
- * Adds or deletes record in table.
- * Data layout (v0):
- * Request: [ ip_fw3_opheader ipfw_table_xentry ]
- *
- * Returns 0 on success
- */
-static int
-manage_table_ent_v0(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
-    struct sockopt_data *sd)
-{
-	ipfw_table_xentry *xent;
-	struct tentry_info tei;
-	struct tid_info ti;
-	struct table_value v;
-	int error, hdrlen, read;
-
-	hdrlen = offsetof(ipfw_table_xentry, k);
-
-	/* Check minimum header size */
-	if (sd->valsize < (sizeof(*op3) + hdrlen))
-		return (EINVAL);
-
-	read = sizeof(ip_fw3_opheader);
-
-	/* Check if xentry len field is valid */
-	xent = (ipfw_table_xentry *)(op3 + 1);
-	if (xent->len < hdrlen || xent->len + read > sd->valsize)
-		return (EINVAL);
-	
-	memset(&tei, 0, sizeof(tei));
-	tei.paddr = &xent->k;
-	tei.masklen = xent->masklen;
-	ipfw_import_table_value_legacy(xent->value, &v);
-	tei.pvalue = &v;
-	/* Old requests compatibility */
-	tei.flags = TEI_FLAGS_COMPAT;
-	if (xent->type == IPFW_TABLE_ADDR) {
-		if (xent->len - hdrlen == sizeof(in_addr_t))
-			tei.subtype = AF_INET;
-		else
-			tei.subtype = AF_INET6;
-	}
-
-	memset(&ti, 0, sizeof(ti));
-	ti.uidx = xent->tbl;
-	ti.type = xent->type;
-
-	error = (op3->opcode == IP_FW_TABLE_XADD) ?
-	    add_table_entry(ch, &ti, &tei, 0, 1) :
-	    del_table_entry(ch, &ti, &tei, 0, 1);
-
-	return (error);
-}
-
-/*
- * Adds or deletes record in table.
- * Data layout (v1)(current):
- * Request: [ ipfw_obj_header
- *   ipfw_obj_ctlv(IPFW_TLV_TBLENT_LIST) [ ipfw_obj_tentry x N ]
- * ]
- *
- * Returns 0 on success
- */
-static int
-manage_table_ent_v1(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
-    struct sockopt_data *sd)
-{
-	ipfw_obj_tentry *tent, *ptent;
-	ipfw_obj_ctlv *ctlv;
-	ipfw_obj_header *oh;
-	struct tentry_info *ptei, tei, *tei_buf;
-	struct tid_info ti;
-	int error, i, kidx, read;
-
-	/* Check minimum header size */
-	if (sd->valsize < (sizeof(*oh) + sizeof(*ctlv)))
-		return (EINVAL);
-
-	/* Check if passed data is too long */
-	if (sd->valsize != sd->kavail)
-		return (EINVAL);
-
-	oh = (ipfw_obj_header *)sd->kbuf;
-
-	/* Basic length checks for TLVs */
-	if (oh->ntlv.head.length != sizeof(oh->ntlv))
-		return (EINVAL);
-
-	read = sizeof(*oh);
-
-	ctlv = (ipfw_obj_ctlv *)(oh + 1);
-	if (ctlv->head.length + read != sd->valsize)
-		return (EINVAL);
-
-	read += sizeof(*ctlv);
-	tent = (ipfw_obj_tentry *)(ctlv + 1);
-	if (ctlv->count * sizeof(*tent) + read != sd->valsize)
-		return (EINVAL);
-
-	if (ctlv->count == 0)
-		return (0);
-
-	/*
-	 * Mark entire buffer as "read".
-	 * This instructs sopt api write it back
-	 * after function return.
-	 */
-	ipfw_get_sopt_header(sd, sd->valsize);
-
-	/* Perform basic checks for each entry */
-	ptent = tent;
-	kidx = tent->idx;
-	for (i = 0; i < ctlv->count; i++, ptent++) {
-		if (ptent->head.length != sizeof(*ptent))
-			return (EINVAL);
-		if (ptent->idx != kidx)
-			return (ENOTSUP);
-	}
-
-	/* Convert data into kernel request objects */
-	objheader_to_ti(oh, &ti);
-	ti.type = oh->ntlv.type;
-	ti.uidx = kidx;
-
-	/* Use on-stack buffer for single add/del */
-	if (ctlv->count == 1) {
-		memset(&tei, 0, sizeof(tei));
-		tei_buf = &tei;
-	} else
-		tei_buf = malloc(ctlv->count * sizeof(tei), M_TEMP,
-		    M_WAITOK | M_ZERO);
-
-	ptei = tei_buf;
-	ptent = tent;
-	for (i = 0; i < ctlv->count; i++, ptent++, ptei++) {
-		ptei->paddr = &ptent->k;
-		ptei->subtype = ptent->subtype;
-		ptei->masklen = ptent->masklen;
-		if (ptent->head.flags & IPFW_TF_UPDATE)
-			ptei->flags |= TEI_FLAGS_UPDATE;
-
-		ipfw_import_table_value_v1(&ptent->v.value);
-		ptei->pvalue = (struct table_value *)&ptent->v.value;
-	}
-
-	error = (oh->opheader.opcode == IP_FW_TABLE_XADD) ?
-	    add_table_entry(ch, &ti, tei_buf, ctlv->flags, ctlv->count) :
-	    del_table_entry(ch, &ti, tei_buf, ctlv->flags, ctlv->count);
-
-	/* Translate result back to userland */
-	ptei = tei_buf;
-	ptent = tent;
-	for (i = 0; i < ctlv->count; i++, ptent++, ptei++) {
-		if (ptei->flags & TEI_FLAGS_ADDED)
-			ptent->result = IPFW_TR_ADDED;
-		else if (ptei->flags & TEI_FLAGS_DELETED)
-			ptent->result = IPFW_TR_DELETED;
-		else if (ptei->flags & TEI_FLAGS_UPDATED)
-			ptent->result = IPFW_TR_UPDATED;
-		else if (ptei->flags & TEI_FLAGS_LIMIT)
-			ptent->result = IPFW_TR_LIMIT;
-		else if (ptei->flags & TEI_FLAGS_ERROR)
-			ptent->result = IPFW_TR_ERROR;
-		else if (ptei->flags & TEI_FLAGS_NOTFOUND)
-			ptent->result = IPFW_TR_NOTFOUND;
-		else if (ptei->flags & TEI_FLAGS_EXISTS)
-			ptent->result = IPFW_TR_EXISTS;
-		ipfw_export_table_value_v1(ptei->pvalue, &ptent->v.value);
-	}
-
-	if (tei_buf != &tei)
-		free(tei_buf, M_TEMP);
-
-	return (error);
-}
-
-/*
- * Looks up an entry in given table.
- * Data layout (v0)(current):
- * Request: [ ipfw_obj_header ipfw_obj_tentry ]
- * Reply: [ ipfw_obj_header ipfw_obj_tentry ]
- *
- * Returns 0 on success
- */
-static int
-find_table_entry(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
-    struct sockopt_data *sd)
-{
-	ipfw_obj_tentry *tent;
-	ipfw_obj_header *oh;
-	struct tid_info ti;
-	struct table_config *tc;
-	struct table_algo *ta;
-	struct table_info *kti;
-	struct table_value *pval;
-	struct namedobj_instance *ni;
-	int error;
-	size_t sz;
-
-	/* Check minimum header size */
-	sz = sizeof(*oh) + sizeof(*tent);
-	if (sd->valsize != sz)
-		return (EINVAL);
-
-	oh = (struct _ipfw_obj_header *)ipfw_get_sopt_header(sd, sz);
-	tent = (ipfw_obj_tentry *)(oh + 1);
-
-	/* Basic length checks for TLVs */
-	if (oh->ntlv.head.length != sizeof(oh->ntlv))
-		return (EINVAL);
-
-	objheader_to_ti(oh, &ti);
-	ti.type = oh->ntlv.type;
-	ti.uidx = tent->idx;
-
-	IPFW_UH_RLOCK(ch);
-	ni = CHAIN_TO_NI(ch);
-
-	/*
-	 * Find existing table and check its type .
-	 */
-	ta = NULL;
-	if ((tc = find_table(ni, &ti)) == NULL) {
-		IPFW_UH_RUNLOCK(ch);
-		return (ESRCH);
-	}
-
-	/* check table type */
-	if (tc->no.subtype != ti.type) {
-		IPFW_UH_RUNLOCK(ch);
-		return (EINVAL);
-	}
-
-	kti = KIDX_TO_TI(ch, tc->no.kidx);
-	ta = tc->ta;
-
-	if (ta->find_tentry == NULL)
-		return (ENOTSUP);
-
-	error = ta->find_tentry(tc->astate, kti, tent);
-	if (error == 0) {
-		pval = get_table_value(ch, tc, tent->v.kidx);
-		ipfw_export_table_value_v1(pval, &tent->v.value);
-	}
-	IPFW_UH_RUNLOCK(ch);
-
-	return (error);
-}
-
-/*
- * Flushes all entries or destroys given table.
- * Data layout (v0)(current):
- * Request: [ ipfw_obj_header ]
- *
- * Returns 0 on success
- */
-static int
-flush_table_v0(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
-    struct sockopt_data *sd)
-{
-	int error;
-	struct _ipfw_obj_header *oh;
-	struct tid_info ti;
-
-	if (sd->valsize != sizeof(*oh))
-		return (EINVAL);
-
-	oh = (struct _ipfw_obj_header *)op3;
-	objheader_to_ti(oh, &ti);
-
-	if (op3->opcode == IP_FW_TABLE_XDESTROY)
-		error = destroy_table(ch, &ti);
-	else if (op3->opcode == IP_FW_TABLE_XFLUSH)
-		error = flush_table(ch, &ti);
-	else
-		return (ENOTSUP);
-
-	return (error);
-}
-
-static void
-restart_flush(void *object, struct op_state *_state)
-{
-	struct tableop_state *ts;
-
-	ts = (struct tableop_state *)_state;
-
-	if (ts->tc != object)
-		return;
-
-	/* Indicate we've called */
-	ts->modified = 1;
-}
-
-/*
- * Flushes given table.
- *
- * Function create new table instance with the same
- * parameters, swaps it with old one and
- * flushes state without holding runtime WLOCK.
- *
- * Returns 0 on success.
- */
-int
-flush_table(struct ip_fw_chain *ch, struct tid_info *ti)
-{
-	struct namedobj_instance *ni;
-	struct table_config *tc;
-	struct table_algo *ta;
-	struct table_info ti_old, ti_new, *tablestate;
-	void *astate_old, *astate_new;
-	char algostate[64], *pstate;
-	struct tableop_state ts;
-	int error, need_gc;
-	uint16_t kidx;
-	uint8_t tflags;
-
-	/*
-	 * Stage 1: save table algorithm.
-	 * Reference found table to ensure it won't disappear.
-	 */
-	IPFW_UH_WLOCK(ch);
-	ni = CHAIN_TO_NI(ch);
-	if ((tc = find_table(ni, ti)) == NULL) {
-		IPFW_UH_WUNLOCK(ch);
-		return (ESRCH);
-	}
-	need_gc = 0;
-	astate_new = NULL;
-	memset(&ti_new, 0, sizeof(ti_new));
-restart:
-	/* Set up swap handler */
-	memset(&ts, 0, sizeof(ts));
-	ts.opstate.func = restart_flush;
-	ts.tc = tc;
-
-	ta = tc->ta;
-	/* Do not flush readonly tables */
-	if ((ta->flags & TA_FLAG_READONLY) != 0) {
-		IPFW_UH_WUNLOCK(ch);
-		return (EACCES);
-	}
-	/* Save startup algo parameters */
-	if (ta->print_config != NULL) {
-		ta->print_config(tc->astate, KIDX_TO_TI(ch, tc->no.kidx),
-		    algostate, sizeof(algostate));
-		pstate = algostate;
-	} else
-		pstate = NULL;
-	tflags = tc->tflags;
-	tc->no.refcnt++;
-	add_toperation_state(ch, &ts);
-	IPFW_UH_WUNLOCK(ch);
-
-	/*
-	 * Stage 1.5: if this is not the first attempt, destroy previous state
-	 */
-	if (need_gc != 0) {
-		ta->destroy(astate_new, &ti_new);
-		need_gc = 0;
-	}
-
-	/*
-	 * Stage 2: allocate new table instance using same algo.
-	 */
-	memset(&ti_new, 0, sizeof(struct table_info));
-	error = ta->init(ch, &astate_new, &ti_new, pstate, tflags);
-
-	/*
-	 * Stage 3: swap old state pointers with newly-allocated ones.
-	 * Decrease refcount.
-	 */
-	IPFW_UH_WLOCK(ch);
-	tc->no.refcnt--;
-	del_toperation_state(ch, &ts);
-
-	if (error != 0) {
-		IPFW_UH_WUNLOCK(ch);
-		return (error);
-	}
-
-	/*
-	 * Restart operation if table swap has happened:
-	 * even if algo may be the same, algo init parameters
-	 * may change. Restart operation instead of doing
-	 * complex checks.
-	 */
-	if (ts.modified != 0) {
-		/* Delay destroying data since we're holding UH lock */
-		need_gc = 1;
-		goto restart;
-	}
-
-	ni = CHAIN_TO_NI(ch);
-	kidx = tc->no.kidx;
-	tablestate = (struct table_info *)ch->tablestate;
-
-	IPFW_WLOCK(ch);
-	ti_old = tablestate[kidx];
-	tablestate[kidx] = ti_new;
-	IPFW_WUNLOCK(ch);
-
-	astate_old = tc->astate;
-	tc->astate = astate_new;
-	tc->ti_copy = ti_new;
-	tc->count = 0;
-
-	/* Notify algo on real @ti address */
-	if (ta->change_ti != NULL)
-		ta->change_ti(tc->astate, &tablestate[kidx]);
-
-	/*
-	 * Stage 4: unref values.
-	 */
-	ipfw_unref_table_values(ch, tc, ta, astate_old, &ti_old);
-	IPFW_UH_WUNLOCK(ch);
-
-	/*
-	 * Stage 5: perform real flush/destroy.
-	 */
-	ta->destroy(astate_old, &ti_old);
-
-	return (0);
-}
-
-/*
- * Swaps two tables.
- * Data layout (v0)(current):
- * Request: [ ipfw_obj_header ipfw_obj_ntlv ]
- *
- * Returns 0 on success
- */
-static int
-swap_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
-    struct sockopt_data *sd)
-{
-	int error;
-	struct _ipfw_obj_header *oh;
-	struct tid_info ti_a, ti_b;
-
-	if (sd->valsize != sizeof(*oh) + sizeof(ipfw_obj_ntlv))
-		return (EINVAL);
-
-	oh = (struct _ipfw_obj_header *)op3;
-	ntlv_to_ti(&oh->ntlv, &ti_a);
-	ntlv_to_ti((ipfw_obj_ntlv *)(oh + 1), &ti_b);
-
-	error = swap_tables(ch, &ti_a, &ti_b);
-
-	return (error);
-}
-
-/*
- * Swaps two tables of the same type/valtype.
- *
- * Checks if tables are compatible and limits
- * permits swap, than actually perform swap.
- *
- * Each table consists of 2 different parts:
- * config:
- *   @tc (with name, set, kidx) and rule bindings, which is "stable".
- *   number of items
- *   table algo
- * runtime:
- *   runtime data @ti (ch->tablestate)
- *   runtime cache in @tc
- *   algo-specific data (@tc->astate)
- *
- * So we switch:
- *  all runtime data
- *   number of items
- *   table algo
- *
- * After that we call @ti change handler for each table.
- *
- * Note that referencing @tc won't protect tc->ta from change.
- * XXX: Do we need to restrict swap between locked tables?
- * XXX: Do we need to exchange ftype?
- *
- * Returns 0 on success.
- */
-static int
-swap_tables(struct ip_fw_chain *ch, struct tid_info *a,
-    struct tid_info *b)
-{
-	struct namedobj_instance *ni;
-	struct table_config *tc_a, *tc_b;
-	struct table_algo *ta;
-	struct table_info ti, *tablestate;
-	void *astate;
-	uint32_t count;
-
-	/*
-	 * Stage 1: find both tables and ensure they are of
-	 * the same type.
-	 */
-	IPFW_UH_WLOCK(ch);
-	ni = CHAIN_TO_NI(ch);
-	if ((tc_a = find_table(ni, a)) == NULL) {
-		IPFW_UH_WUNLOCK(ch);
-		return (ESRCH);
-	}
-	if ((tc_b = find_table(ni, b)) == NULL) {
-		IPFW_UH_WUNLOCK(ch);
-		return (ESRCH);
-	}
-
-	/* It is very easy to swap between the same table */
-	if (tc_a == tc_b) {
-		IPFW_UH_WUNLOCK(ch);
-		return (0);
-	}
-
-	/* Check type and value are the same */
-	if (tc_a->no.subtype!=tc_b->no.subtype || tc_a->tflags!=tc_b->tflags) {
-		IPFW_UH_WUNLOCK(ch);
-		return (EINVAL);
-	}
-
-	/* Check limits before swap */
-	if ((tc_a->limit != 0 && tc_b->count > tc_a->limit) ||
-	    (tc_b->limit != 0 && tc_a->count > tc_b->limit)) {
-		IPFW_UH_WUNLOCK(ch);
-		return (EFBIG);
-	}
-
-	/* Check if one of the tables is readonly */
-	if (((tc_a->ta->flags | tc_b->ta->flags) & TA_FLAG_READONLY) != 0) {
-		IPFW_UH_WUNLOCK(ch);
-		return (EACCES);
-	}
-
-	/* Notify we're going to swap */
-	rollback_toperation_state(ch, tc_a);
-	rollback_toperation_state(ch, tc_b);
-
-	/* Everything is fine, prepare to swap */
-	tablestate = (struct table_info *)ch->tablestate;
-	ti = tablestate[tc_a->no.kidx];
-	ta = tc_a->ta;
-	astate = tc_a->astate;
-	count = tc_a->count;
-
-	IPFW_WLOCK(ch);
-	/* a <- b */
-	tablestate[tc_a->no.kidx] = tablestate[tc_b->no.kidx];
-	tc_a->ta = tc_b->ta;
-	tc_a->astate = tc_b->astate;
-	tc_a->count = tc_b->count;
-	/* b <- a */
-	tablestate[tc_b->no.kidx] = ti;
-	tc_b->ta = ta;
-	tc_b->astate = astate;
-	tc_b->count = count;
-	IPFW_WUNLOCK(ch);
-
-	/* Ensure tc.ti copies are in sync */
-	tc_a->ti_copy = tablestate[tc_a->no.kidx];
-	tc_b->ti_copy = tablestate[tc_b->no.kidx];
-
-	/* Notify both tables on @ti change */
-	if (tc_a->ta->change_ti != NULL)
-		tc_a->ta->change_ti(tc_a->astate, &tablestate[tc_a->no.kidx]);
-	if (tc_b->ta->change_ti != NULL)
-		tc_b->ta->change_ti(tc_b->astate, &tablestate[tc_b->no.kidx]);
-
-	IPFW_UH_WUNLOCK(ch);
-
-	return (0);
-}
-
-/*
- * Destroys table specified by @ti.
- * Data layout (v0)(current):
- * Request: [ ip_fw3_opheader ]
- *
- * Returns 0 on success
- */
-static int
-destroy_table(struct ip_fw_chain *ch, struct tid_info *ti)
-{
-	struct namedobj_instance *ni;
-	struct table_config *tc;
-
-	IPFW_UH_WLOCK(ch);
-
-	ni = CHAIN_TO_NI(ch);
-	if ((tc = find_table(ni, ti)) == NULL) {
-		IPFW_UH_WUNLOCK(ch);
-		return (ESRCH);
-	}
-
-	/* Do not permit destroying referenced tables */
-	if (tc->no.refcnt > 0) {
-		IPFW_UH_WUNLOCK(ch);
-		return (EBUSY);
-	}
-
-	IPFW_WLOCK(ch);
-	unlink_table(ch, tc);
-	IPFW_WUNLOCK(ch);
-
-	/* Free obj index */
-	if (ipfw_objhash_free_idx(ni, tc->no.kidx) != 0)
-		printf("Error unlinking kidx %d from table %s\n",
-		    tc->no.kidx, tc->tablename);
-
-	/* Unref values used in tables while holding UH lock */
-	ipfw_unref_table_values(ch, tc, tc->ta, tc->astate, &tc->ti_copy);
-	IPFW_UH_WUNLOCK(ch);
-
-	free_table_config(ni, tc);
-
-	return (0);
-}
-
-static uint32_t
-roundup2p(uint32_t v)
-{
-
-	v--;
-	v |= v >> 1;
-	v |= v >> 2;
-	v |= v >> 4;
-	v |= v >> 8;
-	v |= v >> 16;
-	v++;
-
-	return (v);
-}
-
-/*
- * Grow tables index.
- *
- * Returns 0 on success.
- */
-int
-ipfw_resize_tables(struct ip_fw_chain *ch, unsigned int ntables)
-{
-	unsigned int ntables_old, tbl;
-	struct namedobj_instance *ni;
-	void *new_idx, *old_tablestate, *tablestate;
-	struct table_info *ti;
-	struct table_config *tc;
-	int i, new_blocks;
-
-	/* Check new value for validity */
-	if (ntables == 0)
-		return (EINVAL);
-	if (ntables > IPFW_TABLES_MAX)
-		ntables = IPFW_TABLES_MAX;
-	/* Alight to nearest power of 2 */
-	ntables = (unsigned int)roundup2p(ntables); 
-
-	/* Allocate new pointers */
-	tablestate = malloc(ntables * sizeof(struct table_info),
-	    M_IPFW, M_WAITOK | M_ZERO);
-
-	ipfw_objhash_bitmap_alloc(ntables, (void *)&new_idx, &new_blocks);
-
-	IPFW_UH_WLOCK(ch);
-
-	tbl = (ntables >= V_fw_tables_max) ? V_fw_tables_max : ntables;
-	ni = CHAIN_TO_NI(ch);
-
-	/* Temporary restrict decreasing max_tables */
-	if (ntables < V_fw_tables_max) {
-
-		/*
-		 * FIXME: Check if we really can shrink
-		 */
-		IPFW_UH_WUNLOCK(ch);
-		return (EINVAL);
-	}
-
-	/* Copy table info/indices */
-	memcpy(tablestate, ch->tablestate, sizeof(struct table_info) * tbl);
-	ipfw_objhash_bitmap_merge(ni, &new_idx, &new_blocks);
-
-	IPFW_WLOCK(ch);
-
-	/* Change pointers */
-	old_tablestate = ch->tablestate;
-	ch->tablestate = tablestate;
-	ipfw_objhash_bitmap_swap(ni, &new_idx, &new_blocks);
-
-	ntables_old = V_fw_tables_max;
-	V_fw_tables_max = ntables;
-
-	IPFW_WUNLOCK(ch);
-
-	/* Notify all consumers that their @ti pointer has changed */
-	ti = (struct table_info *)ch->tablestate;
-	for (i = 0; i < tbl; i++, ti++) {
-		if (ti->lookup == NULL)
-			continue;
-		tc = (struct table_config *)ipfw_objhash_lookup_kidx(ni, i);
-		if (tc == NULL || tc->ta->change_ti == NULL)
-			continue;
-
-		tc->ta->change_ti(tc->astate, ti);
-	}
-
-	IPFW_UH_WUNLOCK(ch);
-
-	/* Free old pointers */
-	free(old_tablestate, M_IPFW);
-	ipfw_objhash_bitmap_free(new_idx, new_blocks);
-
-	return (0);
-}
-
-/*
- * Lookup table's named object by its @kidx.
- */
-struct named_object *
-ipfw_objhash_lookup_table_kidx(struct ip_fw_chain *ch, uint16_t kidx)
-{
-
-	return (ipfw_objhash_lookup_kidx(CHAIN_TO_NI(ch), kidx));
-}
-
-/*
- * Take reference to table specified in @ntlv.
- * On success return its @kidx.
- */
-int
-ipfw_ref_table(struct ip_fw_chain *ch, ipfw_obj_ntlv *ntlv, uint16_t *kidx)
-{
-	struct tid_info ti;
-	struct table_config *tc;
-	int error;
-
-	IPFW_UH_WLOCK_ASSERT(ch);
-
-	ntlv_to_ti(ntlv, &ti);
-	error = find_table_err(CHAIN_TO_NI(ch), &ti, &tc);
-	if (error != 0)
-		return (error);
-
-	if (tc == NULL)
-		return (ESRCH);
-
-	tc_ref(tc);
-	*kidx = tc->no.kidx;
-
-	return (0);
-}
-
-void
-ipfw_unref_table(struct ip_fw_chain *ch, uint16_t kidx)
-{
-
-	struct namedobj_instance *ni;
-	struct named_object *no;
-
-	IPFW_UH_WLOCK_ASSERT(ch);
-	ni = CHAIN_TO_NI(ch);
-	no = ipfw_objhash_lookup_kidx(ni, kidx);
-	KASSERT(no != NULL, ("Table with index %d not found", kidx));
-	no->refcnt--;
-}
-
-/*
- * Lookup an arbtrary key @paddr of legth @plen in table @tbl.
- * Stores found value in @val.
- *
- * Returns 1 if key was found.
- */
-int
-ipfw_lookup_table(struct ip_fw_chain *ch, uint16_t tbl, uint16_t plen,
-    void *paddr, uint32_t *val)
-{
-	struct table_info *ti;
-
-	ti = KIDX_TO_TI(ch, tbl);
-
-	return (ti->lookup(ti, paddr, plen, val));
-}
-
-/*
- * Info/List/dump support for tables.
- *
- */
-
-/*
- * High-level 'get' cmds sysctl handlers
- */
-
-/*
- * Lists all tables currently available in kernel.
- * Data layout (v0)(current):
- * Request: [ ipfw_obj_lheader ], size = ipfw_obj_lheader.size
- * Reply: [ ipfw_obj_lheader ipfw_xtable_info x N ]
- *
- * Returns 0 on success
- */
-static int
-list_tables(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
-    struct sockopt_data *sd)
-{
-	struct _ipfw_obj_lheader *olh;
-	int error;
-
-	olh = (struct _ipfw_obj_lheader *)ipfw_get_sopt_header(sd,sizeof(*olh));
-	if (olh == NULL)
-		return (EINVAL);
-	if (sd->valsize < olh->size)
-		return (EINVAL);
-
-	IPFW_UH_RLOCK(ch);
-	error = export_tables(ch, olh, sd);
-	IPFW_UH_RUNLOCK(ch);
-
-	return (error);
-}
-
-/*
- * Store table info to buffer provided by @sd.
- * Data layout (v0)(current):
- * Request: [ ipfw_obj_header ipfw_xtable_info(empty)]
- * Reply: [ ipfw_obj_header ipfw_xtable_info ]
- *
- * Returns 0 on success.
- */
-static int
-describe_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
-    struct sockopt_data *sd)
-{
-	struct _ipfw_obj_header *oh;
-	struct table_config *tc;
-	struct tid_info ti;
-	size_t sz;
-
-	sz = sizeof(*oh) + sizeof(ipfw_xtable_info);
-	oh = (struct _ipfw_obj_header *)ipfw_get_sopt_header(sd, sz);
-	if (oh == NULL)
-		return (EINVAL);
-
-	objheader_to_ti(oh, &ti);
-
-	IPFW_UH_RLOCK(ch);
-	if ((tc = find_table(CHAIN_TO_NI(ch), &ti)) == NULL) {
-		IPFW_UH_RUNLOCK(ch);
-		return (ESRCH);
-	}
-
-	export_table_info(ch, tc, (ipfw_xtable_info *)(oh + 1));
-	IPFW_UH_RUNLOCK(ch);
-
-	return (0);
-}
-
-/*
- * Modifies existing table.
- * Data layout (v0)(current):
- * Request: [ ipfw_obj_header ipfw_xtable_info ]
- *
- * Returns 0 on success
- */
-static int
-modify_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
-    struct sockopt_data *sd)
-{
-	struct _ipfw_obj_header *oh;
-	ipfw_xtable_info *i;
-	char *tname;
-	struct tid_info ti;
-	struct namedobj_instance *ni;
-	struct table_config *tc;
-
-	if (sd->valsize != sizeof(*oh) + sizeof(ipfw_xtable_info))
-		return (EINVAL);
-
-	oh = (struct _ipfw_obj_header *)sd->kbuf;
-	i = (ipfw_xtable_info *)(oh + 1);
-
-	/*
-	 * Verify user-supplied strings.
-	 * Check for null-terminated/zero-length strings/
-	 */
-	tname = oh->ntlv.name;
-	if (check_table_name(tname) != 0)
-		return (EINVAL);
-
-	objheader_to_ti(oh, &ti);
-	ti.type = i->type;
-
-	IPFW_UH_WLOCK(ch);
-	ni = CHAIN_TO_NI(ch);
-	if ((tc = find_table(ni, &ti)) == NULL) {
-		IPFW_UH_WUNLOCK(ch);
-		return (ESRCH);
-	}
-
-	/* Do not support any modifications for readonly tables */
-	if ((tc->ta->flags & TA_FLAG_READONLY) != 0) {
-		IPFW_UH_WUNLOCK(ch);
-		return (EACCES);
-	}
-
-	if ((i->mflags & IPFW_TMFLAGS_LIMIT) != 0)
-		tc->limit = i->limit;
-	if ((i->mflags & IPFW_TMFLAGS_LOCK) != 0)
-		tc->locked = ((i->flags & IPFW_TGFLAGS_LOCKED) != 0);
-	IPFW_UH_WUNLOCK(ch);
-
-	return (0);
-}
-
-/*
- * Creates new table.
- * Data layout (v0)(current):
- * Request: [ ipfw_obj_header ipfw_xtable_info ]
- *
- * Returns 0 on success
- */
-static int
-create_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
-    struct sockopt_data *sd)
-{
-	struct _ipfw_obj_header *oh;
-	ipfw_xtable_info *i;
-	char *tname, *aname;
-	struct tid_info ti;
-	struct namedobj_instance *ni;
-
-	if (sd->valsize != sizeof(*oh) + sizeof(ipfw_xtable_info))
-		return (EINVAL);
-
-	oh = (struct _ipfw_obj_header *)sd->kbuf;
-	i = (ipfw_xtable_info *)(oh + 1);
-
-	/*
-	 * Verify user-supplied strings.
-	 * Check for null-terminated/zero-length strings/
-	 */
-	tname = oh->ntlv.name;
-	aname = i->algoname;
-	if (check_table_name(tname) != 0 ||
-	    strnlen(aname, sizeof(i->algoname)) == sizeof(i->algoname))
-		return (EINVAL);
-
-	if (aname[0] == '\0') {
-		/* Use default algorithm */
-		aname = NULL;
-	}
-
-	objheader_to_ti(oh, &ti);
-	ti.type = i->type;
-
-	ni = CHAIN_TO_NI(ch);
-
-	IPFW_UH_RLOCK(ch);
-	if (find_table(ni, &ti) != NULL) {
-		IPFW_UH_RUNLOCK(ch);
-		return (EEXIST);
-	}
-	IPFW_UH_RUNLOCK(ch);
-
-	return (create_table_internal(ch, &ti, aname, i, NULL, 0));
-}
-
-/*
- * Creates new table based on @ti and @aname.
- *
- * Assume @aname to be checked and valid.
- * Stores allocated table kidx inside @pkidx (if non-NULL).
- * Reference created table if @compat is non-zero.
- *
- * Returns 0 on success.
- */
-static int
-create_table_internal(struct ip_fw_chain *ch, struct tid_info *ti,
-    char *aname, ipfw_xtable_info *i, uint16_t *pkidx, int compat)
-{
-	struct namedobj_instance *ni;
-	struct table_config *tc, *tc_new, *tmp;
-	struct table_algo *ta;
-	uint16_t kidx;
-
-	ni = CHAIN_TO_NI(ch);
-
-	ta = find_table_algo(CHAIN_TO_TCFG(ch), ti, aname);
-	if (ta == NULL)
-		return (ENOTSUP);
-
-	tc = alloc_table_config(ch, ti, ta, aname, i->tflags);
-	if (tc == NULL)
-		return (ENOMEM);
-
-	tc->vmask = i->vmask;
-	tc->limit = i->limit;
-	if (ta->flags & TA_FLAG_READONLY)
-		tc->locked = 1;
-	else
-		tc->locked = (i->flags & IPFW_TGFLAGS_LOCKED) != 0;
-
-	IPFW_UH_WLOCK(ch);
-
-	/* Check if table has been already created */
-	tc_new = find_table(ni, ti);
-	if (tc_new != NULL) {
-
-		/*
-		 * Compat: do not fail if we're
-		 * requesting to create existing table
-		 * which has the same type
-		 */
-		if (compat == 0 || tc_new->no.subtype != tc->no.subtype) {
-			IPFW_UH_WUNLOCK(ch);
-			free_table_config(ni, tc);
-			return (EEXIST);
-		}
-
-		/* Exchange tc and tc_new for proper refcounting & freeing */
-		tmp = tc;
-		tc = tc_new;
-		tc_new = tmp;
-	} else {
-		/* New table */
-		if (ipfw_objhash_alloc_idx(ni, &kidx) != 0) {
-			IPFW_UH_WUNLOCK(ch);
-			printf("Unable to allocate table index."
-			    " Consider increasing net.inet.ip.fw.tables_max");
-			free_table_config(ni, tc);
-			return (EBUSY);
-		}
-		tc->no.kidx = kidx;
-		tc->no.etlv = IPFW_TLV_TBL_NAME;
-
-		IPFW_WLOCK(ch);
-		link_table(ch, tc);
-		IPFW_WUNLOCK(ch);
-	}
-
-	if (compat != 0)
-		tc->no.refcnt++;
-	if (pkidx != NULL)
-		*pkidx = tc->no.kidx;
-
-	IPFW_UH_WUNLOCK(ch);
-
-	if (tc_new != NULL)
-		free_table_config(ni, tc_new);
-
-	return (0);
-}
-
-static void
-ntlv_to_ti(ipfw_obj_ntlv *ntlv, struct tid_info *ti)
-{
-
-	memset(ti, 0, sizeof(struct tid_info));
-	ti->set = ntlv->set;
-	ti->uidx = ntlv->idx;
-	ti->tlvs = ntlv;
-	ti->tlen = ntlv->head.length;
-}
-
-static void
-objheader_to_ti(struct _ipfw_obj_header *oh, struct tid_info *ti)
-{
-
-	ntlv_to_ti(&oh->ntlv, ti);
-}
-
-struct namedobj_instance *
-ipfw_get_table_objhash(struct ip_fw_chain *ch)
-{
-
-	return (CHAIN_TO_NI(ch));
-}
-
-/*
- * Exports basic table info as name TLV.
- * Used inside dump_static_rules() to provide info
- * about all tables referenced by current ruleset.
- *
- * Returns 0 on success.
- */
-int
-ipfw_export_table_ntlv(struct ip_fw_chain *ch, uint16_t kidx,
-    struct sockopt_data *sd)
-{
-	struct namedobj_instance *ni;
-	struct named_object *no;
-	ipfw_obj_ntlv *ntlv;
-
-	ni = CHAIN_TO_NI(ch);
-
-	no = ipfw_objhash_lookup_kidx(ni, kidx);
-	KASSERT(no != NULL, ("invalid table kidx passed"));
-
-	ntlv = (ipfw_obj_ntlv *)ipfw_get_sopt_space(sd, sizeof(*ntlv));
-	if (ntlv == NULL)
-		return (ENOMEM);
-
-	ntlv->head.type = IPFW_TLV_TBL_NAME;
-	ntlv->head.length = sizeof(*ntlv);
-	ntlv->idx = no->kidx;
-	strlcpy(ntlv->name, no->name, sizeof(ntlv->name));
-
-	return (0);
-}
-
-struct dump_args {
-	struct ip_fw_chain *ch;
-	struct table_info *ti;
-	struct table_config *tc;
-	struct sockopt_data *sd;
-	uint32_t cnt;
-	uint16_t uidx;
-	int error;
-	uint32_t size;
-	ipfw_table_entry *ent;
-	ta_foreach_f *f;
-	void *farg;
-	ipfw_obj_tentry tent;
-};
-
-static int
-count_ext_entries(void *e, void *arg)
-{
-	struct dump_args *da;
-
-	da = (struct dump_args *)arg;
-	da->cnt++;
-
-	return (0);
-}
-
-/*
- * Gets number of items from table either using
- * internal counter or calling algo callback for
- * externally-managed tables.
- *
- * Returns number of records.
- */
-static uint32_t
-table_get_count(struct ip_fw_chain *ch, struct table_config *tc)
-{
-	struct table_info *ti;
-	struct table_algo *ta;
-	struct dump_args da;
-
-	ti = KIDX_TO_TI(ch, tc->no.kidx);
-	ta = tc->ta;
-
-	/* Use internal counter for self-managed tables */
-	if ((ta->flags & TA_FLAG_READONLY) == 0)
-		return (tc->count);
-
-	/* Use callback to quickly get number of items */
-	if ((ta->flags & TA_FLAG_EXTCOUNTER) != 0)
-		return (ta->get_count(tc->astate, ti));
-
-	/* Count number of iterms ourselves */
-	memset(&da, 0, sizeof(da));
-	ta->foreach(tc->astate, ti, count_ext_entries, &da);
-
-	return (da.cnt);
-}
-
-/*
- * Exports table @tc info into standard ipfw_xtable_info format.
- */
-static void
-export_table_info(struct ip_fw_chain *ch, struct table_config *tc,
-    ipfw_xtable_info *i)
-{
-	struct table_info *ti;
-	struct table_algo *ta;
-	
-	i->type = tc->no.subtype;
-	i->tflags = tc->tflags;
-	i->vmask = tc->vmask;
-	i->set = tc->no.set;
-	i->kidx = tc->no.kidx;
-	i->refcnt = tc->no.refcnt;
-	i->count = table_get_count(ch, tc);
-	i->limit = tc->limit;
-	i->flags |= (tc->locked != 0) ? IPFW_TGFLAGS_LOCKED : 0;
-	i->size = i->count * sizeof(ipfw_obj_tentry);
-	i->size += sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info);
-	strlcpy(i->tablename, tc->tablename, sizeof(i->tablename));
-	ti = KIDX_TO_TI(ch, tc->no.kidx);
-	ta = tc->ta;
-	if (ta->print_config != NULL) {
-		/* Use algo function to print table config to string */
-		ta->print_config(tc->astate, ti, i->algoname,
-		    sizeof(i->algoname));
-	} else
-		strlcpy(i->algoname, ta->name, sizeof(i->algoname));
-	/* Dump algo-specific data, if possible */
-	if (ta->dump_tinfo != NULL) {
-		ta->dump_tinfo(tc->astate, ti, &i->ta_info);
-		i->ta_info.flags |= IPFW_TATFLAGS_DATA;
-	}
-}
-
-struct dump_table_args {
-	struct ip_fw_chain *ch;
-	struct sockopt_data *sd;
-};
-
-static int
-export_table_internal(struct namedobj_instance *ni, struct named_object *no,
-    void *arg)
-{
-	ipfw_xtable_info *i;
-	struct dump_table_args *dta;
-
-	dta = (struct dump_table_args *)arg;
-
-	i = (ipfw_xtable_info *)ipfw_get_sopt_space(dta->sd, sizeof(*i));
-	KASSERT(i != NULL, ("previously checked buffer is not enough"));
-
-	export_table_info(dta->ch, (struct table_config *)no, i);
-	return (0);
-}
-
-/*
- * Export all tables as ipfw_xtable_info structures to
- * storage provided by @sd.
- *
- * If supplied buffer is too small, fills in required size
- * and returns ENOMEM.
- * Returns 0 on success.
- */
-static int
-export_tables(struct ip_fw_chain *ch, ipfw_obj_lheader *olh,
-    struct sockopt_data *sd)
-{
-	uint32_t size;
-	uint32_t count;
-	struct dump_table_args dta;
-
-	count = ipfw_objhash_count(CHAIN_TO_NI(ch));
-	size = count * sizeof(ipfw_xtable_info) + sizeof(ipfw_obj_lheader);
-
-	/* Fill in header regadless of buffer size */
-	olh->count = count;
-	olh->objsize = sizeof(ipfw_xtable_info);
-
-	if (size > olh->size) {
-		olh->size = size;
-		return (ENOMEM);
-	}
-
-	olh->size = size;
-
-	dta.ch = ch;
-	dta.sd = sd;
-
-	ipfw_objhash_foreach(CHAIN_TO_NI(ch), export_table_internal, &dta);
-
-	return (0);
-}
-
-/*
- * Dumps all table data
- * Data layout (v1)(current):
- * Request: [ ipfw_obj_header ], size = ipfw_xtable_info.size
- * Reply: [ ipfw_obj_header ipfw_xtable_info ipfw_obj_tentry x N ]
- *
- * Returns 0 on success
- */
-static int
-dump_table_v1(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
-    struct sockopt_data *sd)
-{
-	struct _ipfw_obj_header *oh;
-	ipfw_xtable_info *i;
-	struct tid_info ti;
-	struct table_config *tc;
-	struct table_algo *ta;
-	struct dump_args da;
-	uint32_t sz;
-
-	sz = sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info);
-	oh = (struct _ipfw_obj_header *)ipfw_get_sopt_header(sd, sz);
-	if (oh == NULL)
-		return (EINVAL);
-
-	i = (ipfw_xtable_info *)(oh + 1);
-	objheader_to_ti(oh, &ti);
-
-	IPFW_UH_RLOCK(ch);
-	if ((tc = find_table(CHAIN_TO_NI(ch), &ti)) == NULL) {
-		IPFW_UH_RUNLOCK(ch);
-		return (ESRCH);
-	}
-	export_table_info(ch, tc, i);
-
-	if (sd->valsize < i->size) {
-
-		/*
-		 * Submitted buffer size is not enough.
-		 * WE've already filled in @i structure with
-		 * relevant table info including size, so we
-		 * can return. Buffer will be flushed automatically.
-		 */
-		IPFW_UH_RUNLOCK(ch);
-		return (ENOMEM);
-	}
-
-	/*
-	 * Do the actual dump in eXtended format
-	 */
-	memset(&da, 0, sizeof(da));
-	da.ch = ch;
-	da.ti = KIDX_TO_TI(ch, tc->no.kidx);
-	da.tc = tc;
-	da.sd = sd;
-
-	ta = tc->ta;
-
-	ta->foreach(tc->astate, da.ti, dump_table_tentry, &da);
-	IPFW_UH_RUNLOCK(ch);
-
-	return (da.error);
-}
-
-/*
- * Dumps all table data
- * Data layout (version 0)(legacy):
- * Request: [ ipfw_xtable ], size = IP_FW_TABLE_XGETSIZE()
- * Reply: [ ipfw_xtable ipfw_table_xentry x N ]
- *
- * Returns 0 on success
- */
-static int
-dump_table_v0(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
-    struct sockopt_data *sd)
-{
-	ipfw_xtable *xtbl;
-	struct tid_info ti;
-	struct table_config *tc;
-	struct table_algo *ta;
-	struct dump_args da;
-	size_t sz, count;
-
-	xtbl = (ipfw_xtable *)ipfw_get_sopt_header(sd, sizeof(ipfw_xtable));
-	if (xtbl == NULL)
-		return (EINVAL);
-
-	memset(&ti, 0, sizeof(ti));
-	ti.uidx = xtbl->tbl;
-	
-	IPFW_UH_RLOCK(ch);
-	if ((tc = find_table(CHAIN_TO_NI(ch), &ti)) == NULL) {
-		IPFW_UH_RUNLOCK(ch);
-		return (0);
-	}
-	count = table_get_count(ch, tc);
-	sz = count * sizeof(ipfw_table_xentry) + sizeof(ipfw_xtable);
-
-	xtbl->cnt = count;
-	xtbl->size = sz;
-	xtbl->type = tc->no.subtype;
-	xtbl->tbl = ti.uidx;
-
-	if (sd->valsize < sz) {
-
-		/*
-		 * Submitted buffer size is not enough.
-		 * WE've already filled in @i structure with
-		 * relevant table info including size, so we
-		 * can return. Buffer will be flushed automatically.
-		 */
-		IPFW_UH_RUNLOCK(ch);
-		return (ENOMEM);
-	}
-
-	/* Do the actual dump in eXtended format */
-	memset(&da, 0, sizeof(da));
-	da.ch = ch;
-	da.ti = KIDX_TO_TI(ch, tc->no.kidx);
-	da.tc = tc;
-	da.sd = sd;
-
-	ta = tc->ta;
-
-	ta->foreach(tc->astate, da.ti, dump_table_xentry, &da);
-	IPFW_UH_RUNLOCK(ch);
-
-	return (0);
-}
-
-/*
- * Legacy function to retrieve number of items in table.
- */
-static int
-get_table_size(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
-    struct sockopt_data *sd)
-{
-	uint32_t *tbl;
-	struct tid_info ti;
-	size_t sz;
-	int error;
-
-	sz = sizeof(*op3) + sizeof(uint32_t);
-	op3 = (ip_fw3_opheader *)ipfw_get_sopt_header(sd, sz);
-	if (op3 == NULL)
-		return (EINVAL);
-
-	tbl = (uint32_t *)(op3 + 1);
-	memset(&ti, 0, sizeof(ti));
-	ti.uidx = *tbl;
-	IPFW_UH_RLOCK(ch);
-	error = ipfw_count_xtable(ch, &ti, tbl);
-	IPFW_UH_RUNLOCK(ch);
-	return (error);
-}
-
-/*
- * Legacy IP_FW_TABLE_GETSIZE handler
- */
-int
-ipfw_count_table(struct ip_fw_chain *ch, struct tid_info *ti, uint32_t *cnt)
-{
-	struct table_config *tc;
-
-	if ((tc = find_table(CHAIN_TO_NI(ch), ti)) == NULL)
-		return (ESRCH);
-	*cnt = table_get_count(ch, tc);
-	return (0);
-}
-
-/*
- * Legacy IP_FW_TABLE_XGETSIZE handler
- */
-int
-ipfw_count_xtable(struct ip_fw_chain *ch, struct tid_info *ti, uint32_t *cnt)
-{
-	struct table_config *tc;
-	uint32_t count;
-
-	if ((tc = find_table(CHAIN_TO_NI(ch), ti)) == NULL) {
-		*cnt = 0;
-		return (0); /* 'table all list' requires success */
-	}
-
-	count = table_get_count(ch, tc);
-	*cnt = count * sizeof(ipfw_table_xentry);
-	if (count > 0)
-		*cnt += sizeof(ipfw_xtable);
-	return (0);
-}
-
-static int
-dump_table_entry(void *e, void *arg)
-{
-	struct dump_args *da;
-	struct table_config *tc;
-	struct table_algo *ta;
-	ipfw_table_entry *ent;
-	struct table_value *pval;
-	int error;
-
-	da = (struct dump_args *)arg;
-
-	tc = da->tc;
-	ta = tc->ta;
-
-	/* Out of memory, returning */
-	if (da->cnt == da->size)
-		return (1);
-	ent = da->ent++;
-	ent->tbl = da->uidx;
-	da->cnt++;
-
-	error = ta->dump_tentry(tc->astate, da->ti, e, &da->tent);
-	if (error != 0)
-		return (error);
-
-	ent->addr = da->tent.k.addr.s_addr;
-	ent->masklen = da->tent.masklen;
-	pval = get_table_value(da->ch, da->tc, da->tent.v.kidx);
-	ent->value = ipfw_export_table_value_legacy(pval);
-
-	return (0);
-}
-
-/*
- * Dumps table in pre-8.1 legacy format.
- */
-int
-ipfw_dump_table_legacy(struct ip_fw_chain *ch, struct tid_info *ti,
-    ipfw_table *tbl)
-{
-	struct table_config *tc;
-	struct table_algo *ta;
-	struct dump_args da;
-
-	tbl->cnt = 0;
-
-	if ((tc = find_table(CHAIN_TO_NI(ch), ti)) == NULL)
-		return (0);	/* XXX: We should return ESRCH */
-
-	ta = tc->ta;
-
-	/* This dump format supports IPv4 only */
-	if (tc->no.subtype != IPFW_TABLE_ADDR)
-		return (0);
-
-	memset(&da, 0, sizeof(da));
-	da.ch = ch;
-	da.ti = KIDX_TO_TI(ch, tc->no.kidx);
-	da.tc = tc;
-	da.ent = &tbl->ent[0];
-	da.size = tbl->size;
-
-	tbl->cnt = 0;
-	ta->foreach(tc->astate, da.ti, dump_table_entry, &da);
-	tbl->cnt = da.cnt;
-
-	return (0);
-}
-
-/*
- * Dumps table entry in eXtended format (v1)(current).
- */
-static int
-dump_table_tentry(void *e, void *arg)
-{
-	struct dump_args *da;
-	struct table_config *tc;
-	struct table_algo *ta;
-	struct table_value *pval;
-	ipfw_obj_tentry *tent;
-	int error;
-
-	da = (struct dump_args *)arg;
-
-	tc = da->tc;
-	ta = tc->ta;
-
-	tent = (ipfw_obj_tentry *)ipfw_get_sopt_space(da->sd, sizeof(*tent));
-	/* Out of memory, returning */
-	if (tent == NULL) {
-		da->error = ENOMEM;
-		return (1);
-	}
-	tent->head.length = sizeof(ipfw_obj_tentry);
-	tent->idx = da->uidx;
-
-	error = ta->dump_tentry(tc->astate, da->ti, e, tent);
-	if (error != 0)
-		return (error);
-
-	pval = get_table_value(da->ch, da->tc, tent->v.kidx);
-	ipfw_export_table_value_v1(pval, &tent->v.value);
-
-	return (0);
-}
-
-/*
- * Dumps table entry in eXtended format (v0).
- */
-static int
-dump_table_xentry(void *e, void *arg)
-{
-	struct dump_args *da;
-	struct table_config *tc;
-	struct table_algo *ta;
-	ipfw_table_xentry *xent;
-	ipfw_obj_tentry *tent;
-	struct table_value *pval;
-	int error;
-
-	da = (struct dump_args *)arg;
-
-	tc = da->tc;
-	ta = tc->ta;
-
-	xent = (ipfw_table_xentry *)ipfw_get_sopt_space(da->sd, sizeof(*xent));
-	/* Out of memory, returning */
-	if (xent == NULL)
-		return (1);
-	xent->len = sizeof(ipfw_table_xentry);
-	xent->tbl = da->uidx;
-
-	memset(&da->tent, 0, sizeof(da->tent));
-	tent = &da->tent;
-	error = ta->dump_tentry(tc->astate, da->ti, e, tent);
-	if (error != 0)
-		return (error);
-
-	/* Convert current format to previous one */
-	xent->masklen = tent->masklen;
-	pval = get_table_value(da->ch, da->tc, da->tent.v.kidx);
-	xent->value = ipfw_export_table_value_legacy(pval);
-	/* Apply some hacks */
-	if (tc->no.subtype == IPFW_TABLE_ADDR && tent->subtype == AF_INET) {
-		xent->k.addr6.s6_addr32[3] = tent->k.addr.s_addr;
-		xent->flags = IPFW_TCF_INET;
-	} else
-		memcpy(&xent->k, &tent->k, sizeof(xent->k));
-
-	return (0);
-}
-
-/*
- * Helper function to export table algo data
- * to tentry format before calling user function.
- *
- * Returns 0 on success.
- */
-static int
-prepare_table_tentry(void *e, void *arg)
-{
-	struct dump_args *da;
-	struct table_config *tc;
-	struct table_algo *ta;
-	int error;
-
-	da = (struct dump_args *)arg;
-
-	tc = da->tc;
-	ta = tc->ta;
-
-	error = ta->dump_tentry(tc->astate, da->ti, e, &da->tent);
-	if (error != 0)
-		return (error);
-
-	da->f(&da->tent, da->farg);
-
-	return (0);
-}
-
-/*
- * Allow external consumers to read table entries in standard format.
- */
-int
-ipfw_foreach_table_tentry(struct ip_fw_chain *ch, uint16_t kidx,
-    ta_foreach_f *f, void *arg)
-{
-	struct namedobj_instance *ni;
-	struct table_config *tc;
-	struct table_algo *ta;
-	struct dump_args da;
-
-	ni = CHAIN_TO_NI(ch);
-
-	tc = (struct table_config *)ipfw_objhash_lookup_kidx(ni, kidx);
-	if (tc == NULL)
-		return (ESRCH);
-
-	ta = tc->ta;
-
-	memset(&da, 0, sizeof(da));
-	da.ch = ch;
-	da.ti = KIDX_TO_TI(ch, tc->no.kidx);
-	da.tc = tc;
-	da.f = f;
-	da.farg = arg;
-
-	ta->foreach(tc->astate, da.ti, prepare_table_tentry, &da);
-
-	return (0);
-}
-
-/*
- * Table algorithms
- */ 
-
-/*
- * Finds algorithm by index, table type or supplied name.
- *
- * Returns pointer to algo or NULL.
- */
-static struct table_algo *
-find_table_algo(struct tables_config *tcfg, struct tid_info *ti, char *name)
-{
-	int i, l;
-	struct table_algo *ta;
-
-	if (ti->type > IPFW_TABLE_MAXTYPE)
-		return (NULL);
-
-	/* Search by index */
-	if (ti->atype != 0) {
-		if (ti->atype > tcfg->algo_count)
-			return (NULL);
-		return (tcfg->algo[ti->atype]);
-	}
-
-	if (name == NULL) {
-		/* Return default algorithm for given type if set */
-		return (tcfg->def_algo[ti->type]);
-	}
-
-	/* Search by name */
-	/* TODO: better search */
-	for (i = 1; i <= tcfg->algo_count; i++) {
-		ta = tcfg->algo[i];
-
-		/*
-		 * One can supply additional algorithm
-		 * parameters so we compare only the first word
-		 * of supplied name:
-		 * 'addr:chash hsize=32'
-		 * '^^^^^^^^^'
-		 *
-		 */
-		l = strlen(ta->name);
-		if (strncmp(name, ta->name, l) != 0)
-			continue;
-		if (name[l] != '\0' && name[l] != ' ')
-			continue;
-		/* Check if we're requesting proper table type */
-		if (ti->type != 0 && ti->type != ta->type)
-			return (NULL);
-		return (ta);
-	}
-
-	return (NULL);
-}
-
-/*
- * Register new table algo @ta.
- * Stores algo id inside @idx.
- *
- * Returns 0 on success.
- */
-int
-ipfw_add_table_algo(struct ip_fw_chain *ch, struct table_algo *ta, size_t size,
-    int *idx)
-{
-	struct tables_config *tcfg;
-	struct table_algo *ta_new;
-	size_t sz;
-
-	if (size > sizeof(struct table_algo))
-		return (EINVAL);
-
-	/* Check for the required on-stack size for add/del */
-	sz = roundup2(ta->ta_buf_size, sizeof(void *));
-	if (sz > TA_BUF_SZ)
-		return (EINVAL);
-
-	KASSERT(ta->type <= IPFW_TABLE_MAXTYPE,("Increase IPFW_TABLE_MAXTYPE"));
-
-	/* Copy algorithm data to stable storage. */
-	ta_new = malloc(sizeof(struct table_algo), M_IPFW, M_WAITOK | M_ZERO);
-	memcpy(ta_new, ta, size);
-
-	tcfg = CHAIN_TO_TCFG(ch);
-
-	KASSERT(tcfg->algo_count < 255, ("Increase algo array size"));
-
-	tcfg->algo[++tcfg->algo_count] = ta_new;
-	ta_new->idx = tcfg->algo_count;
-
-	/* Set algorithm as default one for given type */
-	if ((ta_new->flags & TA_FLAG_DEFAULT) != 0 &&
-	    tcfg->def_algo[ta_new->type] == NULL)
-		tcfg->def_algo[ta_new->type] = ta_new;
-
-	*idx = ta_new->idx;
-	
-	return (0);
-}
-
-/*
- * Unregisters table algo using @idx as id.
- * XXX: It is NOT safe to call this function in any place
- * other than ipfw instance destroy handler.
- */
-void
-ipfw_del_table_algo(struct ip_fw_chain *ch, int idx)
-{
-	struct tables_config *tcfg;
-	struct table_algo *ta;
-
-	tcfg = CHAIN_TO_TCFG(ch);
-
-	KASSERT(idx <= tcfg->algo_count, ("algo idx %d out of range 1..%d",
-	    idx, tcfg->algo_count));
-
-	ta = tcfg->algo[idx];
-	KASSERT(ta != NULL, ("algo idx %d is NULL", idx));
-
-	if (tcfg->def_algo[ta->type] == ta)
-		tcfg->def_algo[ta->type] = NULL;
-
-	free(ta, M_IPFW);
-}
-
-/*
- * Lists all table algorithms currently available.
- * Data layout (v0)(current):
- * Request: [ ipfw_obj_lheader ], size = ipfw_obj_lheader.size
- * Reply: [ ipfw_obj_lheader ipfw_ta_info x N ]
- *
- * Returns 0 on success
- */
-static int
-list_table_algo(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
-    struct sockopt_data *sd)
-{
-	struct _ipfw_obj_lheader *olh;
-	struct tables_config *tcfg;
-	ipfw_ta_info *i;
-	struct table_algo *ta;
-	uint32_t count, n, size;
-
-	olh = (struct _ipfw_obj_lheader *)ipfw_get_sopt_header(sd,sizeof(*olh));
-	if (olh == NULL)
-		return (EINVAL);
-	if (sd->valsize < olh->size)
-		return (EINVAL);
-
-	IPFW_UH_RLOCK(ch);
-	tcfg = CHAIN_TO_TCFG(ch);
-	count = tcfg->algo_count;
-	size = count * sizeof(ipfw_ta_info) + sizeof(ipfw_obj_lheader);
-
-	/* Fill in header regadless of buffer size */
-	olh->count = count;
-	olh->objsize = sizeof(ipfw_ta_info);
-
-	if (size > olh->size) {
-		olh->size = size;
-		IPFW_UH_RUNLOCK(ch);
-		return (ENOMEM);
-	}
-	olh->size = size;
-
-	for (n = 1; n <= count; n++) {
-		i = (ipfw_ta_info *)ipfw_get_sopt_space(sd, sizeof(*i));
-		KASSERT(i != NULL, ("previously checked buffer is not enough"));
-		ta = tcfg->algo[n];
-		strlcpy(i->algoname, ta->name, sizeof(i->algoname));
-		i->type = ta->type;
-		i->refcnt = ta->refcnt;
-	}
-
-	IPFW_UH_RUNLOCK(ch);
-
-	return (0);
-}
-
-static int
-classify_srcdst(ipfw_insn *cmd, uint16_t *puidx, uint8_t *ptype)
-{
-	/* Basic IPv4/IPv6 or u32 lookups */
-	*puidx = cmd->arg1;
-	/* Assume ADDR by default */
-	*ptype = IPFW_TABLE_ADDR;
-	int v;
-		
-	if (F_LEN(cmd) > F_INSN_SIZE(ipfw_insn_u32)) {
-		/*
-		 * generic lookup. The key must be
-		 * in 32bit big-endian format.
-		 */
-		v = ((ipfw_insn_u32 *)cmd)->d[1];
-		switch (v) {
-		case 0:
-		case 1:
-			/* IPv4 src/dst */
-			break;
-		case 2:
-		case 3:
-			/* src/dst port */
-			*ptype = IPFW_TABLE_NUMBER;
-			break;
-		case 4:
-			/* uid/gid */
-			*ptype = IPFW_TABLE_NUMBER;
-			break;
-		case 5:
-			/* jid */
-			*ptype = IPFW_TABLE_NUMBER;
-			break;
-		case 6:
-			/* dscp */
-			*ptype = IPFW_TABLE_NUMBER;
-			break;
-		}
-	}
-
-	return (0);
-}
-
-static int
-classify_via(ipfw_insn *cmd, uint16_t *puidx, uint8_t *ptype)
-{
-	ipfw_insn_if *cmdif;
-
-	/* Interface table, possibly */
-	cmdif = (ipfw_insn_if *)cmd;
-	if (cmdif->name[0] != '\1')
-		return (1);
-
-	*ptype = IPFW_TABLE_INTERFACE;
-	*puidx = cmdif->p.kidx;
-
-	return (0);
-}
-
-static int
-classify_flow(ipfw_insn *cmd, uint16_t *puidx, uint8_t *ptype)
-{
-
-	*puidx = cmd->arg1;
-	*ptype = IPFW_TABLE_FLOW;
-
-	return (0);
-}
-
-static void
-update_arg1(ipfw_insn *cmd, uint16_t idx)
-{
-
-	cmd->arg1 = idx;
-}
-
-static void
-update_via(ipfw_insn *cmd, uint16_t idx)
-{
-	ipfw_insn_if *cmdif;
-
-	cmdif = (ipfw_insn_if *)cmd;
-	cmdif->p.kidx = idx;
-}
-
-static int
-table_findbyname(struct ip_fw_chain *ch, struct tid_info *ti,
-    struct named_object **pno)
-{
-	struct table_config *tc;
-	int error;
-
-	IPFW_UH_WLOCK_ASSERT(ch);
-
-	error = find_table_err(CHAIN_TO_NI(ch), ti, &tc);
-	if (error != 0)
-		return (error);
-
-	*pno = &tc->no;
-	return (0);
-}
-
-/* XXX: sets-sets! */
-static struct named_object *
-table_findbykidx(struct ip_fw_chain *ch, uint16_t idx)
-{
-	struct namedobj_instance *ni;
-	struct table_config *tc;
-
-	IPFW_UH_WLOCK_ASSERT(ch);
-	ni = CHAIN_TO_NI(ch);
-	tc = (struct table_config *)ipfw_objhash_lookup_kidx(ni, idx);
-	KASSERT(tc != NULL, ("Table with index %d not found", idx));
-
-	return (&tc->no);
-}
-
-static int
-table_manage_sets(struct ip_fw_chain *ch, uint16_t set, uint8_t new_set,
-    enum ipfw_sets_cmd cmd)
-{
-
-	switch (cmd) {
-	case SWAP_ALL:
-	case TEST_ALL:
-	case MOVE_ALL:
-		/*
-		 * Always return success, the real action and decision
-		 * should make table_manage_sets_all().
-		 */
-		return (0);
-	case TEST_ONE:
-	case MOVE_ONE:
-		/*
-		 * NOTE: we need to use ipfw_objhash_del/ipfw_objhash_add
-		 * if set number will be used in hash function. Currently
-		 * we can just use generic handler that replaces set value.
-		 */
-		if (V_fw_tables_sets == 0)
-			return (0);
-		break;
-	case COUNT_ONE:
-		/*
-		 * Return EOPNOTSUPP for COUNT_ONE when per-set sysctl is
-		 * disabled. This allow skip table's opcodes from additional
-		 * checks when specific rules moved to another set.
-		 */
-		if (V_fw_tables_sets == 0)
-			return (EOPNOTSUPP);
-	}
-	/* Use generic sets handler when per-set sysctl is enabled. */
-	return (ipfw_obj_manage_sets(CHAIN_TO_NI(ch), IPFW_TLV_TBL_NAME,
-	    set, new_set, cmd));
-}
-
-/*
- * We register several opcode rewriters for lookup tables.
- * All tables opcodes have the same ETLV type, but different subtype.
- * To avoid invoking sets handler several times for XXX_ALL commands,
- * we use separate manage_sets handler. O_RECV has the lowest value,
- * so it should be called first.
- */
-static int
-table_manage_sets_all(struct ip_fw_chain *ch, uint16_t set, uint8_t new_set,
-    enum ipfw_sets_cmd cmd)
-{
-
-	switch (cmd) {
-	case SWAP_ALL:
-	case TEST_ALL:
-		/*
-		 * Return success for TEST_ALL, since nothing prevents
-		 * move rules from one set to another. All tables are
-		 * accessible from all sets when per-set tables sysctl
-		 * is disabled.
-		 */
-	case MOVE_ALL:
-		if (V_fw_tables_sets == 0)
-			return (0);
-		break;
-	default:
-		return (table_manage_sets(ch, set, new_set, cmd));
-	}
-	/* Use generic sets handler when per-set sysctl is enabled. */
-	return (ipfw_obj_manage_sets(CHAIN_TO_NI(ch), IPFW_TLV_TBL_NAME,
-	    set, new_set, cmd));
-}
-
-static struct opcode_obj_rewrite opcodes[] = {
-	{
-		.opcode = O_IP_SRC_LOOKUP,
-		.etlv = IPFW_TLV_TBL_NAME,
-		.classifier = classify_srcdst,
-		.update = update_arg1,
-		.find_byname = table_findbyname,
-		.find_bykidx = table_findbykidx,
-		.create_object = create_table_compat,
-		.manage_sets = table_manage_sets,
-	},
-	{
-		.opcode = O_IP_DST_LOOKUP,
-		.etlv = IPFW_TLV_TBL_NAME,
-		.classifier = classify_srcdst,
-		.update = update_arg1,
-		.find_byname = table_findbyname,
-		.find_bykidx = table_findbykidx,
-		.create_object = create_table_compat,
-		.manage_sets = table_manage_sets,
-	},
-	{
-		.opcode = O_IP_FLOW_LOOKUP,
-		.etlv = IPFW_TLV_TBL_NAME,
-		.classifier = classify_flow,
-		.update = update_arg1,
-		.find_byname = table_findbyname,
-		.find_bykidx = table_findbykidx,
-		.create_object = create_table_compat,
-		.manage_sets = table_manage_sets,
-	},
-	{
-		.opcode = O_XMIT,
-		.etlv = IPFW_TLV_TBL_NAME,
-		.classifier = classify_via,
-		.update = update_via,
-		.find_byname = table_findbyname,
-		.find_bykidx = table_findbykidx,
-		.create_object = create_table_compat,
-		.manage_sets = table_manage_sets,
-	},
-	{
-		.opcode = O_RECV,
-		.etlv = IPFW_TLV_TBL_NAME,
-		.classifier = classify_via,
-		.update = update_via,
-		.find_byname = table_findbyname,
-		.find_bykidx = table_findbykidx,
-		.create_object = create_table_compat,
-		.manage_sets = table_manage_sets_all,
-	},
-	{
-		.opcode = O_VIA,
-		.etlv = IPFW_TLV_TBL_NAME,
-		.classifier = classify_via,
-		.update = update_via,
-		.find_byname = table_findbyname,
-		.find_bykidx = table_findbykidx,
-		.create_object = create_table_compat,
-		.manage_sets = table_manage_sets,
-	},
-};
-
-static int
-test_sets_cb(struct namedobj_instance *ni __unused, struct named_object *no,
-    void *arg __unused)
-{
-
-	/* Check that there aren't any tables in not default set */
-	if (no->set != 0)
-		return (EBUSY);
-	return (0);
-}
-
-/*
- * Switch between "set 0" and "rule's set" table binding,
- * Check all ruleset bindings and permits changing
- * IFF each binding has both rule AND table in default set (set 0).
- *
- * Returns 0 on success.
- */
-int
-ipfw_switch_tables_namespace(struct ip_fw_chain *ch, unsigned int sets)
-{
-	struct opcode_obj_rewrite *rw;
-	struct namedobj_instance *ni;
-	struct named_object *no;
-	struct ip_fw *rule;
-	ipfw_insn *cmd;
-	int cmdlen, i, l;
-	uint16_t kidx;
-	uint8_t subtype;
-
-	IPFW_UH_WLOCK(ch);
-
-	if (V_fw_tables_sets == sets) {
-		IPFW_UH_WUNLOCK(ch);
-		return (0);
-	}
-	ni = CHAIN_TO_NI(ch);
-	if (sets == 0) {
-		/*
-		 * Prevent disabling sets support if we have some tables
-		 * in not default sets.
-		 */
-		if (ipfw_objhash_foreach_type(ni, test_sets_cb,
-		    NULL, IPFW_TLV_TBL_NAME) != 0) {
-			IPFW_UH_WUNLOCK(ch);
-			return (EBUSY);
-		}
-	}
-	/*
-	 * Scan all rules and examine tables opcodes.
-	 */
-	for (i = 0; i < ch->n_rules; i++) {
-		rule = ch->map[i];
-
-		l = rule->cmd_len;
-		cmd = rule->cmd;
-		cmdlen = 0;
-		for ( ;	l > 0 ; l -= cmdlen, cmd += cmdlen) {
-			cmdlen = F_LEN(cmd);
-			/* Check only tables opcodes */
-			for (kidx = 0, rw = opcodes;
-			    rw < opcodes + nitems(opcodes); rw++) {
-				if (rw->opcode != cmd->opcode)
-					continue;
-				if (rw->classifier(cmd, &kidx, &subtype) == 0)
-					break;
-			}
-			if (kidx == 0)
-				continue;
-			no = ipfw_objhash_lookup_kidx(ni, kidx);
-			/* Check if both table object and rule has the set 0 */
-			if (no->set != 0 || rule->set != 0) {
-				IPFW_UH_WUNLOCK(ch);
-				return (EBUSY);
-			}
-
-		}
-	}
-	V_fw_tables_sets = sets;
-	IPFW_UH_WUNLOCK(ch);
-	return (0);
-}
-
-/*
- * Checks table name for validity.
- * Enforce basic length checks, the rest
- * should be done in userland.
- *
- * Returns 0 if name is considered valid.
- */
-static int
-check_table_name(const char *name)
-{
-
-	/*
-	 * TODO: do some more complicated checks
-	 */
-	return (ipfw_check_object_name_generic(name));
-}
-
-/*
- * Finds table config based on either legacy index
- * or name in ntlv.
- * Note @ti structure contains unchecked data from userland.
- *
- * Returns 0 in success and fills in @tc with found config
- */
-static int
-find_table_err(struct namedobj_instance *ni, struct tid_info *ti,
-    struct table_config **tc)
-{
-	char *name, bname[16];
-	struct named_object *no;
-	ipfw_obj_ntlv *ntlv;
-	uint32_t set;
-
-	if (ti->tlvs != NULL) {
-		ntlv = ipfw_find_name_tlv_type(ti->tlvs, ti->tlen, ti->uidx,
-		    IPFW_TLV_TBL_NAME);
-		if (ntlv == NULL)
-			return (EINVAL);
-		name = ntlv->name;
-
-		/*
-		 * Use set provided by @ti instead of @ntlv one.
-		 * This is needed due to different sets behavior
-		 * controlled by V_fw_tables_sets.
-		 */
-		set = (V_fw_tables_sets != 0) ? ti->set : 0;
-	} else {
-		snprintf(bname, sizeof(bname), "%d", ti->uidx);
-		name = bname;
-		set = 0;
-	}
-
-	no = ipfw_objhash_lookup_name(ni, set, name);
-	*tc = (struct table_config *)no;
-
-	return (0);
-}
-
-/*
- * Finds table config based on either legacy index
- * or name in ntlv.
- * Note @ti structure contains unchecked data from userland.
- *
- * Returns pointer to table_config or NULL.
- */
-static struct table_config *
-find_table(struct namedobj_instance *ni, struct tid_info *ti)
-{
-	struct table_config *tc;
-
-	if (find_table_err(ni, ti, &tc) != 0)
-		return (NULL);
-
-	return (tc);
-}
-
-/*
- * Allocate new table config structure using
- * specified @algo and @aname.
- *
- * Returns pointer to config or NULL.
- */
-static struct table_config *
-alloc_table_config(struct ip_fw_chain *ch, struct tid_info *ti,
-    struct table_algo *ta, char *aname, uint8_t tflags)
-{
-	char *name, bname[16];
-	struct table_config *tc;
-	int error;
-	ipfw_obj_ntlv *ntlv;
-	uint32_t set;
-
-	if (ti->tlvs != NULL) {
-		ntlv = ipfw_find_name_tlv_type(ti->tlvs, ti->tlen, ti->uidx,
-		    IPFW_TLV_TBL_NAME);
-		if (ntlv == NULL)
-			return (NULL);
-		name = ntlv->name;
-		set = ntlv->set;
-	} else {
-		/* Compat part: convert number to string representation */
-		snprintf(bname, sizeof(bname), "%d", ti->uidx);
-		name = bname;
-		set = 0;
-	}
-
-	tc = malloc(sizeof(struct table_config), M_IPFW, M_WAITOK | M_ZERO);
-	tc->no.name = tc->tablename;
-	tc->no.subtype = ta->type;
-	tc->no.set = set;
-	tc->tflags = tflags;
-	tc->ta = ta;
-	strlcpy(tc->tablename, name, sizeof(tc->tablename));
-	/* Set "shared" value type by default */
-	tc->vshared = 1;
-
-	/* Preallocate data structures for new tables */
-	error = ta->init(ch, &tc->astate, &tc->ti_copy, aname, tflags);
-	if (error != 0) {
-		free(tc, M_IPFW);
-		return (NULL);
-	}
-	
-	return (tc);
-}
-
-/*
- * Destroys table state and config.
- */
-static void
-free_table_config(struct namedobj_instance *ni, struct table_config *tc)
-{
-
-	KASSERT(tc->linked == 0, ("free() on linked config"));
-	/* UH lock MUST NOT be held */
-
-	/*
-	 * We're using ta without any locking/referencing.
-	 * TODO: fix this if we're going to use unloadable algos.
-	 */
-	tc->ta->destroy(tc->astate, &tc->ti_copy);
-	free(tc, M_IPFW);
-}
-
-/*
- * Links @tc to @chain table named instance.
- * Sets appropriate type/states in @chain table info.
- */
-static void
-link_table(struct ip_fw_chain *ch, struct table_config *tc)
-{
-	struct namedobj_instance *ni;
-	struct table_info *ti;
-	uint16_t kidx;
-
-	IPFW_UH_WLOCK_ASSERT(ch);
-	IPFW_WLOCK_ASSERT(ch);
-
-	ni = CHAIN_TO_NI(ch);
-	kidx = tc->no.kidx;
-
-	ipfw_objhash_add(ni, &tc->no);
-
-	ti = KIDX_TO_TI(ch, kidx);
-	*ti = tc->ti_copy;
-
-	/* Notify algo on real @ti address */
-	if (tc->ta->change_ti != NULL)
-		tc->ta->change_ti(tc->astate, ti);
-
-	tc->linked = 1;
-	tc->ta->refcnt++;
-}
-
-/*
- * Unlinks @tc from @chain table named instance.
- * Zeroes states in @chain and stores them in @tc.
- */
-static void
-unlink_table(struct ip_fw_chain *ch, struct table_config *tc)
-{
-	struct namedobj_instance *ni;
-	struct table_info *ti;
-	uint16_t kidx;
-
-	IPFW_UH_WLOCK_ASSERT(ch);
-	IPFW_WLOCK_ASSERT(ch);
-
-	ni = CHAIN_TO_NI(ch);
-	kidx = tc->no.kidx;
-
-	/* Clear state. @ti copy is already saved inside @tc */
-	ipfw_objhash_del(ni, &tc->no);
-	ti = KIDX_TO_TI(ch, kidx);
-	memset(ti, 0, sizeof(struct table_info));
-	tc->linked = 0;
-	tc->ta->refcnt--;
-
-	/* Notify algo on real @ti address */
-	if (tc->ta->change_ti != NULL)
-		tc->ta->change_ti(tc->astate, NULL);
-}
-
-static struct ipfw_sopt_handler	scodes[] = {
-	{ IP_FW_TABLE_XCREATE,	0,	HDIR_SET,	create_table },
-	{ IP_FW_TABLE_XDESTROY,	0,	HDIR_SET,	flush_table_v0 },
-	{ IP_FW_TABLE_XFLUSH,	0,	HDIR_SET,	flush_table_v0 },
-	{ IP_FW_TABLE_XMODIFY,	0,	HDIR_BOTH,	modify_table },
-	{ IP_FW_TABLE_XINFO,	0,	HDIR_GET,	describe_table },
-	{ IP_FW_TABLES_XLIST,	0,	HDIR_GET,	list_tables },
-	{ IP_FW_TABLE_XLIST,	0,	HDIR_GET,	dump_table_v0 },
-	{ IP_FW_TABLE_XLIST,	1,	HDIR_GET,	dump_table_v1 },
-	{ IP_FW_TABLE_XADD,	0,	HDIR_BOTH,	manage_table_ent_v0 },
-	{ IP_FW_TABLE_XADD,	1,	HDIR_BOTH,	manage_table_ent_v1 },
-	{ IP_FW_TABLE_XDEL,	0,	HDIR_BOTH,	manage_table_ent_v0 },
-	{ IP_FW_TABLE_XDEL,	1,	HDIR_BOTH,	manage_table_ent_v1 },
-	{ IP_FW_TABLE_XFIND,	0,	HDIR_GET,	find_table_entry },
-	{ IP_FW_TABLE_XSWAP,	0,	HDIR_SET,	swap_table },
-	{ IP_FW_TABLES_ALIST,	0,	HDIR_GET,	list_table_algo },
-	{ IP_FW_TABLE_XGETSIZE,	0,	HDIR_GET,	get_table_size },
-};
-
-static int
-destroy_table_locked(struct namedobj_instance *ni, struct named_object *no,
-    void *arg)
-{
-
-	unlink_table((struct ip_fw_chain *)arg, (struct table_config *)no);
-	if (ipfw_objhash_free_idx(ni, no->kidx) != 0)
-		printf("Error unlinking kidx %d from table %s\n",
-		    no->kidx, no->name);
-	free_table_config(ni, (struct table_config *)no);
-	return (0);
-}
-
-/*
- * Shuts tables module down.
- */
-void
-ipfw_destroy_tables(struct ip_fw_chain *ch, int last)
-{
-
-	IPFW_DEL_SOPT_HANDLER(last, scodes);
-	IPFW_DEL_OBJ_REWRITER(last, opcodes);
-
-	/* Remove all tables from working set */
-	IPFW_UH_WLOCK(ch);
-	IPFW_WLOCK(ch);
-	ipfw_objhash_foreach(CHAIN_TO_NI(ch), destroy_table_locked, ch);
-	IPFW_WUNLOCK(ch);
-	IPFW_UH_WUNLOCK(ch);
-
-	/* Free pointers itself */
-	free(ch->tablestate, M_IPFW);
-
-	ipfw_table_value_destroy(ch, last);
-	ipfw_table_algo_destroy(ch);
-
-	ipfw_objhash_destroy(CHAIN_TO_NI(ch));
-	free(CHAIN_TO_TCFG(ch), M_IPFW);
-}
-
-/*
- * Starts tables module.
- */
-int
-ipfw_init_tables(struct ip_fw_chain *ch, int first)
-{
-	struct tables_config *tcfg;
-
-	/* Allocate pointers */
-	ch->tablestate = malloc(V_fw_tables_max * sizeof(struct table_info),
-	    M_IPFW, M_WAITOK | M_ZERO);
-
-	tcfg = malloc(sizeof(struct tables_config), M_IPFW, M_WAITOK | M_ZERO);
-	tcfg->namehash = ipfw_objhash_create(V_fw_tables_max);
-	ch->tblcfg = tcfg;
-
-	ipfw_table_value_init(ch, first);
-	ipfw_table_algo_init(ch);
-
-	IPFW_ADD_OBJ_REWRITER(first, opcodes);
-	IPFW_ADD_SOPT_HANDLER(first, scodes);
-	return (0);
-}
-
-
-
Index: eebsd/sys/netpfil/ipfw/ip_fw_table.h
===================================================================
--- freebsd/sys/netpfil/ipfw/ip_fw_table.h	(revision f62c62d2fe57ec02c1350144f7739f8e866ee6d4)
+++ 	(revision )
@@ -1,234 +1,0 @@
-/*-
- * Copyright (c) 2002-2009 Luigi Rizzo, Universita` di Pisa
- *
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
- *
- * $FreeBSD$
- */
-
-#ifndef _IPFW2_TABLE_H
-#define _IPFW2_TABLE_H
-
-/*
- * Internal constants and data structures used by ipfw tables
- * not meant to be exported outside the kernel.
- */
-#ifdef _KERNEL
-
-struct table_algo;
-struct tables_config {
-	struct namedobj_instance	*namehash;
-	struct namedobj_instance	*valhash;
-	uint32_t			val_size;
-	uint32_t			algo_count;
-	struct table_algo 		*algo[256];
-	struct table_algo		*def_algo[IPFW_TABLE_MAXTYPE + 1];
-	TAILQ_HEAD(op_state_l,op_state)	state_list;
-};
-#define	CHAIN_TO_TCFG(chain)	((struct tables_config *)(chain)->tblcfg)
-
-struct table_info {
-	table_lookup_t	*lookup;	/* Lookup function */
-	void		*state;		/* Lookup radix/other structure */
-	void		*xstate;	/* eXtended state */
-	u_long		data;		/* Hints for given func */
-};
-
-struct table_value;
-struct tentry_info {
-	void		*paddr;
-	struct table_value	*pvalue;
-	void		*ptv;		/* Temporary field to hold obj	*/		
-	uint8_t		masklen;	/* mask length			*/
-	uint8_t		subtype;
-	uint16_t	flags;		/* record flags			*/
-	uint32_t	value;		/* value index			*/
-};
-#define	TEI_FLAGS_UPDATE	0x0001	/* Add or update rec if exists	*/
-#define	TEI_FLAGS_UPDATED	0x0002	/* Entry has been updated	*/
-#define	TEI_FLAGS_COMPAT	0x0004	/* Called from old ABI		*/
-#define	TEI_FLAGS_DONTADD	0x0008	/* Do not create new rec	*/
-#define	TEI_FLAGS_ADDED		0x0010	/* Entry was added		*/
-#define	TEI_FLAGS_DELETED	0x0020	/* Entry was deleted		*/
-#define	TEI_FLAGS_LIMIT		0x0040	/* Limit was hit		*/
-#define	TEI_FLAGS_ERROR		0x0080	/* Unknown request error	*/
-#define	TEI_FLAGS_NOTFOUND	0x0100	/* Entry was not found		*/
-#define	TEI_FLAGS_EXISTS	0x0200	/* Entry already exists		*/
-
-typedef int (ta_init)(struct ip_fw_chain *ch, void **ta_state,
-    struct table_info *ti, char *data, uint8_t tflags);
-typedef void (ta_destroy)(void *ta_state, struct table_info *ti);
-typedef int (ta_prepare_add)(struct ip_fw_chain *ch, struct tentry_info *tei,
-    void *ta_buf);
-typedef int (ta_prepare_del)(struct ip_fw_chain *ch, struct tentry_info *tei,
-    void *ta_buf);
-typedef int (ta_add)(void *ta_state, struct table_info *ti,
-    struct tentry_info *tei, void *ta_buf, uint32_t *pnum);
-typedef int (ta_del)(void *ta_state, struct table_info *ti,
-    struct tentry_info *tei, void *ta_buf, uint32_t *pnum);
-typedef void (ta_flush_entry)(struct ip_fw_chain *ch, struct tentry_info *tei,
-    void *ta_buf);
-
-typedef int (ta_need_modify)(void *ta_state, struct table_info *ti,
-    uint32_t count, uint64_t *pflags);
-typedef int (ta_prepare_mod)(void *ta_buf, uint64_t *pflags);
-typedef int (ta_fill_mod)(void *ta_state, struct table_info *ti,
-    void *ta_buf, uint64_t *pflags);
-typedef void (ta_modify)(void *ta_state, struct table_info *ti,
-    void *ta_buf, uint64_t pflags);
-typedef void (ta_flush_mod)(void *ta_buf);
-
-typedef void (ta_change_ti)(void *ta_state, struct table_info *ti);
-typedef void (ta_print_config)(void *ta_state, struct table_info *ti, char *buf,
-    size_t bufsize);
-
-typedef int ta_foreach_f(void *node, void *arg);
-typedef void ta_foreach(void *ta_state, struct table_info *ti, ta_foreach_f *f,
-  void *arg);
-typedef int ta_dump_tentry(void *ta_state, struct table_info *ti, void *e,
-    ipfw_obj_tentry *tent);
-typedef int ta_find_tentry(void *ta_state, struct table_info *ti,
-    ipfw_obj_tentry *tent);
-typedef void ta_dump_tinfo(void *ta_state, struct table_info *ti, 
-    ipfw_ta_tinfo *tinfo);
-typedef uint32_t ta_get_count(void *ta_state, struct table_info *ti);
-
-struct table_algo {
-	char		name[16];
-	uint32_t	idx;
-	uint32_t	type;
-	uint32_t	refcnt;
-	uint32_t	flags;
-	uint32_t	vlimit;
-	size_t		ta_buf_size;
-	ta_init		*init;
-	ta_destroy	*destroy;
-	ta_prepare_add	*prepare_add;
-	ta_prepare_del	*prepare_del;
-	ta_add		*add;
-	ta_del		*del;
-	ta_flush_entry	*flush_entry;
-	ta_find_tentry	*find_tentry;
-	ta_need_modify	*need_modify;
-	ta_prepare_mod	*prepare_mod;
-	ta_fill_mod	*fill_mod;
-	ta_modify	*modify;
-	ta_flush_mod	*flush_mod;
-	ta_change_ti	*change_ti;
-	ta_foreach	*foreach;
-	ta_dump_tentry	*dump_tentry;
-	ta_print_config	*print_config;
-	ta_dump_tinfo	*dump_tinfo;
-	ta_get_count	*get_count;
-};
-#define	TA_FLAG_DEFAULT		0x01	/* Algo is default for given type */
-#define	TA_FLAG_READONLY	0x02	/* Algo does not support modifications*/
-#define	TA_FLAG_EXTCOUNTER	0x04	/* Algo has external counter available*/
-
-int ipfw_add_table_algo(struct ip_fw_chain *ch, struct table_algo *ta,
-    size_t size, int *idx);
-void ipfw_del_table_algo(struct ip_fw_chain *ch, int idx);
-
-void ipfw_table_algo_init(struct ip_fw_chain *chain);
-void ipfw_table_algo_destroy(struct ip_fw_chain *chain);
-
-MALLOC_DECLARE(M_IPFW_TBL);
-/* Exported to support legacy opcodes */
-int add_table_entry(struct ip_fw_chain *ch, struct tid_info *ti,
-    struct tentry_info *tei, uint8_t flags, uint32_t count);
-int del_table_entry(struct ip_fw_chain *ch, struct tid_info *ti,
-    struct tentry_info *tei, uint8_t flags, uint32_t count);
-int flush_table(struct ip_fw_chain *ch, struct tid_info *ti);
-void ipfw_import_table_value_legacy(uint32_t value, struct table_value *v);
-uint32_t ipfw_export_table_value_legacy(struct table_value *v);
-int ipfw_get_table_size(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
-    struct sockopt_data *sd);
-
-/* ipfw_table_value.c functions */
-struct table_config;
-struct tableop_state;
-void ipfw_table_value_init(struct ip_fw_chain *ch, int first);
-void ipfw_table_value_destroy(struct ip_fw_chain *ch, int last);
-int ipfw_link_table_values(struct ip_fw_chain *ch, struct tableop_state *ts);
-void ipfw_garbage_table_values(struct ip_fw_chain *ch, struct table_config *tc,
-    struct tentry_info *tei, uint32_t count, int rollback);
-void ipfw_import_table_value_v1(ipfw_table_value *iv);
-void ipfw_export_table_value_v1(struct table_value *v, ipfw_table_value *iv);
-void ipfw_unref_table_values(struct ip_fw_chain *ch, struct table_config *tc,
-    struct table_algo *ta, void *astate, struct table_info *ti);
-void rollback_table_values(struct tableop_state *ts);
-
-int ipfw_rewrite_table_uidx(struct ip_fw_chain *chain,
-    struct rule_check_info *ci);
-int ipfw_mark_table_kidx(struct ip_fw_chain *chain, struct ip_fw *rule,
-    uint32_t *bmask);
-int ipfw_export_table_ntlv(struct ip_fw_chain *ch, uint16_t kidx,
-    struct sockopt_data *sd);
-void ipfw_unref_rule_tables(struct ip_fw_chain *chain, struct ip_fw *rule);
-struct namedobj_instance *ipfw_get_table_objhash(struct ip_fw_chain *ch);
-
-/* utility functions  */
-int ipfw_move_tables_sets(struct ip_fw_chain *ch, ipfw_range_tlv *rt,
-    uint32_t new_set);
-void ipfw_swap_tables_sets(struct ip_fw_chain *ch, uint32_t old_set,
-    uint32_t new_set, int mv);
-int ipfw_foreach_table_tentry(struct ip_fw_chain *ch, uint16_t kidx,
-    ta_foreach_f f, void *arg);
-
-/* internal functions */
-void tc_ref(struct table_config *tc);
-void tc_unref(struct table_config *tc);
-
-struct op_state;
-typedef void (op_rollback_f)(void *object, struct op_state *state);
-struct op_state {
-	TAILQ_ENTRY(op_state)	next;	/* chain link */
-	op_rollback_f		*func;
-};
-
-struct tableop_state {
-	struct op_state	opstate;
-	struct ip_fw_chain *ch;
-	struct table_config *tc;
-	struct table_algo *ta;
-	struct tentry_info *tei;
-	uint32_t count;
-	uint32_t vmask;
-	int vshared;
-	int modified;
-};
-
-void add_toperation_state(struct ip_fw_chain *ch, struct tableop_state *ts);
-void del_toperation_state(struct ip_fw_chain *ch, struct tableop_state *ts);
-void rollback_toperation_state(struct ip_fw_chain *ch, void *object);
-
-/* Legacy interfaces */
-int ipfw_count_table(struct ip_fw_chain *ch, struct tid_info *ti,
-    uint32_t *cnt);
-int ipfw_count_xtable(struct ip_fw_chain *ch, struct tid_info *ti,
-    uint32_t *cnt);
-int ipfw_dump_table_legacy(struct ip_fw_chain *ch, struct tid_info *ti,
-    ipfw_table *tbl);
-
-
-#endif /* _KERNEL */
-#endif /* _IPFW2_TABLE_H */
Index: eebsd/sys/netpfil/ipfw/ip_fw_table_algo.c
===================================================================
--- freebsd/sys/netpfil/ipfw/ip_fw_table_algo.c	(revision f62c62d2fe57ec02c1350144f7739f8e866ee6d4)
+++ 	(revision )
@@ -1,4112 +1,0 @@
-#include <machine/rtems-bsd-kernel-space.h>
-
-/*-
- * Copyright (c) 2014 Yandex LLC
- * Copyright (c) 2014 Alexander V. Chernikov
- *
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-/*
- * Lookup table algorithms.
- *
- */
-
-#include <rtems/bsd/local/opt_ipfw.h>
-#include <rtems/bsd/local/opt_inet.h>
-#ifndef INET
-#error IPFIREWALL requires INET.
-#endif /* INET */
-#include <rtems/bsd/local/opt_inet6.h>
-
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/malloc.h>
-#include <sys/kernel.h>
-#include <sys/lock.h>
-#include <sys/rwlock.h>
-#include <sys/rmlock.h>
-#include <sys/socket.h>
-#include <sys/queue.h>
-#include <net/if.h>	/* ip_fw.h requires IFNAMSIZ */
-#include <net/radix.h>
-#include <net/route.h>
-#include <net/route_var.h>
-
-#include <netinet/in.h>
-#include <netinet/in_fib.h>
-#include <netinet/ip_var.h>	/* struct ipfw_rule_ref */
-#include <netinet/ip_fw.h>
-#include <netinet6/in6_fib.h>
-
-#include <netpfil/ipfw/ip_fw_private.h>
-#include <netpfil/ipfw/ip_fw_table.h>
-
-
-/*
- * IPFW table lookup algorithms.
- *
- * What is needed to add another table algo?
- *
- * Algo init:
- * * struct table_algo has to be filled with:
- *   name: "type:algoname" format, e.g. "addr:radix". Currently
- *     there are the following types: "addr", "iface", "number" and "flow".
- *   type: one of IPFW_TABLE_* types
- *   flags: one or more TA_FLAGS_*
- *   ta_buf_size: size of structure used to store add/del item state.
- *     Needs to be less than TA_BUF_SZ.
- *   callbacks: see below for description.
- * * ipfw_add_table_algo / ipfw_del_table_algo has to be called
- *
- * Callbacks description:
- *
- * -init: request to initialize new table instance.
- * typedef int (ta_init)(struct ip_fw_chain *ch, void **ta_state,
- *     struct table_info *ti, char *data, uint8_t tflags);
- * MANDATORY, unlocked. (M_WAITOK). Returns 0 on success.
- *
- *  Allocate all structures needed for normal operations.
- *  * Caller may want to parse @data for some algo-specific
- *    options provided by userland.
- *  * Caller may want to save configuration state pointer to @ta_state
- *  * Caller needs to save desired runtime structure pointer(s)
- *    inside @ti fields. Note that it is not correct to save
- *    @ti pointer at this moment. Use -change_ti hook for that.
- *  * Caller has to fill in ti->lookup to appropriate function
- *    pointer.
- *
- *
- *
- * -destroy: request to destroy table instance.
- * typedef void (ta_destroy)(void *ta_state, struct table_info *ti);
- * MANDATORY, unlocked. (M_WAITOK).
- *
- * Frees all table entries and all tables structures allocated by -init.
- *
- *
- *
- * -prepare_add: request to allocate state for adding new entry.
- * typedef int (ta_prepare_add)(struct ip_fw_chain *ch, struct tentry_info *tei,
- *     void *ta_buf);
- * MANDATORY, unlocked. (M_WAITOK). Returns 0 on success.
- *
- * Allocates state and fills it in with all necessary data (EXCEPT value)
- * from @tei to minimize operations needed to be done under WLOCK.
- * "value" field has to be copied to new entry in @add callback.
- * Buffer ta_buf of size ta->ta_buf_sz may be used to store
- * allocated state.
- *
- *
- *
- * -prepare_del: request to set state for deleting existing entry.
- * typedef int (ta_prepare_del)(struct ip_fw_chain *ch, struct tentry_info *tei,
- *     void *ta_buf);
- * MANDATORY, locked, UH. (M_NOWAIT). Returns 0 on success.
- *
- * Buffer ta_buf of size ta->ta_buf_sz may be used to store
- * allocated state. Caller should use on-stack ta_buf allocation
- * instead of doing malloc().
- *
- *
- *
- * -add: request to insert new entry into runtime/config structures.
- *  typedef int (ta_add)(void *ta_state, struct table_info *ti,
- *     struct tentry_info *tei, void *ta_buf, uint32_t *pnum);
- * MANDATORY, UH+WLOCK. (M_NOWAIT). Returns 0 on success.
- *
- * Insert new entry using previously-allocated state in @ta_buf.
- * * @tei may have the following flags:
- *   TEI_FLAGS_UPDATE: request to add or update entry.
- *   TEI_FLAGS_DONTADD: request to update (but not add) entry.
- * * Caller is required to do the following:
- *   copy real entry value from @tei
- *   entry added: return 0, set 1 to @pnum
- *   entry updated: return 0, store 0 to @pnum, store old value in @tei,
- *     add TEI_FLAGS_UPDATED flag to @tei.
- *   entry exists: return EEXIST
- *   entry not found: return ENOENT
- *   other error: return non-zero error code.
- *
- *
- *
- * -del: request to delete existing entry from runtime/config structures.
- *  typedef int (ta_del)(void *ta_state, struct table_info *ti,
- *     struct tentry_info *tei, void *ta_buf, uint32_t *pnum);
- *  MANDATORY, UH+WLOCK. (M_NOWAIT). Returns 0 on success.
- *
- *  Delete entry using previously set up in @ta_buf.
- * * Caller is required to do the following:
- *   entry deleted: return 0, set 1 to @pnum, store old value in @tei.
- *   entry not found: return ENOENT
- *   other error: return non-zero error code.
- *
- *
- *
- * -flush_entry: flush entry state created by -prepare_add / -del / others
- *  typedef void (ta_flush_entry)(struct ip_fw_chain *ch,
- *      struct tentry_info *tei, void *ta_buf);
- *  MANDATORY, may be locked. (M_NOWAIT).
- *
- *  Delete state allocated by:
- *  -prepare_add (-add returned EEXIST|UPDATED)
- *  -prepare_del (if any)
- *  -del
- *  * Caller is required to handle empty @ta_buf correctly.
- *
- *
- * -find_tentry: finds entry specified by key @tei
- *  typedef int ta_find_tentry(void *ta_state, struct table_info *ti,
- *      ipfw_obj_tentry *tent);
- *  OPTIONAL, locked (UH). (M_NOWAIT). Returns 0 on success.
- *
- *  Finds entry specified by given key.
- *  * Caller is required to do the following:
- *    entry found: returns 0, export entry to @tent
- *    entry not found: returns ENOENT
- *
- *
- * -need_modify: checks if @ti has enough space to hold another @count items.
- *  typedef int (ta_need_modify)(void *ta_state, struct table_info *ti,
- *      uint32_t count, uint64_t *pflags);
- *  OPTIONAL, locked (UH). (M_NOWAIT). Returns 0 if has.
- *
- *  Checks if given table has enough space to add @count items without
- *  resize. Caller may use @pflags to store desired modification data.
- *
- *
- *
- * -prepare_mod: allocate structures for table modification.
- *  typedef int (ta_prepare_mod)(void *ta_buf, uint64_t *pflags);
- * OPTIONAL(need_modify), unlocked. (M_WAITOK). Returns 0 on success.
- *
- * Allocate all needed state for table modification. Caller
- * should use `struct mod_item` to store new state in @ta_buf.
- * Up to TA_BUF_SZ (128 bytes) can be stored in @ta_buf.
- * 
- *
- *
- * -fill_mod: copy some data to new state/
- *  typedef int (ta_fill_mod)(void *ta_state, struct table_info *ti,
- *      void *ta_buf, uint64_t *pflags);
- * OPTIONAL(need_modify), locked (UH). (M_NOWAIT). Returns 0 on success.
- *
- * Copy as much data as we can to minimize changes under WLOCK.
- * For example, array can be merged inside this callback.
- *
- *
- *
- * -modify: perform final modification.
- *  typedef void (ta_modify)(void *ta_state, struct table_info *ti,
- *      void *ta_buf, uint64_t pflags);
- * OPTIONAL(need_modify), locked (UH+WLOCK). (M_NOWAIT). 
- *
- * Performs all changes necessary to switch to new structures.
- * * Caller should save old pointers to @ta_buf storage.
- *
- *
- *
- * -flush_mod: flush table modification state.
- *  typedef void (ta_flush_mod)(void *ta_buf);
- * OPTIONAL(need_modify), unlocked. (M_WAITOK).
- *
- * Performs flush for the following:
- *   - prepare_mod (modification was not necessary)
- *   - modify (for the old state)
- *
- *
- *
- * -change_gi: monitor table info pointer changes
- * typedef void (ta_change_ti)(void *ta_state, struct table_info *ti);
- * OPTIONAL, locked (UH). (M_NOWAIT).
- *
- * Called on @ti pointer changed. Called immediately after -init
- * to set initial state.
- *
- *
- *
- * -foreach: calls @f for each table entry
- *  typedef void ta_foreach(void *ta_state, struct table_info *ti,
- *      ta_foreach_f *f, void *arg);
- * MANDATORY, locked(UH). (M_NOWAIT).
- *
- * Runs callback with specified argument for each table entry,
- * Typically used for dumping table entries.
- *
- *
- *
- * -dump_tentry: dump table entry in current @tentry format.
- *  typedef int ta_dump_tentry(void *ta_state, struct table_info *ti, void *e,
- *      ipfw_obj_tentry *tent);
- * MANDATORY, locked(UH). (M_NOWAIT). Returns 0 on success.
- *
- * Dumps entry @e to @tent.
- *
- *
- * -print_config: prints custom algorithm options into buffer.
- *  typedef void (ta_print_config)(void *ta_state, struct table_info *ti,
- *      char *buf, size_t bufsize);
- * OPTIONAL. locked(UH). (M_NOWAIT).
- *
- * Prints custom algorithm options in the format suitable to pass
- * back to -init callback.
- *
- *
- *
- * -dump_tinfo: dumps algo-specific info.
- *  typedef void ta_dump_tinfo(void *ta_state, struct table_info *ti,
- *      ipfw_ta_tinfo *tinfo);
- * OPTIONAL. locked(UH). (M_NOWAIT).
- *
- * Dumps options like items size/hash size, etc.
- */
-
-MALLOC_DEFINE(M_IPFW_TBL, "ipfw_tbl", "IpFw tables");
-
-/*
- * Utility structures/functions common to more than one algo
- */
-
-struct mod_item {
-	void	*main_ptr;
-	size_t	size;
-	void	*main_ptr6;
-	size_t	size6;
-};
-
-static int badd(const void *key, void *item, void *base, size_t nmemb,
-    size_t size, int (*compar) (const void *, const void *));
-static int bdel(const void *key, void *base, size_t nmemb, size_t size,
-    int (*compar) (const void *, const void *));
-
-
-/*
- * ADDR implementation using radix
- *
- */
-
-/*
- * The radix code expects addr and mask to be array of bytes,
- * with the first byte being the length of the array. rn_inithead
- * is called with the offset in bits of the lookup key within the
- * array. If we use a sockaddr_in as the underlying type,
- * sin_len is conveniently located at offset 0, sin_addr is at
- * offset 4 and normally aligned.
- * But for portability, let's avoid assumption and make the code explicit
- */
-#define KEY_LEN(v)	*((uint8_t *)&(v))
-/*
- * Do not require radix to compare more than actual IPv4/IPv6 address
- */
-#define KEY_LEN_INET	(offsetof(struct sockaddr_in, sin_addr) + sizeof(in_addr_t))
-#define KEY_LEN_INET6	(offsetof(struct sa_in6, sin6_addr) + sizeof(struct in6_addr))
-
-#define OFF_LEN_INET	(8 * offsetof(struct sockaddr_in, sin_addr))
-#define OFF_LEN_INET6	(8 * offsetof(struct sa_in6, sin6_addr))
-
-struct radix_addr_entry {
-	struct radix_node	rn[2];
-	struct sockaddr_in	addr;
-	uint32_t		value;
-	uint8_t			masklen;
-};
-
-struct sa_in6 {
-	uint8_t			sin6_len;
-	uint8_t			sin6_family;
-	uint8_t			pad[2];
-	struct in6_addr		sin6_addr;
-};
-
-struct radix_addr_xentry {
-	struct radix_node	rn[2];
-	struct sa_in6		addr6;
-	uint32_t		value;
-	uint8_t			masklen;
-};
-
-struct radix_cfg {
-	struct radix_node_head	*head4;
-	struct radix_node_head	*head6;
-	size_t			count4;
-	size_t			count6;
-};
-
-struct ta_buf_radix
-{
-	void *ent_ptr;
-	struct sockaddr	*addr_ptr;
-	struct sockaddr	*mask_ptr;
-	union {
-		struct {
-			struct sockaddr_in sa;
-			struct sockaddr_in ma;
-		} a4;
-		struct {
-			struct sa_in6 sa;
-			struct sa_in6 ma;
-		} a6;
-	} addr;
-};
-
-static int ta_lookup_radix(struct table_info *ti, void *key, uint32_t keylen,
-    uint32_t *val);
-static int ta_init_radix(struct ip_fw_chain *ch, void **ta_state,
-    struct table_info *ti, char *data, uint8_t tflags);
-static int flush_radix_entry(struct radix_node *rn, void *arg);
-static void ta_destroy_radix(void *ta_state, struct table_info *ti);
-static void ta_dump_radix_tinfo(void *ta_state, struct table_info *ti,
-    ipfw_ta_tinfo *tinfo);
-static int ta_dump_radix_tentry(void *ta_state, struct table_info *ti,
-    void *e, ipfw_obj_tentry *tent);
-static int ta_find_radix_tentry(void *ta_state, struct table_info *ti,
-    ipfw_obj_tentry *tent);
-static void ta_foreach_radix(void *ta_state, struct table_info *ti,
-    ta_foreach_f *f, void *arg);
-static void tei_to_sockaddr_ent(struct tentry_info *tei, struct sockaddr *sa,
-    struct sockaddr *ma, int *set_mask);
-static int ta_prepare_add_radix(struct ip_fw_chain *ch, struct tentry_info *tei,
-    void *ta_buf);
-static int ta_add_radix(void *ta_state, struct table_info *ti,
-    struct tentry_info *tei, void *ta_buf, uint32_t *pnum);
-static int ta_prepare_del_radix(struct ip_fw_chain *ch, struct tentry_info *tei,
-    void *ta_buf);
-static int ta_del_radix(void *ta_state, struct table_info *ti,
-    struct tentry_info *tei, void *ta_buf, uint32_t *pnum);
-static void ta_flush_radix_entry(struct ip_fw_chain *ch, struct tentry_info *tei,
-    void *ta_buf);
-static int ta_need_modify_radix(void *ta_state, struct table_info *ti,
-    uint32_t count, uint64_t *pflags);
-
-static int
-ta_lookup_radix(struct table_info *ti, void *key, uint32_t keylen,
-    uint32_t *val)
-{
-	struct radix_node_head *rnh;
-
-	if (keylen == sizeof(in_addr_t)) {
-		struct radix_addr_entry *ent;
-		struct sockaddr_in sa;
-		KEY_LEN(sa) = KEY_LEN_INET;
-		sa.sin_addr.s_addr = *((in_addr_t *)key);
-		rnh = (struct radix_node_head *)ti->state;
-		ent = (struct radix_addr_entry *)(rnh->rnh_matchaddr(&sa, &rnh->rh));
-		if (ent != NULL) {
-			*val = ent->value;
-			return (1);
-		}
-	} else {
-		struct radix_addr_xentry *xent;
-		struct sa_in6 sa6;
-		KEY_LEN(sa6) = KEY_LEN_INET6;
-		memcpy(&sa6.sin6_addr, key, sizeof(struct in6_addr));
-		rnh = (struct radix_node_head *)ti->xstate;
-		xent = (struct radix_addr_xentry *)(rnh->rnh_matchaddr(&sa6, &rnh->rh));
-		if (xent != NULL) {
-			*val = xent->value;
-			return (1);
-		}
-	}
-
-	return (0);
-}
-
-/*
- * New table
- */
-static int
-ta_init_radix(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti,
-    char *data, uint8_t tflags)
-{
-	struct radix_cfg *cfg;
-
-	if (!rn_inithead(&ti->state, OFF_LEN_INET))
-		return (ENOMEM);
-	if (!rn_inithead(&ti->xstate, OFF_LEN_INET6)) {
-		rn_detachhead(&ti->state);
-		return (ENOMEM);
-	}
-
-	cfg = malloc(sizeof(struct radix_cfg), M_IPFW, M_WAITOK | M_ZERO);
-
-	*ta_state = cfg;
-	ti->lookup = ta_lookup_radix;
-
-	return (0);
-}
-
-static int
-flush_radix_entry(struct radix_node *rn, void *arg)
-{
-	struct radix_node_head * const rnh = arg;
-	struct radix_addr_entry *ent;
-
-	ent = (struct radix_addr_entry *)
-	    rnh->rnh_deladdr(rn->rn_key, rn->rn_mask, &rnh->rh);
-	if (ent != NULL)
-		free(ent, M_IPFW_TBL);
-	return (0);
-}
-
-static void
-ta_destroy_radix(void *ta_state, struct table_info *ti)
-{
-	struct radix_cfg *cfg;
-	struct radix_node_head *rnh;
-
-	cfg = (struct radix_cfg *)ta_state;
-
-	rnh = (struct radix_node_head *)(ti->state);
-	rnh->rnh_walktree(&rnh->rh, flush_radix_entry, rnh);
-	rn_detachhead(&ti->state);
-
-	rnh = (struct radix_node_head *)(ti->xstate);
-	rnh->rnh_walktree(&rnh->rh, flush_radix_entry, rnh);
-	rn_detachhead(&ti->xstate);
-
-	free(cfg, M_IPFW);
-}
-
-/*
- * Provide algo-specific table info
- */
-static void
-ta_dump_radix_tinfo(void *ta_state, struct table_info *ti, ipfw_ta_tinfo *tinfo)
-{
-	struct radix_cfg *cfg;
-
-	cfg = (struct radix_cfg *)ta_state;
-
-	tinfo->flags = IPFW_TATFLAGS_AFDATA | IPFW_TATFLAGS_AFITEM;
-	tinfo->taclass4 = IPFW_TACLASS_RADIX;
-	tinfo->count4 = cfg->count4;
-	tinfo->itemsize4 = sizeof(struct radix_addr_entry);
-	tinfo->taclass6 = IPFW_TACLASS_RADIX;
-	tinfo->count6 = cfg->count6;
-	tinfo->itemsize6 = sizeof(struct radix_addr_xentry);
-}
-
-static int
-ta_dump_radix_tentry(void *ta_state, struct table_info *ti, void *e,
-    ipfw_obj_tentry *tent)
-{
-	struct radix_addr_entry *n;
-#ifdef INET6
-	struct radix_addr_xentry *xn;
-#endif
-
-	n = (struct radix_addr_entry *)e;
-
-	/* Guess IPv4/IPv6 radix by sockaddr family */
-	if (n->addr.sin_family == AF_INET) {
-		tent->k.addr.s_addr = n->addr.sin_addr.s_addr;
-		tent->masklen = n->masklen;
-		tent->subtype = AF_INET;
-		tent->v.kidx = n->value;
-#ifdef INET6
-	} else {
-		xn = (struct radix_addr_xentry *)e;
-		memcpy(&tent->k, &xn->addr6.sin6_addr, sizeof(struct in6_addr));
-		tent->masklen = xn->masklen;
-		tent->subtype = AF_INET6;
-		tent->v.kidx = xn->value;
-#endif
-	}
-
-	return (0);
-}
-
-static int
-ta_find_radix_tentry(void *ta_state, struct table_info *ti,
-    ipfw_obj_tentry *tent)
-{
-	struct radix_node_head *rnh;
-	void *e;
-
-	e = NULL;
-	if (tent->subtype == AF_INET) {
-		struct sockaddr_in sa;
-		KEY_LEN(sa) = KEY_LEN_INET;
-		sa.sin_addr.s_addr = tent->k.addr.s_addr;
-		rnh = (struct radix_node_head *)ti->state;
-		e = rnh->rnh_matchaddr(&sa, &rnh->rh);
-	} else {
-		struct sa_in6 sa6;
-		KEY_LEN(sa6) = KEY_LEN_INET6;
-		memcpy(&sa6.sin6_addr, &tent->k.addr6, sizeof(struct in6_addr));
-		rnh = (struct radix_node_head *)ti->xstate;
-		e = rnh->rnh_matchaddr(&sa6, &rnh->rh);
-	}
-
-	if (e != NULL) {
-		ta_dump_radix_tentry(ta_state, ti, e, tent);
-		return (0);
-	}
-
-	return (ENOENT);
-}
-
-static void
-ta_foreach_radix(void *ta_state, struct table_info *ti, ta_foreach_f *f,
-    void *arg)
-{
-	struct radix_node_head *rnh;
-
-	rnh = (struct radix_node_head *)(ti->state);
-	rnh->rnh_walktree(&rnh->rh, (walktree_f_t *)f, arg);
-
-	rnh = (struct radix_node_head *)(ti->xstate);
-	rnh->rnh_walktree(&rnh->rh, (walktree_f_t *)f, arg);
-}
-
-
-#ifdef INET6
-static inline void ipv6_writemask(struct in6_addr *addr6, uint8_t mask);
-
-static inline void
-ipv6_writemask(struct in6_addr *addr6, uint8_t mask)
-{
-	uint32_t *cp;
-
-	for (cp = (uint32_t *)addr6; mask >= 32; mask -= 32)
-		*cp++ = 0xFFFFFFFF;
-	if (mask > 0)
-		*cp = htonl(mask ? ~((1 << (32 - mask)) - 1) : 0);
-}
-#endif
-
-static void
-tei_to_sockaddr_ent(struct tentry_info *tei, struct sockaddr *sa,
-    struct sockaddr *ma, int *set_mask)
-{
-	int mlen;
-#ifdef INET
-	struct sockaddr_in *addr, *mask;
-#endif
-#ifdef INET6
-	struct sa_in6 *addr6, *mask6;
-#endif
-	in_addr_t a4;
-
-	mlen = tei->masklen;
-
-	if (tei->subtype == AF_INET) {
-#ifdef INET
-		addr = (struct sockaddr_in *)sa;
-		mask = (struct sockaddr_in *)ma;
-		/* Set 'total' structure length */
-		KEY_LEN(*addr) = KEY_LEN_INET;
-		KEY_LEN(*mask) = KEY_LEN_INET;
-		addr->sin_family = AF_INET;
-		mask->sin_addr.s_addr =
-		    htonl(mlen ? ~((1 << (32 - mlen)) - 1) : 0);
-		a4 = *((in_addr_t *)tei->paddr);
-		addr->sin_addr.s_addr = a4 & mask->sin_addr.s_addr;
-		if (mlen != 32)
-			*set_mask = 1;
-		else
-			*set_mask = 0;
-#endif
-#ifdef INET6
-	} else if (tei->subtype == AF_INET6) {
-		/* IPv6 case */
-		addr6 = (struct sa_in6 *)sa;
-		mask6 = (struct sa_in6 *)ma;
-		/* Set 'total' structure length */
-		KEY_LEN(*addr6) = KEY_LEN_INET6;
-		KEY_LEN(*mask6) = KEY_LEN_INET6;
-		addr6->sin6_family = AF_INET6;
-		ipv6_writemask(&mask6->sin6_addr, mlen);
-		memcpy(&addr6->sin6_addr, tei->paddr, sizeof(struct in6_addr));
-		APPLY_MASK(&addr6->sin6_addr, &mask6->sin6_addr);
-		if (mlen != 128)
-			*set_mask = 1;
-		else
-			*set_mask = 0;
-#endif
-	}
-}
-
-static int
-ta_prepare_add_radix(struct ip_fw_chain *ch, struct tentry_info *tei,
-    void *ta_buf)
-{
-	struct ta_buf_radix *tb;
-	struct radix_addr_entry *ent;
-#ifdef INET6
-	struct radix_addr_xentry *xent;
-#endif
-	struct sockaddr *addr, *mask;
-	int mlen, set_mask;
-
-	tb = (struct ta_buf_radix *)ta_buf;
-
-	mlen = tei->masklen;
-	set_mask = 0;
-	
-	if (tei->subtype == AF_INET) {
-#ifdef INET
-		if (mlen > 32)
-			return (EINVAL);
-		ent = malloc(sizeof(*ent), M_IPFW_TBL, M_WAITOK | M_ZERO);
-		ent->masklen = mlen;
-
-		addr = (struct sockaddr *)&ent->addr;
-		mask = (struct sockaddr *)&tb->addr.a4.ma;
-		tb->ent_ptr = ent;
-#endif
-#ifdef INET6
-	} else if (tei->subtype == AF_INET6) {
-		/* IPv6 case */
-		if (mlen > 128)
-			return (EINVAL);
-		xent = malloc(sizeof(*xent), M_IPFW_TBL, M_WAITOK | M_ZERO);
-		xent->masklen = mlen;
-
-		addr = (struct sockaddr *)&xent->addr6;
-		mask = (struct sockaddr *)&tb->addr.a6.ma;
-		tb->ent_ptr = xent;
-#endif
-	} else {
-		/* Unknown CIDR type */
-		return (EINVAL);
-	}
-
-	tei_to_sockaddr_ent(tei, addr, mask, &set_mask);
-	/* Set pointers */
-	tb->addr_ptr = addr;
-	if (set_mask != 0)
-		tb->mask_ptr = mask;
-
-	return (0);
-}
-
-static int
-ta_add_radix(void *ta_state, struct table_info *ti, struct tentry_info *tei,
-    void *ta_buf, uint32_t *pnum)
-{
-	struct radix_cfg *cfg;
-	struct radix_node_head *rnh;
-	struct radix_node *rn;
-	struct ta_buf_radix *tb;
-	uint32_t *old_value, value;
-
-	cfg = (struct radix_cfg *)ta_state;
-	tb = (struct ta_buf_radix *)ta_buf;
-
-	/* Save current entry value from @tei */
-	if (tei->subtype == AF_INET) {
-		rnh = ti->state;
-		((struct radix_addr_entry *)tb->ent_ptr)->value = tei->value;
-	} else {
-		rnh = ti->xstate;
-		((struct radix_addr_xentry *)tb->ent_ptr)->value = tei->value;
-	}
-
-	/* Search for an entry first */
-	rn = rnh->rnh_lookup(tb->addr_ptr, tb->mask_ptr, &rnh->rh);
-	if (rn != NULL) {
-		if ((tei->flags & TEI_FLAGS_UPDATE) == 0)
-			return (EEXIST);
-		/* Record already exists. Update value if we're asked to */
-		if (tei->subtype == AF_INET)
-			old_value = &((struct radix_addr_entry *)rn)->value;
-		else
-			old_value = &((struct radix_addr_xentry *)rn)->value;
-
-		value = *old_value;
-		*old_value = tei->value;
-		tei->value = value;
-
-		/* Indicate that update has happened instead of addition */
-		tei->flags |= TEI_FLAGS_UPDATED;
-		*pnum = 0;
-
-		return (0);
-	}
-
-	if ((tei->flags & TEI_FLAGS_DONTADD) != 0)
-		return (EFBIG);
-
-	rn = rnh->rnh_addaddr(tb->addr_ptr, tb->mask_ptr, &rnh->rh,tb->ent_ptr);
-	if (rn == NULL) {
-		/* Unknown error */
-		return (EINVAL);
-	}
-	
-	if (tei->subtype == AF_INET)
-		cfg->count4++;
-	else
-		cfg->count6++;
-	tb->ent_ptr = NULL;
-	*pnum = 1;
-
-	return (0);
-}
-
-static int
-ta_prepare_del_radix(struct ip_fw_chain *ch, struct tentry_info *tei,
-    void *ta_buf)
-{
-	struct ta_buf_radix *tb;
-	struct sockaddr *addr, *mask;
-	int mlen, set_mask;
-
-	tb = (struct ta_buf_radix *)ta_buf;
-
-	mlen = tei->masklen;
-	set_mask = 0;
-
-	if (tei->subtype == AF_INET) {
-		if (mlen > 32)
-			return (EINVAL);
-
-		addr = (struct sockaddr *)&tb->addr.a4.sa;
-		mask = (struct sockaddr *)&tb->addr.a4.ma;
-#ifdef INET6
-	} else if (tei->subtype == AF_INET6) {
-		if (mlen > 128)
-			return (EINVAL);
-
-		addr = (struct sockaddr *)&tb->addr.a6.sa;
-		mask = (struct sockaddr *)&tb->addr.a6.ma;
-#endif
-	} else
-		return (EINVAL);
-
-	tei_to_sockaddr_ent(tei, addr, mask, &set_mask);
-	tb->addr_ptr = addr;
-	if (set_mask != 0)
-		tb->mask_ptr = mask;
-
-	return (0);
-}
-
-static int
-ta_del_radix(void *ta_state, struct table_info *ti, struct tentry_info *tei,
-    void *ta_buf, uint32_t *pnum)
-{
-	struct radix_cfg *cfg;
-	struct radix_node_head *rnh;
-	struct radix_node *rn;
-	struct ta_buf_radix *tb;
-
-	cfg = (struct radix_cfg *)ta_state;
-	tb = (struct ta_buf_radix *)ta_buf;
-
-	if (tei->subtype == AF_INET)
-		rnh = ti->state;
-	else
-		rnh = ti->xstate;
-
-	rn = rnh->rnh_deladdr(tb->addr_ptr, tb->mask_ptr, &rnh->rh);
-
-	if (rn == NULL)
-		return (ENOENT);
-
-	/* Save entry value to @tei */
-	if (tei->subtype == AF_INET)
-		tei->value = ((struct radix_addr_entry *)rn)->value;
-	else
-		tei->value = ((struct radix_addr_xentry *)rn)->value;
-
-	tb->ent_ptr = rn;
-	
-	if (tei->subtype == AF_INET)
-		cfg->count4--;
-	else
-		cfg->count6--;
-	*pnum = 1;
-
-	return (0);
-}
-
-static void
-ta_flush_radix_entry(struct ip_fw_chain *ch, struct tentry_info *tei,
-    void *ta_buf)
-{
-	struct ta_buf_radix *tb;
-
-	tb = (struct ta_buf_radix *)ta_buf;
-
-	if (tb->ent_ptr != NULL)
-		free(tb->ent_ptr, M_IPFW_TBL);
-}
-
-static int
-ta_need_modify_radix(void *ta_state, struct table_info *ti, uint32_t count,
-    uint64_t *pflags)
-{
-
-	/*
-	 * radix does not require additional memory allocations
-	 * other than nodes itself. Adding new masks to the tree do
-	 * but we don't have any API to call (and we don't known which
-	 * sizes do we need).
-	 */
-	return (0);
-}
-
-struct table_algo addr_radix = {
-	.name		= "addr:radix",
-	.type		= IPFW_TABLE_ADDR,
-	.flags		= TA_FLAG_DEFAULT,
-	.ta_buf_size	= sizeof(struct ta_buf_radix),
-	.init		= ta_init_radix,
-	.destroy	= ta_destroy_radix,
-	.prepare_add	= ta_prepare_add_radix,
-	.prepare_del	= ta_prepare_del_radix,
-	.add		= ta_add_radix,
-	.del		= ta_del_radix,
-	.flush_entry	= ta_flush_radix_entry,
-	.foreach	= ta_foreach_radix,
-	.dump_tentry	= ta_dump_radix_tentry,
-	.find_tentry	= ta_find_radix_tentry,
-	.dump_tinfo	= ta_dump_radix_tinfo,
-	.need_modify	= ta_need_modify_radix,
-};
-
-
-/*
- * addr:hash cmds
- *
- *
- * ti->data:
- * [inv.mask4][inv.mask6][log2hsize4][log2hsize6]
- * [        8][        8[          8][         8]
- *
- * inv.mask4: 32 - mask
- * inv.mask6:
- * 1) _slow lookup: mask
- * 2) _aligned: (128 - mask) / 8
- * 3) _64: 8
- *
- *
- * pflags:
- * [v4=1/v6=0][hsize]
- * [       32][   32]
- */
-
-struct chashentry;
-
-SLIST_HEAD(chashbhead, chashentry);
-
-struct chash_cfg {
-	struct chashbhead *head4;
-	struct chashbhead *head6;
-	size_t	size4;
-	size_t	size6;
-	size_t	items4;
-	size_t	items6;
-	uint8_t	mask4;
-	uint8_t	mask6;
-};
-
-struct chashentry {
-	SLIST_ENTRY(chashentry)	next;
-	uint32_t	value;
-	uint32_t	type;
-	union {
-		uint32_t	a4;	/* Host format */
-		struct in6_addr	a6;	/* Network format */
-	} a;
-};
-
-struct ta_buf_chash
-{
-	void *ent_ptr;
-	struct chashentry ent;
-};
-
-#ifdef INET
-static __inline uint32_t hash_ip(uint32_t addr, int hsize);
-#endif
-#ifdef INET6
-static __inline uint32_t hash_ip6(struct in6_addr *addr6, int hsize);
-static __inline uint16_t hash_ip64(struct in6_addr *addr6, int hsize);
-static __inline uint32_t hash_ip6_slow(struct in6_addr *addr6, void *key,
-    int mask, int hsize);
-static __inline uint32_t hash_ip6_al(struct in6_addr *addr6, void *key, int mask,
-    int hsize);
-#endif
-static int ta_lookup_chash_slow(struct table_info *ti, void *key, uint32_t keylen,
-    uint32_t *val);
-static int ta_lookup_chash_aligned(struct table_info *ti, void *key,
-    uint32_t keylen, uint32_t *val);
-static int ta_lookup_chash_64(struct table_info *ti, void *key, uint32_t keylen,
-    uint32_t *val);
-static int chash_parse_opts(struct chash_cfg *cfg, char *data);
-static void ta_print_chash_config(void *ta_state, struct table_info *ti,
-    char *buf, size_t bufsize);
-static int ta_log2(uint32_t v);
-static int ta_init_chash(struct ip_fw_chain *ch, void **ta_state,
-    struct table_info *ti, char *data, uint8_t tflags);
-static void ta_destroy_chash(void *ta_state, struct table_info *ti);
-static void ta_dump_chash_tinfo(void *ta_state, struct table_info *ti,
-    ipfw_ta_tinfo *tinfo);
-static int ta_dump_chash_tentry(void *ta_state, struct table_info *ti,
-    void *e, ipfw_obj_tentry *tent);
-static uint32_t hash_ent(struct chashentry *ent, int af, int mlen,
-    uint32_t size);
-static int tei_to_chash_ent(struct tentry_info *tei, struct chashentry *ent);
-static int ta_find_chash_tentry(void *ta_state, struct table_info *ti,
-    ipfw_obj_tentry *tent);
-static void ta_foreach_chash(void *ta_state, struct table_info *ti,
-    ta_foreach_f *f, void *arg);
-static int ta_prepare_add_chash(struct ip_fw_chain *ch, struct tentry_info *tei,
-    void *ta_buf);
-static int ta_add_chash(void *ta_state, struct table_info *ti,
-    struct tentry_info *tei, void *ta_buf, uint32_t *pnum);
-static int ta_prepare_del_chash(struct ip_fw_chain *ch, struct tentry_info *tei,
-    void *ta_buf);
-static int ta_del_chash(void *ta_state, struct table_info *ti,
-    struct tentry_info *tei, void *ta_buf, uint32_t *pnum);
-static void ta_flush_chash_entry(struct ip_fw_chain *ch, struct tentry_info *tei,
-    void *ta_buf);
-static int ta_need_modify_chash(void *ta_state, struct table_info *ti,
-    uint32_t count, uint64_t *pflags);
-static int ta_prepare_mod_chash(void *ta_buf, uint64_t *pflags);
-static int ta_fill_mod_chash(void *ta_state, struct table_info *ti, void *ta_buf,
-    uint64_t *pflags);
-static void ta_modify_chash(void *ta_state, struct table_info *ti, void *ta_buf,
-    uint64_t pflags);
-static void ta_flush_mod_chash(void *ta_buf);
-
-
-#ifdef INET
-static __inline uint32_t
-hash_ip(uint32_t addr, int hsize)
-{
-
-	return (addr % (hsize - 1));
-}
-#endif
-
-#ifdef INET6
-static __inline uint32_t
-hash_ip6(struct in6_addr *addr6, int hsize)
-{
-	uint32_t i;
-
-	i = addr6->s6_addr32[0] ^ addr6->s6_addr32[1] ^
-	    addr6->s6_addr32[2] ^ addr6->s6_addr32[3];
-
-	return (i % (hsize - 1));
-}
-
-
-static __inline uint16_t
-hash_ip64(struct in6_addr *addr6, int hsize)
-{
-	uint32_t i;
-
-	i = addr6->s6_addr32[0] ^ addr6->s6_addr32[1];
-
-	return (i % (hsize - 1));
-}
-
-
-static __inline uint32_t
-hash_ip6_slow(struct in6_addr *addr6, void *key, int mask, int hsize)
-{
-	struct in6_addr mask6;
-
-	ipv6_writemask(&mask6, mask);
-	memcpy(addr6, key, sizeof(struct in6_addr));
-	APPLY_MASK(addr6, &mask6);
-	return (hash_ip6(addr6, hsize));
-}
-
-static __inline uint32_t
-hash_ip6_al(struct in6_addr *addr6, void *key, int mask, int hsize)
-{
-	uint64_t *paddr;
-
-	paddr = (uint64_t *)addr6;
-	*paddr = 0;
-	*(paddr + 1) = 0;
-	memcpy(addr6, key, mask);
-	return (hash_ip6(addr6, hsize));
-}
-#endif
-
-static int
-ta_lookup_chash_slow(struct table_info *ti, void *key, uint32_t keylen,
-    uint32_t *val)
-{
-	struct chashbhead *head;
-	struct chashentry *ent;
-	uint16_t hash, hsize;
-	uint8_t imask;
-
-	if (keylen == sizeof(in_addr_t)) {
-#ifdef INET
-		head = (struct chashbhead *)ti->state;
-		imask = ti->data >> 24;
-		hsize = 1 << ((ti->data & 0xFFFF) >> 8);
-		uint32_t a;
-		a = ntohl(*((in_addr_t *)key));
-		a = a >> imask;
-		hash = hash_ip(a, hsize);
-		SLIST_FOREACH(ent, &head[hash], next) {
-			if (ent->a.a4 == a) {
-				*val = ent->value;
-				return (1);
-			}
-		}
-#endif
-	} else {
-#ifdef INET6
-		/* IPv6: worst scenario: non-round mask */
-		struct in6_addr addr6;
-		head = (struct chashbhead *)ti->xstate;
-		imask = (ti->data & 0xFF0000) >> 16;
-		hsize = 1 << (ti->data & 0xFF);
-		hash = hash_ip6_slow(&addr6, key, imask, hsize);
-		SLIST_FOREACH(ent, &head[hash], next) {
-			if (memcmp(&ent->a.a6, &addr6, 16) == 0) {
-				*val = ent->value;
-				return (1);
-			}
-		}
-#endif
-	}
-
-	return (0);
-}
-
-static int
-ta_lookup_chash_aligned(struct table_info *ti, void *key, uint32_t keylen,
-    uint32_t *val)
-{
-	struct chashbhead *head;
-	struct chashentry *ent;
-	uint16_t hash, hsize;
-	uint8_t imask;
-
-	if (keylen == sizeof(in_addr_t)) {
-#ifdef INET
-		head = (struct chashbhead *)ti->state;
-		imask = ti->data >> 24;
-		hsize = 1 << ((ti->data & 0xFFFF) >> 8);
-		uint32_t a;
-		a = ntohl(*((in_addr_t *)key));
-		a = a >> imask;
-		hash = hash_ip(a, hsize);
-		SLIST_FOREACH(ent, &head[hash], next) {
-			if (ent->a.a4 == a) {
-				*val = ent->value;
-				return (1);
-			}
-		}
-#endif
-	} else {
-#ifdef INET6
-		/* IPv6: aligned to 8bit mask */
-		struct in6_addr addr6;
-		uint64_t *paddr, *ptmp;
-		head = (struct chashbhead *)ti->xstate;
-		imask = (ti->data & 0xFF0000) >> 16;
-		hsize = 1 << (ti->data & 0xFF);
-
-		hash = hash_ip6_al(&addr6, key, imask, hsize);
-		paddr = (uint64_t *)&addr6;
-		SLIST_FOREACH(ent, &head[hash], next) {
-			ptmp = (uint64_t *)&ent->a.a6;
-			if (paddr[0] == ptmp[0] && paddr[1] == ptmp[1]) {
-				*val = ent->value;
-				return (1);
-			}
-		}
-#endif
-	}
-
-	return (0);
-}
-
-static int
-ta_lookup_chash_64(struct table_info *ti, void *key, uint32_t keylen,
-    uint32_t *val)
-{
-	struct chashbhead *head;
-	struct chashentry *ent;
-	uint16_t hash, hsize;
-	uint8_t imask;
-
-	if (keylen == sizeof(in_addr_t)) {
-#ifdef INET
-		head = (struct chashbhead *)ti->state;
-		imask = ti->data >> 24;
-		hsize = 1 << ((ti->data & 0xFFFF) >> 8);
-		uint32_t a;
-		a = ntohl(*((in_addr_t *)key));
-		a = a >> imask;
-		hash = hash_ip(a, hsize);
-		SLIST_FOREACH(ent, &head[hash], next) {
-			if (ent->a.a4 == a) {
-				*val = ent->value;
-				return (1);
-			}
-		}
-#endif
-	} else {
-#ifdef INET6
-		/* IPv6: /64 */
-		uint64_t a6, *paddr;
-		head = (struct chashbhead *)ti->xstate;
-		paddr = (uint64_t *)key;
-		hsize = 1 << (ti->data & 0xFF);
-		a6 = *paddr;
-		hash = hash_ip64((struct in6_addr *)key, hsize);
-		SLIST_FOREACH(ent, &head[hash], next) {
-			paddr = (uint64_t *)&ent->a.a6;
-			if (a6 == *paddr) {
-				*val = ent->value;
-				return (1);
-			}
-		}
-#endif
-	}
-
-	return (0);
-}
-
-static int
-chash_parse_opts(struct chash_cfg *cfg, char *data)
-{
-	char *pdel, *pend, *s;
-	int mask4, mask6;
-
-	mask4 = cfg->mask4;
-	mask6 = cfg->mask6;
-
-	if (data == NULL)
-		return (0);
-	if ((pdel = strchr(data, ' ')) == NULL)
-		return (0);
-	while (*pdel == ' ')
-		pdel++;
-	if (strncmp(pdel, "masks=", 6) != 0)
-		return (EINVAL);
-	if ((s = strchr(pdel, ' ')) != NULL)
-		*s++ = '\0';
-
-	pdel += 6;
-	/* Need /XX[,/YY] */
-	if (*pdel++ != '/')
-		return (EINVAL);
-	mask4 = strtol(pdel, &pend, 10);
-	if (*pend == ',') {
-		/* ,/YY */
-		pdel = pend + 1;
-		if (*pdel++ != '/')
-			return (EINVAL);
-		mask6 = strtol(pdel, &pend, 10);
-		if (*pend != '\0')
-			return (EINVAL);
-	} else if (*pend != '\0')
-		return (EINVAL);
-
-	if (mask4 < 0 || mask4 > 32 || mask6 < 0 || mask6 > 128)
-		return (EINVAL);
-
-	cfg->mask4 = mask4;
-	cfg->mask6 = mask6;
-
-	return (0);
-}
-
-static void
-ta_print_chash_config(void *ta_state, struct table_info *ti, char *buf,
-    size_t bufsize)
-{
-	struct chash_cfg *cfg;
-
-	cfg = (struct chash_cfg *)ta_state;
-
-	if (cfg->mask4 != 32 || cfg->mask6 != 128)
-		snprintf(buf, bufsize, "%s masks=/%d,/%d", "addr:hash",
-		    cfg->mask4, cfg->mask6);
-	else
-		snprintf(buf, bufsize, "%s", "addr:hash");
-}
-
-static int
-ta_log2(uint32_t v)
-{
-	uint32_t r;
-
-	r = 0;
-	while (v >>= 1)
-		r++;
-
-	return (r);
-}
-
-/*
- * New table.
- * We assume 'data' to be either NULL or the following format:
- * 'addr:hash [masks=/32[,/128]]'
- */
-static int
-ta_init_chash(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti,
-    char *data, uint8_t tflags)
-{
-	int error, i;
-	uint32_t hsize;
-	struct chash_cfg *cfg;
-
-	cfg = malloc(sizeof(struct chash_cfg), M_IPFW, M_WAITOK | M_ZERO);
-
-	cfg->mask4 = 32;
-	cfg->mask6 = 128;
-
-	if ((error = chash_parse_opts(cfg, data)) != 0) {
-		free(cfg, M_IPFW);
-		return (error);
-	}
-
-	cfg->size4 = 128;
-	cfg->size6 = 128;
-
-	cfg->head4 = malloc(sizeof(struct chashbhead) * cfg->size4, M_IPFW,
-	    M_WAITOK | M_ZERO);
-	cfg->head6 = malloc(sizeof(struct chashbhead) * cfg->size6, M_IPFW,
-	    M_WAITOK | M_ZERO);
-	for (i = 0; i < cfg->size4; i++)
-		SLIST_INIT(&cfg->head4[i]);
-	for (i = 0; i < cfg->size6; i++)
-		SLIST_INIT(&cfg->head6[i]);
-
-
-	*ta_state = cfg;
-	ti->state = cfg->head4;
-	ti->xstate = cfg->head6;
-
-	/* Store data depending on v6 mask length */
-	hsize = ta_log2(cfg->size4) << 8 | ta_log2(cfg->size6);
-	if (cfg->mask6 == 64) {
-		ti->data = (32 - cfg->mask4) << 24 | (128 - cfg->mask6) << 16|
-		    hsize;
-		ti->lookup = ta_lookup_chash_64;
-	} else if ((cfg->mask6  % 8) == 0) {
-		ti->data = (32 - cfg->mask4) << 24 |
-		    cfg->mask6 << 13 | hsize;
-		ti->lookup = ta_lookup_chash_aligned;
-	} else {
-		/* don't do that! */
-		ti->data = (32 - cfg->mask4) << 24 |
-		    cfg->mask6 << 16 | hsize;
-		ti->lookup = ta_lookup_chash_slow;
-	}
-
-	return (0);
-}
-
-static void
-ta_destroy_chash(void *ta_state, struct table_info *ti)
-{
-	struct chash_cfg *cfg;
-	struct chashentry *ent, *ent_next;
-	int i;
-
-	cfg = (struct chash_cfg *)ta_state;
-
-	for (i = 0; i < cfg->size4; i++)
-		SLIST_FOREACH_SAFE(ent, &cfg->head4[i], next, ent_next)
-			free(ent, M_IPFW_TBL);
-
-	for (i = 0; i < cfg->size6; i++)
-		SLIST_FOREACH_SAFE(ent, &cfg->head6[i], next, ent_next)
-			free(ent, M_IPFW_TBL);
-
-	free(cfg->head4, M_IPFW);
-	free(cfg->head6, M_IPFW);
-
-	free(cfg, M_IPFW);
-}
-
-static void
-ta_dump_chash_tinfo(void *ta_state, struct table_info *ti, ipfw_ta_tinfo *tinfo)
-{
-	struct chash_cfg *cfg;
-
-	cfg = (struct chash_cfg *)ta_state;
-
-	tinfo->flags = IPFW_TATFLAGS_AFDATA | IPFW_TATFLAGS_AFITEM;
-	tinfo->taclass4 = IPFW_TACLASS_HASH;
-	tinfo->size4 = cfg->size4;
-	tinfo->count4 = cfg->items4;
-	tinfo->itemsize4 = sizeof(struct chashentry);
-	tinfo->taclass6 = IPFW_TACLASS_HASH;
-	tinfo->size6 = cfg->size6;
-	tinfo->count6 = cfg->items6;
-	tinfo->itemsize6 = sizeof(struct chashentry);
-}
-
-static int
-ta_dump_chash_tentry(void *ta_state, struct table_info *ti, void *e,
-    ipfw_obj_tentry *tent)
-{
-	struct chash_cfg *cfg;
-	struct chashentry *ent;
-
-	cfg = (struct chash_cfg *)ta_state;
-	ent = (struct chashentry *)e;
-
-	if (ent->type == AF_INET) {
-		tent->k.addr.s_addr = htonl(ent->a.a4 << (32 - cfg->mask4));
-		tent->masklen = cfg->mask4;
-		tent->subtype = AF_INET;
-		tent->v.kidx = ent->value;
-#ifdef INET6
-	} else {
-		memcpy(&tent->k, &ent->a.a6, sizeof(struct in6_addr));
-		tent->masklen = cfg->mask6;
-		tent->subtype = AF_INET6;
-		tent->v.kidx = ent->value;
-#endif
-	}
-
-	return (0);
-}
-
-static uint32_t
-hash_ent(struct chashentry *ent, int af, int mlen, uint32_t size)
-{
-	uint32_t hash;
-
-	hash = 0;
-
-	if (af == AF_INET) {
-#ifdef INET
-		hash = hash_ip(ent->a.a4, size);
-#endif
-	} else {
-#ifdef INET6
-		if (mlen == 64)
-			hash = hash_ip64(&ent->a.a6, size);
-		else
-			hash = hash_ip6(&ent->a.a6, size);
-#endif
-	}
-
-	return (hash);
-}
-
-static int
-tei_to_chash_ent(struct tentry_info *tei, struct chashentry *ent)
-{
-	int mlen;
-#ifdef INET6
-	struct in6_addr mask6;
-#endif
-
-
-	mlen = tei->masklen;
-	
-	if (tei->subtype == AF_INET) {
-#ifdef INET
-		if (mlen > 32)
-			return (EINVAL);
-		ent->type = AF_INET;
-
-		/* Calculate masked address */
-		ent->a.a4 = ntohl(*((in_addr_t *)tei->paddr)) >> (32 - mlen);
-#endif
-#ifdef INET6
-	} else if (tei->subtype == AF_INET6) {
-		/* IPv6 case */
-		if (mlen > 128)
-			return (EINVAL);
-		ent->type = AF_INET6;
-
-		ipv6_writemask(&mask6, mlen);
-		memcpy(&ent->a.a6, tei->paddr, sizeof(struct in6_addr));
-		APPLY_MASK(&ent->a.a6, &mask6);
-#endif
-	} else {
-		/* Unknown CIDR type */
-		return (EINVAL);
-	}
-
-	return (0);
-}
-
-static int
-ta_find_chash_tentry(void *ta_state, struct table_info *ti,
-    ipfw_obj_tentry *tent)
-{
-	struct chash_cfg *cfg;
-	struct chashbhead *head;
-	struct chashentry ent, *tmp;
-	struct tentry_info tei;
-	int error;
-	uint32_t hash;
-
-	cfg = (struct chash_cfg *)ta_state;
-
-	memset(&ent, 0, sizeof(ent));
-	memset(&tei, 0, sizeof(tei));
-
-	if (tent->subtype == AF_INET) {
-		tei.paddr = &tent->k.addr;
-		tei.masklen = cfg->mask4;
-		tei.subtype = AF_INET;
-
-		if ((error = tei_to_chash_ent(&tei, &ent)) != 0)
-			return (error);
-
-		head = cfg->head4;
-		hash = hash_ent(&ent, AF_INET, cfg->mask4, cfg->size4);
-		/* Check for existence */
-		SLIST_FOREACH(tmp, &head[hash], next) {
-			if (tmp->a.a4 != ent.a.a4)
-				continue;
-
-			ta_dump_chash_tentry(ta_state, ti, tmp, tent);
-			return (0);
-		}
-	} else {
-		tei.paddr = &tent->k.addr6;
-		tei.masklen = cfg->mask6;
-		tei.subtype = AF_INET6;
-
-		if ((error = tei_to_chash_ent(&tei, &ent)) != 0)
-			return (error);
-
-		head = cfg->head6;
-		hash = hash_ent(&ent, AF_INET6, cfg->mask6, cfg->size6);
-		/* Check for existence */
-		SLIST_FOREACH(tmp, &head[hash], next) {
-			if (memcmp(&tmp->a.a6, &ent.a.a6, 16) != 0)
-				continue;
-			ta_dump_chash_tentry(ta_state, ti, tmp, tent);
-			return (0);
-		}
-	}
-
-	return (ENOENT);
-}
-
-static void
-ta_foreach_chash(void *ta_state, struct table_info *ti, ta_foreach_f *f,
-    void *arg)
-{
-	struct chash_cfg *cfg;
-	struct chashentry *ent, *ent_next;
-	int i;
-
-	cfg = (struct chash_cfg *)ta_state;
-
-	for (i = 0; i < cfg->size4; i++)
-		SLIST_FOREACH_SAFE(ent, &cfg->head4[i], next, ent_next)
-			f(ent, arg);
-
-	for (i = 0; i < cfg->size6; i++)
-		SLIST_FOREACH_SAFE(ent, &cfg->head6[i], next, ent_next)
-			f(ent, arg);
-}
-
-static int
-ta_prepare_add_chash(struct ip_fw_chain *ch, struct tentry_info *tei,
-    void *ta_buf)
-{
-	struct ta_buf_chash *tb;
-	struct chashentry *ent;
-	int error;
-
-	tb = (struct ta_buf_chash *)ta_buf;
-
-	ent = malloc(sizeof(*ent), M_IPFW_TBL, M_WAITOK | M_ZERO);
-
-	error = tei_to_chash_ent(tei, ent);
-	if (error != 0) {
-		free(ent, M_IPFW_TBL);
-		return (error);
-	}
-	tb->ent_ptr = ent;
-
-	return (0);
-}
-
-static int
-ta_add_chash(void *ta_state, struct table_info *ti, struct tentry_info *tei,
-    void *ta_buf, uint32_t *pnum)
-{
-	struct chash_cfg *cfg;
-	struct chashbhead *head;
-	struct chashentry *ent, *tmp;
-	struct ta_buf_chash *tb;
-	int exists;
-	uint32_t hash, value;
-
-	cfg = (struct chash_cfg *)ta_state;
-	tb = (struct ta_buf_chash *)ta_buf;
-	ent = (struct chashentry *)tb->ent_ptr;
-	hash = 0;
-	exists = 0;
-
-	/* Read current value from @tei */
-	ent->value = tei->value;
-
-	/* Read cuurrent value */
-	if (tei->subtype == AF_INET) {
-		if (tei->masklen != cfg->mask4)
-			return (EINVAL);
-		head = cfg->head4;
-		hash = hash_ent(ent, AF_INET, cfg->mask4, cfg->size4);
-
-		/* Check for existence */
-		SLIST_FOREACH(tmp, &head[hash], next) {
-			if (tmp->a.a4 == ent->a.a4) {
-				exists = 1;
-				break;
-			}
-		}
-	} else {
-		if (tei->masklen != cfg->mask6)
-			return (EINVAL);
-		head = cfg->head6;
-		hash = hash_ent(ent, AF_INET6, cfg->mask6, cfg->size6);
-		/* Check for existence */
-		SLIST_FOREACH(tmp, &head[hash], next) {
-			if (memcmp(&tmp->a.a6, &ent->a.a6, 16) == 0) {
-				exists = 1;
-				break;
-			}
-		}
-	}
-
-	if (exists == 1) {
-		if ((tei->flags & TEI_FLAGS_UPDATE) == 0)
-			return (EEXIST);
-		/* Record already exists. Update value if we're asked to */
-		value = tmp->value;
-		tmp->value = tei->value;
-		tei->value = value;
-		/* Indicate that update has happened instead of addition */
-		tei->flags |= TEI_FLAGS_UPDATED;
-		*pnum = 0;
-	} else {
-		if ((tei->flags & TEI_FLAGS_DONTADD) != 0)
-			return (EFBIG);
-		SLIST_INSERT_HEAD(&head[hash], ent, next);
-		tb->ent_ptr = NULL;
-		*pnum = 1;
-
-		/* Update counters */
-		if (tei->subtype == AF_INET)
-			cfg->items4++;
-		else
-			cfg->items6++;
-	}
-
-	return (0);
-}
-
-static int
-ta_prepare_del_chash(struct ip_fw_chain *ch, struct tentry_info *tei,
-    void *ta_buf)
-{
-	struct ta_buf_chash *tb;
-
-	tb = (struct ta_buf_chash *)ta_buf;
-
-	return (tei_to_chash_ent(tei, &tb->ent));
-}
-
-static int
-ta_del_chash(void *ta_state, struct table_info *ti, struct tentry_info *tei,
-    void *ta_buf, uint32_t *pnum)
-{
-	struct chash_cfg *cfg;
-	struct chashbhead *head;
-	struct chashentry *tmp, *tmp_next, *ent;
-	struct ta_buf_chash *tb;
-	uint32_t hash;
-
-	cfg = (struct chash_cfg *)ta_state;
-	tb = (struct ta_buf_chash *)ta_buf;
-	ent = &tb->ent;
-
-	if (tei->subtype == AF_INET) {
-		if (tei->masklen != cfg->mask4)
-			return (EINVAL);
-		head = cfg->head4;
-		hash = hash_ent(ent, AF_INET, cfg->mask4, cfg->size4);
-
-		SLIST_FOREACH_SAFE(tmp, &head[hash], next, tmp_next) {
-			if (tmp->a.a4 != ent->a.a4)
-				continue;
-
-			SLIST_REMOVE(&head[hash], tmp, chashentry, next);
-			cfg->items4--;
-			tb->ent_ptr = tmp;
-			tei->value = tmp->value;
-			*pnum = 1;
-			return (0);
-		}
-	} else {
-		if (tei->masklen != cfg->mask6)
-			return (EINVAL);
-		head = cfg->head6;
-		hash = hash_ent(ent, AF_INET6, cfg->mask6, cfg->size6);
-		SLIST_FOREACH_SAFE(tmp, &head[hash], next, tmp_next) {
-			if (memcmp(&tmp->a.a6, &ent->a.a6, 16) != 0)
-				continue;
-
-			SLIST_REMOVE(&head[hash], tmp, chashentry, next);
-			cfg->items6--;
-			tb->ent_ptr = tmp;
-			tei->value = tmp->value;
-			*pnum = 1;
-			return (0);
-		}
-	}
-
-	return (ENOENT);
-}
-
-static void
-ta_flush_chash_entry(struct ip_fw_chain *ch, struct tentry_info *tei,
-    void *ta_buf)
-{
-	struct ta_buf_chash *tb;
-
-	tb = (struct ta_buf_chash *)ta_buf;
-
-	if (tb->ent_ptr != NULL)
-		free(tb->ent_ptr, M_IPFW_TBL);
-}
-
-/*
- * Hash growing callbacks.
- */
-
-static int
-ta_need_modify_chash(void *ta_state, struct table_info *ti, uint32_t count,
-    uint64_t *pflags)
-{
-	struct chash_cfg *cfg;
-	uint64_t data;
-
-	/*
-	 * Since we don't know exact number of IPv4/IPv6 records in @count,
-	 * ignore non-zero @count value at all. Check current hash sizes
-	 * and return appropriate data.
-	 */
-
-	cfg = (struct chash_cfg *)ta_state;
-
-	data = 0;
-	if (cfg->items4 > cfg->size4 && cfg->size4 < 65536)
-		data |= (cfg->size4 * 2) << 16;
-	if (cfg->items6 > cfg->size6 && cfg->size6 < 65536)
-		data |= cfg->size6 * 2;
-
-	if (data != 0) {
-		*pflags = data;
-		return (1);
-	}
-
-	return (0);
-}
-
-/*
- * Allocate new, larger chash.
- */
-static int
-ta_prepare_mod_chash(void *ta_buf, uint64_t *pflags)
-{
-	struct mod_item *mi;
-	struct chashbhead *head;
-	int i;
-
-	mi = (struct mod_item *)ta_buf;
-
-	memset(mi, 0, sizeof(struct mod_item));
-	mi->size = (*pflags >> 16) & 0xFFFF;
-	mi->size6 = *pflags & 0xFFFF;
-	if (mi->size > 0) {
-		head = malloc(sizeof(struct chashbhead) * mi->size,
-		    M_IPFW, M_WAITOK | M_ZERO);
-		for (i = 0; i < mi->size; i++)
-			SLIST_INIT(&head[i]);
-		mi->main_ptr = head;
-	}
-
-	if (mi->size6 > 0) {
-		head = malloc(sizeof(struct chashbhead) * mi->size6,
-		    M_IPFW, M_WAITOK | M_ZERO);
-		for (i = 0; i < mi->size6; i++)
-			SLIST_INIT(&head[i]);
-		mi->main_ptr6 = head;
-	}
-
-	return (0);
-}
-
-/*
- * Copy data from old runtime array to new one.
- */
-static int
-ta_fill_mod_chash(void *ta_state, struct table_info *ti, void *ta_buf,
-    uint64_t *pflags)
-{
-
-	/* In is not possible to do rehash if we're not holidng WLOCK. */
-	return (0);
-}
-
-/*
- * Switch old & new arrays.
- */
-static void
-ta_modify_chash(void *ta_state, struct table_info *ti, void *ta_buf,
-    uint64_t pflags)
-{
-	struct mod_item *mi;
-	struct chash_cfg *cfg;
-	struct chashbhead *old_head, *new_head;
-	struct chashentry *ent, *ent_next;
-	int af, i, mlen;
-	uint32_t nhash;
-	size_t old_size, new_size;
-
-	mi = (struct mod_item *)ta_buf;
-	cfg = (struct chash_cfg *)ta_state;
-
-	/* Check which hash we need to grow and do we still need that */
-	if (mi->size > 0 && cfg->size4 < mi->size) {
-		new_head = (struct chashbhead *)mi->main_ptr;
-		new_size = mi->size;
-		old_size = cfg->size4;
-		old_head = ti->state;
-		mlen = cfg->mask4;
-		af = AF_INET;
-
-		for (i = 0; i < old_size; i++) {
-			SLIST_FOREACH_SAFE(ent, &old_head[i], next, ent_next) {
-				nhash = hash_ent(ent, af, mlen, new_size);
-				SLIST_INSERT_HEAD(&new_head[nhash], ent, next);
-			}
-		}
-
-		ti->state = new_head;
-		cfg->head4 = new_head;
-		cfg->size4 = mi->size;
-		mi->main_ptr = old_head;
-	}
-
-	if (mi->size6 > 0 && cfg->size6 < mi->size6) {
-		new_head = (struct chashbhead *)mi->main_ptr6;
-		new_size = mi->size6;
-		old_size = cfg->size6;
-		old_head = ti->xstate;
-		mlen = cfg->mask6;
-		af = AF_INET6;
-
-		for (i = 0; i < old_size; i++) {
-			SLIST_FOREACH_SAFE(ent, &old_head[i], next, ent_next) {
-				nhash = hash_ent(ent, af, mlen, new_size);
-				SLIST_INSERT_HEAD(&new_head[nhash], ent, next);
-			}
-		}
-
-		ti->xstate = new_head;
-		cfg->head6 = new_head;
-		cfg->size6 = mi->size6;
-		mi->main_ptr6 = old_head;
-	}
-
-	/* Update lower 32 bits with new values */
-	ti->data &= 0xFFFFFFFF00000000;
-	ti->data |= ta_log2(cfg->size4) << 8 | ta_log2(cfg->size6);
-}
-
-/*
- * Free unneded array.
- */
-static void
-ta_flush_mod_chash(void *ta_buf)
-{
-	struct mod_item *mi;
-
-	mi = (struct mod_item *)ta_buf;
-	if (mi->main_ptr != NULL)
-		free(mi->main_ptr, M_IPFW);
-	if (mi->main_ptr6 != NULL)
-		free(mi->main_ptr6, M_IPFW);
-}
-
-struct table_algo addr_hash = {
-	.name		= "addr:hash",
-	.type		= IPFW_TABLE_ADDR,
-	.ta_buf_size	= sizeof(struct ta_buf_chash),
-	.init		= ta_init_chash,
-	.destroy	= ta_destroy_chash,
-	.prepare_add	= ta_prepare_add_chash,
-	.prepare_del	= ta_prepare_del_chash,
-	.add		= ta_add_chash,
-	.del		= ta_del_chash,
-	.flush_entry	= ta_flush_chash_entry,
-	.foreach	= ta_foreach_chash,
-	.dump_tentry	= ta_dump_chash_tentry,
-	.find_tentry	= ta_find_chash_tentry,
-	.print_config	= ta_print_chash_config,
-	.dump_tinfo	= ta_dump_chash_tinfo,
-	.need_modify	= ta_need_modify_chash,
-	.prepare_mod	= ta_prepare_mod_chash,
-	.fill_mod	= ta_fill_mod_chash,
-	.modify		= ta_modify_chash,
-	.flush_mod	= ta_flush_mod_chash,
-};
-
-
-/*
- * Iface table cmds.
- *
- * Implementation:
- *
- * Runtime part:
- * - sorted array of "struct ifidx" pointed by ti->state.
- *   Array is allocated with rounding up to IFIDX_CHUNK. Only existing
- *   interfaces are stored in array, however its allocated size is
- *   sufficient to hold all table records if needed.
- * - current array size is stored in ti->data
- *
- * Table data:
- * - "struct iftable_cfg" is allocated to store table state (ta_state).
- * - All table records are stored inside namedobj instance.
- *
- */
-
-struct ifidx {
-	uint16_t	kidx;
-	uint16_t	spare;
-	uint32_t	value;
-};
-#define	DEFAULT_IFIDX_SIZE	64
-
-struct iftable_cfg;
-
-struct ifentry {
-	struct named_object	no;
-	struct ipfw_ifc		ic;
-	struct iftable_cfg	*icfg;
-	uint32_t		value;
-	int			linked;
-};
-
-struct iftable_cfg {
-	struct namedobj_instance	*ii;
-	struct ip_fw_chain	*ch;
-	struct table_info	*ti;
-	void	*main_ptr;
-	size_t	size;	/* Number of items allocated in array */
-	size_t	count;	/* Number of all items */
-	size_t	used;	/* Number of items _active_ now */
-};
-
-struct ta_buf_ifidx
-{
-	struct ifentry *ife;
-	uint32_t value;
-};
-
-int compare_ifidx(const void *k, const void *v);
-static struct ifidx * ifidx_find(struct table_info *ti, void *key);
-static int ta_lookup_ifidx(struct table_info *ti, void *key, uint32_t keylen,
-    uint32_t *val);
-static int ta_init_ifidx(struct ip_fw_chain *ch, void **ta_state,
-    struct table_info *ti, char *data, uint8_t tflags);
-static void ta_change_ti_ifidx(void *ta_state, struct table_info *ti);
-static int destroy_ifidx_locked(struct namedobj_instance *ii,
-    struct named_object *no, void *arg);
-static void ta_destroy_ifidx(void *ta_state, struct table_info *ti);
-static void ta_dump_ifidx_tinfo(void *ta_state, struct table_info *ti,
-    ipfw_ta_tinfo *tinfo);
-static int ta_prepare_add_ifidx(struct ip_fw_chain *ch, struct tentry_info *tei,
-    void *ta_buf);
-static int ta_add_ifidx(void *ta_state, struct table_info *ti,
-    struct tentry_info *tei, void *ta_buf, uint32_t *pnum);
-static int ta_prepare_del_ifidx(struct ip_fw_chain *ch, struct tentry_info *tei,
-    void *ta_buf);
-static int ta_del_ifidx(void *ta_state, struct table_info *ti,
-    struct tentry_info *tei, void *ta_buf, uint32_t *pnum);
-static void ta_flush_ifidx_entry(struct ip_fw_chain *ch,
-    struct tentry_info *tei, void *ta_buf);
-static void if_notifier(struct ip_fw_chain *ch, void *cbdata, uint16_t ifindex);
-static int ta_need_modify_ifidx(void *ta_state, struct table_info *ti,
-    uint32_t count, uint64_t *pflags);
-static int ta_prepare_mod_ifidx(void *ta_buf, uint64_t *pflags);
-static int ta_fill_mod_ifidx(void *ta_state, struct table_info *ti,
-    void *ta_buf, uint64_t *pflags);
-static void ta_modify_ifidx(void *ta_state, struct table_info *ti, void *ta_buf,
-    uint64_t pflags);
-static void ta_flush_mod_ifidx(void *ta_buf);
-static int ta_dump_ifidx_tentry(void *ta_state, struct table_info *ti, void *e,
-    ipfw_obj_tentry *tent);
-static int ta_find_ifidx_tentry(void *ta_state, struct table_info *ti,
-    ipfw_obj_tentry *tent);
-static int foreach_ifidx(struct namedobj_instance *ii, struct named_object *no,
-    void *arg);
-static void ta_foreach_ifidx(void *ta_state, struct table_info *ti,
-    ta_foreach_f *f, void *arg);
-
-int
-compare_ifidx(const void *k, const void *v)
-{
-	const struct ifidx *ifidx;
-	uint16_t key;
-
-	key = *((const uint16_t *)k);
-	ifidx = (const struct ifidx *)v;
-
-	if (key < ifidx->kidx)
-		return (-1);
-	else if (key > ifidx->kidx)
-		return (1);
-
-	return (0);
-}
-
-/*
- * Adds item @item with key @key into ascending-sorted array @base.
- * Assumes @base has enough additional storage.
- *
- * Returns 1 on success, 0 on duplicate key.
- */
-static int
-badd(const void *key, void *item, void *base, size_t nmemb,
-    size_t size, int (*compar) (const void *, const void *))
-{
-	int min, max, mid, shift, res;
-	caddr_t paddr;
-
-	if (nmemb == 0) {
-		memcpy(base, item, size);
-		return (1);
-	}
-
-	/* Binary search */
-	min = 0;
-	max = nmemb - 1;
-	mid = 0;
-	while (min <= max) {
-		mid = (min + max) / 2;
-		res = compar(key, (const void *)((caddr_t)base + mid * size));
-		if (res == 0)
-			return (0);
-
-		if (res > 0)
-			min = mid + 1;
-		else
-			max = mid - 1;
-	}
-
-	/* Item not found. */
-	res = compar(key, (const void *)((caddr_t)base + mid * size));
-	if (res > 0)
-		shift = mid + 1;
-	else
-		shift = mid;
-
-	paddr = (caddr_t)base + shift * size;
-	if (nmemb > shift)
-		memmove(paddr + size, paddr, (nmemb - shift) * size);
-
-	memcpy(paddr, item, size);
-
-	return (1);
-}
-
-/*
- * Deletes item with key @key from ascending-sorted array @base.
- *
- * Returns 1 on success, 0 for non-existent key.
- */
-static int
-bdel(const void *key, void *base, size_t nmemb, size_t size,
-    int (*compar) (const void *, const void *))
-{
-	caddr_t item;
-	size_t sz;
-
-	item = (caddr_t)bsearch(key, base, nmemb, size, compar);
-
-	if (item == NULL)
-		return (0);
-
-	sz = (caddr_t)base + nmemb * size - item;
-
-	if (sz > 0)
-		memmove(item, item + size, sz);
-
-	return (1);
-}
-
-static struct ifidx *
-ifidx_find(struct table_info *ti, void *key)
-{
-	struct ifidx *ifi;
-
-	ifi = bsearch(key, ti->state, ti->data, sizeof(struct ifidx),
-	    compare_ifidx);
-
-	return (ifi);
-}
-
-static int
-ta_lookup_ifidx(struct table_info *ti, void *key, uint32_t keylen,
-    uint32_t *val)
-{
-	struct ifidx *ifi;
-
-	ifi = ifidx_find(ti, key);
-
-	if (ifi != NULL) {
-		*val = ifi->value;
-		return (1);
-	}
-
-	return (0);
-}
-
-static int
-ta_init_ifidx(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti,
-    char *data, uint8_t tflags)
-{
-	struct iftable_cfg *icfg;
-
-	icfg = malloc(sizeof(struct iftable_cfg), M_IPFW, M_WAITOK | M_ZERO);
-
-	icfg->ii = ipfw_objhash_create(DEFAULT_IFIDX_SIZE);
-	icfg->size = DEFAULT_IFIDX_SIZE;
-	icfg->main_ptr = malloc(sizeof(struct ifidx) * icfg->size, M_IPFW,
-	    M_WAITOK | M_ZERO);
-	icfg->ch = ch;
-
-	*ta_state = icfg;
-	ti->state = icfg->main_ptr;
-	ti->lookup = ta_lookup_ifidx;
-
-	return (0);
-}
-
-/*
- * Handle tableinfo @ti pointer change (on table array resize).
- */
-static void
-ta_change_ti_ifidx(void *ta_state, struct table_info *ti)
-{
-	struct iftable_cfg *icfg;
-
-	icfg = (struct iftable_cfg *)ta_state;
-	icfg->ti = ti;
-}
-
-static int
-destroy_ifidx_locked(struct namedobj_instance *ii, struct named_object *no,
-    void *arg)
-{
-	struct ifentry *ife;
-	struct ip_fw_chain *ch;
-
-	ch = (struct ip_fw_chain *)arg;
-	ife = (struct ifentry *)no;
-
-	ipfw_iface_del_notify(ch, &ife->ic);
-	ipfw_iface_unref(ch, &ife->ic);
-	free(ife, M_IPFW_TBL);
-	return (0);
-}
-
-
-/*
- * Destroys table @ti
- */
-static void
-ta_destroy_ifidx(void *ta_state, struct table_info *ti)
-{
-	struct iftable_cfg *icfg;
-	struct ip_fw_chain *ch;
-
-	icfg = (struct iftable_cfg *)ta_state;
-	ch = icfg->ch;
-
-	if (icfg->main_ptr != NULL)
-		free(icfg->main_ptr, M_IPFW);
-
-	IPFW_UH_WLOCK(ch);
-	ipfw_objhash_foreach(icfg->ii, destroy_ifidx_locked, ch);
-	IPFW_UH_WUNLOCK(ch);
-
-	ipfw_objhash_destroy(icfg->ii);
-
-	free(icfg, M_IPFW);
-}
-
-/*
- * Provide algo-specific table info
- */
-static void
-ta_dump_ifidx_tinfo(void *ta_state, struct table_info *ti, ipfw_ta_tinfo *tinfo)
-{
-	struct iftable_cfg *cfg;
-
-	cfg = (struct iftable_cfg *)ta_state;
-
-	tinfo->taclass4 = IPFW_TACLASS_ARRAY;
-	tinfo->size4 = cfg->size;
-	tinfo->count4 = cfg->used;
-	tinfo->itemsize4 = sizeof(struct ifidx);
-}
-
-/*
- * Prepare state to add to the table:
- * allocate ifentry and reference needed interface.
- */
-static int
-ta_prepare_add_ifidx(struct ip_fw_chain *ch, struct tentry_info *tei,
-    void *ta_buf)
-{
-	struct ta_buf_ifidx *tb;
-	char *ifname;
-	struct ifentry *ife;
-
-	tb = (struct ta_buf_ifidx *)ta_buf;
-
-	/* Check if string is terminated */
-	ifname = (char *)tei->paddr;
-	if (strnlen(ifname, IF_NAMESIZE) == IF_NAMESIZE)
-		return (EINVAL);
-
-	ife = malloc(sizeof(struct ifentry), M_IPFW_TBL, M_WAITOK | M_ZERO);
-	ife->ic.cb = if_notifier;
-	ife->ic.cbdata = ife;
-
-	if (ipfw_iface_ref(ch, ifname, &ife->ic) != 0) {
-		free(ife, M_IPFW_TBL);
-		return (EINVAL);
-	}
-
-	/* Use ipfw_iface 'ifname' field as stable storage */
-	ife->no.name = ife->ic.iface->ifname;
-
-	tb->ife = ife;
-
-	return (0);
-}
-
-static int
-ta_add_ifidx(void *ta_state, struct table_info *ti, struct tentry_info *tei,
-    void *ta_buf, uint32_t *pnum)
-{
-	struct iftable_cfg *icfg;
-	struct ifentry *ife, *tmp;
-	struct ta_buf_ifidx *tb;
-	struct ipfw_iface *iif;
-	struct ifidx *ifi;
-	char *ifname;
-	uint32_t value;
-
-	tb = (struct ta_buf_ifidx *)ta_buf;
-	ifname = (char *)tei->paddr;
-	icfg = (struct iftable_cfg *)ta_state;
-	ife = tb->ife;
-
-	ife->icfg = icfg;
-	ife->value = tei->value;
-
-	tmp = (struct ifentry *)ipfw_objhash_lookup_name(icfg->ii, 0, ifname);
-
-	if (tmp != NULL) {
-		if ((tei->flags & TEI_FLAGS_UPDATE) == 0)
-			return (EEXIST);
-
-		/* Exchange values in @tmp and @tei */
-		value = tmp->value;
-		tmp->value = tei->value;
-		tei->value = value;
-
-		iif = tmp->ic.iface;
-		if (iif->resolved != 0) {
-			/* We have to update runtime value, too */
-			ifi = ifidx_find(ti, &iif->ifindex);
-			ifi->value = ife->value;
-		}
-
-		/* Indicate that update has happened instead of addition */
-		tei->flags |= TEI_FLAGS_UPDATED;
-		*pnum = 0;
-		return (0);
-	}
-
-	if ((tei->flags & TEI_FLAGS_DONTADD) != 0)
-		return (EFBIG);
-
-	/* Link to internal list */
-	ipfw_objhash_add(icfg->ii, &ife->no);
-
-	/* Link notifier (possible running its callback) */
-	ipfw_iface_add_notify(icfg->ch, &ife->ic);
-	icfg->count++;
-
-	tb->ife = NULL;
-	*pnum = 1;
-
-	return (0);
-}
-
-/*
- * Prepare to delete key from table.
- * Do basic interface name checks.
- */
-static int
-ta_prepare_del_ifidx(struct ip_fw_chain *ch, struct tentry_info *tei,
-    void *ta_buf)
-{
-	struct ta_buf_ifidx *tb;
-	char *ifname;
-
-	tb = (struct ta_buf_ifidx *)ta_buf;
-
-	/* Check if string is terminated */
-	ifname = (char *)tei->paddr;
-	if (strnlen(ifname, IF_NAMESIZE) == IF_NAMESIZE)
-		return (EINVAL);
-
-	return (0);
-}
-
-/*
- * Remove key from both configuration list and
- * runtime array. Removed interface notification.
- */
-static int
-ta_del_ifidx(void *ta_state, struct table_info *ti, struct tentry_info *tei,
-    void *ta_buf, uint32_t *pnum)
-{
-	struct iftable_cfg *icfg;
-	struct ifentry *ife;
-	struct ta_buf_ifidx *tb;
-	char *ifname;
-	uint16_t ifindex;
-	int res;
-
-	tb = (struct ta_buf_ifidx *)ta_buf;
-	ifname = (char *)tei->paddr;
-	icfg = (struct iftable_cfg *)ta_state;
-	ife = tb->ife;
-
-	ife = (struct ifentry *)ipfw_objhash_lookup_name(icfg->ii, 0, ifname);
-
-	if (ife == NULL)
-		return (ENOENT);
-
-	if (ife->linked != 0) {
-		/* We have to remove item from runtime */
-		ifindex = ife->ic.iface->ifindex;
-
-		res = bdel(&ifindex, icfg->main_ptr, icfg->used,
-		    sizeof(struct ifidx), compare_ifidx);
-
-		KASSERT(res == 1, ("index %d does not exist", ifindex));
-		icfg->used--;
-		ti->data = icfg->used;
-		ife->linked = 0;
-	}
-
-	/* Unlink from local list */
-	ipfw_objhash_del(icfg->ii, &ife->no);
-	/* Unlink notifier and deref */
-	ipfw_iface_del_notify(icfg->ch, &ife->ic);
-	ipfw_iface_unref(icfg->ch, &ife->ic);
-
-	icfg->count--;
-	tei->value = ife->value;
-
-	tb->ife = ife;
-	*pnum = 1;
-
-	return (0);
-}
-
-/*
- * Flush deleted entry.
- * Drops interface reference and frees entry.
- */
-static void
-ta_flush_ifidx_entry(struct ip_fw_chain *ch, struct tentry_info *tei,
-    void *ta_buf)
-{
-	struct ta_buf_ifidx *tb;
-
-	tb = (struct ta_buf_ifidx *)ta_buf;
-
-	if (tb->ife != NULL)
-		free(tb->ife, M_IPFW_TBL);
-}
-
-
-/*
- * Handle interface announce/withdrawal for particular table.
- * Every real runtime array modification happens here.
- */
-static void
-if_notifier(struct ip_fw_chain *ch, void *cbdata, uint16_t ifindex)
-{
-	struct ifentry *ife;
-	struct ifidx ifi;
-	struct iftable_cfg *icfg;
-	struct table_info *ti;
-	int res;
-
-	ife = (struct ifentry *)cbdata;
-	icfg = ife->icfg;
-	ti = icfg->ti;
-
-	KASSERT(ti != NULL, ("ti=NULL, check change_ti handler"));
-
-	if (ife->linked == 0 && ifindex != 0) {
-		/* Interface announce */
-		ifi.kidx = ifindex;
-		ifi.spare = 0;
-		ifi.value = ife->value;
-		res = badd(&ifindex, &ifi, icfg->main_ptr, icfg->used,
-		    sizeof(struct ifidx), compare_ifidx);
-		KASSERT(res == 1, ("index %d already exists", ifindex));
-		icfg->used++;
-		ti->data = icfg->used;
-		ife->linked = 1;
-	} else if (ife->linked != 0 && ifindex == 0) {
-		/* Interface withdrawal */
-		ifindex = ife->ic.iface->ifindex;
-
-		res = bdel(&ifindex, icfg->main_ptr, icfg->used,
-		    sizeof(struct ifidx), compare_ifidx);
-
-		KASSERT(res == 1, ("index %d does not exist", ifindex));
-		icfg->used--;
-		ti->data = icfg->used;
-		ife->linked = 0;
-	}
-}
-
-
-/*
- * Table growing callbacks.
- */
-
-static int
-ta_need_modify_ifidx(void *ta_state, struct table_info *ti, uint32_t count,
-    uint64_t *pflags)
-{
-	struct iftable_cfg *cfg;
-	uint32_t size;
-
-	cfg = (struct iftable_cfg *)ta_state;
-
-	size = cfg->size;
-	while (size < cfg->count + count)
-		size *= 2;
-
-	if (size != cfg->size) {
-		*pflags = size;
-		return (1);
-	}
-
-	return (0);
-}
-
-/*
- * Allocate ned, larger runtime ifidx array.
- */
-static int
-ta_prepare_mod_ifidx(void *ta_buf, uint64_t *pflags)
-{
-	struct mod_item *mi;
-
-	mi = (struct mod_item *)ta_buf;
-
-	memset(mi, 0, sizeof(struct mod_item));
-	mi->size = *pflags;
-	mi->main_ptr = malloc(sizeof(struct ifidx) * mi->size, M_IPFW,
-	    M_WAITOK | M_ZERO);
-
-	return (0);
-}
-
-/*
- * Copy data from old runtime array to new one.
- */
-static int
-ta_fill_mod_ifidx(void *ta_state, struct table_info *ti, void *ta_buf,
-    uint64_t *pflags)
-{
-	struct mod_item *mi;
-	struct iftable_cfg *icfg;
-
-	mi = (struct mod_item *)ta_buf;
-	icfg = (struct iftable_cfg *)ta_state;
-
-	/* Check if we still need to grow array */
-	if (icfg->size >= mi->size) {
-		*pflags = 0;
-		return (0);
-	}
-
-	memcpy(mi->main_ptr, icfg->main_ptr, icfg->used * sizeof(struct ifidx));
-
-	return (0);
-}
-
-/*
- * Switch old & new arrays.
- */
-static void
-ta_modify_ifidx(void *ta_state, struct table_info *ti, void *ta_buf,
-    uint64_t pflags)
-{
-	struct mod_item *mi;
-	struct iftable_cfg *icfg;
-	void *old_ptr;
-
-	mi = (struct mod_item *)ta_buf;
-	icfg = (struct iftable_cfg *)ta_state;
-
-	old_ptr = icfg->main_ptr;
-	icfg->main_ptr = mi->main_ptr;
-	icfg->size = mi->size;
-	ti->state = icfg->main_ptr;
-
-	mi->main_ptr = old_ptr;
-}
-
-/*
- * Free unneded array.
- */
-static void
-ta_flush_mod_ifidx(void *ta_buf)
-{
-	struct mod_item *mi;
-
-	mi = (struct mod_item *)ta_buf;
-	if (mi->main_ptr != NULL)
-		free(mi->main_ptr, M_IPFW);
-}
-
-static int
-ta_dump_ifidx_tentry(void *ta_state, struct table_info *ti, void *e,
-    ipfw_obj_tentry *tent)
-{
-	struct ifentry *ife;
-
-	ife = (struct ifentry *)e;
-
-	tent->masklen = 8 * IF_NAMESIZE;
-	memcpy(&tent->k, ife->no.name, IF_NAMESIZE);
-	tent->v.kidx = ife->value;
-
-	return (0);
-}
-
-static int
-ta_find_ifidx_tentry(void *ta_state, struct table_info *ti,
-    ipfw_obj_tentry *tent)
-{
-	struct iftable_cfg *icfg;
-	struct ifentry *ife;
-	char *ifname;
-
-	icfg = (struct iftable_cfg *)ta_state;
-	ifname = tent->k.iface;
-
-	if (strnlen(ifname, IF_NAMESIZE) == IF_NAMESIZE)
-		return (EINVAL);
-
-	ife = (struct ifentry *)ipfw_objhash_lookup_name(icfg->ii, 0, ifname);
-
-	if (ife != NULL) {
-		ta_dump_ifidx_tentry(ta_state, ti, ife, tent);
-		return (0);
-	}
-
-	return (ENOENT);
-}
-
-struct wa_ifidx {
-	ta_foreach_f	*f;
-	void		*arg;
-};
-
-static int
-foreach_ifidx(struct namedobj_instance *ii, struct named_object *no,
-    void *arg)
-{
-	struct ifentry *ife;
-	struct wa_ifidx *wa;
-
-	ife = (struct ifentry *)no;
-	wa = (struct wa_ifidx *)arg;
-
-	wa->f(ife, wa->arg);
-	return (0);
-}
-
-static void
-ta_foreach_ifidx(void *ta_state, struct table_info *ti, ta_foreach_f *f,
-    void *arg)
-{
-	struct iftable_cfg *icfg;
-	struct wa_ifidx wa;
-
-	icfg = (struct iftable_cfg *)ta_state;
-
-	wa.f = f;
-	wa.arg = arg;
-
-	ipfw_objhash_foreach(icfg->ii, foreach_ifidx, &wa);
-}
-
-struct table_algo iface_idx = {
-	.name		= "iface:array",
-	.type		= IPFW_TABLE_INTERFACE,
-	.flags		= TA_FLAG_DEFAULT,
-	.ta_buf_size	= sizeof(struct ta_buf_ifidx),
-	.init		= ta_init_ifidx,
-	.destroy	= ta_destroy_ifidx,
-	.prepare_add	= ta_prepare_add_ifidx,
-	.prepare_del	= ta_prepare_del_ifidx,
-	.add		= ta_add_ifidx,
-	.del		= ta_del_ifidx,
-	.flush_entry	= ta_flush_ifidx_entry,
-	.foreach	= ta_foreach_ifidx,
-	.dump_tentry	= ta_dump_ifidx_tentry,
-	.find_tentry	= ta_find_ifidx_tentry,
-	.dump_tinfo	= ta_dump_ifidx_tinfo,
-	.need_modify	= ta_need_modify_ifidx,
-	.prepare_mod	= ta_prepare_mod_ifidx,
-	.fill_mod	= ta_fill_mod_ifidx,
-	.modify		= ta_modify_ifidx,
-	.flush_mod	= ta_flush_mod_ifidx,
-	.change_ti	= ta_change_ti_ifidx,
-};
-
-/*
- * Number array cmds.
- *
- * Implementation:
- *
- * Runtime part:
- * - sorted array of "struct numarray" pointed by ti->state.
- *   Array is allocated with rounding up to NUMARRAY_CHUNK.
- * - current array size is stored in ti->data
- *
- */
-
-struct numarray {
-	uint32_t	number;
-	uint32_t	value;
-};
-
-struct numarray_cfg {
-	void	*main_ptr;
-	size_t	size;	/* Number of items allocated in array */
-	size_t	used;	/* Number of items _active_ now */
-};
-
-struct ta_buf_numarray
-{
-	struct numarray na;
-};
-
-int compare_numarray(const void *k, const void *v);
-static struct numarray *numarray_find(struct table_info *ti, void *key);
-static int ta_lookup_numarray(struct table_info *ti, void *key,
-    uint32_t keylen, uint32_t *val);
-static int ta_init_numarray(struct ip_fw_chain *ch, void **ta_state,
-    struct table_info *ti, char *data, uint8_t tflags);
-static void ta_destroy_numarray(void *ta_state, struct table_info *ti);
-static void ta_dump_numarray_tinfo(void *ta_state, struct table_info *ti,
-    ipfw_ta_tinfo *tinfo);
-static int ta_prepare_add_numarray(struct ip_fw_chain *ch,
-    struct tentry_info *tei, void *ta_buf);
-static int ta_add_numarray(void *ta_state, struct table_info *ti,
-    struct tentry_info *tei, void *ta_buf, uint32_t *pnum);
-static int ta_del_numarray(void *ta_state, struct table_info *ti,
-    struct tentry_info *tei, void *ta_buf, uint32_t *pnum);
-static void ta_flush_numarray_entry(struct ip_fw_chain *ch,
-    struct tentry_info *tei, void *ta_buf);
-static int ta_need_modify_numarray(void *ta_state, struct table_info *ti,
-    uint32_t count, uint64_t *pflags);
-static int ta_prepare_mod_numarray(void *ta_buf, uint64_t *pflags);
-static int ta_fill_mod_numarray(void *ta_state, struct table_info *ti,
-    void *ta_buf, uint64_t *pflags);
-static void ta_modify_numarray(void *ta_state, struct table_info *ti,
-    void *ta_buf, uint64_t pflags);
-static void ta_flush_mod_numarray(void *ta_buf);
-static int ta_dump_numarray_tentry(void *ta_state, struct table_info *ti,
-    void *e, ipfw_obj_tentry *tent);
-static int ta_find_numarray_tentry(void *ta_state, struct table_info *ti,
-    ipfw_obj_tentry *tent);
-static void ta_foreach_numarray(void *ta_state, struct table_info *ti,
-    ta_foreach_f *f, void *arg);
-
-int
-compare_numarray(const void *k, const void *v)
-{
-	const struct numarray *na;
-	uint32_t key;
-
-	key = *((const uint32_t *)k);
-	na = (const struct numarray *)v;
-
-	if (key < na->number)
-		return (-1);
-	else if (key > na->number)
-		return (1);
-
-	return (0);
-}
-
-static struct numarray *
-numarray_find(struct table_info *ti, void *key)
-{
-	struct numarray *ri;
-
-	ri = bsearch(key, ti->state, ti->data, sizeof(struct numarray),
-	    compare_ifidx);
-
-	return (ri);
-}
-
-static int
-ta_lookup_numarray(struct table_info *ti, void *key, uint32_t keylen,
-    uint32_t *val)
-{
-	struct numarray *ri;
-
-	ri = numarray_find(ti, key);
-
-	if (ri != NULL) {
-		*val = ri->value;
-		return (1);
-	}
-
-	return (0);
-}
-
-static int
-ta_init_numarray(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti,
-    char *data, uint8_t tflags)
-{
-	struct numarray_cfg *cfg;
-
-	cfg = malloc(sizeof(*cfg), M_IPFW, M_WAITOK | M_ZERO);
-
-	cfg->size = 16;
-	cfg->main_ptr = malloc(sizeof(struct numarray) * cfg->size, M_IPFW,
-	    M_WAITOK | M_ZERO);
-
-	*ta_state = cfg;
-	ti->state = cfg->main_ptr;
-	ti->lookup = ta_lookup_numarray;
-
-	return (0);
-}
-
-/*
- * Destroys table @ti
- */
-static void
-ta_destroy_numarray(void *ta_state, struct table_info *ti)
-{
-	struct numarray_cfg *cfg;
-
-	cfg = (struct numarray_cfg *)ta_state;
-
-	if (cfg->main_ptr != NULL)
-		free(cfg->main_ptr, M_IPFW);
-
-	free(cfg, M_IPFW);
-}
-
-/*
- * Provide algo-specific table info
- */
-static void
-ta_dump_numarray_tinfo(void *ta_state, struct table_info *ti, ipfw_ta_tinfo *tinfo)
-{
-	struct numarray_cfg *cfg;
-
-	cfg = (struct numarray_cfg *)ta_state;
-
-	tinfo->taclass4 = IPFW_TACLASS_ARRAY;
-	tinfo->size4 = cfg->size;
-	tinfo->count4 = cfg->used;
-	tinfo->itemsize4 = sizeof(struct numarray);
-}
-
-/*
- * Prepare for addition/deletion to an array.
- */
-static int
-ta_prepare_add_numarray(struct ip_fw_chain *ch, struct tentry_info *tei,
-    void *ta_buf)
-{
-	struct ta_buf_numarray *tb;
-
-	tb = (struct ta_buf_numarray *)ta_buf;
-
-	tb->na.number = *((uint32_t *)tei->paddr);
-
-	return (0);
-}
-
-static int
-ta_add_numarray(void *ta_state, struct table_info *ti, struct tentry_info *tei,
-    void *ta_buf, uint32_t *pnum)
-{
-	struct numarray_cfg *cfg;
-	struct ta_buf_numarray *tb;
-	struct numarray *ri;
-	int res;
-	uint32_t value;
-
-	tb = (struct ta_buf_numarray *)ta_buf;
-	cfg = (struct numarray_cfg *)ta_state;
-
-	/* Read current value from @tei */
-	tb->na.value = tei->value;
-
-	ri = numarray_find(ti, &tb->na.number);
-	
-	if (ri != NULL) {
-		if ((tei->flags & TEI_FLAGS_UPDATE) == 0)
-			return (EEXIST);
-
-		/* Exchange values between ri and @tei */
-		value = ri->value;
-		ri->value = tei->value;
-		tei->value = value;
-		/* Indicate that update has happened instead of addition */
-		tei->flags |= TEI_FLAGS_UPDATED;
-		*pnum = 0;
-		return (0);
-	}
-
-	if ((tei->flags & TEI_FLAGS_DONTADD) != 0)
-		return (EFBIG);
-
-	res = badd(&tb->na.number, &tb->na, cfg->main_ptr, cfg->used,
-	    sizeof(struct numarray), compare_numarray);
-
-	KASSERT(res == 1, ("number %d already exists", tb->na.number));
-	cfg->used++;
-	ti->data = cfg->used;
-	*pnum = 1;
-
-	return (0);
-}
-
-/*
- * Remove key from both configuration list and
- * runtime array. Removed interface notification.
- */
-static int
-ta_del_numarray(void *ta_state, struct table_info *ti, struct tentry_info *tei,
-    void *ta_buf, uint32_t *pnum)
-{
-	struct numarray_cfg *cfg;
-	struct ta_buf_numarray *tb;
-	struct numarray *ri;
-	int res;
-
-	tb = (struct ta_buf_numarray *)ta_buf;
-	cfg = (struct numarray_cfg *)ta_state;
-
-	ri = numarray_find(ti, &tb->na.number);
-	if (ri == NULL)
-		return (ENOENT);
-
-	tei->value = ri->value;
-	
-	res = bdel(&tb->na.number, cfg->main_ptr, cfg->used,
-	    sizeof(struct numarray), compare_numarray);
-
-	KASSERT(res == 1, ("number %u does not exist", tb->na.number));
-	cfg->used--;
-	ti->data = cfg->used;
-	*pnum = 1;
-
-	return (0);
-}
-
-static void
-ta_flush_numarray_entry(struct ip_fw_chain *ch, struct tentry_info *tei,
-    void *ta_buf)
-{
-
-	/* We don't have any state, do nothing */
-}
-
-
-/*
- * Table growing callbacks.
- */
-
-static int
-ta_need_modify_numarray(void *ta_state, struct table_info *ti, uint32_t count,
-    uint64_t *pflags)
-{
-	struct numarray_cfg *cfg;
-	size_t size;
-
-	cfg = (struct numarray_cfg *)ta_state;
-
-	size = cfg->size;
-	while (size < cfg->used + count)
-		size *= 2;
-
-	if (size != cfg->size) {
-		*pflags = size;
-		return (1);
-	}
-
-	return (0);
-}
-
-/*
- * Allocate new, larger runtime array.
- */
-static int
-ta_prepare_mod_numarray(void *ta_buf, uint64_t *pflags)
-{
-	struct mod_item *mi;
-
-	mi = (struct mod_item *)ta_buf;
-
-	memset(mi, 0, sizeof(struct mod_item));
-	mi->size = *pflags;
-	mi->main_ptr = malloc(sizeof(struct numarray) * mi->size, M_IPFW,
-	    M_WAITOK | M_ZERO);
-
-	return (0);
-}
-
-/*
- * Copy data from old runtime array to new one.
- */
-static int
-ta_fill_mod_numarray(void *ta_state, struct table_info *ti, void *ta_buf,
-    uint64_t *pflags)
-{
-	struct mod_item *mi;
-	struct numarray_cfg *cfg;
-
-	mi = (struct mod_item *)ta_buf;
-	cfg = (struct numarray_cfg *)ta_state;
-
-	/* Check if we still need to grow array */
-	if (cfg->size >= mi->size) {
-		*pflags = 0;
-		return (0);
-	}
-
-	memcpy(mi->main_ptr, cfg->main_ptr, cfg->used * sizeof(struct numarray));
-
-	return (0);
-}
-
-/*
- * Switch old & new arrays.
- */
-static void
-ta_modify_numarray(void *ta_state, struct table_info *ti, void *ta_buf,
-    uint64_t pflags)
-{
-	struct mod_item *mi;
-	struct numarray_cfg *cfg;
-	void *old_ptr;
-
-	mi = (struct mod_item *)ta_buf;
-	cfg = (struct numarray_cfg *)ta_state;
-
-	old_ptr = cfg->main_ptr;
-	cfg->main_ptr = mi->main_ptr;
-	cfg->size = mi->size;
-	ti->state = cfg->main_ptr;
-
-	mi->main_ptr = old_ptr;
-}
-
-/*
- * Free unneded array.
- */
-static void
-ta_flush_mod_numarray(void *ta_buf)
-{
-	struct mod_item *mi;
-
-	mi = (struct mod_item *)ta_buf;
-	if (mi->main_ptr != NULL)
-		free(mi->main_ptr, M_IPFW);
-}
-
-static int
-ta_dump_numarray_tentry(void *ta_state, struct table_info *ti, void *e,
-    ipfw_obj_tentry *tent)
-{
-	struct numarray *na;
-
-	na = (struct numarray *)e;
-
-	tent->k.key = na->number;
-	tent->v.kidx = na->value;
-
-	return (0);
-}
-
-static int
-ta_find_numarray_tentry(void *ta_state, struct table_info *ti,
-    ipfw_obj_tentry *tent)
-{
-	struct numarray_cfg *cfg;
-	struct numarray *ri;
-
-	cfg = (struct numarray_cfg *)ta_state;
-
-	ri = numarray_find(ti, &tent->k.key);
-
-	if (ri != NULL) {
-		ta_dump_numarray_tentry(ta_state, ti, ri, tent);
-		return (0);
-	}
-
-	return (ENOENT);
-}
-
-static void
-ta_foreach_numarray(void *ta_state, struct table_info *ti, ta_foreach_f *f,
-    void *arg)
-{
-	struct numarray_cfg *cfg;
-	struct numarray *array;
-	int i;
-
-	cfg = (struct numarray_cfg *)ta_state;
-	array = cfg->main_ptr;
-
-	for (i = 0; i < cfg->used; i++)
-		f(&array[i], arg);
-}
-
-struct table_algo number_array = {
-	.name		= "number:array",
-	.type		= IPFW_TABLE_NUMBER,
-	.ta_buf_size	= sizeof(struct ta_buf_numarray),
-	.init		= ta_init_numarray,
-	.destroy	= ta_destroy_numarray,
-	.prepare_add	= ta_prepare_add_numarray,
-	.prepare_del	= ta_prepare_add_numarray,
-	.add		= ta_add_numarray,
-	.del		= ta_del_numarray,
-	.flush_entry	= ta_flush_numarray_entry,
-	.foreach	= ta_foreach_numarray,
-	.dump_tentry	= ta_dump_numarray_tentry,
-	.find_tentry	= ta_find_numarray_tentry,
-	.dump_tinfo	= ta_dump_numarray_tinfo,
-	.need_modify	= ta_need_modify_numarray,
-	.prepare_mod	= ta_prepare_mod_numarray,
-	.fill_mod	= ta_fill_mod_numarray,
-	.modify		= ta_modify_numarray,
-	.flush_mod	= ta_flush_mod_numarray,
-};
-
-/*
- * flow:hash cmds
- *
- *
- * ti->data:
- * [inv.mask4][inv.mask6][log2hsize4][log2hsize6]
- * [        8][        8[          8][         8]
- *
- * inv.mask4: 32 - mask
- * inv.mask6:
- * 1) _slow lookup: mask
- * 2) _aligned: (128 - mask) / 8
- * 3) _64: 8
- *
- *
- * pflags:
- * [hsize4][hsize6]
- * [    16][    16]
- */
-
-struct fhashentry;
-
-SLIST_HEAD(fhashbhead, fhashentry);
-
-struct fhashentry {
-	SLIST_ENTRY(fhashentry)	next;
-	uint8_t		af;
-	uint8_t		proto;
-	uint16_t	spare0;
-	uint16_t	dport;
-	uint16_t	sport;
-	uint32_t	value;
-	uint32_t	spare1;
-};
-
-struct fhashentry4 {
-	struct fhashentry	e;
-	struct in_addr		dip;
-	struct in_addr		sip;
-};
-
-struct fhashentry6 {
-	struct fhashentry	e;
-	struct in6_addr		dip6;
-	struct in6_addr		sip6;
-};
-
-struct fhash_cfg {
-	struct fhashbhead	*head;
-	size_t			size;
-	size_t			items;
-	struct fhashentry4	fe4;
-	struct fhashentry6	fe6;
-};
-
-struct ta_buf_fhash {
-	void	*ent_ptr;
-	struct fhashentry6 fe6;
-};
-
-static __inline int cmp_flow_ent(struct fhashentry *a,
-    struct fhashentry *b, size_t sz);
-static __inline uint32_t hash_flow4(struct fhashentry4 *f, int hsize);
-static __inline uint32_t hash_flow6(struct fhashentry6 *f, int hsize);
-static uint32_t hash_flow_ent(struct fhashentry *ent, uint32_t size);
-static int ta_lookup_fhash(struct table_info *ti, void *key, uint32_t keylen,
-    uint32_t *val);
-static int ta_init_fhash(struct ip_fw_chain *ch, void **ta_state,
-struct table_info *ti, char *data, uint8_t tflags);
-static void ta_destroy_fhash(void *ta_state, struct table_info *ti);
-static void ta_dump_fhash_tinfo(void *ta_state, struct table_info *ti,
-    ipfw_ta_tinfo *tinfo);
-static int ta_dump_fhash_tentry(void *ta_state, struct table_info *ti,
-    void *e, ipfw_obj_tentry *tent);
-static int tei_to_fhash_ent(struct tentry_info *tei, struct fhashentry *ent);
-static int ta_find_fhash_tentry(void *ta_state, struct table_info *ti,
-    ipfw_obj_tentry *tent);
-static void ta_foreach_fhash(void *ta_state, struct table_info *ti,
-    ta_foreach_f *f, void *arg);
-static int ta_prepare_add_fhash(struct ip_fw_chain *ch,
-    struct tentry_info *tei, void *ta_buf);
-static int ta_add_fhash(void *ta_state, struct table_info *ti,
-    struct tentry_info *tei, void *ta_buf, uint32_t *pnum);
-static int ta_prepare_del_fhash(struct ip_fw_chain *ch, struct tentry_info *tei,
-    void *ta_buf);
-static int ta_del_fhash(void *ta_state, struct table_info *ti,
-    struct tentry_info *tei, void *ta_buf, uint32_t *pnum);
-static void ta_flush_fhash_entry(struct ip_fw_chain *ch, struct tentry_info *tei,
-    void *ta_buf);
-static int ta_need_modify_fhash(void *ta_state, struct table_info *ti,
-    uint32_t count, uint64_t *pflags);
-static int ta_prepare_mod_fhash(void *ta_buf, uint64_t *pflags);
-static int ta_fill_mod_fhash(void *ta_state, struct table_info *ti,
-    void *ta_buf, uint64_t *pflags);
-static void ta_modify_fhash(void *ta_state, struct table_info *ti, void *ta_buf,
-    uint64_t pflags);
-static void ta_flush_mod_fhash(void *ta_buf);
-
-static __inline int
-cmp_flow_ent(struct fhashentry *a, struct fhashentry *b, size_t sz)
-{
-	uint64_t *ka, *kb;
-
-	ka = (uint64_t *)(&a->next + 1);
-	kb = (uint64_t *)(&b->next + 1);
-
-	if (*ka == *kb && (memcmp(a + 1, b + 1, sz) == 0))
-		return (1);
-
-	return (0);
-}
-
-static __inline uint32_t
-hash_flow4(struct fhashentry4 *f, int hsize)
-{
-	uint32_t i;
-
-	i = (f->dip.s_addr) ^ (f->sip.s_addr) ^ (f->e.dport) ^ (f->e.sport);
-
-	return (i % (hsize - 1));
-}
-
-static __inline uint32_t
-hash_flow6(struct fhashentry6 *f, int hsize)
-{
-	uint32_t i;
-
-	i = (f->dip6.__u6_addr.__u6_addr32[2]) ^
-	    (f->dip6.__u6_addr.__u6_addr32[3]) ^
-	    (f->sip6.__u6_addr.__u6_addr32[2]) ^
-	    (f->sip6.__u6_addr.__u6_addr32[3]) ^
-	    (f->e.dport) ^ (f->e.sport);
-
-	return (i % (hsize - 1));
-}
-
-static uint32_t
-hash_flow_ent(struct fhashentry *ent, uint32_t size)
-{
-	uint32_t hash;
-
-	if (ent->af == AF_INET) {
-		hash = hash_flow4((struct fhashentry4 *)ent, size);
-	} else {
-		hash = hash_flow6((struct fhashentry6 *)ent, size);
-	}
-
-	return (hash);
-}
-
-static int
-ta_lookup_fhash(struct table_info *ti, void *key, uint32_t keylen,
-    uint32_t *val)
-{
-	struct fhashbhead *head;
-	struct fhashentry *ent;
-	struct fhashentry4 *m4;
-	struct ipfw_flow_id *id;
-	uint16_t hash, hsize;
-
-	id = (struct ipfw_flow_id *)key;
-	head = (struct fhashbhead *)ti->state;
-	hsize = ti->data;
-	m4 = (struct fhashentry4 *)ti->xstate;
-
-	if (id->addr_type == 4) {
-		struct fhashentry4 f;
-
-		/* Copy hash mask */
-		f = *m4;
-
-		f.dip.s_addr &= id->dst_ip;
-		f.sip.s_addr &= id->src_ip;
-		f.e.dport &= id->dst_port;
-		f.e.sport &= id->src_port;
-		f.e.proto &= id->proto;
-		hash = hash_flow4(&f, hsize);
-		SLIST_FOREACH(ent, &head[hash], next) {
-			if (cmp_flow_ent(ent, &f.e, 2 * 4) != 0) {
-				*val = ent->value;
-				return (1);
-			}
-		}
-	} else if (id->addr_type == 6) {
-		struct fhashentry6 f;
-		uint64_t *fp, *idp;
-
-		/* Copy hash mask */
-		f = *((struct fhashentry6 *)(m4 + 1));
-
-		/* Handle lack of __u6_addr.__u6_addr64 */
-		fp = (uint64_t *)&f.dip6;
-		idp = (uint64_t *)&id->dst_ip6;
-		/* src IPv6 is stored after dst IPv6 */
-		*fp++ &= *idp++;
-		*fp++ &= *idp++;
-		*fp++ &= *idp++;
-		*fp &= *idp;
-		f.e.dport &= id->dst_port;
-		f.e.sport &= id->src_port;
-		f.e.proto &= id->proto;
-		hash = hash_flow6(&f, hsize);
-		SLIST_FOREACH(ent, &head[hash], next) {
-			if (cmp_flow_ent(ent, &f.e, 2 * 16) != 0) {
-				*val = ent->value;
-				return (1);
-			}
-		}
-	}
-
-	return (0);
-}
-
-/*
- * New table.
- */
-static int
-ta_init_fhash(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti,
-    char *data, uint8_t tflags)
-{
-	int i;
-	struct fhash_cfg *cfg;
-	struct fhashentry4 *fe4;
-	struct fhashentry6 *fe6;
-
-	cfg = malloc(sizeof(struct fhash_cfg), M_IPFW, M_WAITOK | M_ZERO);
-
-	cfg->size = 512;
-
-	cfg->head = malloc(sizeof(struct fhashbhead) * cfg->size, M_IPFW,
-	    M_WAITOK | M_ZERO);
-	for (i = 0; i < cfg->size; i++)
-		SLIST_INIT(&cfg->head[i]);
-
-	/* Fill in fe masks based on @tflags */
-	fe4 = &cfg->fe4;
-	fe6 = &cfg->fe6;
-	if (tflags & IPFW_TFFLAG_SRCIP) {
-		memset(&fe4->sip, 0xFF, sizeof(fe4->sip));
-		memset(&fe6->sip6, 0xFF, sizeof(fe6->sip6));
-	}
-	if (tflags & IPFW_TFFLAG_DSTIP) {
-		memset(&fe4->dip, 0xFF, sizeof(fe4->dip));
-		memset(&fe6->dip6, 0xFF, sizeof(fe6->dip6));
-	}
-	if (tflags & IPFW_TFFLAG_SRCPORT) {
-		memset(&fe4->e.sport, 0xFF, sizeof(fe4->e.sport));
-		memset(&fe6->e.sport, 0xFF, sizeof(fe6->e.sport));
-	}
-	if (tflags & IPFW_TFFLAG_DSTPORT) {
-		memset(&fe4->e.dport, 0xFF, sizeof(fe4->e.dport));
-		memset(&fe6->e.dport, 0xFF, sizeof(fe6->e.dport));
-	}
-	if (tflags & IPFW_TFFLAG_PROTO) {
-		memset(&fe4->e.proto, 0xFF, sizeof(fe4->e.proto));
-		memset(&fe6->e.proto, 0xFF, sizeof(fe6->e.proto));
-	}
-
-	fe4->e.af = AF_INET;
-	fe6->e.af = AF_INET6;
-
-	*ta_state = cfg;
-	ti->state = cfg->head;
-	ti->xstate = &cfg->fe4;
-	ti->data = cfg->size;
-	ti->lookup = ta_lookup_fhash;
-
-	return (0);
-}
-
-static void
-ta_destroy_fhash(void *ta_state, struct table_info *ti)
-{
-	struct fhash_cfg *cfg;
-	struct fhashentry *ent, *ent_next;
-	int i;
-
-	cfg = (struct fhash_cfg *)ta_state;
-
-	for (i = 0; i < cfg->size; i++)
-		SLIST_FOREACH_SAFE(ent, &cfg->head[i], next, ent_next)
-			free(ent, M_IPFW_TBL);
-
-	free(cfg->head, M_IPFW);
-	free(cfg, M_IPFW);
-}
-
-/*
- * Provide algo-specific table info
- */
-static void
-ta_dump_fhash_tinfo(void *ta_state, struct table_info *ti, ipfw_ta_tinfo *tinfo)
-{
-	struct fhash_cfg *cfg;
-
-	cfg = (struct fhash_cfg *)ta_state;
-
-	tinfo->flags = IPFW_TATFLAGS_AFITEM;
-	tinfo->taclass4 = IPFW_TACLASS_HASH;
-	tinfo->size4 = cfg->size;
-	tinfo->count4 = cfg->items;
-	tinfo->itemsize4 = sizeof(struct fhashentry4);
-	tinfo->itemsize6 = sizeof(struct fhashentry6);
-}
-
-static int
-ta_dump_fhash_tentry(void *ta_state, struct table_info *ti, void *e,
-    ipfw_obj_tentry *tent)
-{
-	struct fhash_cfg *cfg;
-	struct fhashentry *ent;
-	struct fhashentry4 *fe4;
-#ifdef INET6
-	struct fhashentry6 *fe6;
-#endif
-	struct tflow_entry *tfe;
-
-	cfg = (struct fhash_cfg *)ta_state;
-	ent = (struct fhashentry *)e;
-	tfe = &tent->k.flow;
-
-	tfe->af = ent->af;
-	tfe->proto = ent->proto;
-	tfe->dport = htons(ent->dport);
-	tfe->sport = htons(ent->sport);
-	tent->v.kidx = ent->value;
-	tent->subtype = ent->af;
-
-	if (ent->af == AF_INET) {
-		fe4 = (struct fhashentry4 *)ent;
-		tfe->a.a4.sip.s_addr = htonl(fe4->sip.s_addr);
-		tfe->a.a4.dip.s_addr = htonl(fe4->dip.s_addr);
-		tent->masklen = 32;
-#ifdef INET6
-	} else {
-		fe6 = (struct fhashentry6 *)ent;
-		tfe->a.a6.sip6 = fe6->sip6;
-		tfe->a.a6.dip6 = fe6->dip6;
-		tent->masklen = 128;
-#endif
-	}
-
-	return (0);
-}
-
-static int
-tei_to_fhash_ent(struct tentry_info *tei, struct fhashentry *ent)
-{
-#ifdef INET
-	struct fhashentry4 *fe4;
-#endif
-#ifdef INET6
-	struct fhashentry6 *fe6;
-#endif
-	struct tflow_entry *tfe;
-
-	tfe = (struct tflow_entry *)tei->paddr;
-
-	ent->af = tei->subtype;
-	ent->proto = tfe->proto;
-	ent->dport = ntohs(tfe->dport);
-	ent->sport = ntohs(tfe->sport);
-
-	if (tei->subtype == AF_INET) {
-#ifdef INET
-		fe4 = (struct fhashentry4 *)ent;
-		fe4->sip.s_addr = ntohl(tfe->a.a4.sip.s_addr);
-		fe4->dip.s_addr = ntohl(tfe->a.a4.dip.s_addr);
-#endif
-#ifdef INET6
-	} else if (tei->subtype == AF_INET6) {
-		fe6 = (struct fhashentry6 *)ent;
-		fe6->sip6 = tfe->a.a6.sip6;
-		fe6->dip6 = tfe->a.a6.dip6;
-#endif
-	} else {
-		/* Unknown CIDR type */
-		return (EINVAL);
-	}
-
-	return (0);
-}
-
-
-static int
-ta_find_fhash_tentry(void *ta_state, struct table_info *ti,
-    ipfw_obj_tentry *tent)
-{
-	struct fhash_cfg *cfg;
-	struct fhashbhead *head;
-	struct fhashentry *ent, *tmp;
-	struct fhashentry6 fe6;
-	struct tentry_info tei;
-	int error;
-	uint32_t hash;
-	size_t sz;
-
-	cfg = (struct fhash_cfg *)ta_state;
-
-	ent = &fe6.e;
-
-	memset(&fe6, 0, sizeof(fe6));
-	memset(&tei, 0, sizeof(tei));
-
-	tei.paddr = &tent->k.flow;
-	tei.subtype = tent->subtype;
-
-	if ((error = tei_to_fhash_ent(&tei, ent)) != 0)
-		return (error);
-
-	head = cfg->head;
-	hash = hash_flow_ent(ent, cfg->size);
-
-	if (tei.subtype == AF_INET)
-		sz = 2 * sizeof(struct in_addr);
-	else
-		sz = 2 * sizeof(struct in6_addr);
-
-	/* Check for existence */
-	SLIST_FOREACH(tmp, &head[hash], next) {
-		if (cmp_flow_ent(tmp, ent, sz) != 0) {
-			ta_dump_fhash_tentry(ta_state, ti, tmp, tent);
-			return (0);
-		}
-	}
-
-	return (ENOENT);
-}
-
-static void
-ta_foreach_fhash(void *ta_state, struct table_info *ti, ta_foreach_f *f,
-    void *arg)
-{
-	struct fhash_cfg *cfg;
-	struct fhashentry *ent, *ent_next;
-	int i;
-
-	cfg = (struct fhash_cfg *)ta_state;
-
-	for (i = 0; i < cfg->size; i++)
-		SLIST_FOREACH_SAFE(ent, &cfg->head[i], next, ent_next)
-			f(ent, arg);
-}
-
-static int
-ta_prepare_add_fhash(struct ip_fw_chain *ch, struct tentry_info *tei,
-    void *ta_buf)
-{
-	struct ta_buf_fhash *tb;
-	struct fhashentry *ent;
-	size_t sz;
-	int error;
-
-	tb = (struct ta_buf_fhash *)ta_buf;
-
-	if (tei->subtype == AF_INET)
-		sz = sizeof(struct fhashentry4);
-	else if (tei->subtype == AF_INET6)
-		sz = sizeof(struct fhashentry6);
-	else
-		return (EINVAL);
-
-	ent = malloc(sz, M_IPFW_TBL, M_WAITOK | M_ZERO);
-
-	error = tei_to_fhash_ent(tei, ent);
-	if (error != 0) {
-		free(ent, M_IPFW_TBL);
-		return (error);
-	}
-	tb->ent_ptr = ent;
-
-	return (0);
-}
-
-static int
-ta_add_fhash(void *ta_state, struct table_info *ti, struct tentry_info *tei,
-    void *ta_buf, uint32_t *pnum)
-{
-	struct fhash_cfg *cfg;
-	struct fhashbhead *head;
-	struct fhashentry *ent, *tmp;
-	struct ta_buf_fhash *tb;
-	int exists;
-	uint32_t hash, value;
-	size_t sz;
-
-	cfg = (struct fhash_cfg *)ta_state;
-	tb = (struct ta_buf_fhash *)ta_buf;
-	ent = (struct fhashentry *)tb->ent_ptr;
-	exists = 0;
-
-	/* Read current value from @tei */
-	ent->value = tei->value;
-
-	head = cfg->head;
-	hash = hash_flow_ent(ent, cfg->size);
-
-	if (tei->subtype == AF_INET)
-		sz = 2 * sizeof(struct in_addr);
-	else
-		sz = 2 * sizeof(struct in6_addr);
-
-	/* Check for existence */
-	SLIST_FOREACH(tmp, &head[hash], next) {
-		if (cmp_flow_ent(tmp, ent, sz) != 0) {
-			exists = 1;
-			break;
-		}
-	}
-
-	if (exists == 1) {
-		if ((tei->flags & TEI_FLAGS_UPDATE) == 0)
-			return (EEXIST);
-		/* Record already exists. Update value if we're asked to */
-		/* Exchange values between tmp and @tei */
-		value = tmp->value;
-		tmp->value = tei->value;
-		tei->value = value;
-		/* Indicate that update has happened instead of addition */
-		tei->flags |= TEI_FLAGS_UPDATED;
-		*pnum = 0;
-	} else {
-		if ((tei->flags & TEI_FLAGS_DONTADD) != 0)
-			return (EFBIG);
-
-		SLIST_INSERT_HEAD(&head[hash], ent, next);
-		tb->ent_ptr = NULL;
-		*pnum = 1;
-
-		/* Update counters and check if we need to grow hash */
-		cfg->items++;
-	}
-
-	return (0);
-}
-
-static int
-ta_prepare_del_fhash(struct ip_fw_chain *ch, struct tentry_info *tei,
-    void *ta_buf)
-{
-	struct ta_buf_fhash *tb;
-
-	tb = (struct ta_buf_fhash *)ta_buf;
-
-	return (tei_to_fhash_ent(tei, &tb->fe6.e));
-}
-
-static int
-ta_del_fhash(void *ta_state, struct table_info *ti, struct tentry_info *tei,
-    void *ta_buf, uint32_t *pnum)
-{
-	struct fhash_cfg *cfg;
-	struct fhashbhead *head;
-	struct fhashentry *ent, *tmp;
-	struct ta_buf_fhash *tb;
-	uint32_t hash;
-	size_t sz;
-
-	cfg = (struct fhash_cfg *)ta_state;
-	tb = (struct ta_buf_fhash *)ta_buf;
-	ent = &tb->fe6.e;
-
-	head = cfg->head;
-	hash = hash_flow_ent(ent, cfg->size);
-
-	if (tei->subtype == AF_INET)
-		sz = 2 * sizeof(struct in_addr);
-	else
-		sz = 2 * sizeof(struct in6_addr);
-
-	/* Check for existence */
-	SLIST_FOREACH(tmp, &head[hash], next) {
-		if (cmp_flow_ent(tmp, ent, sz) == 0)
-			continue;
-
-		SLIST_REMOVE(&head[hash], tmp, fhashentry, next);
-		tei->value = tmp->value;
-		*pnum = 1;
-		cfg->items--;
-		tb->ent_ptr = tmp;
-		return (0);
-	}
-
-	return (ENOENT);
-}
-
-static void
-ta_flush_fhash_entry(struct ip_fw_chain *ch, struct tentry_info *tei,
-    void *ta_buf)
-{
-	struct ta_buf_fhash *tb;
-
-	tb = (struct ta_buf_fhash *)ta_buf;
-
-	if (tb->ent_ptr != NULL)
-		free(tb->ent_ptr, M_IPFW_TBL);
-}
-
-/*
- * Hash growing callbacks.
- */
-
-static int
-ta_need_modify_fhash(void *ta_state, struct table_info *ti, uint32_t count,
-    uint64_t *pflags)
-{
-	struct fhash_cfg *cfg;
-
-	cfg = (struct fhash_cfg *)ta_state;
-
-	if (cfg->items > cfg->size && cfg->size < 65536) {
-		*pflags = cfg->size * 2;
-		return (1);
-	}
-
-	return (0);
-}
-
-/*
- * Allocate new, larger fhash.
- */
-static int
-ta_prepare_mod_fhash(void *ta_buf, uint64_t *pflags)
-{
-	struct mod_item *mi;
-	struct fhashbhead *head;
-	int i;
-
-	mi = (struct mod_item *)ta_buf;
-
-	memset(mi, 0, sizeof(struct mod_item));
-	mi->size = *pflags;
-	head = malloc(sizeof(struct fhashbhead) * mi->size, M_IPFW,
-	    M_WAITOK | M_ZERO);
-	for (i = 0; i < mi->size; i++)
-		SLIST_INIT(&head[i]);
-
-	mi->main_ptr = head;
-
-	return (0);
-}
-
-/*
- * Copy data from old runtime array to new one.
- */
-static int
-ta_fill_mod_fhash(void *ta_state, struct table_info *ti, void *ta_buf,
-    uint64_t *pflags)
-{
-
-	/* In is not possible to do rehash if we're not holidng WLOCK. */
-	return (0);
-}
-
-/*
- * Switch old & new arrays.
- */
-static void
-ta_modify_fhash(void *ta_state, struct table_info *ti, void *ta_buf,
-    uint64_t pflags)
-{
-	struct mod_item *mi;
-	struct fhash_cfg *cfg;
-	struct fhashbhead *old_head, *new_head;
-	struct fhashentry *ent, *ent_next;
-	int i;
-	uint32_t nhash;
-	size_t old_size;
-
-	mi = (struct mod_item *)ta_buf;
-	cfg = (struct fhash_cfg *)ta_state;
-
-	old_size = cfg->size;
-	old_head = ti->state;
-
-	new_head = (struct fhashbhead *)mi->main_ptr;
-	for (i = 0; i < old_size; i++) {
-		SLIST_FOREACH_SAFE(ent, &old_head[i], next, ent_next) {
-			nhash = hash_flow_ent(ent, mi->size);
-			SLIST_INSERT_HEAD(&new_head[nhash], ent, next);
-		}
-	}
-
-	ti->state = new_head;
-	ti->data = mi->size;
-	cfg->head = new_head;
-	cfg->size = mi->size;
-
-	mi->main_ptr = old_head;
-}
-
-/*
- * Free unneded array.
- */
-static void
-ta_flush_mod_fhash(void *ta_buf)
-{
-	struct mod_item *mi;
-
-	mi = (struct mod_item *)ta_buf;
-	if (mi->main_ptr != NULL)
-		free(mi->main_ptr, M_IPFW);
-}
-
-struct table_algo flow_hash = {
-	.name		= "flow:hash",
-	.type		= IPFW_TABLE_FLOW,
-	.flags		= TA_FLAG_DEFAULT,
-	.ta_buf_size	= sizeof(struct ta_buf_fhash),
-	.init		= ta_init_fhash,
-	.destroy	= ta_destroy_fhash,
-	.prepare_add	= ta_prepare_add_fhash,
-	.prepare_del	= ta_prepare_del_fhash,
-	.add		= ta_add_fhash,
-	.del		= ta_del_fhash,
-	.flush_entry	= ta_flush_fhash_entry,
-	.foreach	= ta_foreach_fhash,
-	.dump_tentry	= ta_dump_fhash_tentry,
-	.find_tentry	= ta_find_fhash_tentry,
-	.dump_tinfo	= ta_dump_fhash_tinfo,
-	.need_modify	= ta_need_modify_fhash,
-	.prepare_mod	= ta_prepare_mod_fhash,
-	.fill_mod	= ta_fill_mod_fhash,
-	.modify		= ta_modify_fhash,
-	.flush_mod	= ta_flush_mod_fhash,
-};
-
-/*
- * Kernel fibs bindings.
- *
- * Implementation:
- *
- * Runtime part:
- * - fully relies on route API
- * - fib number is stored in ti->data
- *
- */
-
-static int ta_lookup_kfib(struct table_info *ti, void *key, uint32_t keylen,
-    uint32_t *val);
-static int kfib_parse_opts(int *pfib, char *data);
-static void ta_print_kfib_config(void *ta_state, struct table_info *ti,
-    char *buf, size_t bufsize);
-static int ta_init_kfib(struct ip_fw_chain *ch, void **ta_state,
-    struct table_info *ti, char *data, uint8_t tflags);
-static void ta_destroy_kfib(void *ta_state, struct table_info *ti);
-static void ta_dump_kfib_tinfo(void *ta_state, struct table_info *ti,
-    ipfw_ta_tinfo *tinfo);
-static int contigmask(uint8_t *p, int len);
-static int ta_dump_kfib_tentry(void *ta_state, struct table_info *ti, void *e,
-    ipfw_obj_tentry *tent);
-static int ta_dump_kfib_tentry_int(struct sockaddr *paddr,
-    struct sockaddr *pmask, ipfw_obj_tentry *tent);
-static int ta_find_kfib_tentry(void *ta_state, struct table_info *ti,
-    ipfw_obj_tentry *tent);
-static void ta_foreach_kfib(void *ta_state, struct table_info *ti,
-    ta_foreach_f *f, void *arg);
-
-
-static int
-ta_lookup_kfib(struct table_info *ti, void *key, uint32_t keylen,
-    uint32_t *val)
-{
-#ifdef INET
-	struct nhop4_basic nh4;
-	struct in_addr in;
-#endif
-#ifdef INET6
-	struct nhop6_basic nh6;
-#endif
-	int error;
-
-	error = ENOENT;
-#ifdef INET
-	if (keylen == 4) {
-		in.s_addr = *(in_addr_t *)key;
-		error = fib4_lookup_nh_basic(ti->data,
-		    in, 0, 0, &nh4);
-	}
-#endif
-#ifdef INET6
-	if (keylen == 6)
-		error = fib6_lookup_nh_basic(ti->data,
-		    (struct in6_addr *)key, 0, 0, 0, &nh6);
-#endif
-
-	if (error != 0)
-		return (0);
-
-	*val = 0;
-
-	return (1);
-}
-
-/* Parse 'fib=%d' */
-static int
-kfib_parse_opts(int *pfib, char *data)
-{
-	char *pdel, *pend, *s;
-	int fibnum;
-
-	if (data == NULL)
-		return (0);
-	if ((pdel = strchr(data, ' ')) == NULL)
-		return (0);
-	while (*pdel == ' ')
-		pdel++;
-	if (strncmp(pdel, "fib=", 4) != 0)
-		return (EINVAL);
-	if ((s = strchr(pdel, ' ')) != NULL)
-		*s++ = '\0';
-
-	pdel += 4;
-	/* Need \d+ */
-	fibnum = strtol(pdel, &pend, 10);
-	if (*pend != '\0')
-		return (EINVAL);
-
-	*pfib = fibnum;
-
-	return (0);
-}
-
-static void
-ta_print_kfib_config(void *ta_state, struct table_info *ti, char *buf,
-    size_t bufsize)
-{
-
-	if (ti->data != 0)
-		snprintf(buf, bufsize, "%s fib=%lu", "addr:kfib", ti->data);
-	else
-		snprintf(buf, bufsize, "%s", "addr:kfib");
-}
-
-static int
-ta_init_kfib(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti,
-    char *data, uint8_t tflags)
-{
-	int error, fibnum;
-
-	fibnum = 0;
-	if ((error = kfib_parse_opts(&fibnum, data)) != 0)
-		return (error);
-
-	if (fibnum >= rt_numfibs)
-		return (E2BIG);
-
-	ti->data = fibnum;
-	ti->lookup = ta_lookup_kfib;
-
-	return (0);
-}
-
-/*
- * Destroys table @ti
- */
-static void
-ta_destroy_kfib(void *ta_state, struct table_info *ti)
-{
-
-}
-
-/*
- * Provide algo-specific table info
- */
-static void
-ta_dump_kfib_tinfo(void *ta_state, struct table_info *ti, ipfw_ta_tinfo *tinfo)
-{
-
-	tinfo->flags = IPFW_TATFLAGS_AFDATA;
-	tinfo->taclass4 = IPFW_TACLASS_RADIX;
-	tinfo->count4 = 0;
-	tinfo->itemsize4 = sizeof(struct rtentry);
-	tinfo->taclass6 = IPFW_TACLASS_RADIX;
-	tinfo->count6 = 0;
-	tinfo->itemsize6 = sizeof(struct rtentry);
-}
-
-static int
-contigmask(uint8_t *p, int len)
-{
-	int i, n;
-
-	for (i = 0; i < len ; i++)
-		if ( (p[i/8] & (1 << (7 - (i%8)))) == 0) /* first bit unset */
-			break;
-	for (n= i + 1; n < len; n++)
-		if ( (p[n/8] & (1 << (7 - (n % 8)))) != 0)
-			return (-1); /* mask not contiguous */
-	return (i);
-}
-
-
-static int
-ta_dump_kfib_tentry(void *ta_state, struct table_info *ti, void *e,
-    ipfw_obj_tentry *tent)
-{
-	struct rtentry *rte;
-
-	rte = (struct rtentry *)e;
-
-	return ta_dump_kfib_tentry_int(rt_key(rte), rt_mask(rte), tent);
-}
-
-static int
-ta_dump_kfib_tentry_int(struct sockaddr *paddr, struct sockaddr *pmask,
-    ipfw_obj_tentry *tent)
-{
-#ifdef INET
-	struct sockaddr_in *addr, *mask;
-#endif
-#ifdef INET6
-	struct sockaddr_in6 *addr6, *mask6;
-#endif
-	int len;
-
-	len = 0;
-
-	/* Guess IPv4/IPv6 radix by sockaddr family */
-#ifdef INET
-	if (paddr->sa_family == AF_INET) {
-		addr = (struct sockaddr_in *)paddr;
-		mask = (struct sockaddr_in *)pmask;
-		tent->k.addr.s_addr = addr->sin_addr.s_addr;
-		len = 32;
-		if (mask != NULL)
-			len = contigmask((uint8_t *)&mask->sin_addr, 32);
-		if (len == -1)
-			len = 0;
-		tent->masklen = len;
-		tent->subtype = AF_INET;
-		tent->v.kidx = 0; /* Do we need to put GW here? */
-	}
-#endif
-#ifdef INET6
-	if (paddr->sa_family == AF_INET6) {
-		addr6 = (struct sockaddr_in6 *)paddr;
-		mask6 = (struct sockaddr_in6 *)pmask;
-		memcpy(&tent->k, &addr6->sin6_addr, sizeof(struct in6_addr));
-		len = 128;
-		if (mask6 != NULL)
-			len = contigmask((uint8_t *)&mask6->sin6_addr, 128);
-		if (len == -1)
-			len = 0;
-		tent->masklen = len;
-		tent->subtype = AF_INET6;
-		tent->v.kidx = 0;
-	}
-#endif
-
-	return (0);
-}
-
-static int
-ta_find_kfib_tentry(void *ta_state, struct table_info *ti,
-    ipfw_obj_tentry *tent)
-{
-	struct rt_addrinfo info;
-	struct sockaddr_in6 key6, dst6, mask6;
-	struct sockaddr *dst, *key, *mask;
-
-	/* Prepare sockaddr for prefix/mask and info */
-	bzero(&dst6, sizeof(dst6));
-	dst6.sin6_len = sizeof(dst6);
-	dst = (struct sockaddr *)&dst6;
-	bzero(&mask6, sizeof(mask6));
-	mask6.sin6_len = sizeof(mask6);
-	mask = (struct sockaddr *)&mask6;
-
-	bzero(&info, sizeof(info));
-	info.rti_info[RTAX_DST] = dst;
-	info.rti_info[RTAX_NETMASK] = mask;
-
-	/* Prepare the lookup key */
-	bzero(&key6, sizeof(key6));
-	key6.sin6_family = tent->subtype;
-	key = (struct sockaddr *)&key6;
-
-	if (tent->subtype == AF_INET) {
-		((struct sockaddr_in *)&key6)->sin_addr = tent->k.addr;
-		key6.sin6_len = sizeof(struct sockaddr_in);
-	} else {
-		key6.sin6_addr = tent->k.addr6;
-		key6.sin6_len = sizeof(struct sockaddr_in6);
-	}
-
-	if (rib_lookup_info(ti->data, key, 0, 0, &info) != 0)
-		return (ENOENT);
-	if ((info.rti_addrs & RTA_NETMASK) == 0)
-		mask = NULL;
-
-	ta_dump_kfib_tentry_int(dst, mask, tent);
-
-	return (0);
-}
-
-static void
-ta_foreach_kfib(void *ta_state, struct table_info *ti, ta_foreach_f *f,
-    void *arg)
-{
-	struct rib_head *rh;
-	int error;
-
-	rh = rt_tables_get_rnh(ti->data, AF_INET);
-	if (rh != NULL) {
-		RIB_RLOCK(rh); 
-		error = rh->rnh_walktree(&rh->head, (walktree_f_t *)f, arg);
-		RIB_RUNLOCK(rh);
-	}
-
-	rh = rt_tables_get_rnh(ti->data, AF_INET6);
-	if (rh != NULL) {
-		RIB_RLOCK(rh); 
-		error = rh->rnh_walktree(&rh->head, (walktree_f_t *)f, arg);
-		RIB_RUNLOCK(rh); 
-	}
-}
-
-struct table_algo addr_kfib = {
-	.name		= "addr:kfib",
-	.type		= IPFW_TABLE_ADDR,
-	.flags		= TA_FLAG_READONLY,
-	.ta_buf_size	= 0,
-	.init		= ta_init_kfib,
-	.destroy	= ta_destroy_kfib,
-	.foreach	= ta_foreach_kfib,
-	.dump_tentry	= ta_dump_kfib_tentry,
-	.find_tentry	= ta_find_kfib_tentry,
-	.dump_tinfo	= ta_dump_kfib_tinfo,
-	.print_config	= ta_print_kfib_config,
-};
-
-void
-ipfw_table_algo_init(struct ip_fw_chain *ch)
-{
-	size_t sz;
-
-	/*
-	 * Register all algorithms presented here.
-	 */
-	sz = sizeof(struct table_algo);
-	ipfw_add_table_algo(ch, &addr_radix, sz, &addr_radix.idx);
-	ipfw_add_table_algo(ch, &addr_hash, sz, &addr_hash.idx);
-	ipfw_add_table_algo(ch, &iface_idx, sz, &iface_idx.idx);
-	ipfw_add_table_algo(ch, &number_array, sz, &number_array.idx);
-	ipfw_add_table_algo(ch, &flow_hash, sz, &flow_hash.idx);
-	ipfw_add_table_algo(ch, &addr_kfib, sz, &addr_kfib.idx);
-}
-
-void
-ipfw_table_algo_destroy(struct ip_fw_chain *ch)
-{
-
-	ipfw_del_table_algo(ch, addr_radix.idx);
-	ipfw_del_table_algo(ch, addr_hash.idx);
-	ipfw_del_table_algo(ch, iface_idx.idx);
-	ipfw_del_table_algo(ch, number_array.idx);
-	ipfw_del_table_algo(ch, flow_hash.idx);
-	ipfw_del_table_algo(ch, addr_kfib.idx);
-}
-
-
Index: eebsd/sys/netpfil/ipfw/ip_fw_table_value.c
===================================================================
--- freebsd/sys/netpfil/ipfw/ip_fw_table_value.c	(revision f62c62d2fe57ec02c1350144f7739f8e866ee6d4)
+++ 	(revision )
@@ -1,811 +1,0 @@
-#include <machine/rtems-bsd-kernel-space.h>
-
-/*-
- * Copyright (c) 2014 Yandex LLC
- * Copyright (c) 2014 Alexander V. Chernikov
- *
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-/*
- * Multi-field value support for ipfw tables.
- *
- * This file contains necessary functions to convert
- * large multi-field values into u32 indices suitable to be fed
- * to various table algorithms. Other machinery like proper refcounting,
- * internal structures resizing are also kept here.
- */
-
-#include <rtems/bsd/local/opt_ipfw.h>
-
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/malloc.h>
-#include <sys/kernel.h>
-#include <sys/hash.h>
-#include <sys/lock.h>
-#include <sys/rwlock.h>
-#include <sys/rmlock.h>
-#include <sys/socket.h>
-#include <sys/socketvar.h>
-#include <sys/queue.h>
-#include <net/if.h>	/* ip_fw.h requires IFNAMSIZ */
-#include <net/pfil.h>
-
-#include <netinet/in.h>
-#include <netinet/ip_var.h>	/* struct ipfw_rule_ref */
-#include <netinet/ip_fw.h>
-
-#include <netpfil/ipfw/ip_fw_private.h>
-#include <netpfil/ipfw/ip_fw_table.h>
-
-static uint32_t hash_table_value(struct namedobj_instance *ni, const void *key,
-    uint32_t kopt);
-static int cmp_table_value(struct named_object *no, const void *key,
-    uint32_t kopt);
-
-static int list_table_values(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
-    struct sockopt_data *sd);
-
-static struct ipfw_sopt_handler	scodes[] = {
-	{ IP_FW_TABLE_VLIST,	0,	HDIR_GET,	list_table_values },
-};
-
-#define	CHAIN_TO_VI(chain)	(CHAIN_TO_TCFG(chain)->valhash)
-
-struct table_val_link
-{
-	struct named_object	no;
-	struct table_value	*pval;	/* Pointer to real table value */
-};
-#define	VALDATA_START_SIZE	64	/* Allocate 64-items array by default */
-
-struct vdump_args {
-	struct ip_fw_chain *ch;
-	struct sockopt_data *sd;
-	struct table_value *pval;
-	int error;
-};
-
-
-static uint32_t
-hash_table_value(struct namedobj_instance *ni, const void *key, uint32_t kopt)
-{
-
-	return (hash32_buf(key, 56, 0));
-}
-
-static int
-cmp_table_value(struct named_object *no, const void *key, uint32_t kopt)
-{
-
-	return (memcmp(((struct table_val_link *)no)->pval, key, 56));
-}
-
-static void
-mask_table_value(struct table_value *src, struct table_value *dst,
-    uint32_t mask)
-{
-#define	_MCPY(f, b)	if ((mask & (b)) != 0) { dst->f = src->f; }
-
-	memset(dst, 0, sizeof(*dst));
-	_MCPY(tag, IPFW_VTYPE_TAG);
-	_MCPY(pipe, IPFW_VTYPE_PIPE);
-	_MCPY(divert, IPFW_VTYPE_DIVERT);
-	_MCPY(skipto, IPFW_VTYPE_SKIPTO);
-	_MCPY(netgraph, IPFW_VTYPE_NETGRAPH);
-	_MCPY(fib, IPFW_VTYPE_FIB);
-	_MCPY(nat, IPFW_VTYPE_NAT);
-	_MCPY(dscp, IPFW_VTYPE_DSCP);
-	_MCPY(nh4, IPFW_VTYPE_NH4);
-	_MCPY(nh6, IPFW_VTYPE_NH6);
-	_MCPY(zoneid, IPFW_VTYPE_NH6);
-#undef	_MCPY
-}
-
-static void
-get_value_ptrs(struct ip_fw_chain *ch, struct table_config *tc, int vshared,
-    struct table_value **ptv, struct namedobj_instance **pvi)
-{
-	struct table_value *pval;
-	struct namedobj_instance *vi;
-
-	if (vshared != 0) {
-		pval = (struct table_value *)ch->valuestate;
-		vi = CHAIN_TO_VI(ch);
-	} else {
-		pval = NULL;
-		vi = NULL;
-		//pval = (struct table_value *)&tc->ti.data;
-	}
-
-	if (ptv != NULL)
-		*ptv = pval;
-	if (pvi != NULL)
-		*pvi = vi;
-}
-
-/*
- * Update pointers to real vaues after @pval change.
- */
-static int
-update_tvalue(struct namedobj_instance *ni, struct named_object *no, void *arg)
-{
-	struct vdump_args *da;
-	struct table_val_link *ptv;
-	struct table_value *pval;
-
-	da = (struct vdump_args *)arg;
-	ptv = (struct table_val_link *)no;
-
-	pval = da->pval;
-	ptv->pval = &pval[ptv->no.kidx];
-	ptv->no.name = (char *)&pval[ptv->no.kidx];
-	return (0);
-}
-
-/*
- * Grows value storage shared among all tables.
- * Drops/reacquires UH locks.
- * Notifies other running adds on @ch shared storage resize.
- * Note function does not guarantee that free space
- * will be available after invocation, so one caller needs
- * to roll cycle himself.
- *
- * Returns 0 if case of no errors.
- */
-static int
-resize_shared_value_storage(struct ip_fw_chain *ch)
-{
-	struct tables_config *tcfg;
-	struct namedobj_instance *vi;
-	struct table_value *pval, *valuestate, *old_valuestate;
-	void *new_idx;
-	struct vdump_args da;
-	int new_blocks;
-	int val_size, val_size_old;
-
-	IPFW_UH_WLOCK_ASSERT(ch);
-
-	valuestate = NULL;
-	new_idx = NULL;
-
-	pval = (struct table_value *)ch->valuestate;
-	vi = CHAIN_TO_VI(ch);
-	tcfg = CHAIN_TO_TCFG(ch);
-
-	val_size = tcfg->val_size * 2;
-
-	if (val_size == (1 << 30))
-		return (ENOSPC);
-
-	IPFW_UH_WUNLOCK(ch);
-
-	valuestate = malloc(sizeof(struct table_value) * val_size, M_IPFW,
-	    M_WAITOK | M_ZERO);
-	ipfw_objhash_bitmap_alloc(val_size, (void *)&new_idx,
-	    &new_blocks);
-
-	IPFW_UH_WLOCK(ch);
-
-	/*
-	 * Check if we still need to resize
-	 */
-	if (tcfg->val_size >= val_size)
-		goto done;
-
-	/* Update pointers and notify everyone we're changing @ch */
-	pval = (struct table_value *)ch->valuestate;
-	rollback_toperation_state(ch, ch);
-
-	/* Good. Let's merge */
-	memcpy(valuestate, pval, sizeof(struct table_value) * tcfg->val_size);
-	ipfw_objhash_bitmap_merge(CHAIN_TO_VI(ch), &new_idx, &new_blocks);
-
-	IPFW_WLOCK(ch);
-	/* Change pointers */
-	old_valuestate = ch->valuestate;
-	ch->valuestate = valuestate;
-	valuestate = old_valuestate;
-	ipfw_objhash_bitmap_swap(CHAIN_TO_VI(ch), &new_idx, &new_blocks);
-
-	val_size_old = tcfg->val_size;
-	tcfg->val_size = val_size;
-	val_size = val_size_old;
-	IPFW_WUNLOCK(ch);
-	/* Update pointers to reflect resize */
-	memset(&da, 0, sizeof(da));
-	da.pval = (struct table_value *)ch->valuestate;
-	ipfw_objhash_foreach(vi, update_tvalue, &da);
-
-done:
-	free(valuestate, M_IPFW);
-	ipfw_objhash_bitmap_free(new_idx, new_blocks);
-
-	return (0);
-}
-
-/*
- * Drops reference for table value with index @kidx, stored in @pval and
- * @vi. Frees value if it has no references.
- */
-static void
-unref_table_value(struct namedobj_instance *vi, struct table_value *pval,
-    uint32_t kidx)
-{
-	struct table_val_link *ptvl;
-
-	KASSERT(pval[kidx].refcnt > 0, ("Refcount is 0 on kidx %d", kidx));
-	if (--pval[kidx].refcnt > 0)
-		return;
-
-	/* Last reference, delete item */
-	ptvl = (struct table_val_link *)ipfw_objhash_lookup_kidx(vi, kidx);
-	KASSERT(ptvl != NULL, ("lookup on value kidx %d failed", kidx));
-	ipfw_objhash_del(vi, &ptvl->no);
-	ipfw_objhash_free_idx(vi, kidx);
-	free(ptvl, M_IPFW);
-}
-
-struct flush_args {
-	struct ip_fw_chain *ch;
-	struct table_algo *ta;
-	struct table_info *ti;
-	void *astate;
-	ipfw_obj_tentry tent;
-};
-
-static int
-unref_table_value_cb(void *e, void *arg)
-{
-	struct flush_args *fa;
-	struct ip_fw_chain *ch;
-	struct table_algo *ta;
-	ipfw_obj_tentry *tent;
-	int error;
-
-	fa = (struct flush_args *)arg;
-
-	ta = fa->ta;
-	memset(&fa->tent, 0, sizeof(fa->tent));
-	tent = &fa->tent;
-	error = ta->dump_tentry(fa->astate, fa->ti, e, tent);
-	if (error != 0)
-		return (error);
-
-	ch = fa->ch;
-
-	unref_table_value(CHAIN_TO_VI(ch),
-	    (struct table_value *)ch->valuestate, tent->v.kidx);
-
-	return (0);
-}
-
-/*
- * Drop references for each value used in @tc.
- */
-void
-ipfw_unref_table_values(struct ip_fw_chain *ch, struct table_config *tc,
-    struct table_algo *ta, void *astate, struct table_info *ti)
-{
-	struct flush_args fa;
-
-	IPFW_UH_WLOCK_ASSERT(ch);
-
-	memset(&fa, 0, sizeof(fa));
-	fa.ch = ch;
-	fa.ta = ta;
-	fa.astate = astate;
-	fa.ti = ti;
-
-	ta->foreach(astate, ti, unref_table_value_cb, &fa);
-}
-
-/*
- * Table operation state handler.
- * Called when we are going to change something in @tc which
- * may lead to inconsistencies in on-going table data addition.
- *
- * Here we rollback all already committed state (table values, currently)
- * and set "modified" field to non-zero value to indicate
- * that we need to restart original operation.
- */
-void
-rollback_table_values(struct tableop_state *ts)
-{
-	struct ip_fw_chain *ch;
-	struct table_value *pval;
-	struct tentry_info *ptei;
-	struct namedobj_instance *vi;
-	int i;
-
-	ch = ts->ch;
-
-	IPFW_UH_WLOCK_ASSERT(ch);
-
-	/* Get current table value pointer */
-	get_value_ptrs(ch, ts->tc, ts->vshared, &pval, &vi);
-
-	for (i = 0; i < ts->count; i++) {
-		ptei = &ts->tei[i];
-
-		if (ptei->value == 0)
-			continue;
-
-		unref_table_value(vi, pval, ptei->value);
-	}
-}
-
-/*
- * Allocate new value index in either shared or per-table array.
- * Function may drop/reacquire UH lock.
- *
- * Returns 0 on success.
- */
-static int
-alloc_table_vidx(struct ip_fw_chain *ch, struct tableop_state *ts,
-    struct namedobj_instance *vi, uint16_t *pvidx)
-{
-	int error, vlimit;
-	uint16_t vidx;
-
-	IPFW_UH_WLOCK_ASSERT(ch);
-
-	error = ipfw_objhash_alloc_idx(vi, &vidx);
-	if (error != 0) {
-
-		/*
-		 * We need to resize array. This involves
-		 * lock/unlock, so we need to check "modified"
-		 * state.
-		 */
-		ts->opstate.func(ts->tc, &ts->opstate);
-		error = resize_shared_value_storage(ch);
-		return (error); /* ts->modified should be set, we will restart */
-	}
-
-	vlimit = ts->ta->vlimit;
-	if (vlimit != 0 && vidx >= vlimit) {
-
-		/*
-		 * Algorithm is not able to store given index.
-		 * We have to rollback state, start using
-		 * per-table value array or return error
-		 * if we're already using it.
-		 *
-		 * TODO: do not rollback state if
-		 * atomicity is not required.
-		 */
-		if (ts->vshared != 0) {
-			/* shared -> per-table  */
-			return (ENOSPC); /* TODO: proper error */
-		}
-
-		/* per-table. Fail for now. */
-		return (ENOSPC); /* TODO: proper error */
-	}
-
-	*pvidx = vidx;
-	return (0);
-}
-
-/*
- * Drops value reference for unused values (updates, deletes, partially
- * successful adds or rollbacks).
- */
-void
-ipfw_garbage_table_values(struct ip_fw_chain *ch, struct table_config *tc,
-    struct tentry_info *tei, uint32_t count, int rollback)
-{
-	int i;
-	struct tentry_info *ptei;
-	struct table_value *pval;
-	struct namedobj_instance *vi;
-
-	/*
-	 * We have two slightly different ADD cases here:
-	 * either (1) we are successful / partially successful,
-	 * in that case we need
-	 * * to ignore ADDED entries values
-	 * * rollback every other values (either UPDATED since
-	 *   old value has been stored there, or some failure like
-	 *   EXISTS or LIMIT or simply "ignored" case.
-	 *
-	 * (2): atomic rollback of partially successful operation
-	 * in that case we simply need to unref all entries.
-	 *
-	 * DELETE case is simpler: no atomic support there, so
-	 * we simply unref all non-zero values.
-	 */
-
-	/*
-	 * Get current table value pointers.
-	 * XXX: Properly read vshared
-	 */
-	get_value_ptrs(ch, tc, 1, &pval, &vi);
-
-	for (i = 0; i < count; i++) {
-		ptei = &tei[i];
-
-		if (ptei->value == 0) {
-
-			/*
-			 * We may be deleting non-existing record.
-			 * Skip.
-			 */
-			continue;
-		}
-
-		if ((ptei->flags & TEI_FLAGS_ADDED) != 0 && rollback == 0) {
-			ptei->value = 0;
-			continue;
-		}
-
-		unref_table_value(vi, pval, ptei->value);
-		ptei->value = 0;
-	}
-}
-
-/*
- * Main function used to link values of entries going to be added,
- * to the index. Since we may perform many UH locks drops/acquires,
- * handle changes by checking tablestate "modified" field.
- *
- * Success: return 0.
- */
-int
-ipfw_link_table_values(struct ip_fw_chain *ch, struct tableop_state *ts)
-{
-	int error, i, found;
-	struct namedobj_instance *vi;
-	struct table_config *tc;
-	struct tentry_info *tei, *ptei;
-	uint32_t count, vlimit;
-	uint16_t vidx;
-	struct table_val_link *ptv;
-	struct table_value tval, *pval;
-
-	/*
-	 * Stage 1: reference all existing values and
-	 * save their indices.
-	 */
-	IPFW_UH_WLOCK_ASSERT(ch);
-	get_value_ptrs(ch, ts->tc, ts->vshared, &pval, &vi);
-
-	error = 0;
-	found = 0;
-	vlimit = ts->ta->vlimit;
-	vidx = 0;
-	tc = ts->tc;
-	tei = ts->tei;
-	count = ts->count;
-	for (i = 0; i < count; i++) {
-		ptei = &tei[i];
-		ptei->value = 0; /* Ensure value is always 0 in the beginning */
-		mask_table_value(ptei->pvalue, &tval, ts->vmask);
-		ptv = (struct table_val_link *)ipfw_objhash_lookup_name(vi, 0,
-		    (char *)&tval);
-		if (ptv == NULL)
-			continue;
-		/* Deal with vlimit later */
-		if (vlimit > 0 && vlimit <= ptv->no.kidx)
-			continue;
-
-		/* Value found. Bump refcount */
-		ptv->pval->refcnt++;
-		ptei->value = ptv->no.kidx;
-		found++;
-	}
-
-	if (ts->count == found) {
-		/* We've found all values , no need ts create new ones */
-		return (0);
-	}
-
-	/*
-	 * we have added some state here, let's attach operation
-	 * state ts the list ts be able ts rollback if necessary.
-	 */
-	add_toperation_state(ch, ts);
-	/* Ensure table won't disappear */
-	tc_ref(tc);
-	IPFW_UH_WUNLOCK(ch);
-
-	/*
-	 * Stage 2: allocate objects for non-existing values.
-	 */
-	for (i = 0; i < count; i++) {
-		ptei = &tei[i];
-		if (ptei->value != 0)
-			continue;
-		if (ptei->ptv != NULL)
-			continue;
-		ptei->ptv = malloc(sizeof(struct table_val_link), M_IPFW,
-		    M_WAITOK | M_ZERO);
-	}
-
-	/*
-	 * Stage 3: allocate index numbers for new values
-	 * and link them to index.
-	 */
-	IPFW_UH_WLOCK(ch);
-	tc_unref(tc);
-	del_toperation_state(ch, ts);
-	if (ts->modified != 0) {
-
-		/*
-		 * In general, we should free all state/indexes here
-		 * and return. However, we keep allocated state instead
-		 * to ensure we achieve some progress on each restart.
-		 */
-		return (0);
-	}
-
-	KASSERT(pval == ch->valuestate, ("resize_storage() notify failure"));
-
-	/* Let's try to link values */
-	for (i = 0; i < count; i++) {
-		ptei = &tei[i];
-
-		/* Check if record has appeared */
-		mask_table_value(ptei->pvalue, &tval, ts->vmask);
-		ptv = (struct table_val_link *)ipfw_objhash_lookup_name(vi, 0,
-		    (char *)&tval);
-		if (ptv != NULL) {
-			ptv->pval->refcnt++;
-			ptei->value = ptv->no.kidx;
-			continue;
-		}
-
-		/* May perform UH unlock/lock */
-		error = alloc_table_vidx(ch, ts, vi, &vidx);
-		if (error != 0) {
-			ts->opstate.func(ts->tc, &ts->opstate);
-			return (error);
-		}
-		/* value storage resize has happened, return */
-		if (ts->modified != 0)
-			return (0);
-
-		/* Finally, we have allocated valid index, let's add entry */
-		ptei->value = vidx;
-		ptv = (struct table_val_link *)ptei->ptv;
-		ptei->ptv = NULL;
-
-		ptv->no.kidx = vidx;
-		ptv->no.name = (char *)&pval[vidx];
-		ptv->pval = &pval[vidx];
-		memcpy(ptv->pval, &tval, sizeof(struct table_value));
-		pval[vidx].refcnt = 1;
-		ipfw_objhash_add(vi, &ptv->no);
-	}
-
-	return (0);
-}
-
-/*
- * Compatibility function used to import data from old
- * IP_FW_TABLE_ADD / IP_FW_TABLE_XADD opcodes.
- */
-void
-ipfw_import_table_value_legacy(uint32_t value, struct table_value *v)
-{
-
-	memset(v, 0, sizeof(*v));
-	v->tag = value;
-	v->pipe = value;
-	v->divert = value;
-	v->skipto = value;
-	v->netgraph = value;
-	v->fib = value;
-	v->nat = value;
-	v->nh4 = value; /* host format */
-	v->dscp = value;
-	v->limit = value;
-}
-
-/*
- * Export data to legacy table dumps opcodes.
- */
-uint32_t
-ipfw_export_table_value_legacy(struct table_value *v)
-{
-
-	/*
-	 * TODO: provide more compatibility depending on
-	 * vmask value.
-	 */
-	return (v->tag);
-}
-
-/*
- * Imports table value from current userland format.
- * Saves value in kernel format to the same place.
- */
-void
-ipfw_import_table_value_v1(ipfw_table_value *iv)
-{
-	struct table_value v;
-
-	memset(&v, 0, sizeof(v));
-	v.tag = iv->tag;
-	v.pipe = iv->pipe;
-	v.divert = iv->divert;
-	v.skipto = iv->skipto;
-	v.netgraph = iv->netgraph;
-	v.fib = iv->fib;
-	v.nat = iv->nat;
-	v.dscp = iv->dscp;
-	v.nh4 = iv->nh4;
-	v.nh6 = iv->nh6;
-	v.limit = iv->limit;
-	v.zoneid = iv->zoneid;
-
-	memcpy(iv, &v, sizeof(ipfw_table_value));
-}
-
-/*
- * Export real table value @v to current userland format.
- * Note that @v and @piv may point to the same memory.
- */
-void
-ipfw_export_table_value_v1(struct table_value *v, ipfw_table_value *piv)
-{
-	ipfw_table_value iv;
-
-	memset(&iv, 0, sizeof(iv));
-	iv.tag = v->tag;
-	iv.pipe = v->pipe;
-	iv.divert = v->divert;
-	iv.skipto = v->skipto;
-	iv.netgraph = v->netgraph;
-	iv.fib = v->fib;
-	iv.nat = v->nat;
-	iv.dscp = v->dscp;
-	iv.limit = v->limit;
-	iv.nh4 = v->nh4;
-	iv.nh6 = v->nh6;
-	iv.zoneid = v->zoneid;
-
-	memcpy(piv, &iv, sizeof(iv));
-}
-
-/*
- * Exports real value data into ipfw_table_value structure.
- * Utilizes "spare1" field to store kernel index.
- */
-static int
-dump_tvalue(struct namedobj_instance *ni, struct named_object *no, void *arg)
-{
-	struct vdump_args *da;
-	struct table_val_link *ptv;
-	struct table_value *v;
-
-	da = (struct vdump_args *)arg;
-	ptv = (struct table_val_link *)no;
-
-	v = (struct table_value *)ipfw_get_sopt_space(da->sd, sizeof(*v));
-	/* Out of memory, returning */
-	if (v == NULL) {
-		da->error = ENOMEM;
-		return (ENOMEM);
-	}
-
-	memcpy(v, ptv->pval, sizeof(*v));
-	v->spare1 = ptv->no.kidx;
-	return (0);
-}
-
-/*
- * Dumps all shared/table value data
- * Data layout (v1)(current):
- * Request: [ ipfw_obj_lheader ], size = ipfw_obj_lheader.size
- * Reply: [ ipfw_obj_lheader ipfw_table_value x N ]
- *
- * Returns 0 on success
- */
-static int
-list_table_values(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
-    struct sockopt_data *sd)
-{
-	struct _ipfw_obj_lheader *olh;
-	struct namedobj_instance *vi;
-	struct vdump_args da;
-	uint32_t count, size;
-
-	olh = (struct _ipfw_obj_lheader *)ipfw_get_sopt_header(sd,sizeof(*olh));
-	if (olh == NULL)
-		return (EINVAL);
-	if (sd->valsize < olh->size)
-		return (EINVAL);
-
-	IPFW_UH_RLOCK(ch);
-	vi = CHAIN_TO_VI(ch);
-
-	count = ipfw_objhash_count(vi);
-	size = count * sizeof(ipfw_table_value) + sizeof(ipfw_obj_lheader);
-
-	/* Fill in header regadless of buffer size */
-	olh->count = count;
-	olh->objsize = sizeof(ipfw_table_value);
-
-	if (size > olh->size) {
-		olh->size = size;
-		IPFW_UH_RUNLOCK(ch);
-		return (ENOMEM);
-	}
-	olh->size = size;
-
-	/*
-	 * Do the actual value dump
-	 */
-	memset(&da, 0, sizeof(da));
-	da.ch = ch;
-	da.sd = sd;
-	ipfw_objhash_foreach(vi, dump_tvalue, &da);
-
-	IPFW_UH_RUNLOCK(ch);
-
-	return (0);
-}
-
-void
-ipfw_table_value_init(struct ip_fw_chain *ch, int first)
-{
-	struct tables_config *tcfg;
-
-	ch->valuestate = malloc(VALDATA_START_SIZE * sizeof(struct table_value),
-	    M_IPFW, M_WAITOK | M_ZERO);
-
-	tcfg = ch->tblcfg;
-
-	tcfg->val_size = VALDATA_START_SIZE;
-	tcfg->valhash = ipfw_objhash_create(tcfg->val_size);
-	ipfw_objhash_set_funcs(tcfg->valhash, hash_table_value,
-	    cmp_table_value);
-
-	IPFW_ADD_SOPT_HANDLER(first, scodes);
-}
-
-static int
-destroy_value(struct namedobj_instance *ni, struct named_object *no,
-    void *arg)
-{
-
-	free(no, M_IPFW);
-	return (0);
-}
-
-void
-ipfw_table_value_destroy(struct ip_fw_chain *ch, int last)
-{
-
-	IPFW_DEL_SOPT_HANDLER(last, scodes);
-
-	free(ch->valuestate, M_IPFW);
-	ipfw_objhash_foreach(CHAIN_TO_VI(ch), destroy_value, ch);
-	ipfw_objhash_destroy(CHAIN_TO_VI(ch));
-}
-
Index: eebsd/sys/netpfil/ipfw/nat64/ip_fw_nat64.c
===================================================================
--- freebsd/sys/netpfil/ipfw/nat64/ip_fw_nat64.c	(revision f62c62d2fe57ec02c1350144f7739f8e866ee6d4)
+++ 	(revision )
@@ -1,131 +1,0 @@
-#include <machine/rtems-bsd-kernel-space.h>
-
-/*-
- * Copyright (c) 2015-2016 Yandex LLC
- * Copyright (c) 2015-2016 Andrey V. Elsukov <ae@FreeBSD.org>
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/kernel.h>
-#include <sys/lock.h>
-#include <sys/malloc.h>
-#include <sys/module.h>
-#include <sys/rwlock.h>
-#include <sys/socket.h>
-#include <sys/sysctl.h>
-
-#include <net/if.h>
-#include <net/vnet.h>
-
-#include <netinet/in.h>
-#include <netinet/ip_var.h>
-#include <netinet/ip_fw.h>
-
-#include <netpfil/ipfw/ip_fw_private.h>
-#include <netpfil/ipfw/nat64/ip_fw_nat64.h>
-#include <netpfil/ipfw/nat64/nat64_translate.h>
-
-
-int nat64_debug = 0;
-SYSCTL_DECL(_net_inet_ip_fw);
-SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, nat64_debug, CTLFLAG_RW,
-    &nat64_debug, 0, "Debug level for NAT64 module");
-
-int nat64_allow_private = 0;
-SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, nat64_allow_private, CTLFLAG_RW,
-    &nat64_allow_private, 0,
-    "Allow use of non-global IPv4 addresses with NAT64");
-
-static int
-vnet_ipfw_nat64_init(const void *arg __unused)
-{
-	struct ip_fw_chain *ch;
-	int first, error;
-
-	ch = &V_layer3_chain;
-	first = IS_DEFAULT_VNET(curvnet) ? 1: 0;
-	error = nat64stl_init(ch, first);
-	if (error != 0)
-		return (error);
-	error = nat64lsn_init(ch, first);
-	if (error != 0) {
-		nat64stl_uninit(ch, first);
-		return (error);
-	}
-	return (0);
-}
-
-static int
-vnet_ipfw_nat64_uninit(const void *arg __unused)
-{
-	struct ip_fw_chain *ch;
-	int last;
-
-	ch = &V_layer3_chain;
-	last = IS_DEFAULT_VNET(curvnet) ? 1: 0;
-	nat64stl_uninit(ch, last);
-	nat64lsn_uninit(ch, last);
-	return (0);
-}
-
-static int
-ipfw_nat64_modevent(module_t mod, int type, void *unused)
-{
-
-	switch (type) {
-	case MOD_LOAD:
-	case MOD_UNLOAD:
-		break;
-	default:
-		return (EOPNOTSUPP);
-	}
-	return (0);
-}
-
-static moduledata_t ipfw_nat64_mod = {
-	"ipfw_nat64",
-	ipfw_nat64_modevent,
-	0
-};
-
-/* Define startup order. */
-#define	IPFW_NAT64_SI_SUB_FIREWALL	SI_SUB_PROTO_IFATTACHDOMAIN
-#define	IPFW_NAT64_MODEVENT_ORDER	(SI_ORDER_ANY - 128) /* after ipfw */
-#define	IPFW_NAT64_MODULE_ORDER		(IPFW_NAT64_MODEVENT_ORDER + 1)
-#define	IPFW_NAT64_VNET_ORDER		(IPFW_NAT64_MODEVENT_ORDER + 2)
-
-DECLARE_MODULE(ipfw_nat64, ipfw_nat64_mod, IPFW_NAT64_SI_SUB_FIREWALL,
-    SI_ORDER_ANY);
-MODULE_DEPEND(ipfw_nat64, ipfw, 3, 3, 3);
-MODULE_VERSION(ipfw_nat64, 1);
-
-VNET_SYSINIT(vnet_ipfw_nat64_init, IPFW_NAT64_SI_SUB_FIREWALL,
-    IPFW_NAT64_VNET_ORDER, vnet_ipfw_nat64_init, NULL);
-VNET_SYSUNINIT(vnet_ipfw_nat64_uninit, IPFW_NAT64_SI_SUB_FIREWALL,
-    IPFW_NAT64_VNET_ORDER, vnet_ipfw_nat64_uninit, NULL);
Index: eebsd/sys/netpfil/ipfw/nat64/ip_fw_nat64.h
===================================================================
--- freebsd/sys/netpfil/ipfw/nat64/ip_fw_nat64.h	(revision f62c62d2fe57ec02c1350144f7739f8e866ee6d4)
+++ 	(revision )
@@ -1,117 +1,0 @@
-/*-
- * Copyright (c) 2015-2016 Yandex LLC
- * Copyright (c) 2015-2016 Andrey V. Elsukov <ae@FreeBSD.org>
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
- *
- * $FreeBSD$
- */
-
-#ifndef	_IP_FW_NAT64_H_
-#define	_IP_FW_NAT64_H_
-
-#define	DPRINTF(mask, fmt, ...)	\
-    if (nat64_debug & (mask))	\
-	printf("NAT64: %s: " fmt "\n", __func__, ## __VA_ARGS__)
-#define	DP_GENERIC	0x0001
-#define	DP_OBJ		0x0002
-#define	DP_JQUEUE	0x0004
-#define	DP_STATE	0x0008
-#define	DP_DROPS	0x0010
-#define	DP_ALL		0xFFFF
-extern int nat64_debug;
-
-#if 0
-#define	NAT64NOINLINE	__noinline
-#else
-#define	NAT64NOINLINE
-#endif
-
-int nat64stl_init(struct ip_fw_chain *ch, int first);
-void nat64stl_uninit(struct ip_fw_chain *ch, int last);
-int nat64lsn_init(struct ip_fw_chain *ch, int first);
-void nat64lsn_uninit(struct ip_fw_chain *ch, int last);
-
-struct ip_fw_nat64_stats {
-	counter_u64_t	opcnt64;	/* 6to4 of packets translated */
-	counter_u64_t	opcnt46;	/* 4to6 of packets translated */
-	counter_u64_t	ofrags;		/* number of fragments generated */
-	counter_u64_t	ifrags;		/* number of fragments received */
-	counter_u64_t	oerrors;	/* number of output errors */
-	counter_u64_t	noroute4;
-	counter_u64_t	noroute6;
-	counter_u64_t	nomatch4;	/* No addr/port match */
-	counter_u64_t	noproto;	/* Protocol not supported */
-	counter_u64_t	nomem;		/* mbufs allocation failed */
-	counter_u64_t	dropped;	/* number of packets silently
-					 * dropped due to some errors/
-					 * unsupported/etc.
-					 */
-
-	counter_u64_t	jrequests;	/* number of jobs requests queued */
-	counter_u64_t	jcalls;		/* number of jobs handler calls */
-	counter_u64_t	jhostsreq;	/* number of hosts requests */
-	counter_u64_t	jportreq;
-	counter_u64_t	jhostfails;
-	counter_u64_t	jportfails;
-	counter_u64_t	jmaxlen;
-	counter_u64_t	jnomem;
-	counter_u64_t	jreinjected;
-
-	counter_u64_t	screated;
-	counter_u64_t	sdeleted;
-	counter_u64_t	spgcreated;
-	counter_u64_t	spgdeleted;
-};
-
-#define	IPFW_NAT64_VERSION	1
-#define	NAT64STATS	(sizeof(struct ip_fw_nat64_stats) / sizeof(uint64_t))
-typedef struct _nat64_stats_block {
-	counter_u64_t		stats[NAT64STATS];
-} nat64_stats_block;
-#define	NAT64STAT_ADD(s, f, v)		\
-    counter_u64_add((s)->stats[		\
-	offsetof(struct ip_fw_nat64_stats, f) / sizeof(uint64_t)], (v))
-#define	NAT64STAT_INC(s, f)	NAT64STAT_ADD(s, f, 1)
-#define	NAT64STAT_FETCH(s, f)		\
-    counter_u64_fetch((s)->stats[	\
-	offsetof(struct ip_fw_nat64_stats, f) / sizeof(uint64_t)])
-
-#define	L3HDR(_ip, _t)	((_t)((u_int32_t *)(_ip) + (_ip)->ip_hl))
-#define	TCP(p)		((struct tcphdr *)(p))
-#define	UDP(p)		((struct udphdr *)(p))
-#define	ICMP(p)		((struct icmphdr *)(p))
-#define	ICMP6(p)	((struct icmp6_hdr *)(p))
-
-#define	NAT64SKIP	0
-#define	NAT64RETURN	1
-#define	NAT64MFREE	-1
-
-/* Well-known prefix 64:ff9b::/96 */
-#define	IPV6_ADDR_INT32_WKPFX	htonl(0x64ff9b)
-#define	IN6_IS_ADDR_WKPFX(a)	\
-    ((a)->s6_addr32[0] == IPV6_ADDR_INT32_WKPFX && \
-	(a)->s6_addr32[1] == 0 && (a)->s6_addr32[2] == 0)
-
-#endif
-
Index: eebsd/sys/netpfil/ipfw/nat64/nat64_translate.c
===================================================================
--- freebsd/sys/netpfil/ipfw/nat64/nat64_translate.c	(revision f62c62d2fe57ec02c1350144f7739f8e866ee6d4)
+++ 	(revision )
@@ -1,1574 +1,0 @@
-#include <machine/rtems-bsd-kernel-space.h>
-
-/*-
- * Copyright (c) 2015-2016 Yandex LLC
- * Copyright (c) 2015-2016 Andrey V. Elsukov <ae@FreeBSD.org>
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
- */
-
-#include <rtems/bsd/local/opt_ipfw.h>
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/counter.h>
-#include <sys/errno.h>
-#include <sys/kernel.h>
-#include <sys/lock.h>
-#include <sys/mbuf.h>
-#include <sys/module.h>
-#include <sys/rmlock.h>
-#include <sys/rwlock.h>
-#include <sys/socket.h>
-#include <sys/queue.h>
-
-#include <net/if.h>
-#include <net/if_var.h>
-#include <net/if_pflog.h>
-#include <net/pfil.h>
-#include <net/netisr.h>
-#include <net/route.h>
-
-#include <netinet/in.h>
-#include <netinet/ip.h>
-#include <netinet/ip_var.h>
-#include <netinet/ip_fw.h>
-#include <netinet/ip6.h>
-#include <netinet/icmp6.h>
-#include <netinet/ip_icmp.h>
-#include <netinet/tcp.h>
-#include <netinet/udp.h>
-#include <netinet6/in6_var.h>
-#include <netinet6/ip6_var.h>
-
-#include <netpfil/pf/pf.h>
-#include <netpfil/ipfw/ip_fw_private.h>
-#include <netpfil/ipfw/nat64/ip_fw_nat64.h>
-#include <netpfil/ipfw/nat64/nat64_translate.h>
-#include <machine/in_cksum.h>
-
-static void
-nat64_log(struct pfloghdr *logdata, struct mbuf *m, sa_family_t family)
-{
-
-	logdata->dir = PF_OUT;
-	logdata->af = family;
-	ipfw_bpf_mtap2(logdata, PFLOG_HDRLEN, m);
-}
-#ifdef IPFIREWALL_NAT64_DIRECT_OUTPUT
-static NAT64NOINLINE struct sockaddr* nat64_find_route4(struct route *ro,
-    in_addr_t dest, struct mbuf *m);
-static NAT64NOINLINE struct sockaddr* nat64_find_route6(struct route_in6 *ro,
-    struct in6_addr *dest, struct mbuf *m);
-
-static NAT64NOINLINE int
-nat64_output(struct ifnet *ifp, struct mbuf *m,
-    struct sockaddr *dst, struct route *ro, nat64_stats_block *stats,
-    void *logdata)
-{
-	int error;
-
-	if (logdata != NULL)
-		nat64_log(logdata, m, dst->sa_family);
-	error = (*ifp->if_output)(ifp, m, dst, ro);
-	if (error != 0)
-		NAT64STAT_INC(stats, oerrors);
-	return (error);
-}
-
-static NAT64NOINLINE int
-nat64_output_one(struct mbuf *m, nat64_stats_block *stats, void *logdata)
-{
-	struct route_in6 ro6;
-	struct route ro4, *ro;
-	struct sockaddr *dst;
-	struct ifnet *ifp;
-	struct ip6_hdr *ip6;
-	struct ip *ip4;
-	int error;
-
-	ip4 = mtod(m, struct ip *);
-	switch (ip4->ip_v) {
-	case IPVERSION:
-		ro = &ro4;
-		dst = nat64_find_route4(&ro4, ip4->ip_dst.s_addr, m);
-		if (dst == NULL)
-			NAT64STAT_INC(stats, noroute4);
-		break;
-	case (IPV6_VERSION >> 4):
-		ip6 = (struct ip6_hdr *)ip4;
-		ro = (struct route *)&ro6;
-		dst = nat64_find_route6(&ro6, &ip6->ip6_dst, m);
-		if (dst == NULL)
-			NAT64STAT_INC(stats, noroute6);
-		break;
-	default:
-		m_freem(m);
-		NAT64STAT_INC(stats, dropped);
-		DPRINTF(DP_DROPS, "dropped due to unknown IP version");
-		return (EAFNOSUPPORT);
-	}
-	if (dst == NULL) {
-		FREE_ROUTE(ro);
-		m_freem(m);
-		return (EHOSTUNREACH);
-	}
-	if (logdata != NULL)
-		nat64_log(logdata, m, dst->sa_family);
-	ifp = ro->ro_rt->rt_ifp;
-	error = (*ifp->if_output)(ifp, m, dst, ro);
-	if (error != 0)
-		NAT64STAT_INC(stats, oerrors);
-	FREE_ROUTE(ro);
-	return (error);
-}
-#else /* !IPFIREWALL_NAT64_DIRECT_OUTPUT */
-static NAT64NOINLINE int
-nat64_output(struct ifnet *ifp, struct mbuf *m,
-    struct sockaddr *dst, struct route *ro, nat64_stats_block *stats,
-    void *logdata)
-{
-	struct ip *ip4;
-	int ret, af;
-
-	ip4 = mtod(m, struct ip *);
-	switch (ip4->ip_v) {
-	case IPVERSION:
-		af = AF_INET;
-		ret = NETISR_IP;
-		break;
-	case (IPV6_VERSION >> 4):
-		af = AF_INET6;
-		ret = NETISR_IPV6;
-		break;
-	default:
-		m_freem(m);
-		NAT64STAT_INC(stats, dropped);
-		DPRINTF(DP_DROPS, "unknown IP version");
-		return (EAFNOSUPPORT);
-	}
-	if (logdata != NULL)
-		nat64_log(logdata, m, af);
-	ret = netisr_queue(ret, m);
-	if (ret != 0)
-		NAT64STAT_INC(stats, oerrors);
-	return (ret);
-}
-
-static NAT64NOINLINE int
-nat64_output_one(struct mbuf *m, nat64_stats_block *stats, void *logdata)
-{
-
-	return (nat64_output(NULL, m, NULL, NULL, stats, logdata));
-}
-#endif /* !IPFIREWALL_NAT64_DIRECT_OUTPUT */
-
-
-#if 0
-void print_ipv6_header(struct ip6_hdr *ip6, char *buf, size_t bufsize);
-
-void
-print_ipv6_header(struct ip6_hdr *ip6, char *buf, size_t bufsize)
-{
-	char sbuf[INET6_ADDRSTRLEN], dbuf[INET6_ADDRSTRLEN];
-
-	inet_ntop(AF_INET6, &ip6->ip6_src, sbuf, sizeof(sbuf));
-	inet_ntop(AF_INET6, &ip6->ip6_dst, dbuf, sizeof(dbuf));
-	snprintf(buf, bufsize, "%s -> %s %d", sbuf, dbuf, ip6->ip6_nxt);
-}
-
-
-static NAT64NOINLINE int
-nat64_embed_ip4(struct nat64_cfg *cfg, in_addr_t ia, struct in6_addr *ip6)
-{
-
-	/* assume the prefix is properly filled with zeros */
-	bcopy(&cfg->prefix, ip6, sizeof(*ip6));
-	switch (cfg->plen) {
-	case 32:
-	case 96:
-		ip6->s6_addr32[cfg->plen / 32] = ia;
-		break;
-	case 40:
-	case 48:
-	case 56:
-#if BYTE_ORDER == BIG_ENDIAN
-		ip6->s6_addr32[1] = cfg->prefix.s6_addr32[1] |
-		    (ia >> (cfg->plen % 32));
-		ip6->s6_addr32[2] = ia << (24 - cfg->plen % 32);
-#elif BYTE_ORDER == LITTLE_ENDIAN
-		ip6->s6_addr32[1] = cfg->prefix.s6_addr32[1] |
-		    (ia << (cfg->plen % 32));
-		ip6->s6_addr32[2] = ia >> (24 - cfg->plen % 32);
-#endif
-		break;
-	case 64:
-#if BYTE_ORDER == BIG_ENDIAN
-		ip6->s6_addr32[2] = ia >> 8;
-		ip6->s6_addr32[3] = ia << 24;
-#elif BYTE_ORDER == LITTLE_ENDIAN
-		ip6->s6_addr32[2] = ia << 8;
-		ip6->s6_addr32[3] = ia >> 24;
-#endif
-		break;
-	default:
-		return (0);
-	};
-	ip6->s6_addr8[8] = 0;
-	return (1);
-}
-
-static NAT64NOINLINE in_addr_t
-nat64_extract_ip4(struct in6_addr *ip6, int plen)
-{
-	in_addr_t ia;
-
-	/*
-	 * According to RFC 6052 p2.2:
-	 * IPv4-embedded IPv6 addresses are composed of a variable-length
-	 * prefix, the embedded IPv4 address, and a variable length suffix.
-	 * The suffix bits are reserved for future extensions and SHOULD
-	 * be set to zero.
-	 */
-	switch (plen) {
-	case 32:
-		if (ip6->s6_addr32[3] != 0 || ip6->s6_addr32[2] != 0)
-			goto badip6;
-		break;
-	case 40:
-		if (ip6->s6_addr32[3] != 0 ||
-		    (ip6->s6_addr32[2] & htonl(0xff00ffff)) != 0)
-			goto badip6;
-		break;
-	case 48:
-		if (ip6->s6_addr32[3] != 0 ||
-		    (ip6->s6_addr32[2] & htonl(0xff0000ff)) != 0)
-			goto badip6;
-		break;
-	case 56:
-		if (ip6->s6_addr32[3] != 0 || ip6->s6_addr8[8] != 0)
-			goto badip6;
-		break;
-	case 64:
-		if (ip6->s6_addr8[8] != 0 ||
-		    (ip6->s6_addr32[3] & htonl(0x00ffffff)) != 0)
-			goto badip6;
-	};
-	switch (plen) {
-	case 32:
-	case 96:
-		ia = ip6->s6_addr32[plen / 32];
-		break;
-	case 40:
-	case 48:
-	case 56:
-#if BYTE_ORDER == BIG_ENDIAN
-		ia = (ip6->s6_addr32[1] << (plen % 32)) |
-		    (ip6->s6_addr32[2] >> (24 - plen % 32));
-#elif BYTE_ORDER == LITTLE_ENDIAN
-		ia = (ip6->s6_addr32[1] >> (plen % 32)) |
-		    (ip6->s6_addr32[2] << (24 - plen % 32));
-#endif
-		break;
-	case 64:
-#if BYTE_ORDER == BIG_ENDIAN
-		ia = (ip6->s6_addr32[2] << 8) | (ip6->s6_addr32[3] >> 24);
-#elif BYTE_ORDER == LITTLE_ENDIAN
-		ia = (ip6->s6_addr32[2] >> 8) | (ip6->s6_addr32[3] << 24);
-#endif
-		break;
-	default:
-		return (0);
-	};
-	if (nat64_check_ip4(ia) != 0 ||
-	    nat64_check_private_ip4(ia) != 0)
-		goto badip4;
-
-	return (ia);
-badip4:
-	DPRINTF(DP_GENERIC, "invalid destination address: %08x", ia);
-	return (0);
-badip6:
-	DPRINTF(DP_GENERIC, "invalid IPv4-embedded IPv6 address");
-	return (0);
-}
-#endif
-
-/*
- * According to RFC 1624 the equation for incremental checksum update is:
- *	HC' = ~(~HC + ~m + m')	--	[Eqn. 3]
- *	HC' = HC - ~m - m'	--	[Eqn. 4]
- * So, when we are replacing IPv4 addresses to IPv6, we
- * can assume, that new bytes previously were zeros, and vise versa -
- * when we replacing IPv6 addresses to IPv4, now unused bytes become
- * zeros. The payload length in pseudo header has bigger size, but one
- * half of it should be zero. Using the equation 4 we get:
- *	HC' = HC - (~m0 + m0')	-- m0 is first changed word
- *	HC' = (HC - (~m0 + m0')) - (~m1 + m1')	-- m1 is second changed word
- *	HC' = HC - ~m0 - m0' - ~m1 - m1' - ... =
- *	  = HC - sum(~m[i] + m'[i])
- *
- * The function result should be used as follows:
- *	IPv6 to IPv4:	HC' = cksum_add(HC, result)
- *	IPv4 to IPv6:	HC' = cksum_add(HC, ~result)
- */
-static NAT64NOINLINE uint16_t
-nat64_cksum_convert(struct ip6_hdr *ip6, struct ip *ip)
-{
-	uint32_t sum;
-	uint16_t *p;
-
-	sum = ~ip->ip_src.s_addr >> 16;
-	sum += ~ip->ip_src.s_addr & 0xffff;
-	sum += ~ip->ip_dst.s_addr >> 16;
-	sum += ~ip->ip_dst.s_addr & 0xffff;
-
-	for (p = (uint16_t *)&ip6->ip6_src;
-	    p < (uint16_t *)(&ip6->ip6_src + 2); p++)
-		sum += *p;
-
-	while (sum >> 16)
-		sum = (sum & 0xffff) + (sum >> 16);
-	return (sum);
-}
-
-#if __FreeBSD_version < 1100000
-#define	ip_fillid(ip)		(ip)->ip_id = ip_newid()
-#endif
-static NAT64NOINLINE void
-nat64_init_ip4hdr(const struct ip6_hdr *ip6, const struct ip6_frag *frag,
-    uint16_t plen, uint8_t proto, struct ip *ip)
-{
-
-	/* assume addresses are already initialized */
-	ip->ip_v = IPVERSION;
-	ip->ip_hl = sizeof(*ip) >> 2;
-	ip->ip_tos = (ntohl(ip6->ip6_flow) >> 20) & 0xff;
-	ip->ip_len = htons(sizeof(*ip) + plen);
-#ifdef IPFIREWALL_NAT64_DIRECT_OUTPUT
-	ip->ip_ttl = ip6->ip6_hlim - IPV6_HLIMDEC;
-#else
-	/* Forwarding code will decrement TTL. */
-	ip->ip_ttl = ip6->ip6_hlim;
-#endif
-	ip->ip_sum = 0;
-	ip->ip_p = (proto == IPPROTO_ICMPV6) ? IPPROTO_ICMP: proto;
-	ip_fillid(ip);
-	if (frag != NULL) {
-		ip->ip_off = htons(ntohs(frag->ip6f_offlg) >> 3);
-		if (frag->ip6f_offlg & IP6F_MORE_FRAG)
-			ip->ip_off |= htons(IP_MF);
-	} else {
-		ip->ip_off = htons(IP_DF);
-	}
-	ip->ip_sum = in_cksum_hdr(ip);
-}
-
-#define	FRAGSZ(mtu) ((mtu) - sizeof(struct ip6_hdr) - sizeof(struct ip6_frag))
-static NAT64NOINLINE int
-nat64_fragment6(nat64_stats_block *stats, struct ip6_hdr *ip6, struct mbufq *mq,
-    struct mbuf *m, uint32_t mtu, uint16_t ip_id, uint16_t ip_off)
-{
-	struct ip6_frag ip6f;
-	struct mbuf *n;
-	uint16_t hlen, len, offset;
-	int plen;
-
-	plen = ntohs(ip6->ip6_plen);
-	hlen = sizeof(struct ip6_hdr);
-
-	/* Fragmentation isn't needed */
-	if (ip_off == 0 && plen <= mtu - hlen) {
-		M_PREPEND(m, hlen, M_NOWAIT);
-		if (m == NULL) {
-			NAT64STAT_INC(stats, nomem);
-			return (ENOMEM);
-		}
-		bcopy(ip6, mtod(m, void *), hlen);
-		if (mbufq_enqueue(mq, m) != 0) {
-			m_freem(m);
-			NAT64STAT_INC(stats, dropped);
-			DPRINTF(DP_DROPS, "dropped due to mbufq overflow");
-			return (ENOBUFS);
-		}
-		return (0);
-	}
-
-	hlen += sizeof(struct ip6_frag);
-	ip6f.ip6f_reserved = 0;
-	ip6f.ip6f_nxt = ip6->ip6_nxt;
-	ip6->ip6_nxt = IPPROTO_FRAGMENT;
-	if (ip_off != 0) {
-		/*
-		 * We have got an IPv4 fragment.
-		 * Use offset value and ip_id from original fragment.
-		 */
-		ip6f.ip6f_ident = htonl(ntohs(ip_id));
-		offset = (ntohs(ip_off) & IP_OFFMASK) << 3;
-		NAT64STAT_INC(stats, ifrags);
-	} else {
-		/* The packet size exceeds interface MTU */
-		ip6f.ip6f_ident = htonl(ip6_randomid());
-		offset = 0; /* First fragment*/
-	}
-	while (plen > 0 && m != NULL) {
-		n = NULL;
-		len = FRAGSZ(mtu) & ~7;
-		if (len > plen)
-			len = plen;
-		ip6->ip6_plen = htons(len + sizeof(ip6f));
-		ip6f.ip6f_offlg = ntohs(offset);
-		if (len < plen || (ip_off & htons(IP_MF)) != 0)
-			ip6f.ip6f_offlg |= IP6F_MORE_FRAG;
-		offset += len;
-		plen -= len;
-		if (plen > 0) {
-			n = m_split(m, len, M_NOWAIT);
-			if (n == NULL)
-				goto fail;
-		}
-		M_PREPEND(m, hlen, M_NOWAIT);
-		if (m == NULL)
-			goto fail;
-		bcopy(ip6, mtod(m, void *), sizeof(struct ip6_hdr));
-		bcopy(&ip6f, mtodo(m, sizeof(struct ip6_hdr)),
-		    sizeof(struct ip6_frag));
-		if (mbufq_enqueue(mq, m) != 0)
-			goto fail;
-		m = n;
-	}
-	NAT64STAT_ADD(stats, ofrags, mbufq_len(mq));
-	return (0);
-fail:
-	if (m != NULL)
-		m_freem(m);
-	if (n != NULL)
-		m_freem(n);
-	mbufq_drain(mq);
-	NAT64STAT_INC(stats, nomem);
-	return (ENOMEM);
-}
-
-#if __FreeBSD_version < 1100000
-#define	rt_expire	rt_rmx.rmx_expire
-#define	rt_mtu		rt_rmx.rmx_mtu
-#endif
-static NAT64NOINLINE struct sockaddr*
-nat64_find_route6(struct route_in6 *ro, struct in6_addr *dest, struct mbuf *m)
-{
-	struct sockaddr_in6 *dst;
-	struct rtentry *rt;
-
-	bzero(ro, sizeof(*ro));
-	dst = (struct sockaddr_in6 *)&ro->ro_dst;
-	dst->sin6_family = AF_INET6;
-	dst->sin6_len = sizeof(*dst);
-	dst->sin6_addr = *dest;
-	IN6_LOOKUP_ROUTE(ro, M_GETFIB(m));
-	rt = ro->ro_rt;
-	if (rt && (rt->rt_flags & RTF_UP) &&
-	    (rt->rt_ifp->if_flags & IFF_UP) &&
-	    (rt->rt_ifp->if_drv_flags & IFF_DRV_RUNNING)) {
-		if (rt->rt_flags & RTF_GATEWAY)
-			dst = (struct sockaddr_in6 *)rt->rt_gateway;
-	} else
-		return (NULL);
-	if (((rt->rt_flags & RTF_REJECT) &&
-	    (rt->rt_expire == 0 ||
-	    time_uptime < rt->rt_expire)) ||
-	    rt->rt_ifp->if_link_state == LINK_STATE_DOWN)
-		return (NULL);
-	return ((struct sockaddr *)dst);
-}
-
-#define	NAT64_ICMP6_PLEN	64
-static NAT64NOINLINE void
-nat64_icmp6_reflect(struct mbuf *m, uint8_t type, uint8_t code, uint32_t mtu,
-    nat64_stats_block *stats, void *logdata)
-{
-	struct icmp6_hdr *icmp6;
-	struct ip6_hdr *ip6, *oip6;
-	struct mbuf *n;
-	int len, plen;
-
-	len = 0;
-	plen = nat64_getlasthdr(m, &len);
-	if (plen < 0) {
-		DPRINTF(DP_DROPS, "mbuf isn't contigious");
-		goto freeit;
-	}
-	/*
-	 * Do not send ICMPv6 in reply to ICMPv6 errors.
-	 */
-	if (plen == IPPROTO_ICMPV6) {
-		if (m->m_len < len + sizeof(*icmp6)) {
-			DPRINTF(DP_DROPS, "mbuf isn't contigious");
-			goto freeit;
-		}
-		icmp6 = mtodo(m, len);
-		if (icmp6->icmp6_type < ICMP6_ECHO_REQUEST ||
-		    icmp6->icmp6_type == ND_REDIRECT) {
-			DPRINTF(DP_DROPS, "do not send ICMPv6 in reply to "
-			    "ICMPv6 errors");
-			goto freeit;
-		}
-	}
-	/*
-	if (icmp6_ratelimit(&ip6->ip6_src, type, code))
-		goto freeit;
-		*/
-	ip6 = mtod(m, struct ip6_hdr *);
-	switch (type) {
-	case ICMP6_DST_UNREACH:
-	case ICMP6_PACKET_TOO_BIG:
-	case ICMP6_TIME_EXCEEDED:
-	case ICMP6_PARAM_PROB:
-		break;
-	default:
-		goto freeit;
-	}
-	/* Calculate length of ICMPv6 payload */
-	len = (m->m_pkthdr.len > NAT64_ICMP6_PLEN) ? NAT64_ICMP6_PLEN:
-	    m->m_pkthdr.len;
-
-	/* Create new ICMPv6 datagram */
-	plen = len + sizeof(struct icmp6_hdr);
-	n = m_get2(sizeof(struct ip6_hdr) + plen + max_hdr, M_NOWAIT,
-	    MT_HEADER, M_PKTHDR);
-	if (n == NULL) {
-		NAT64STAT_INC(stats, nomem);
-		m_freem(m);
-		return;
-	}
-	/*
-	 * Move pkthdr from original mbuf. We should have initialized some
-	 * fields, because we can reinject this mbuf to netisr and it will
-	 * go trough input path (it requires at least rcvif should be set).
-	 * Also do M_ALIGN() to reduce chances of need to allocate new mbuf
-	 * in the chain, when we will do M_PREPEND() or make some type of
-	 * tunneling.
-	 */
-	m_move_pkthdr(n, m);
-	M_ALIGN(n, sizeof(struct ip6_hdr) + plen + max_hdr);
-
-	n->m_len = n->m_pkthdr.len = sizeof(struct ip6_hdr) + plen;
-	oip6 = mtod(n, struct ip6_hdr *);
-	oip6->ip6_src = ip6->ip6_dst;
-	oip6->ip6_dst = ip6->ip6_src;
-	oip6->ip6_nxt = IPPROTO_ICMPV6;
-	oip6->ip6_flow = 0;
-	oip6->ip6_vfc |= IPV6_VERSION;
-	oip6->ip6_hlim = V_ip6_defhlim;
-	oip6->ip6_plen = htons(plen);
-
-	icmp6 = mtodo(n, sizeof(struct ip6_hdr));
-	icmp6->icmp6_cksum = 0;
-	icmp6->icmp6_type = type;
-	icmp6->icmp6_code = code;
-	icmp6->icmp6_mtu = htonl(mtu);
-
-	m_copydata(m, 0, len, mtodo(n, sizeof(struct ip6_hdr) +
-	    sizeof(struct icmp6_hdr)));
-	icmp6->icmp6_cksum = in6_cksum(n, IPPROTO_ICMPV6,
-	    sizeof(struct ip6_hdr), plen);
-	m_freem(m);
-	nat64_output_one(n, stats, logdata);
-	return;
-freeit:
-	NAT64STAT_INC(stats, dropped);
-	m_freem(m);
-}
-
-static NAT64NOINLINE struct sockaddr*
-nat64_find_route4(struct route *ro, in_addr_t dest, struct mbuf *m)
-{
-	struct sockaddr_in *dst;
-	struct rtentry *rt;
-
-	bzero(ro, sizeof(*ro));
-	dst = (struct sockaddr_in *)&ro->ro_dst;
-	dst->sin_family = AF_INET;
-	dst->sin_len = sizeof(*dst);
-	dst->sin_addr.s_addr = dest;
-	IN_LOOKUP_ROUTE(ro, M_GETFIB(m));
-	rt = ro->ro_rt;
-	if (rt && (rt->rt_flags & RTF_UP) &&
-	    (rt->rt_ifp->if_flags & IFF_UP) &&
-	    (rt->rt_ifp->if_drv_flags & IFF_DRV_RUNNING)) {
-		if (rt->rt_flags & RTF_GATEWAY)
-			dst = (struct sockaddr_in *)rt->rt_gateway;
-	} else
-		return (NULL);
-	if (((rt->rt_flags & RTF_REJECT) &&
-	    (rt->rt_expire == 0 ||
-	    time_uptime < rt->rt_expire)) ||
-	    rt->rt_ifp->if_link_state == LINK_STATE_DOWN)
-		return (NULL);
-	return ((struct sockaddr *)dst);
-}
-
-#define	NAT64_ICMP_PLEN	64
-static NAT64NOINLINE void
-nat64_icmp_reflect(struct mbuf *m, uint8_t type,
-    uint8_t code, uint16_t mtu, nat64_stats_block *stats, void *logdata)
-{
-	struct icmp *icmp;
-	struct ip *ip, *oip;
-	struct mbuf *n;
-	int len, plen;
-
-	ip = mtod(m, struct ip *);
-	/* Do not send ICMP error if packet is not the first fragment */
-	if (ip->ip_off & ~ntohs(IP_MF|IP_DF)) {
-		DPRINTF(DP_DROPS, "not first fragment");
-		goto freeit;
-	}
-	/* Do not send ICMP in reply to ICMP errors */
-	if (ip->ip_p == IPPROTO_ICMP) {
-		if (m->m_len < (ip->ip_hl << 2)) {
-			DPRINTF(DP_DROPS, "mbuf isn't contigious");
-			goto freeit;
-		}
-		icmp = mtodo(m, ip->ip_hl << 2);
-		if (!ICMP_INFOTYPE(icmp->icmp_type)) {
-			DPRINTF(DP_DROPS, "do not send ICMP in reply to "
-			    "ICMP errors");
-			goto freeit;
-		}
-	}
-	switch (type) {
-	case ICMP_UNREACH:
-	case ICMP_TIMXCEED:
-	case ICMP_PARAMPROB:
-		break;
-	default:
-		goto freeit;
-	}
-	/* Calculate length of ICMP payload */
-	len = (m->m_pkthdr.len > NAT64_ICMP_PLEN) ? (ip->ip_hl << 2) + 8:
-	    m->m_pkthdr.len;
-
-	/* Create new ICMPv4 datagram */
-	plen = len + sizeof(struct icmphdr) + sizeof(uint32_t);
-	n = m_get2(sizeof(struct ip) + plen + max_hdr, M_NOWAIT,
-	    MT_HEADER, M_PKTHDR);
-	if (n == NULL) {
-		NAT64STAT_INC(stats, nomem);
-		m_freem(m);
-		return;
-	}
-	m_move_pkthdr(n, m);
-	M_ALIGN(n, sizeof(struct ip) + plen + max_hdr);
-
-	n->m_len = n->m_pkthdr.len = sizeof(struct ip) + plen;
-	oip = mtod(n, struct ip *);
-	oip->ip_v = IPVERSION;
-	oip->ip_hl = sizeof(struct ip) >> 2;
-	oip->ip_tos = 0;
-	oip->ip_len = htons(n->m_pkthdr.len);
-	oip->ip_ttl = V_ip_defttl;
-	oip->ip_p = IPPROTO_ICMP;
-	ip_fillid(oip);
-	oip->ip_off = htons(IP_DF);
-	oip->ip_src = ip->ip_dst;
-	oip->ip_dst = ip->ip_src;
-	oip->ip_sum = 0;
-	oip->ip_sum = in_cksum_hdr(oip);
-
-	icmp = mtodo(n, sizeof(struct ip));
-	icmp->icmp_type = type;
-	icmp->icmp_code = code;
-	icmp->icmp_cksum = 0;
-	icmp->icmp_pmvoid = 0;
-	icmp->icmp_nextmtu = htons(mtu);
-	m_copydata(m, 0, len, mtodo(n, sizeof(struct ip) +
-	    sizeof(struct icmphdr) + sizeof(uint32_t)));
-	icmp->icmp_cksum = in_cksum_skip(n, sizeof(struct ip) + plen,
-	    sizeof(struct ip));
-	m_freem(m);
-	nat64_output_one(n, stats, logdata);
-	return;
-freeit:
-	NAT64STAT_INC(stats, dropped);
-	m_freem(m);
-}
-
-/* Translate ICMP echo request/reply into ICMPv6 */
-static void
-nat64_icmp_handle_echo(struct ip6_hdr *ip6, struct icmp6_hdr *icmp6,
-    uint16_t id, uint8_t type)
-{
-	uint16_t old;
-
-	old = *(uint16_t *)icmp6;	/* save type+code in one word */
-	icmp6->icmp6_type = type;
-	/* Reflect ICMPv6 -> ICMPv4 type translation in the cksum */
-	icmp6->icmp6_cksum = cksum_adjust(icmp6->icmp6_cksum,
-	    old, *(uint16_t *)icmp6);
-	if (id != 0) {
-		old = icmp6->icmp6_id;
-		icmp6->icmp6_id = id;
-		/* Reflect ICMP id translation in the cksum */
-		icmp6->icmp6_cksum = cksum_adjust(icmp6->icmp6_cksum,
-		    old, id);
-	}
-	/* Reflect IPv6 pseudo header in the cksum */
-	icmp6->icmp6_cksum = ~in6_cksum_pseudo(ip6, ntohs(ip6->ip6_plen),
-	    IPPROTO_ICMPV6, ~icmp6->icmp6_cksum);
-}
-
-static NAT64NOINLINE struct mbuf *
-nat64_icmp_translate(struct mbuf *m, struct ip6_hdr *ip6, uint16_t icmpid,
-    int offset, nat64_stats_block *stats)
-{
-	struct ip ip;
-	struct icmp *icmp;
-	struct tcphdr *tcp;
-	struct udphdr *udp;
-	struct ip6_hdr *eip6;
-	struct mbuf *n;
-	uint32_t mtu;
-	int len, hlen, plen;
-	uint8_t type, code;
-
-	if (m->m_len < offset + ICMP_MINLEN)
-		m = m_pullup(m, offset + ICMP_MINLEN);
-	if (m == NULL) {
-		NAT64STAT_INC(stats, nomem);
-		return (m);
-	}
-	mtu = 0;
-	icmp = mtodo(m, offset);
-	/* RFC 7915 p4.2 */
-	switch (icmp->icmp_type) {
-	case ICMP_ECHOREPLY:
-		type = ICMP6_ECHO_REPLY;
-		code = 0;
-		break;
-	case ICMP_UNREACH:
-		type = ICMP6_DST_UNREACH;
-		switch (icmp->icmp_code) {
-		case ICMP_UNREACH_NET:
-		case ICMP_UNREACH_HOST:
-		case ICMP_UNREACH_SRCFAIL:
-		case ICMP_UNREACH_NET_UNKNOWN:
-		case ICMP_UNREACH_HOST_UNKNOWN:
-		case ICMP_UNREACH_TOSNET:
-		case ICMP_UNREACH_TOSHOST:
-			code = ICMP6_DST_UNREACH_NOROUTE;
-			break;
-		case ICMP_UNREACH_PROTOCOL:
-			type = ICMP6_PARAM_PROB;
-			code = ICMP6_PARAMPROB_NEXTHEADER;
-			break;
-		case ICMP_UNREACH_PORT:
-			code = ICMP6_DST_UNREACH_NOPORT;
-			break;
-		case ICMP_UNREACH_NEEDFRAG:
-			type = ICMP6_PACKET_TOO_BIG;
-			code = 0;
-			/* XXX: needs an additional look */
-			mtu = max(IPV6_MMTU, ntohs(icmp->icmp_nextmtu) + 20);
-			break;
-		case ICMP_UNREACH_NET_PROHIB:
-		case ICMP_UNREACH_HOST_PROHIB:
-		case ICMP_UNREACH_FILTER_PROHIB:
-		case ICMP_UNREACH_PRECEDENCE_CUTOFF:
-			code = ICMP6_DST_UNREACH_ADMIN;
-			break;
-		default:
-			DPRINTF(DP_DROPS, "Unsupported ICMP type %d, code %d",
-			    icmp->icmp_type, icmp->icmp_code);
-			goto freeit;
-		}
-		break;
-	case ICMP_TIMXCEED:
-		type = ICMP6_TIME_EXCEEDED;
-		code = icmp->icmp_code;
-		break;
-	case ICMP_ECHO:
-		type = ICMP6_ECHO_REQUEST;
-		code = 0;
-		break;
-	case ICMP_PARAMPROB:
-		type = ICMP6_PARAM_PROB;
-		switch (icmp->icmp_code) {
-		case ICMP_PARAMPROB_ERRATPTR:
-		case ICMP_PARAMPROB_LENGTH:
-			code = ICMP6_PARAMPROB_HEADER;
-			switch (icmp->icmp_pptr) {
-			case 0: /* Version/IHL */
-			case 1: /* Type Of Service */
-				mtu = icmp->icmp_pptr;
-				break;
-			case 2: /* Total Length */
-			case 3: mtu = 4; /* Payload Length */
-				break;
-			case 8: /* Time to Live */
-				mtu = 7; /* Hop Limit */
-				break;
-			case 9: /* Protocol */
-				mtu = 6; /* Next Header */
-				break;
-			case 12: /* Source address */
-			case 13:
-			case 14:
-			case 15:
-				mtu = 8;
-				break;
-			case 16: /* Destination address */
-			case 17:
-			case 18:
-			case 19:
-				mtu = 24;
-				break;
-			default: /* Silently drop */
-				DPRINTF(DP_DROPS, "Unsupported ICMP type %d,"
-				    " code %d, pptr %d", icmp->icmp_type,
-				    icmp->icmp_code, icmp->icmp_pptr);
-				goto freeit;
-			}
-			break;
-		default:
-			DPRINTF(DP_DROPS, "Unsupported ICMP type %d,"
-			    " code %d, pptr %d", icmp->icmp_type,
-			    icmp->icmp_code, icmp->icmp_pptr);
-			goto freeit;
-		}
-		break;
-	default:
-		DPRINTF(DP_DROPS, "Unsupported ICMP type %d, code %d",
-		    icmp->icmp_type, icmp->icmp_code);
-		goto freeit;
-	}
-	/*
-	 * For echo request/reply we can use original payload,
-	 * but we need adjust icmp_cksum, because ICMPv6 cksum covers
-	 * IPv6 pseudo header and ICMPv6 types differs from ICMPv4.
-	 */
-	if (type == ICMP6_ECHO_REQUEST || type == ICMP6_ECHO_REPLY) {
-		nat64_icmp_handle_echo(ip6, ICMP6(icmp), icmpid, type);
-		return (m);
-	}
-	/*
-	 * For other types of ICMP messages we need to translate inner
-	 * IPv4 header to IPv6 header.
-	 * Assume ICMP src is the same as payload dst
-	 * E.g. we have ( GWsrc1 , NATIP1 ) in outer header
-	 * and          ( NATIP1, Hostdst1 ) in ICMP copy header.
-	 * In that case, we already have map for NATIP1 and GWsrc1.
-	 * The only thing we need is to copy IPv6 map prefix to
-	 * Hostdst1.
-	 */
-	hlen = offset + ICMP_MINLEN;
-	if (m->m_pkthdr.len < hlen + sizeof(struct ip) + ICMP_MINLEN) {
-		DPRINTF(DP_DROPS, "Message is too short %d",
-		    m->m_pkthdr.len);
-		goto freeit;
-	}
-	m_copydata(m, hlen, sizeof(struct ip), (char *)&ip);
-	if (ip.ip_v != IPVERSION) {
-		DPRINTF(DP_DROPS, "Wrong IP version %d", ip.ip_v);
-		goto freeit;
-	}
-	hlen += ip.ip_hl << 2; /* Skip inner IP header */
-	if (nat64_check_ip4(ip.ip_src.s_addr) != 0 ||
-	    nat64_check_ip4(ip.ip_dst.s_addr) != 0 ||
-	    nat64_check_private_ip4(ip.ip_src.s_addr) != 0 ||
-	    nat64_check_private_ip4(ip.ip_dst.s_addr) != 0) {
-		DPRINTF(DP_DROPS, "IP addresses checks failed %04x -> %04x",
-		    ntohl(ip.ip_src.s_addr), ntohl(ip.ip_dst.s_addr));
-		goto freeit;
-	}
-	if (m->m_pkthdr.len < hlen + ICMP_MINLEN) {
-		DPRINTF(DP_DROPS, "Message is too short %d",
-		    m->m_pkthdr.len);
-		goto freeit;
-	}
-#if 0
-	/*
-	 * Check that inner source matches the outer destination.
-	 * XXX: We need some method to convert IPv4 into IPv6 address here,
-	 *	and compare IPv6 addresses.
-	 */
-	if (ip.ip_src.s_addr != nat64_get_ip4(&ip6->ip6_dst)) {
-		DPRINTF(DP_GENERIC, "Inner source doesn't match destination ",
-		    "%04x vs %04x", ip.ip_src.s_addr,
-		    nat64_get_ip4(&ip6->ip6_dst));
-		goto freeit;
-	}
-#endif
-	/*
-	 * Create new mbuf for ICMPv6 datagram.
-	 * NOTE: len is data length just after inner IP header.
-	 */
-	len = m->m_pkthdr.len - hlen;
-	if (sizeof(struct ip6_hdr) +
-	    sizeof(struct icmp6_hdr) + len > NAT64_ICMP6_PLEN)
-		len = NAT64_ICMP6_PLEN - sizeof(struct icmp6_hdr) -
-		    sizeof(struct ip6_hdr);
-	plen = sizeof(struct icmp6_hdr) + sizeof(struct ip6_hdr) + len;
-	n = m_get2(offset + plen + max_hdr, M_NOWAIT, MT_HEADER, M_PKTHDR);
-	if (n == NULL) {
-		NAT64STAT_INC(stats, nomem);
-		m_freem(m);
-		return (NULL);
-	}
-	m_move_pkthdr(n, m);
-	M_ALIGN(n, offset + plen + max_hdr);
-	n->m_len = n->m_pkthdr.len = offset + plen;
-	/* Adjust ip6_plen in outer header */
-	ip6->ip6_plen = htons(plen);
-	/* Construct new inner IPv6 header */
-	eip6 = mtodo(n, offset + sizeof(struct icmp6_hdr));
-	eip6->ip6_src = ip6->ip6_dst;
-	/* Use the fact that we have single /96 prefix for IPv4 map */
-	eip6->ip6_dst = ip6->ip6_src;
-	nat64_set_ip4(&eip6->ip6_dst, ip.ip_dst.s_addr);
-
-	eip6->ip6_flow = htonl(ip.ip_tos << 20);
-	eip6->ip6_vfc |= IPV6_VERSION;
-	eip6->ip6_hlim = ip.ip_ttl;
-	eip6->ip6_plen = htons(ntohs(ip.ip_len) - (ip.ip_hl << 2));
-	eip6->ip6_nxt = (ip.ip_p == IPPROTO_ICMP) ? IPPROTO_ICMPV6: ip.ip_p;
-	m_copydata(m, hlen, len, (char *)(eip6 + 1));
-	/*
-	 * We need to translate source port in the inner ULP header,
-	 * and adjust ULP checksum.
-	 */
-	switch (ip.ip_p) {
-	case IPPROTO_TCP:
-		if (len < offsetof(struct tcphdr, th_sum))
-			break;
-		tcp = TCP(eip6 + 1);
-		if (icmpid != 0) {
-			tcp->th_sum = cksum_adjust(tcp->th_sum,
-			    tcp->th_sport, icmpid);
-			tcp->th_sport = icmpid;
-		}
-		tcp->th_sum = cksum_add(tcp->th_sum,
-		    ~nat64_cksum_convert(eip6, &ip));
-		break;
-	case IPPROTO_UDP:
-		if (len < offsetof(struct udphdr, uh_sum))
-			break;
-		udp = UDP(eip6 + 1);
-		if (icmpid != 0) {
-			udp->uh_sum = cksum_adjust(udp->uh_sum,
-			    udp->uh_sport, icmpid);
-			udp->uh_sport = icmpid;
-		}
-		udp->uh_sum = cksum_add(udp->uh_sum,
-		    ~nat64_cksum_convert(eip6, &ip));
-		break;
-	case IPPROTO_ICMP:
-		/*
-		 * Check if this is an ICMP error message for echo request
-		 * that we sent. I.e. ULP in the data containing invoking
-		 * packet is IPPROTO_ICMP and its type is ICMP_ECHO.
-		 */
-		icmp = (struct icmp *)(eip6 + 1);
-		if (icmp->icmp_type != ICMP_ECHO) {
-			m_freem(n);
-			goto freeit;
-		}
-		/*
-		 * For our client this original datagram should looks
-		 * like it was ICMPv6 datagram with type ICMP6_ECHO_REQUEST.
-		 * Thus we need adjust icmp_cksum and convert type from
-		 * ICMP_ECHO to ICMP6_ECHO_REQUEST.
-		 */
-		nat64_icmp_handle_echo(eip6, ICMP6(icmp), icmpid,
-		    ICMP6_ECHO_REQUEST);
-	}
-	m_freem(m);
-	/* Convert ICMPv4 into ICMPv6 header */
-	icmp = mtodo(n, offset);
-	ICMP6(icmp)->icmp6_type = type;
-	ICMP6(icmp)->icmp6_code = code;
-	ICMP6(icmp)->icmp6_mtu = htonl(mtu);
-	ICMP6(icmp)->icmp6_cksum = 0;
-	ICMP6(icmp)->icmp6_cksum = cksum_add(
-	    ~in6_cksum_pseudo(ip6, plen, IPPROTO_ICMPV6, 0),
-	    in_cksum_skip(n, n->m_pkthdr.len, offset));
-	return (n);
-freeit:
-	m_freem(m);
-	NAT64STAT_INC(stats, dropped);
-	return (NULL);
-}
-
-int
-nat64_getlasthdr(struct mbuf *m, int *offset)
-{
-	struct ip6_hdr *ip6;
-	struct ip6_hbh *hbh;
-	int proto, hlen;
-
-	if (offset != NULL)
-		hlen = *offset;
-	else
-		hlen = 0;
-
-	if (m->m_len < hlen + sizeof(*ip6))
-		return (-1);
-
-	ip6 = mtodo(m, hlen);
-	hlen += sizeof(*ip6);
-	proto = ip6->ip6_nxt;
-	/* Skip extension headers */
-	while (proto == IPPROTO_HOPOPTS || proto == IPPROTO_ROUTING ||
-	    proto == IPPROTO_DSTOPTS) {
-		hbh = mtodo(m, hlen);
-		/*
-		 * We expect mbuf has contigious data up to
-		 * upper level header.
-		 */
-		if (m->m_len < hlen)
-			return (-1);
-		/*
-		 * We doesn't support Jumbo payload option,
-		 * so return error.
-		 */
-		if (proto == IPPROTO_HOPOPTS && ip6->ip6_plen == 0)
-			return (-1);
-		proto = hbh->ip6h_nxt;
-		hlen += hbh->ip6h_len << 3;
-	}
-	if (offset != NULL)
-		*offset = hlen;
-	return (proto);
-}
-
-int
-nat64_do_handle_ip4(struct mbuf *m, struct in6_addr *saddr,
-    struct in6_addr *daddr, uint16_t lport, nat64_stats_block *stats,
-    void *logdata)
-{
-	struct route_in6 ro;
-	struct ip6_hdr ip6;
-	struct ifnet *ifp;
-	struct ip *ip;
-	struct mbufq mq;
-	struct sockaddr *dst;
-	uint32_t mtu;
-	uint16_t ip_id, ip_off;
-	uint16_t *csum;
-	int plen, hlen;
-	uint8_t proto;
-
-	ip = mtod(m, struct ip*);
-
-	if (ip->ip_ttl <= IPTTLDEC) {
-		nat64_icmp_reflect(m, ICMP_TIMXCEED,
-		    ICMP_TIMXCEED_INTRANS, 0, stats, logdata);
-		return (NAT64RETURN);
-	}
-
-	ip6.ip6_dst = *daddr;
-	ip6.ip6_src = *saddr;
-
-	hlen = ip->ip_hl << 2;
-	plen = ntohs(ip->ip_len) - hlen;
-	proto = ip->ip_p;
-
-	/* Save ip_id and ip_off, both are in network byte order */
-	ip_id = ip->ip_id;
-	ip_off = ip->ip_off & htons(IP_OFFMASK | IP_MF);
-
-	/* Fragment length must be multiple of 8 octets */
-	if ((ip->ip_off & htons(IP_MF)) != 0 && (plen & 0x7) != 0) {
-		nat64_icmp_reflect(m, ICMP_PARAMPROB,
-		    ICMP_PARAMPROB_LENGTH, 0, stats, logdata);
-		return (NAT64RETURN);
-	}
-	/* Fragmented ICMP is unsupported */
-	if (proto == IPPROTO_ICMP && ip_off != 0) {
-		DPRINTF(DP_DROPS, "dropped due to fragmented ICMP");
-		NAT64STAT_INC(stats, dropped);
-		return (NAT64MFREE);
-	}
-
-	dst = nat64_find_route6(&ro, &ip6.ip6_dst, m);
-	if (dst == NULL) {
-		FREE_ROUTE(&ro);
-		NAT64STAT_INC(stats, noroute6);
-		nat64_icmp_reflect(m, ICMP_UNREACH, ICMP_UNREACH_HOST, 0,
-		    stats, logdata);
-		return (NAT64RETURN);
-	}
-	ifp = ro.ro_rt->rt_ifp;
-	if (ro.ro_rt->rt_mtu != 0)
-		mtu = min(ro.ro_rt->rt_mtu, ifp->if_mtu);
-	else
-		mtu = ifp->if_mtu;
-	if (mtu < plen + sizeof(ip6) && (ip->ip_off & htons(IP_DF)) != 0) {
-		FREE_ROUTE(&ro);
-		nat64_icmp_reflect(m, ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG,
-		    FRAGSZ(mtu) + sizeof(struct ip), stats, logdata);
-		return (NAT64RETURN);
-	}
-
-	ip6.ip6_flow = htonl(ip->ip_tos << 20);
-	ip6.ip6_vfc |= IPV6_VERSION;
-#ifdef IPFIREWALL_NAT64_DIRECT_OUTPUT
-	ip6.ip6_hlim = ip->ip_ttl - IPTTLDEC;
-#else
-	/* Forwarding code will decrement HLIM. */
-	ip6.ip6_hlim = ip->ip_ttl;
-#endif
-	ip6.ip6_plen = htons(plen);
-	ip6.ip6_nxt = (proto == IPPROTO_ICMP) ? IPPROTO_ICMPV6: proto;
-	/* Convert checksums. */
-	switch (proto) {
-	case IPPROTO_TCP:
-		csum = &TCP(mtodo(m, hlen))->th_sum;
-		if (lport != 0) {
-			struct tcphdr *tcp = TCP(mtodo(m, hlen));
-			*csum = cksum_adjust(*csum, tcp->th_dport, lport);
-			tcp->th_dport = lport;
-		}
-		*csum = cksum_add(*csum, ~nat64_cksum_convert(&ip6, ip));
-		break;
-	case IPPROTO_UDP:
-		csum = &UDP(mtodo(m, hlen))->uh_sum;
-		if (lport != 0) {
-			struct udphdr *udp = UDP(mtodo(m, hlen));
-			*csum = cksum_adjust(*csum, udp->uh_dport, lport);
-			udp->uh_dport = lport;
-		}
-		*csum = cksum_add(*csum, ~nat64_cksum_convert(&ip6, ip));
-		break;
-	case IPPROTO_ICMP:
-		m = nat64_icmp_translate(m, &ip6, lport, hlen, stats);
-		if (m == NULL) {
-			FREE_ROUTE(&ro);
-			/* stats already accounted */
-			return (NAT64RETURN);
-		}
-	}
-
-	m_adj(m, hlen);
-	mbufq_init(&mq, 255);
-	nat64_fragment6(stats, &ip6, &mq, m, mtu, ip_id, ip_off);
-	while ((m = mbufq_dequeue(&mq)) != NULL) {
-		if (nat64_output(ifp, m, dst, (struct route *)&ro, stats,
-		    logdata) != 0)
-			break;
-		NAT64STAT_INC(stats, opcnt46);
-	}
-	mbufq_drain(&mq);
-	FREE_ROUTE(&ro);
-	return (NAT64RETURN);
-}
-
-int
-nat64_handle_icmp6(struct mbuf *m, int hlen, uint32_t aaddr, uint16_t aport,
-    nat64_stats_block *stats, void *logdata)
-{
-	struct ip ip;
-	struct icmp6_hdr *icmp6;
-	struct ip6_frag *ip6f;
-	struct ip6_hdr *ip6, *ip6i;
-	uint32_t mtu;
-	int plen, proto;
-	uint8_t type, code;
-
-	if (hlen == 0) {
-		ip6 = mtod(m, struct ip6_hdr *);
-		if (nat64_check_ip6(&ip6->ip6_src) != 0 ||
-		    nat64_check_ip6(&ip6->ip6_dst) != 0)
-			return (NAT64SKIP);
-
-		proto = nat64_getlasthdr(m, &hlen);
-		if (proto != IPPROTO_ICMPV6) {
-			DPRINTF(DP_DROPS,
-			    "dropped due to mbuf isn't contigious");
-			NAT64STAT_INC(stats, dropped);
-			return (NAT64MFREE);
-		}
-	}
-
-	/*
-	 * Translate ICMPv6 type and code to ICMPv4 (RFC7915).
-	 * NOTE: ICMPv6 echo handled by nat64_do_handle_ip6().
-	 */
-	icmp6 = mtodo(m, hlen);
-	mtu = 0;
-	switch (icmp6->icmp6_type) {
-	case ICMP6_DST_UNREACH:
-		type = ICMP_UNREACH;
-		switch (icmp6->icmp6_code) {
-		case ICMP6_DST_UNREACH_NOROUTE:
-		case ICMP6_DST_UNREACH_BEYONDSCOPE:
-		case ICMP6_DST_UNREACH_ADDR:
-			code = ICMP_UNREACH_HOST;
-			break;
-		case ICMP6_DST_UNREACH_ADMIN:
-			code = ICMP_UNREACH_HOST_PROHIB;
-			break;
-		case ICMP6_DST_UNREACH_NOPORT:
-			code = ICMP_UNREACH_PORT;
-			break;
-		default:
-			DPRINTF(DP_DROPS, "Unsupported ICMPv6 type %d,"
-			    " code %d", icmp6->icmp6_type,
-			    icmp6->icmp6_code);
-			NAT64STAT_INC(stats, dropped);
-			return (NAT64MFREE);
-		}
-		break;
-	case ICMP6_PACKET_TOO_BIG:
-		type = ICMP_UNREACH;
-		code = ICMP_UNREACH_NEEDFRAG;
-		mtu = ntohl(icmp6->icmp6_mtu);
-		if (mtu < IPV6_MMTU) {
-			DPRINTF(DP_DROPS, "Wrong MTU %d in ICMPv6 type %d,"
-			    " code %d", mtu, icmp6->icmp6_type,
-			    icmp6->icmp6_code);
-			NAT64STAT_INC(stats, dropped);
-			return (NAT64MFREE);
-		}
-		/*
-		 * Adjust MTU to reflect difference between
-		 * IPv6 an IPv4 headers.
-		 */
-		mtu -= sizeof(struct ip6_hdr) - sizeof(struct ip);
-		break;
-	case ICMP6_TIME_EXCEEDED:
-		type = ICMP_TIMXCEED;
-		code = icmp6->icmp6_code;
-		break;
-	case ICMP6_PARAM_PROB:
-		switch (icmp6->icmp6_code) {
-		case ICMP6_PARAMPROB_HEADER:
-			type = ICMP_PARAMPROB;
-			code = ICMP_PARAMPROB_ERRATPTR;
-			mtu = ntohl(icmp6->icmp6_pptr);
-			switch (mtu) {
-			case 0: /* Version/Traffic Class */
-			case 1: /* Traffic Class/Flow Label */
-				break;
-			case 4: /* Payload Length */
-			case 5:
-				mtu = 2;
-				break;
-			case 6: /* Next Header */
-				mtu = 9;
-				break;
-			case 7: /* Hop Limit */
-				mtu = 8;
-				break;
-			default:
-				if (mtu >= 8 && mtu <= 23) {
-					mtu = 12; /* Source address */
-					break;
-				}
-				if (mtu >= 24 && mtu <= 39) {
-					mtu = 16; /* Destination address */
-					break;
-				}
-				DPRINTF(DP_DROPS, "Unsupported ICMPv6 type %d,"
-				    " code %d, pptr %d", icmp6->icmp6_type,
-				    icmp6->icmp6_code, mtu);
-				NAT64STAT_INC(stats, dropped);
-				return (NAT64MFREE);
-			}
-		case ICMP6_PARAMPROB_NEXTHEADER:
-			type = ICMP_UNREACH;
-			code = ICMP_UNREACH_PROTOCOL;
-			break;
-		default:
-			DPRINTF(DP_DROPS, "Unsupported ICMPv6 type %d,"
-			    " code %d, pptr %d", icmp6->icmp6_type,
-			    icmp6->icmp6_code, ntohl(icmp6->icmp6_pptr));
-			NAT64STAT_INC(stats, dropped);
-			return (NAT64MFREE);
-		}
-		break;
-	default:
-		DPRINTF(DP_DROPS, "Unsupported ICMPv6 type %d, code %d",
-		    icmp6->icmp6_type, icmp6->icmp6_code);
-		NAT64STAT_INC(stats, dropped);
-		return (NAT64MFREE);
-	}
-
-	hlen += sizeof(struct icmp6_hdr);
-	if (m->m_pkthdr.len < hlen + sizeof(struct ip6_hdr) + ICMP_MINLEN) {
-		NAT64STAT_INC(stats, dropped);
-		DPRINTF(DP_DROPS, "Message is too short %d",
-		    m->m_pkthdr.len);
-		return (NAT64MFREE);
-	}
-	/*
-	 * We need at least ICMP_MINLEN bytes of original datagram payload
-	 * to generate ICMP message. It is nice that ICMP_MINLEN is equal
-	 * to sizeof(struct ip6_frag). So, if embedded datagram had a fragment
-	 * header we will not have to do m_pullup() again.
-	 *
-	 * What we have here:
-	 * Outer header: (IPv6iGW, v4mapPRefix+v4exthost)
-	 * Inner header: (v4mapPRefix+v4host, IPv6iHost) [sport, dport]
-	 * We need to translate it to:
-	 *
-	 * Outer header: (alias_host, v4exthost)
-	 * Inner header: (v4exthost, alias_host) [sport, alias_port]
-	 *
-	 * Assume caller function has checked if v4mapPRefix+v4host
-	 * matches configured prefix.
-	 * The only two things we should be provided with are mapping between
-	 * IPv6iHost <> alias_host and between dport and alias_port.
-	 */
-	if (m->m_len < hlen + sizeof(struct ip6_hdr) + ICMP_MINLEN)
-		m = m_pullup(m, hlen + sizeof(struct ip6_hdr) + ICMP_MINLEN);
-	if (m == NULL) {
-		NAT64STAT_INC(stats, nomem);
-		return (NAT64RETURN);
-	}
-	ip6 = mtod(m, struct ip6_hdr *);
-	ip6i = mtodo(m, hlen);
-	ip6f = NULL;
-	proto = ip6i->ip6_nxt;
-	plen = ntohs(ip6i->ip6_plen);
-	hlen += sizeof(struct ip6_hdr);
-	if (proto == IPPROTO_FRAGMENT) {
-		if (m->m_pkthdr.len < hlen + sizeof(struct ip6_frag) +
-		    ICMP_MINLEN)
-			goto fail;
-		ip6f = mtodo(m, hlen);
-		proto = ip6f->ip6f_nxt;
-		plen -= sizeof(struct ip6_frag);
-		hlen += sizeof(struct ip6_frag);
-		/* Ajust MTU to reflect frag header size */
-		if (type == ICMP_UNREACH && code == ICMP_UNREACH_NEEDFRAG)
-			mtu -= sizeof(struct ip6_frag);
-	}
-	if (proto != IPPROTO_TCP && proto != IPPROTO_UDP) {
-		DPRINTF(DP_DROPS, "Unsupported proto %d in the inner header",
-		    proto);
-		goto fail;
-	}
-	if (nat64_check_ip6(&ip6i->ip6_src) != 0 ||
-	    nat64_check_ip6(&ip6i->ip6_dst) != 0) {
-		DPRINTF(DP_DROPS, "Inner addresses do not passes the check");
-		goto fail;
-	}
-	/* Check if outer dst is the same as inner src */
-	if (!IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, &ip6i->ip6_src)) {
-		DPRINTF(DP_DROPS, "Inner src doesn't match outer dst");
-		goto fail;
-	}
-
-	/* Now we need to make a fake IPv4 packet to generate ICMP message */
-	ip.ip_dst.s_addr = aaddr;
-	ip.ip_src.s_addr = nat64_get_ip4(&ip6i->ip6_src);
-	/* XXX: Make fake ulp header */
-#ifdef IPFIREWALL_NAT64_DIRECT_OUTPUT
-	ip6i->ip6_hlim += IPV6_HLIMDEC; /* init_ip4hdr will decrement it */
-#endif
-	nat64_init_ip4hdr(ip6i, ip6f, plen, proto, &ip);
-	m_adj(m, hlen - sizeof(struct ip));
-	bcopy(&ip, mtod(m, void *), sizeof(ip));
-	nat64_icmp_reflect(m, type, code, (uint16_t)mtu, stats, logdata);
-	return (NAT64RETURN);
-fail:
-	/*
-	 * We must call m_freem() because mbuf pointer could be
-	 * changed with m_pullup().
-	 */
-	m_freem(m);
-	NAT64STAT_INC(stats, dropped);
-	return (NAT64RETURN);
-}
-
-int
-nat64_do_handle_ip6(struct mbuf *m, uint32_t aaddr, uint16_t aport,
-    nat64_stats_block *stats, void *logdata)
-{
-	struct route ro;
-	struct ip ip;
-	struct ifnet *ifp;
-	struct ip6_frag *frag;
-	struct ip6_hdr *ip6;
-	struct icmp6_hdr *icmp6;
-	struct sockaddr *dst;
-	uint16_t *csum;
-	uint32_t mtu;
-	int plen, hlen, proto;
-
-	/*
-	 * XXX: we expect ipfw_chk() did m_pullup() up to upper level
-	 * protocol's headers. Also we skip some checks, that ip6_input(),
-	 * ip6_forward(), ip6_fastfwd() and ipfw_chk() already did.
-	 */
-	ip6 = mtod(m, struct ip6_hdr *);
-	if (nat64_check_ip6(&ip6->ip6_src) != 0 ||
-	    nat64_check_ip6(&ip6->ip6_dst) != 0) {
-		return (NAT64SKIP);
-	}
-
-	/* Starting from this point we must not return zero */
-	ip.ip_src.s_addr = aaddr;
-	if (nat64_check_ip4(ip.ip_src.s_addr) != 0) {
-		DPRINTF(DP_GENERIC, "invalid source address: %08x",
-		    ip.ip_src.s_addr);
-		/* XXX: stats? */
-		return (NAT64MFREE);
-	}
-
-	ip.ip_dst.s_addr = nat64_get_ip4(&ip6->ip6_dst);
-	if (ip.ip_dst.s_addr == 0) {
-		/* XXX: stats? */
-		return (NAT64MFREE);
-	}
-
-	if (ip6->ip6_hlim <= IPV6_HLIMDEC) {
-		nat64_icmp6_reflect(m, ICMP6_TIME_EXCEEDED,
-		    ICMP6_TIME_EXCEED_TRANSIT, 0, stats, logdata);
-		return (NAT64RETURN);
-	}
-
-	hlen = 0;
-	plen = ntohs(ip6->ip6_plen);
-	proto = nat64_getlasthdr(m, &hlen);
-	if (proto < 0) {
-		DPRINTF(DP_DROPS, "dropped due to mbuf isn't contigious");
-		NAT64STAT_INC(stats, dropped);
-		return (NAT64MFREE);
-	}
-	frag = NULL;
-	if (proto == IPPROTO_FRAGMENT) {
-		/* ipfw_chk should m_pullup up to frag header */
-		if (m->m_len < hlen + sizeof(*frag)) {
-			DPRINTF(DP_DROPS,
-			    "dropped due to mbuf isn't contigious");
-			NAT64STAT_INC(stats, dropped);
-			return (NAT64MFREE);
-		}
-		frag = mtodo(m, hlen);
-		proto = frag->ip6f_nxt;
-		hlen += sizeof(*frag);
-		/* Fragmented ICMPv6 is unsupported */
-		if (proto == IPPROTO_ICMPV6) {
-			DPRINTF(DP_DROPS, "dropped due to fragmented ICMPv6");
-			NAT64STAT_INC(stats, dropped);
-			return (NAT64MFREE);
-		}
-		/* Fragment length must be multiple of 8 octets */
-		if ((frag->ip6f_offlg & IP6F_MORE_FRAG) != 0 &&
-		    ((plen + sizeof(struct ip6_hdr) - hlen) & 0x7) != 0) {
-			nat64_icmp6_reflect(m, ICMP6_PARAM_PROB,
-			    ICMP6_PARAMPROB_HEADER,
-			    offsetof(struct ip6_hdr, ip6_plen), stats,
-			    logdata);
-			return (NAT64RETURN);
-		}
-	}
-	plen -= hlen - sizeof(struct ip6_hdr);
-	if (plen < 0 || m->m_pkthdr.len < plen + hlen) {
-		DPRINTF(DP_DROPS, "plen %d, pkthdr.len %d, hlen %d",
-		    plen, m->m_pkthdr.len, hlen);
-		NAT64STAT_INC(stats, dropped);
-		return (NAT64MFREE);
-	}
-
-	icmp6 = NULL;	/* Make gcc happy */
-	if (proto == IPPROTO_ICMPV6) {
-		icmp6 = mtodo(m, hlen);
-		if (icmp6->icmp6_type != ICMP6_ECHO_REQUEST &&
-		    icmp6->icmp6_type != ICMP6_ECHO_REPLY)
-			return (nat64_handle_icmp6(m, hlen, aaddr, aport,
-			    stats, logdata));
-	}
-	dst = nat64_find_route4(&ro, ip.ip_dst.s_addr, m);
-	if (dst == NULL) {
-		FREE_ROUTE(&ro);
-		NAT64STAT_INC(stats, noroute4);
-		nat64_icmp6_reflect(m, ICMP6_DST_UNREACH,
-		    ICMP6_DST_UNREACH_NOROUTE, 0, stats, logdata);
-		return (NAT64RETURN);
-	}
-
-	ifp = ro.ro_rt->rt_ifp;
-	if (ro.ro_rt->rt_mtu != 0)
-		mtu = min(ro.ro_rt->rt_mtu, ifp->if_mtu);
-	else
-		mtu = ifp->if_mtu;
-	if (mtu < plen + sizeof(ip)) {
-		FREE_ROUTE(&ro);
-		nat64_icmp6_reflect(m, ICMP6_PACKET_TOO_BIG, 0, mtu, stats,
-		    logdata);
-		return (NAT64RETURN);
-	}
-	nat64_init_ip4hdr(ip6, frag, plen, proto, &ip);
-	/* Convert checksums. */
-	switch (proto) {
-	case IPPROTO_TCP:
-		csum = &TCP(mtodo(m, hlen))->th_sum;
-		if (aport != 0) {
-			struct tcphdr *tcp = TCP(mtodo(m, hlen));
-			*csum = cksum_adjust(*csum, tcp->th_sport, aport);
-			tcp->th_sport = aport;
-		}
-		*csum = cksum_add(*csum, nat64_cksum_convert(ip6, &ip));
-		break;
-	case IPPROTO_UDP:
-		csum = &UDP(mtodo(m, hlen))->uh_sum;
-		if (aport != 0) {
-			struct udphdr *udp = UDP(mtodo(m, hlen));
-			*csum = cksum_adjust(*csum, udp->uh_sport, aport);
-			udp->uh_sport = aport;
-		}
-		*csum = cksum_add(*csum, nat64_cksum_convert(ip6, &ip));
-		break;
-	case IPPROTO_ICMPV6:
-		/* Checksum in ICMPv6 covers pseudo header */
-		csum = &icmp6->icmp6_cksum;
-		*csum = cksum_add(*csum, in6_cksum_pseudo(ip6, plen,
-		    IPPROTO_ICMPV6, 0));
-		/* Convert ICMPv6 types to ICMP */
-		mtu = *(uint16_t *)icmp6; /* save old word for cksum_adjust */
-		if (icmp6->icmp6_type == ICMP6_ECHO_REQUEST)
-			icmp6->icmp6_type = ICMP_ECHO;
-		else /* ICMP6_ECHO_REPLY */
-			icmp6->icmp6_type = ICMP_ECHOREPLY;
-		*csum = cksum_adjust(*csum, (uint16_t)mtu, *(uint16_t *)icmp6);
-		if (aport != 0) {
-			uint16_t old_id = icmp6->icmp6_id;
-			icmp6->icmp6_id = aport;
-			*csum = cksum_adjust(*csum, old_id, aport);
-		}
-		break;
-	};
-
-	m_adj(m, hlen - sizeof(ip));
-	bcopy(&ip, mtod(m, void *), sizeof(ip));
-	if (nat64_output(ifp, m, dst, &ro, stats, logdata) == 0)
-		NAT64STAT_INC(stats, opcnt64);
-	FREE_ROUTE(&ro);
-	return (NAT64RETURN);
-}
-
Index: eebsd/sys/netpfil/ipfw/nat64/nat64_translate.h
===================================================================
--- freebsd/sys/netpfil/ipfw/nat64/nat64_translate.h	(revision f62c62d2fe57ec02c1350144f7739f8e866ee6d4)
+++ 	(revision )
@@ -1,116 +1,0 @@
-/*-
- * Copyright (c) 2015-2016 Yandex LLC
- * Copyright (c) 2015-2016 Andrey V. Elsukov <ae@FreeBSD.org>
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
- *
- * $FreeBSD$
- */
-
-#ifndef	_IP_FW_NAT64_TRANSLATE_H_
-#define	_IP_FW_NAT64_TRANSLATE_H_
-
-#ifdef RTALLOC_NOLOCK
-#define	IN_LOOKUP_ROUTE(ro, fib)	rtalloc_fib_nolock((ro), 0, (fib))
-#define	IN6_LOOKUP_ROUTE(ro, fib)	in6_rtalloc_nolock((ro), (fib))
-#define	FREE_ROUTE(ro)
-#else
-#define	IN_LOOKUP_ROUTE(ro, fib)	rtalloc_ign_fib((ro), 0, (fib))
-#define	IN6_LOOKUP_ROUTE(ro, fib)	in6_rtalloc((ro), (fib))
-#define	FREE_ROUTE(ro)			RO_RTFREE((ro))
-#endif
-
-static inline int
-nat64_check_ip6(struct in6_addr *addr)
-{
-
-	/* XXX: We should really check /8 */
-	if (addr->s6_addr16[0] == 0 || /* 0000::/8 Reserved by IETF */
-	    IN6_IS_ADDR_MULTICAST(addr) || IN6_IS_ADDR_LINKLOCAL(addr))
-		return (1);
-	return (0);
-}
-
-extern int nat64_allow_private;
-static inline int
-nat64_check_private_ip4(in_addr_t ia)
-{
-
-	if (nat64_allow_private)
-		return (0);
-	/* WKPFX must not be used to represent non-global IPv4 addresses */
-//	if (cfg->flags & NAT64_WKPFX) {
-		/* IN_PRIVATE */
-		if ((ia & htonl(0xff000000)) == htonl(0x0a000000) ||
-		    (ia & htonl(0xfff00000)) == htonl(0xac100000) ||
-		    (ia & htonl(0xffff0000)) == htonl(0xc0a80000))
-			return (1);
-		/*
-		 * RFC 5735:
-		 *  192.0.0.0/24 - reserved for IETF protocol assignments
-		 *  192.88.99.0/24 - for use as 6to4 relay anycast addresses
-		 *  198.18.0.0/15 - for use in benchmark tests
-		 *  192.0.2.0/24, 198.51.100.0/24, 203.0.113.0/24 - for use
-		 *   in documentation and example code
-		 */
-		if ((ia & htonl(0xffffff00)) == htonl(0xc0000000) ||
-		    (ia & htonl(0xffffff00)) == htonl(0xc0586300) ||
-		    (ia & htonl(0xfffffe00)) == htonl(0xc6120000) ||
-		    (ia & htonl(0xffffff00)) == htonl(0xc0000200) ||
-		    (ia & htonl(0xfffffe00)) == htonl(0xc6336400) ||
-		    (ia & htonl(0xffffff00)) == htonl(0xcb007100))
-			return (1);
-//	}
-	return (0);
-}
-
-static inline int
-nat64_check_ip4(in_addr_t ia)
-{
-
-	/* IN_LOOPBACK */
-	if ((ia & htonl(0xff000000)) == htonl(0x7f000000))
-		return (1);
-	/* IN_LINKLOCAL */
-	if ((ia & htonl(0xffff0000)) == htonl(0xa9fe0000))
-		return (1);
-	/* IN_MULTICAST & IN_EXPERIMENTAL */
-	if ((ia & htonl(0xe0000000)) == htonl(0xe0000000))
-		return (1);
-	return (0);
-}
-
-#define	nat64_get_ip4(_ip6)		((_ip6)->s6_addr32[3])
-#define	nat64_set_ip4(_ip6, _ip4)	(_ip6)->s6_addr32[3] = (_ip4)
-
-int nat64_getlasthdr(struct mbuf *m, int *offset);
-int nat64_do_handle_ip4(struct mbuf *m, struct in6_addr *saddr,
-    struct in6_addr *daddr, uint16_t lport, nat64_stats_block *stats,
-    void *logdata);
-int nat64_do_handle_ip6(struct mbuf *m, uint32_t aaddr, uint16_t aport,
-    nat64_stats_block *stats, void *logdata);
-int nat64_handle_icmp6(struct mbuf *m, int hlen, uint32_t aaddr, uint16_t aport,
-    nat64_stats_block *stats, void *logdata);
-
-#endif
-
Index: eebsd/sys/netpfil/ipfw/nat64/nat64lsn.c
===================================================================
--- freebsd/sys/netpfil/ipfw/nat64/nat64lsn.c	(revision f62c62d2fe57ec02c1350144f7739f8e866ee6d4)
+++ 	(revision )
@@ -1,1772 +1,0 @@
-#include <machine/rtems-bsd-kernel-space.h>
-
-/*-
- * Copyright (c) 2015-2016 Yandex LLC
- * Copyright (c) 2015 Alexander V. Chernikov <melifaro@FreeBSD.org>
- * Copyright (c) 2016 Andrey V. Elsukov <ae@FreeBSD.org>
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/counter.h>
-#include <sys/errno.h>
-#include <sys/kernel.h>
-#include <sys/lock.h>
-#include <sys/malloc.h>
-#include <sys/mbuf.h>
-#include <sys/module.h>
-#include <sys/rmlock.h>
-#include <sys/rwlock.h>
-#include <sys/socket.h>
-#include <sys/queue.h>
-#include <sys/syslog.h>
-#include <sys/sysctl.h>
-
-#include <net/if.h>
-#include <net/if_var.h>
-#include <net/if_pflog.h>
-#include <net/pfil.h>
-
-#include <netinet/in.h>
-#include <netinet/ip.h>
-#include <netinet/ip_var.h>
-#include <netinet/ip_fw.h>
-#include <netinet/ip6.h>
-#include <netinet/icmp6.h>
-#include <netinet/ip_icmp.h>
-#include <netinet/tcp.h>
-#include <netinet/udp.h>
-#include <netinet6/in6_var.h>
-#include <netinet6/ip6_var.h>
-#include <netinet6/ip_fw_nat64.h>
-
-#include <netpfil/ipfw/ip_fw_private.h>
-#include <netpfil/ipfw/nat64/ip_fw_nat64.h>
-#include <netpfil/ipfw/nat64/nat64lsn.h>
-#include <netpfil/ipfw/nat64/nat64_translate.h>
-#include <netpfil/pf/pf.h>
-
-MALLOC_DEFINE(M_NAT64LSN, "NAT64LSN", "NAT64LSN");
-
-static void nat64lsn_periodic(void *data);
-#define	PERIODIC_DELAY	4
-static uint8_t nat64lsn_proto_map[256];
-uint8_t nat64lsn_rproto_map[NAT_MAX_PROTO];
-
-#define	NAT64_FLAG_FIN		0x01	/* FIN was seen */
-#define	NAT64_FLAG_SYN		0x02	/* First syn in->out */
-#define	NAT64_FLAG_ESTAB	0x04	/* Packet with Ack */
-#define	NAT64_FLAGS_TCP	(NAT64_FLAG_SYN|NAT64_FLAG_ESTAB|NAT64_FLAG_FIN)
-
-#define	NAT64_FLAG_RDR		0x80	/* Port redirect */
-#define	NAT64_LOOKUP(chain, cmd)	\
-	(struct nat64lsn_cfg *)SRV_OBJECT((chain), (cmd)->arg1)
-/*
- * Delayed job queue, used to create new hosts
- * and new portgroups
- */
-enum nat64lsn_jtype {
-	JTYPE_NEWHOST = 1,
-	JTYPE_NEWPORTGROUP,
-	JTYPE_DELPORTGROUP,
-};
-
-struct nat64lsn_job_item {
-	TAILQ_ENTRY(nat64lsn_job_item)	next;
-	enum nat64lsn_jtype	jtype;
-	struct nat64lsn_host	*nh;
-	struct nat64lsn_portgroup	*pg;
-	void			*spare_idx;
-	struct in6_addr		haddr;
-	uint8_t			nat_proto;
-	uint8_t			done;
-	int			needs_idx;
-	int			delcount;
-	unsigned int		fhash;	/* Flow hash */
-	uint32_t		aaddr;	/* Last used address (net) */
-	struct mbuf		*m;
-	struct ipfw_flow_id	f_id;
-	uint64_t		delmask[NAT64LSN_PGPTRNMASK];
-};
-
-static struct mtx jmtx;
-#define	JQUEUE_LOCK_INIT()	mtx_init(&jmtx, "qlock", NULL, MTX_DEF)
-#define	JQUEUE_LOCK_DESTROY()	mtx_destroy(&jmtx)
-#define	JQUEUE_LOCK()		mtx_lock(&jmtx)
-#define	JQUEUE_UNLOCK()		mtx_unlock(&jmtx)
-
-static void nat64lsn_enqueue_job(struct nat64lsn_cfg *cfg,
-    struct nat64lsn_job_item *ji);
-static void nat64lsn_enqueue_jobs(struct nat64lsn_cfg *cfg,
-    struct nat64lsn_job_head *jhead, int jlen);
-
-static struct nat64lsn_job_item *nat64lsn_create_job(struct nat64lsn_cfg *cfg,
-    const struct ipfw_flow_id *f_id, int jtype);
-static int nat64lsn_request_portgroup(struct nat64lsn_cfg *cfg,
-    const struct ipfw_flow_id *f_id, struct mbuf **pm, uint32_t aaddr,
-    int needs_idx);
-static int nat64lsn_request_host(struct nat64lsn_cfg *cfg,
-    const struct ipfw_flow_id *f_id, struct mbuf **pm);
-static int nat64lsn_translate4(struct nat64lsn_cfg *cfg,
-    const struct ipfw_flow_id *f_id, struct mbuf **pm);
-static int nat64lsn_translate6(struct nat64lsn_cfg *cfg,
-    struct ipfw_flow_id *f_id, struct mbuf **pm);
-
-static int alloc_portgroup(struct nat64lsn_job_item *ji);
-static void destroy_portgroup(struct nat64lsn_portgroup *pg);
-static void destroy_host6(struct nat64lsn_host *nh);
-static int alloc_host6(struct nat64lsn_cfg *cfg, struct nat64lsn_job_item *ji);
-
-static int attach_portgroup(struct nat64lsn_cfg *cfg,
-    struct nat64lsn_job_item *ji);
-static int attach_host6(struct nat64lsn_cfg *cfg, struct nat64lsn_job_item *ji);
-
-
-/* XXX tmp */
-static uma_zone_t nat64lsn_host_zone;
-static uma_zone_t nat64lsn_pg_zone;
-static uma_zone_t nat64lsn_pgidx_zone;
-
-static unsigned int nat64lsn_periodic_chkstates(struct nat64lsn_cfg *cfg,
-    struct nat64lsn_host *nh);
-
-#define	I6_hash(x)		(djb_hash((const unsigned char *)(x), 16))
-#define	I6_first(_ph, h)	(_ph)[h]
-#define	I6_next(x)		(x)->next
-#define	I6_val(x)		(&(x)->addr)
-#define	I6_cmp(a, b)		IN6_ARE_ADDR_EQUAL(a, b)
-#define	I6_lock(a, b)
-#define	I6_unlock(a, b)
-
-#define	I6HASH_FIND(_cfg, _res, _a) \
-	CHT_FIND(_cfg->ih, _cfg->ihsize, I6_, _res, _a)
-#define	I6HASH_INSERT(_cfg, _i)	\
-	CHT_INSERT_HEAD(_cfg->ih, _cfg->ihsize, I6_, _i)
-#define	I6HASH_REMOVE(_cfg, _res, _tmp, _a)	\
-	CHT_REMOVE(_cfg->ih, _cfg->ihsize, I6_, _res, _tmp, _a)
-
-#define	I6HASH_FOREACH_SAFE(_cfg, _x, _tmp, _cb, _arg)	\
-	CHT_FOREACH_SAFE(_cfg->ih, _cfg->ihsize, I6_, _x, _tmp, _cb, _arg)
-
-#define	HASH_IN4(x)	djb_hash((const unsigned char *)(x), 8)
-
-static unsigned
-djb_hash(const unsigned char *h, const int len)
-{
-	unsigned int result = 0;
-	int i;
-
-	for (i = 0; i < len; i++)
-		result = 33 * result ^ h[i];
-
-	return (result);
-}
-
-/*
-static size_t 
-bitmask_size(size_t num, int *level)
-{
-	size_t x;
-	int c;
-
-	for (c = 0, x = num; num > 1; num /= 64, c++)
-		;
-
-	return (x);
-}
-
-static void
-bitmask_prepare(uint64_t *pmask, size_t bufsize, int level)
-{
-	size_t x, z;
-
-	memset(pmask, 0xFF, bufsize);
-	for (x = 0, z = 1; level > 1; x += z, z *= 64, level--)
-		;
-	pmask[x] ~= 0x01;
-}
-*/
-
-static void
-nat64lsn_log(struct pfloghdr *plog, struct mbuf *m, sa_family_t family,
-    uint32_t n, uint32_t sn)
-{
-
-	memset(plog, 0, sizeof(*plog));
-	plog->length = PFLOG_REAL_HDRLEN;
-	plog->af = family;
-	plog->action = PF_NAT;
-	plog->dir = PF_IN;
-	plog->rulenr = htonl(n);
-	plog->subrulenr = htonl(sn);
-	plog->ruleset[0] = '\0';
-	strlcpy(plog->ifname, "NAT64LSN", sizeof(plog->ifname));
-	ipfw_bpf_mtap2(plog, PFLOG_HDRLEN, m);
-}
-/*
- * Inspects icmp packets to see if the message contains different
- * packet header so we need to alter @addr and @port.
- */
-static int
-inspect_icmp_mbuf(struct mbuf **m, uint8_t *nat_proto, uint32_t *addr,
-    uint16_t *port)
-{
-	struct ip *ip;
-	struct tcphdr *tcp;
-	struct udphdr *udp;
-	struct icmphdr *icmp;
-	int off;
-	uint8_t proto;
-
-	ip = mtod(*m, struct ip *); /* Outer IP header */
-	off = (ip->ip_hl << 2) + ICMP_MINLEN;
-	if ((*m)->m_len < off)
-		*m = m_pullup(*m, off);
-	if (*m == NULL)
-		return (ENOMEM);
-
-	ip = mtod(*m, struct ip *); /* Outer IP header */
-	icmp = L3HDR(ip, struct icmphdr *);
-	switch (icmp->icmp_type) {
-	case ICMP_ECHO:
-	case ICMP_ECHOREPLY:
-		/* Use icmp ID as distinguisher */
-		*port = ntohs(*((uint16_t *)(icmp + 1)));
-		return (0);
-	case ICMP_UNREACH:
-	case ICMP_TIMXCEED:
-		break;
-	default:
-		return (EOPNOTSUPP);
-	}
-	/*
-	 * ICMP_UNREACH and ICMP_TIMXCEED contains IP header + 64 bits
-	 * of ULP header.
-	 */
-	if ((*m)->m_pkthdr.len < off + sizeof(struct ip) + ICMP_MINLEN)
-		return (EINVAL);
-	if ((*m)->m_len < off + sizeof(struct ip) + ICMP_MINLEN)
-		*m = m_pullup(*m, off + sizeof(struct ip) + ICMP_MINLEN);
-	if (*m == NULL)
-		return (ENOMEM);
-	ip = mtodo(*m, off); /* Inner IP header */
-	proto = ip->ip_p;
-	off += ip->ip_hl << 2; /* Skip inner IP header */
-	*addr = ntohl(ip->ip_src.s_addr);
-	if ((*m)->m_len < off + ICMP_MINLEN)
-		*m = m_pullup(*m, off + ICMP_MINLEN);
-	if (*m == NULL)
-		return (ENOMEM);
-	switch (proto) {
-	case IPPROTO_TCP:
-		tcp = mtodo(*m, off);
-		*nat_proto = NAT_PROTO_TCP;
-		*port = ntohs(tcp->th_sport);
-		return (0);
-	case IPPROTO_UDP:
-		udp = mtodo(*m, off);
-		*nat_proto = NAT_PROTO_UDP;
-		*port = ntohs(udp->uh_sport);
-		return (0);
-	case IPPROTO_ICMP:
-		/*
-		 * We will translate only ICMP errors for our ICMP
-		 * echo requests.
-		 */
-		icmp = mtodo(*m, off);
-		if (icmp->icmp_type != ICMP_ECHO)
-			return (EOPNOTSUPP);
-		*port = ntohs(*((uint16_t *)(icmp + 1)));
-		return (0);
-	};
-	return (EOPNOTSUPP);
-}
-
-static inline uint8_t
-convert_tcp_flags(uint8_t flags)
-{
-	uint8_t result;
-
-	result = flags & (TH_FIN|TH_SYN);
-	result |= (flags & TH_RST) >> 2; /* Treat RST as FIN */
-	result |= (flags & TH_ACK) >> 2; /* Treat ACK as estab */
-
-	return (result);
-}
-
-static NAT64NOINLINE int
-nat64lsn_translate4(struct nat64lsn_cfg *cfg, const struct ipfw_flow_id *f_id,
-    struct mbuf **pm)
-{
-	struct pfloghdr loghdr, *logdata;
-	struct in6_addr src6;
-	struct nat64lsn_portgroup *pg;
-	struct nat64lsn_host *nh;
-	struct nat64lsn_state *st;
-	struct ip *ip;
-	uint32_t addr;
-	uint16_t state_flags, state_ts;
-	uint16_t port, lport;
-	uint8_t nat_proto;
-	int ret;
-
-	addr = f_id->dst_ip;
-	port = f_id->dst_port;
-	if (addr < cfg->prefix4 || addr > cfg->pmask4) {
-		NAT64STAT_INC(&cfg->stats, nomatch4);
-		return (cfg->nomatch_verdict);
-	}
-
-	/* Check if protocol is supported and get its short id */
-	nat_proto = nat64lsn_proto_map[f_id->proto];
-	if (nat_proto == 0) {
-		NAT64STAT_INC(&cfg->stats, noproto);
-		return (cfg->nomatch_verdict);
-	}
-
-	/* We might need to handle icmp differently */
-	if (nat_proto == NAT_PROTO_ICMP) {
-		ret = inspect_icmp_mbuf(pm, &nat_proto, &addr, &port);
-		if (ret != 0) {
-			if (ret == ENOMEM)
-				NAT64STAT_INC(&cfg->stats, nomem);
-			else
-				NAT64STAT_INC(&cfg->stats, noproto);
-			return (cfg->nomatch_verdict);
-		}
-		/* XXX: Check addr for validity */
-		if (addr < cfg->prefix4 || addr > cfg->pmask4) {
-			NAT64STAT_INC(&cfg->stats, nomatch4);
-			return (cfg->nomatch_verdict);
-		}
-	}
-
-	/* Calc portgroup offset w.r.t protocol */
-	pg = GET_PORTGROUP(cfg, addr, nat_proto, port);
-
-	/* Check if this port is occupied by any portgroup */
-	if (pg == NULL) {
-		NAT64STAT_INC(&cfg->stats, nomatch4);
-#if 0
-		DPRINTF(DP_STATE, "NOMATCH %u %d %d (%d)", addr, nat_proto, port,
-		    _GET_PORTGROUP_IDX(cfg, addr, nat_proto, port));
-#endif
-		return (cfg->nomatch_verdict);
-	}
-
-	/* TODO: Check flags to see if we need to do some static mapping */
-	nh = pg->host;
-
-	/* Prepare some fields we might need to update */
-	SET_AGE(state_ts);
-	ip = mtod(*pm, struct ip *);
-	if (ip->ip_p == IPPROTO_TCP)
-		state_flags = convert_tcp_flags(
-		    L3HDR(ip, struct tcphdr *)->th_flags);
-	else
-		state_flags = 0;
-
-	/* Lock host and get port mapping */
-	NAT64_LOCK(nh);
-
-	st = &pg->states[port & (NAT64_CHUNK_SIZE - 1)];
-	if (st->timestamp != state_ts)
-		st->timestamp = state_ts;
-	if ((st->flags & state_flags) != state_flags)
-		st->flags |= state_flags;
-	lport = htons(st->u.s.lport);
-
-	NAT64_UNLOCK(nh);
-
-	if (cfg->flags & NAT64_LOG) {
-		logdata = &loghdr;
-		nat64lsn_log(logdata, *pm, AF_INET, pg->idx, st->cur.off);
-	} else
-		logdata = NULL;
-
-	src6.s6_addr32[0] = cfg->prefix6.s6_addr32[0];
-	src6.s6_addr32[1] = cfg->prefix6.s6_addr32[1];
-	src6.s6_addr32[2] = cfg->prefix6.s6_addr32[2];
-	src6.s6_addr32[3] = htonl(f_id->src_ip);
-
-	ret = nat64_do_handle_ip4(*pm, &src6, &nh->addr, lport,
-	    &cfg->stats, logdata);
-
-	if (ret == NAT64SKIP)
-		return (IP_FW_PASS);
-	if (ret == NAT64MFREE)
-		m_freem(*pm);
-	*pm = NULL;
-
-	return (IP_FW_DENY);
-}
-
-void
-nat64lsn_dump_state(const struct nat64lsn_cfg *cfg,
-   const struct nat64lsn_portgroup *pg, const struct nat64lsn_state *st,
-   const char *px, int off)
-{
-	char s[INET6_ADDRSTRLEN], a[INET_ADDRSTRLEN], d[INET_ADDRSTRLEN];
-
-	if ((nat64_debug & DP_STATE) == 0)
-		return;
-	inet_ntop(AF_INET6, &pg->host->addr, s, sizeof(s));
-	inet_ntop(AF_INET, &pg->aaddr, a, sizeof(a));
-	inet_ntop(AF_INET, &st->u.s.faddr, d, sizeof(d));
-
-	DPRINTF(DP_STATE, "%s: PG %d ST [%p|%d]: %s:%d/%d <%s:%d> "
-	    "%s:%d AGE %d", px, pg->idx, st, off,
-	    s, st->u.s.lport, pg->nat_proto, a, pg->aport + off,
-	    d, st->u.s.fport, GET_AGE(st->timestamp));
-}
-
-/*
- * Check if particular TCP state is stale and should be deleted.
- * Return 1 if true, 0 otherwise.
- */
-static int
-nat64lsn_periodic_check_tcp(const struct nat64lsn_cfg *cfg,
-    const struct nat64lsn_state *st, int age)
-{
-	int ttl;
-
-	if (st->flags & NAT64_FLAG_FIN)
-		ttl = cfg->st_close_ttl;
-	else if (st->flags & NAT64_FLAG_ESTAB)
-		ttl = cfg->st_estab_ttl;
-	else if (st->flags & NAT64_FLAG_SYN)
-		ttl = cfg->st_syn_ttl;
-	else
-		ttl = cfg->st_syn_ttl;
-
-	if (age > ttl)
-		return (1);
-	return (0);
-}
-
-/*
- * Check if nat state @st is stale and should be deleted.
- * Return 1 if true, 0 otherwise.
- */
-static NAT64NOINLINE int
-nat64lsn_periodic_chkstate(const struct nat64lsn_cfg *cfg,
-    const struct nat64lsn_portgroup *pg, const struct nat64lsn_state *st)
-{
-	int age, delete;
-
-	age = GET_AGE(st->timestamp);
-	delete = 0;
-
-	/* Skip immutable records */
-	if (st->flags & NAT64_FLAG_RDR)
-		return (0);
-
-	switch (pg->nat_proto) {
-		case NAT_PROTO_TCP:
-			delete = nat64lsn_periodic_check_tcp(cfg, st, age);
-			break;
-		case NAT_PROTO_UDP:
-			if (age > cfg->st_udp_ttl)
-				delete = 1;
-			break;
-		case NAT_PROTO_ICMP:
-			if (age > cfg->st_icmp_ttl)
-				delete = 1;
-			break;
-	}
-
-	return (delete);
-}
-
-
-/*
- * The following structures and functions
- * are used to perform SLIST_FOREACH_SAFE()
- * analog for states identified by struct st_ptr.
- */
-
-struct st_idx {
-	struct nat64lsn_portgroup *pg;
-	struct nat64lsn_state *st;
-	struct st_ptr sidx_next;
-};
-
-static struct st_idx *
-st_first(const struct nat64lsn_cfg *cfg, const struct nat64lsn_host *nh,
-    struct st_ptr *sidx, struct st_idx *si)
-{
-	struct nat64lsn_portgroup *pg;
-	struct nat64lsn_state *st;
-
-	if (sidx->idx == 0) {
-		memset(si, 0, sizeof(*si));
-		return (si);
-	}
-
-	pg = PORTGROUP_BYSIDX(cfg, nh, sidx->idx);
-	st = &pg->states[sidx->off];
-
-	si->pg = pg;
-	si->st = st;
-	si->sidx_next = st->next;
-
-	return (si);
-}
-
-static struct st_idx *
-st_next(const struct nat64lsn_cfg *cfg, const struct nat64lsn_host *nh,
-    struct st_idx *si)
-{
-	struct st_ptr sidx;
-	struct nat64lsn_portgroup *pg;
-	struct nat64lsn_state *st;
-
-	sidx = si->sidx_next;
-	if (sidx.idx == 0) {
-		memset(si, 0, sizeof(*si));
-		si->st = NULL;
-		si->pg = NULL;
-		return (si);
-	}
-
-	pg = PORTGROUP_BYSIDX(cfg, nh, sidx.idx);
-	st = &pg->states[sidx.off];
-
-	si->pg = pg;
-	si->st = st;
-	si->sidx_next = st->next;
-
-	return (si);
-}
-
-static struct st_idx *
-st_save_cond(struct st_idx *si_dst, struct st_idx *si)
-{
-	if (si->st != NULL)
-		*si_dst = *si;
-
-	return (si_dst);
-}
-
-unsigned int
-nat64lsn_periodic_chkstates(struct nat64lsn_cfg *cfg, struct nat64lsn_host *nh)
-{
-	struct st_idx si, si_prev;
-	int i;
-	unsigned int delcount;
-
-	delcount = 0;
-	for (i = 0; i < nh->hsize; i++) {
-		memset(&si_prev, 0, sizeof(si_prev));
-		for (st_first(cfg, nh, &nh->phash[i], &si);
-		    si.st != NULL;
-		    st_save_cond(&si_prev, &si), st_next(cfg, nh, &si)) {
-			if (nat64lsn_periodic_chkstate(cfg, si.pg, si.st) == 0)
-				continue;
-			nat64lsn_dump_state(cfg, si.pg, si.st, "DELETE STATE",
-			    si.st->cur.off);
-			/* Unlink from hash */
-			if (si_prev.st != NULL)
-				si_prev.st->next = si.st->next;
-			else
-				nh->phash[i] = si.st->next;
-			/* Delete state and free its data */
-			PG_MARK_FREE_IDX(si.pg, si.st->cur.off);
-			memset(si.st, 0, sizeof(struct nat64lsn_state));
-			si.st = NULL;
-			delcount++;
-
-			/* Update portgroup timestamp */
-			SET_AGE(si.pg->timestamp);
-		}
-	}
-	NAT64STAT_ADD(&cfg->stats, sdeleted, delcount);
-	return (delcount);
-}
-
-/*
- * Checks if portgroup is not used and can be deleted,
- * Returns 1 if stale, 0 otherwise
- */
-static int
-stale_pg(const struct nat64lsn_cfg *cfg, const struct nat64lsn_portgroup *pg)
-{
-
-	if (!PG_IS_EMPTY(pg))
-		return (0);
-	if (GET_AGE(pg->timestamp) < cfg->pg_delete_delay)
-		return (0);
-	return (1);
-}
-
-/*
- * Checks if host record is not used and can be deleted,
- * Returns 1 if stale, 0 otherwise
- */
-static int
-stale_nh(const struct nat64lsn_cfg *cfg, const struct nat64lsn_host *nh)
-{
-
-	if (nh->pg_used != 0)
-		return (0);
-	if (GET_AGE(nh->timestamp) < cfg->nh_delete_delay)
-		return (0);
-	return (1);
-}
-
-struct nat64lsn_periodic_data {
-	struct nat64lsn_cfg *cfg;
-	struct nat64lsn_job_head jhead;
-	int jlen;
-};
-
-static NAT64NOINLINE int
-nat64lsn_periodic_chkhost(struct nat64lsn_host *nh,
-    struct nat64lsn_periodic_data *d)
-{
-	char a[INET6_ADDRSTRLEN];
-	struct nat64lsn_portgroup *pg;
-	struct nat64lsn_job_item *ji;
-	uint64_t delmask[NAT64LSN_PGPTRNMASK];
-	int delcount, i;
-
-	delcount = 0;
-	memset(delmask, 0, sizeof(delmask));
-
-	inet_ntop(AF_INET6, &nh->addr, a, sizeof(a));
-	DPRINTF(DP_JQUEUE, "Checking %s host %s on cpu %d",
-	    stale_nh(d->cfg, nh) ? "stale" : "non-stale", a, curcpu);
-	if (!stale_nh(d->cfg, nh)) {
-		/* Non-stale host. Inspect internals */
-		NAT64_LOCK(nh);
-
-		/* Stage 1: Check&expire states */
-		if (nat64lsn_periodic_chkstates(d->cfg, nh) != 0)
-			SET_AGE(nh->timestamp);
-
-		/* Stage 2: Check if we need to expire */
-		for (i = 0; i < nh->pg_used; i++) {
-			pg = PORTGROUP_BYSIDX(d->cfg, nh, i + 1);
-			if (pg == NULL)
-				continue;
-
-			/* Check if we can delete portgroup */
-			if (stale_pg(d->cfg, pg) == 0)
-				continue;
-
-			DPRINTF(DP_JQUEUE, "Check PG %d", i);
-			delmask[i / 64] |= ((uint64_t)1 << (i % 64));
-			delcount++;
-		}
-
-		NAT64_UNLOCK(nh);
-		if (delcount == 0)
-			return (0);
-	}
-
-	DPRINTF(DP_JQUEUE, "Queueing %d portgroups for deleting", delcount);
-	/* We have something to delete - add it to queue */
-	ji = nat64lsn_create_job(d->cfg, NULL, JTYPE_DELPORTGROUP);
-	if (ji == NULL)
-		return (0);
-
-	ji->haddr = nh->addr;
-	ji->delcount = delcount;
-	memcpy(ji->delmask, delmask, sizeof(ji->delmask));
-
-	TAILQ_INSERT_TAIL(&d->jhead, ji, next);
-	d->jlen++;
-	return (0);
-}
-
-/*
- * This procedure is used to perform various maintance
- * on dynamic hash list. Currently it is called every second.
- */
-static void
-nat64lsn_periodic(void *data)
-{
-	struct ip_fw_chain *ch;
-	IPFW_RLOCK_TRACKER;
-	struct nat64lsn_cfg *cfg;
-	struct nat64lsn_periodic_data d;
-	struct nat64lsn_host *nh, *tmp;
-
-	cfg = (struct nat64lsn_cfg *) data;
-	ch = cfg->ch;
-	CURVNET_SET(cfg->vp);
-
-	memset(&d, 0, sizeof(d));
-	d.cfg = cfg;
-	TAILQ_INIT(&d.jhead);
-
-	IPFW_RLOCK(ch);
-
-	/* Stage 1: foreach host, check all its portgroups */
-	I6HASH_FOREACH_SAFE(cfg, nh, tmp, nat64lsn_periodic_chkhost, &d);
-
-	/* Enqueue everything we have requested */
-	nat64lsn_enqueue_jobs(cfg, &d.jhead, d.jlen);
-
-	callout_schedule(&cfg->periodic, hz * PERIODIC_DELAY);
-
-	IPFW_RUNLOCK(ch);
-
-	CURVNET_RESTORE();
-}
-
-static NAT64NOINLINE void
-reinject_mbuf(struct nat64lsn_cfg *cfg, struct nat64lsn_job_item *ji)
-{
-
-	if (ji->m == NULL)
-		return;
-
-	/* Request has failed or packet type is wrong */
-	if (ji->f_id.addr_type != 6 || ji->done == 0) {
-		m_freem(ji->m);
-		ji->m = NULL;
-		NAT64STAT_INC(&cfg->stats, dropped);
-		DPRINTF(DP_DROPS, "mbuf dropped: type %d, done %d",
-		    ji->jtype, ji->done);
-		return;
-	}
-
-	/*
-	 * XXX: Limit recursion level
-	 */
-
-	NAT64STAT_INC(&cfg->stats, jreinjected);
-	DPRINTF(DP_JQUEUE, "Reinject mbuf");
-	nat64lsn_translate6(cfg, &ji->f_id, &ji->m);
-}
-
-static void
-destroy_portgroup(struct nat64lsn_portgroup *pg)
-{
-
-	DPRINTF(DP_OBJ, "DESTROY PORTGROUP %d %p", pg->idx, pg);
-	uma_zfree(nat64lsn_pg_zone, pg);
-}
-
-static NAT64NOINLINE int
-alloc_portgroup(struct nat64lsn_job_item *ji)
-{
-	struct nat64lsn_portgroup *pg;
-
-	pg = uma_zalloc(nat64lsn_pg_zone, M_NOWAIT);
-	if (pg == NULL)
-		return (1);
-
-	if (ji->needs_idx != 0) {
-		ji->spare_idx = uma_zalloc(nat64lsn_pgidx_zone, M_NOWAIT);
-		/* Failed alloc isn't always fatal, so don't check */
-	}
-	memset(&pg->freemask, 0xFF, sizeof(pg->freemask));
-	pg->nat_proto = ji->nat_proto;
-	ji->pg = pg;
-	return (0);
-
-}
-
-static void
-destroy_host6(struct nat64lsn_host *nh)
-{
-	char a[INET6_ADDRSTRLEN];
-	int i;
-
-	inet_ntop(AF_INET6, &nh->addr, a, sizeof(a));
-	DPRINTF(DP_OBJ, "DESTROY HOST %s %p (pg used %d)", a, nh,
-	    nh->pg_used);
-	NAT64_LOCK_DESTROY(nh);
-	for (i = 0; i < nh->pg_allocated / NAT64LSN_PGIDX_CHUNK; i++)
-		uma_zfree(nat64lsn_pgidx_zone, PORTGROUP_CHUNK(nh, i));
-	uma_zfree(nat64lsn_host_zone, nh);
-}
-
-static NAT64NOINLINE int
-alloc_host6(struct nat64lsn_cfg *cfg, struct nat64lsn_job_item *ji)
-{
-	struct nat64lsn_host *nh;
-	char a[INET6_ADDRSTRLEN];
-
-	nh = uma_zalloc(nat64lsn_host_zone, M_NOWAIT);
-	if (nh == NULL)
-		return (1);
-	PORTGROUP_CHUNK(nh, 0) = uma_zalloc(nat64lsn_pgidx_zone, M_NOWAIT);
-	if (PORTGROUP_CHUNK(nh, 0) == NULL) {
-		uma_zfree(nat64lsn_host_zone, nh);
-		return (2);
-	}
-	if (alloc_portgroup(ji) != 0) {
-		NAT64STAT_INC(&cfg->stats, jportfails);
-		uma_zfree(nat64lsn_pgidx_zone, PORTGROUP_CHUNK(nh, 0));
-		uma_zfree(nat64lsn_host_zone, nh);
-		return (3);
-	}
-
-	NAT64_LOCK_INIT(nh);
-	nh->addr = ji->haddr;
-	nh->hsize = NAT64LSN_HSIZE; /* XXX: hardcoded size */
-	nh->pg_allocated = NAT64LSN_PGIDX_CHUNK;
-	nh->pg_used = 0;
-	ji->nh = nh;
-
-	inet_ntop(AF_INET6, &nh->addr, a, sizeof(a));
-	DPRINTF(DP_OBJ, "ALLOC HOST %s %p", a, ji->nh);
-	return (0);
-}
-
-/*
- * Finds free @pg index inside @nh
- */
-static NAT64NOINLINE int
-find_nh_pg_idx(struct nat64lsn_cfg *cfg, struct nat64lsn_host *nh, int *idx)
-{
-	int i;
-
-	for (i = 0; i < nh->pg_allocated; i++) {
-		if (PORTGROUP_BYSIDX(cfg, nh, i + 1) == NULL) {
-			*idx = i;
-			return (0);
-		}
-	}
-	return (1);
-}
-
-static NAT64NOINLINE int
-attach_host6(struct nat64lsn_cfg *cfg, struct nat64lsn_job_item *ji)
-{
-	char a[INET6_ADDRSTRLEN];
-	struct nat64lsn_host *nh;
-
-	I6HASH_FIND(cfg, nh, &ji->haddr);
-	if (nh == NULL) {
-		/* Add new host to list */
-		nh = ji->nh;
-		I6HASH_INSERT(cfg, nh);
-		cfg->ihcount++;
-		ji->nh = NULL;
-
-		inet_ntop(AF_INET6, &nh->addr, a, sizeof(a));
-		DPRINTF(DP_OBJ, "ATTACH HOST %s %p", a, nh);
-		/*
-		 * Try to add portgroup.
-		 * Note it will automatically set
-		 * 'done' on ji if successful.
-		 */
-		if (attach_portgroup(cfg, ji) != 0) {
-			DPRINTF(DP_DROPS, "%s %p failed to attach PG",
-			    a, nh);
-			NAT64STAT_INC(&cfg->stats, jportfails);
-			return (1);
-		}
-		return (0);
-	}
-
-	/*
-	 * nh isn't NULL. This probably means we had several simultaneous
-	 * host requests. The previous one request has already attached
-	 * this host. Requeue attached mbuf and mark job as done, but
-	 * leave nh and pg pointers not changed, so nat64lsn_do_request()
-	 * will release all allocated resources.
-	 */
-	inet_ntop(AF_INET6, &nh->addr, a, sizeof(a));
-	DPRINTF(DP_OBJ, "%s %p is already attached as %p",
-	    a, ji->nh, nh);
-	ji->done = 1;
-	return (0);
-}
-
-static NAT64NOINLINE int
-find_pg_place_addr(const struct nat64lsn_cfg *cfg, int addr_off,
-    int nat_proto, uint16_t *aport, int *ppg_idx)
-{
-	int j, pg_idx;
-
-	pg_idx = addr_off * _ADDR_PG_COUNT +
-	    (nat_proto - 1) * _ADDR_PG_PROTO_COUNT;
-
-	for (j = NAT64_MIN_CHUNK; j < _ADDR_PG_PROTO_COUNT; j++) {
-		if (cfg->pg[pg_idx + j] != NULL)
-			continue;
-
-		*aport = j * NAT64_CHUNK_SIZE;
-		*ppg_idx = pg_idx + j;
-		return (1);
-	}
-
-	return (0);
-}
-
-/*
- * XXX: This function needs to be rewritten to
- * use free bitmask for faster pg finding,
- * additionally, it should take into consideration
- * a) randomization and
- * b) previous addresses allocated to given nat instance
- *
- */
-static NAT64NOINLINE int
-find_portgroup_place(struct nat64lsn_cfg *cfg, struct nat64lsn_job_item *ji,
-    uint32_t *aaddr, uint16_t *aport, int *ppg_idx)
-{
-	int i, nat_proto;
-
-	/*
-	 * XXX: Use bitmask index to be able to find/check if IP address
-	 * has some spare pg's
-	 */
-	nat_proto = ji->nat_proto;
-
-	/* First, try to use same address */
-	if (ji->aaddr != 0) {
-		i = ntohl(ji->aaddr) - cfg->prefix4;
-		if (find_pg_place_addr(cfg, i, nat_proto, aport,
-		    ppg_idx) != 0){
-			/* Found! */
-			*aaddr = htonl(cfg->prefix4 + i);
-			return (0);
-		}
-	}
-
-	/* Next, try to use random address based on flow hash */
-	i = ji->fhash % (1 << (32 - cfg->plen4));
-	if (find_pg_place_addr(cfg, i, nat_proto, aport, ppg_idx) != 0) {
-		/* Found! */
-		*aaddr = htonl(cfg->prefix4 + i);
-		return (0);
-	}
-
-
-	/* Last one: simply find ANY available */
-	for (i = 0; i < (1 << (32 - cfg->plen4)); i++) {
-		if (find_pg_place_addr(cfg, i, nat_proto, aport,
-		    ppg_idx) != 0){
-			/* Found! */
-			*aaddr = htonl(cfg->prefix4 + i);
-			return (0);
-		}
-	}
-
-	return (1);
-}
-
-static NAT64NOINLINE int
-attach_portgroup(struct nat64lsn_cfg *cfg, struct nat64lsn_job_item *ji)
-{
-	char a[INET6_ADDRSTRLEN];
-	struct nat64lsn_portgroup *pg;
-	struct nat64lsn_host *nh;
-	uint32_t aaddr;
-	uint16_t aport;
-	int nh_pg_idx, pg_idx;
-
-	pg = ji->pg;
-
-	/*
-	 * Find source host and bind: we can't rely on
-	 * pg->host
-	 */
-	I6HASH_FIND(cfg, nh, &ji->haddr);
-	if (nh == NULL)
-		return (1);
-
-	/* Find spare port chunk */
-	if (find_portgroup_place(cfg, ji, &aaddr, &aport, &pg_idx) != 0) {
-		inet_ntop(AF_INET6, &nh->addr, a, sizeof(a));
-		DPRINTF(DP_OBJ | DP_DROPS, "empty PG not found for %s", a);
-		return (2);
-	}
-
-	/* Expand PG indexes if needed */
-	if (nh->pg_allocated < cfg->max_chunks && ji->spare_idx != NULL) {
-		PORTGROUP_CHUNK(nh, nh->pg_allocated / NAT64LSN_PGIDX_CHUNK) =
-		    ji->spare_idx;
-		nh->pg_allocated += NAT64LSN_PGIDX_CHUNK;
-		ji->spare_idx = NULL;
-	}
-
-	/* Find empty index to store PG in the @nh */
-	if (find_nh_pg_idx(cfg, nh, &nh_pg_idx) != 0) {
-		inet_ntop(AF_INET6, &nh->addr, a, sizeof(a));
-		DPRINTF(DP_OBJ | DP_DROPS, "free PG index not found for %s",
-		    a);
-		return (3);
-	}
-
-	cfg->pg[pg_idx] = pg;
-	cfg->protochunks[pg->nat_proto]++;
-	NAT64STAT_INC(&cfg->stats, spgcreated);
-
-	pg->aaddr = aaddr;
-	pg->aport = aport;
-	pg->host = nh;
-	pg->idx = pg_idx;
-	SET_AGE(pg->timestamp);
-
-	PORTGROUP_BYSIDX(cfg, nh, nh_pg_idx + 1) = pg;
-	if (nh->pg_used == nh_pg_idx)
-		nh->pg_used++;
-	SET_AGE(nh->timestamp);
-
-	ji->pg = NULL;
-	ji->done = 1;
-
-	return (0);
-}
-
-static NAT64NOINLINE void
-consider_del_portgroup(struct nat64lsn_cfg *cfg, struct nat64lsn_job_item *ji)
-{
-	struct nat64lsn_host *nh, *nh_tmp;
-	struct nat64lsn_portgroup *pg, *pg_list[256];
-	int i, pg_lidx, idx;
-
-	/* Find source host */
-	I6HASH_FIND(cfg, nh, &ji->haddr);
-	if (nh == NULL || nh->pg_used == 0)
-		return;
-
-	memset(pg_list, 0, sizeof(pg_list));
-	pg_lidx = 0;
-
-	NAT64_LOCK(nh);
-
-	for (i = nh->pg_used - 1; i >= 0; i--) {
-		if ((ji->delmask[i / 64] & ((uint64_t)1 << (i % 64))) == 0)
-			continue;
-		pg = PORTGROUP_BYSIDX(cfg, nh, i + 1);
-
-		/* Check that PG isn't busy. */
-		if (stale_pg(cfg, pg) == 0)
-			continue;
-
-		/* DO delete */
-		pg_list[pg_lidx++] = pg;
-		PORTGROUP_BYSIDX(cfg, nh, i + 1) = NULL;
-
-		idx = _GET_PORTGROUP_IDX(cfg, ntohl(pg->aaddr), pg->nat_proto,
-		    pg->aport);
-		KASSERT(cfg->pg[idx] == pg, ("Non matched pg"));
-		cfg->pg[idx] = NULL;
-		cfg->protochunks[pg->nat_proto]--;
-		NAT64STAT_INC(&cfg->stats, spgdeleted);
-
-		/* Decrease pg_used */
-		while (nh->pg_used > 0 &&
-		    PORTGROUP_BYSIDX(cfg, nh, nh->pg_used) == NULL)
-			nh->pg_used--;
-
-		/* Check if on-stack buffer has ended */
-		if (pg_lidx == nitems(pg_list))
-			break;
-	}
-
-	NAT64_UNLOCK(nh);
-
-	if (stale_nh(cfg, nh)) {
-		I6HASH_REMOVE(cfg, nh, nh_tmp, &ji->haddr);
-		KASSERT(nh != NULL, ("Unable to find address"));
-		cfg->ihcount--;
-		ji->nh = nh;
-		I6HASH_FIND(cfg, nh, &ji->haddr);
-		KASSERT(nh == NULL, ("Failed to delete address"));
-	}
-
-	/* TODO: Delay freeing portgroups */
-	while (pg_lidx > 0) {
-		pg_lidx--;
-		NAT64STAT_INC(&cfg->stats, spgdeleted);
-		destroy_portgroup(pg_list[pg_lidx]);
-	}
-}
-
-/*
- * Main request handler.
- * Responsible for handling jqueue, e.g.
- * creating new hosts, addind/deleting portgroups.
- */
-static NAT64NOINLINE void
-nat64lsn_do_request(void *data) 
-{
-	IPFW_RLOCK_TRACKER;
-	struct nat64lsn_job_head jhead;
-	struct nat64lsn_job_item *ji;
-	int jcount, nhsize;
-	struct nat64lsn_cfg *cfg = (struct nat64lsn_cfg *) data;
-	struct ip_fw_chain *ch;
-	int delcount;
-
-	CURVNET_SET(cfg->vp);
-
-	TAILQ_INIT(&jhead);
-
-	/* XXX: We're running unlocked here */
-
-	ch = cfg->ch;
-	delcount = 0;
-	IPFW_RLOCK(ch);
-
-	/* Grab queue */
-	JQUEUE_LOCK();
-	TAILQ_SWAP(&jhead, &cfg->jhead, nat64lsn_job_item, next);
-	jcount = cfg->jlen;
-	cfg->jlen = 0;
-	JQUEUE_UNLOCK();
-
-	/* check if we need to resize hash */
-	nhsize = 0;
-	if (cfg->ihcount > cfg->ihsize && cfg->ihsize < 65536) {
-		nhsize = cfg->ihsize;
-		for ( ; cfg->ihcount > nhsize && nhsize < 65536; nhsize *= 2)
-			;
-	} else if (cfg->ihcount < cfg->ihsize * 4) {
-		nhsize = cfg->ihsize;
-		for ( ; cfg->ihcount < nhsize * 4 && nhsize > 32; nhsize /= 2)
-			;
-	}
-
-	IPFW_RUNLOCK(ch);
-
-	if (TAILQ_EMPTY(&jhead)) {
-		CURVNET_RESTORE();
-		return;
-	}
-
-	NAT64STAT_INC(&cfg->stats, jcalls);
-	DPRINTF(DP_JQUEUE, "count=%d", jcount);
-
-	/*
-	 * TODO:
-	 * What we should do here is to build a hash
-	 * to ensure we don't have lots of duplicate requests.
-	 * Skip this for now.
-	 *
-	 * TODO: Limit per-call number of items
-	 */
-
-	/* Pre-allocate everything for entire chain */
-	TAILQ_FOREACH(ji, &jhead,  next) {
-		switch (ji->jtype) {
-			case JTYPE_NEWHOST:
-				if (alloc_host6(cfg, ji) != 0)
-					NAT64STAT_INC(&cfg->stats, jhostfails);
-				break;
-			case JTYPE_NEWPORTGROUP:
-				if (alloc_portgroup(ji) != 0)
-					NAT64STAT_INC(&cfg->stats, jportfails);
-				break;
-			case JTYPE_DELPORTGROUP:
-				delcount += ji->delcount;
-				break;
-			default:
-				break;
-		}
-	}
-
-	/*
-	 * TODO: Alloc hew hash
-	 */
-	nhsize = 0;
-	if (nhsize > 0) {
-		/* XXX: */
-	}
-
-	/* Apply all changes in batch */
-	IPFW_UH_WLOCK(ch);
-	IPFW_WLOCK(ch);
-
-	TAILQ_FOREACH(ji, &jhead,  next) {
-		switch (ji->jtype) {
-			case JTYPE_NEWHOST:
-				if (ji->nh != NULL)
-					attach_host6(cfg, ji);
-				break;
-			case JTYPE_NEWPORTGROUP:
-				if (ji->pg != NULL &&
-				    attach_portgroup(cfg, ji) != 0)
-					NAT64STAT_INC(&cfg->stats, jportfails);
-				break;
-			case JTYPE_DELPORTGROUP:
-				consider_del_portgroup(cfg, ji);
-				break;
-		}
-	}
-
-	if (nhsize > 0) {
-		/* XXX: Move everything to new hash */
-	}
-
-	IPFW_WUNLOCK(ch);
-	IPFW_UH_WUNLOCK(ch);
-
-	/* Flush unused entries */
-	while (!TAILQ_EMPTY(&jhead)) {
-		ji = TAILQ_FIRST(&jhead);
-		TAILQ_REMOVE(&jhead, ji, next);
-		if (ji->nh != NULL)
-			destroy_host6(ji->nh);
-		if (ji->pg != NULL)
-			destroy_portgroup(ji->pg);
-		if (ji->m != NULL)
-			reinject_mbuf(cfg, ji);
-		if (ji->spare_idx != NULL)
-			uma_zfree(nat64lsn_pgidx_zone, ji->spare_idx);
-		free(ji, M_IPFW);
-	}
-	CURVNET_RESTORE();
-}
-
-static NAT64NOINLINE struct nat64lsn_job_item *
-nat64lsn_create_job(struct nat64lsn_cfg *cfg, const struct ipfw_flow_id *f_id,
-    int jtype)
-{
-	struct nat64lsn_job_item *ji;
-	struct in6_addr haddr;
-	uint8_t nat_proto;
-
-	/*
-	 * Do not try to lock possibly contested mutex if we're near the limit.
-	 * Drop packet instead.
-	 */
-	if (cfg->jlen >= cfg->jmaxlen) {
-		NAT64STAT_INC(&cfg->stats, jmaxlen);
-		return (NULL);
-	}
-
-	memset(&haddr, 0, sizeof(haddr));
-	nat_proto = 0;
-	if (f_id != NULL) {
-		haddr = f_id->src_ip6;
-		nat_proto = nat64lsn_proto_map[f_id->proto];
-
-		DPRINTF(DP_JQUEUE, "REQUEST pg nat_proto %d on proto %d",
-		    nat_proto, f_id->proto);
-
-		if (nat_proto == 0)
-			return (NULL);
-	}
-
-	ji = malloc(sizeof(struct nat64lsn_job_item), M_IPFW,
-	    M_NOWAIT | M_ZERO);
-
-	if (ji == NULL) {
-		NAT64STAT_INC(&cfg->stats, jnomem);
-		return (NULL);
-	}
-
-	ji->jtype = jtype;
-
-	if (f_id != NULL) {
-		ji->f_id = *f_id;
-		ji->haddr = haddr;
-		ji->nat_proto = nat_proto;
-	}
-
-	return (ji);
-}
-
-static NAT64NOINLINE void
-nat64lsn_enqueue_job(struct nat64lsn_cfg *cfg, struct nat64lsn_job_item *ji)
-{
-
-	if (ji == NULL)
-		return;
-
-	JQUEUE_LOCK();
-	TAILQ_INSERT_TAIL(&cfg->jhead, ji, next);
-	cfg->jlen++;
-	NAT64STAT_INC(&cfg->stats, jrequests);
-
-	if (callout_pending(&cfg->jcallout) == 0)
-		callout_reset(&cfg->jcallout, 1, nat64lsn_do_request, cfg);
-	JQUEUE_UNLOCK();
-}
-
-static NAT64NOINLINE void
-nat64lsn_enqueue_jobs(struct nat64lsn_cfg *cfg,
-    struct nat64lsn_job_head *jhead, int jlen)
-{
-
-	if (TAILQ_EMPTY(jhead))
-		return;
-
-	/* Attach current queue to execution one */
-	JQUEUE_LOCK();
-	TAILQ_CONCAT(&cfg->jhead, jhead, next);
-	cfg->jlen += jlen;
-	NAT64STAT_ADD(&cfg->stats, jrequests, jlen);
-
-	if (callout_pending(&cfg->jcallout) == 0)
-		callout_reset(&cfg->jcallout, 1, nat64lsn_do_request, cfg);
-	JQUEUE_UNLOCK();
-}
-
-static unsigned int
-flow6_hash(const struct ipfw_flow_id *f_id)
-{
-	unsigned char hbuf[36];
-
-	memcpy(hbuf, &f_id->dst_ip6, 16);
-	memcpy(&hbuf[16], &f_id->src_ip6, 16);
-	memcpy(&hbuf[32], &f_id->dst_port, 2);
-	memcpy(&hbuf[32], &f_id->src_port, 2);
-
-	return (djb_hash(hbuf, sizeof(hbuf)));
-}
-
-static NAT64NOINLINE int
-nat64lsn_request_host(struct nat64lsn_cfg *cfg,
-    const struct ipfw_flow_id *f_id, struct mbuf **pm)
-{
-	struct nat64lsn_job_item *ji;
-	struct mbuf *m;
-
-	m = *pm;
-	*pm = NULL;
-
-	ji = nat64lsn_create_job(cfg, f_id, JTYPE_NEWHOST);
-	if (ji == NULL) {
-		m_freem(m);
-		NAT64STAT_INC(&cfg->stats, dropped);
-		DPRINTF(DP_DROPS, "failed to create job");
-	} else {
-		ji->m = m;
-		/* Provide pseudo-random value based on flow */
-		ji->fhash = flow6_hash(f_id);
-		nat64lsn_enqueue_job(cfg, ji);
-		NAT64STAT_INC(&cfg->stats, jhostsreq);
-	}
-
-	return (IP_FW_PASS);
-}
-
-static NAT64NOINLINE int
-nat64lsn_request_portgroup(struct nat64lsn_cfg *cfg,
-    const struct ipfw_flow_id *f_id, struct mbuf **pm, uint32_t aaddr,
-    int needs_idx)
-{
-	struct nat64lsn_job_item *ji;
-	struct mbuf *m;
-
-	m = *pm;
-	*pm = NULL;
-
-	ji = nat64lsn_create_job(cfg, f_id, JTYPE_NEWPORTGROUP);
-	if (ji == NULL) {
-		m_freem(m);
-		NAT64STAT_INC(&cfg->stats, dropped);
-		DPRINTF(DP_DROPS, "failed to create job");
-	} else {
-		ji->m = m;
-		/* Provide pseudo-random value based on flow */
-		ji->fhash = flow6_hash(f_id);
-		ji->aaddr = aaddr;
-		ji->needs_idx = needs_idx;
-		nat64lsn_enqueue_job(cfg, ji);
-		NAT64STAT_INC(&cfg->stats, jportreq);
-	}
-
-	return (IP_FW_PASS);
-}
-
-static NAT64NOINLINE struct nat64lsn_state * 
-nat64lsn_create_state(struct nat64lsn_cfg *cfg, struct nat64lsn_host *nh,
-    int nat_proto, struct nat64lsn_state *kst, uint32_t *aaddr)
-{
-	struct nat64lsn_portgroup *pg;
-	struct nat64lsn_state *st;
-	int i, hval, off;
-
-	/* XXX: create additional bitmask for selecting proper portgroup */
-	for (i = 0; i < nh->pg_used; i++) {
-		pg = PORTGROUP_BYSIDX(cfg, nh, i + 1);
-		if (pg == NULL)
-			continue;
-		if (*aaddr == 0)
-			*aaddr = pg->aaddr;
-		if (pg->nat_proto != nat_proto)
-			continue;
-
-		off = PG_GET_FREE_IDX(pg);
-		if (off != 0) {
-			/* We have found spare state. Use it */
-			off--;
-			PG_MARK_BUSY_IDX(pg, off);
-			st = &pg->states[off];
-
-			/*
-			 * Fill in new info. Assume state was zeroed.
-			 * Timestamp and flags will be filled by caller.
-			 */
-			st->u.s = kst->u.s;
-			st->cur.idx = i + 1;
-			st->cur.off = off;
-
-			/* Insert into host hash table */
-			hval = HASH_IN4(&st->u.hkey) & (nh->hsize - 1);
-			st->next = nh->phash[hval];
-			nh->phash[hval] = st->cur;
-
-			nat64lsn_dump_state(cfg, pg, st, "ALLOC STATE", off);
-
-			NAT64STAT_INC(&cfg->stats, screated);
-
-			return (st);
-		}
-		/* Saev last used alias affress */
-		*aaddr = pg->aaddr;
-	}
-
-	return (NULL);
-}
-
-static NAT64NOINLINE int
-nat64lsn_translate6(struct nat64lsn_cfg *cfg, struct ipfw_flow_id *f_id,
-    struct mbuf **pm)
-{
-	struct pfloghdr loghdr, *logdata;
-	char a[INET6_ADDRSTRLEN];
-	struct nat64lsn_host *nh;
-	struct st_ptr sidx;
-	struct nat64lsn_state *st, kst;
-	struct nat64lsn_portgroup *pg;
-	struct icmp6_hdr *icmp6;
-	uint32_t aaddr;
-	int action, hval, nat_proto, proto;
-	uint16_t aport, state_ts, state_flags;
-
-	/* Check if af/protocol is supported and get it short id */
-	nat_proto = nat64lsn_proto_map[f_id->proto];
-	if (nat_proto == 0) {
-		/*
-		 * Since we can be called from jobs handler, we need
-		 * to free mbuf by self, do not leave this task to
-		 * ipfw_check_packet().
-		 */
-		NAT64STAT_INC(&cfg->stats, noproto);
-		m_freem(*pm);
-		*pm = NULL;
-		return (IP_FW_DENY);
-	}
-
-	/* Try to find host first */
-	I6HASH_FIND(cfg, nh, &f_id->src_ip6);
-
-	if (nh == NULL)
-		return (nat64lsn_request_host(cfg, f_id, pm));
-
-	/* Fill-in on-stack state structure */
-	kst.u.s.faddr = f_id->dst_ip6.s6_addr32[3];
-	kst.u.s.fport = f_id->dst_port;
-	kst.u.s.lport = f_id->src_port;
-
-	/* Prepare some fields we might need to update */
-	hval = 0;
-	proto = nat64_getlasthdr(*pm, &hval);
-	if (proto < 0) {
-		NAT64STAT_INC(&cfg->stats, dropped);
-		DPRINTF(DP_DROPS, "dropped due to mbuf isn't contigious");
-		m_freem(*pm);
-		*pm = NULL;
-		return (IP_FW_DENY);
-	}
-
-	SET_AGE(state_ts);
-	if (proto == IPPROTO_TCP)
-		state_flags = convert_tcp_flags(
-		    TCP(mtodo(*pm, hval))->th_flags);
-	else
-		state_flags = 0;
-	if (proto == IPPROTO_ICMPV6) {
-		/* Alter local port data */
-		icmp6 = mtodo(*pm, hval);
-		if (icmp6->icmp6_type == ICMP6_ECHO_REQUEST ||
-		    icmp6->icmp6_type == ICMP6_ECHO_REPLY)
-			kst.u.s.lport = ntohs(icmp6->icmp6_id);
-	}
-
-	hval = HASH_IN4(&kst.u.hkey) & (nh->hsize - 1);
-	pg = NULL;
-	st = NULL;
-
-	/* OK, let's find state in host hash */
-	NAT64_LOCK(nh);
-	sidx = nh->phash[hval];
-	int k = 0;
-	while (sidx.idx != 0) {
-		pg = PORTGROUP_BYSIDX(cfg, nh, sidx.idx);
-		st = &pg->states[sidx.off];
-		//DPRINTF("SISX: %d/%d next: %d/%d", sidx.idx, sidx.off,
-		//st->next.idx, st->next.off);
-		if (st->u.hkey == kst.u.hkey && pg->nat_proto == nat_proto)
-			break;
-		if (k++ > 1000) {
-			DPRINTF(DP_ALL, "XXX: too long %d/%d %d/%d\n",
-			    sidx.idx, sidx.off, st->next.idx, st->next.off);
-			inet_ntop(AF_INET6, &nh->addr, a, sizeof(a));
-			DPRINTF(DP_GENERIC, "TR host %s %p on cpu %d",
-			    a, nh, curcpu);
-			k = 0;
-		}
-		sidx = st->next;
-	}
-
-	if (sidx.idx == 0) {
-		aaddr = 0;
-		st = nat64lsn_create_state(cfg, nh, nat_proto, &kst, &aaddr);
-		if (st == NULL) {
-			/* No free states. Request more if we can */
-			if (nh->pg_used >= cfg->max_chunks) {
-				/* Limit reached */
-				NAT64STAT_INC(&cfg->stats, dropped);
-				inet_ntop(AF_INET6, &nh->addr, a, sizeof(a));
-				DPRINTF(DP_DROPS, "PG limit reached "
-				    " for host %s (used %u, allocated %u, "
-				    "limit %u)", a,
-				    nh->pg_used * NAT64_CHUNK_SIZE,
-				    nh->pg_allocated * NAT64_CHUNK_SIZE,
-				    cfg->max_chunks * NAT64_CHUNK_SIZE);
-				m_freem(*pm);
-				*pm = NULL;
-				NAT64_UNLOCK(nh);
-				return (IP_FW_DENY);
-			}
-			if ((nh->pg_allocated <=
-			    nh->pg_used + NAT64LSN_REMAININGPG) &&
-			    nh->pg_allocated < cfg->max_chunks)
-				action = 1; /* Request new indexes */
-			else
-				action = 0;
-			NAT64_UNLOCK(nh);
-			//DPRINTF("No state, unlock for %p", nh);
-			return (nat64lsn_request_portgroup(cfg, f_id,
-			    pm, aaddr, action));
-		}
-
-		/* We've got new state. */
-		sidx = st->cur;
-		pg = PORTGROUP_BYSIDX(cfg, nh, sidx.idx);
-	}
-
-	/* Okay, state found */
-
-	/* Update necessary fileds */
-	if (st->timestamp != state_ts)
-		st->timestamp = state_ts;
-	if ((st->flags & state_flags) != 0)
-		st->flags |= state_flags;
-
-	/* Copy needed state data */
-	aaddr = pg->aaddr;
-	aport = htons(pg->aport + sidx.off);
-
-	NAT64_UNLOCK(nh);
-
-	if (cfg->flags & NAT64_LOG) {
-		logdata = &loghdr;
-		nat64lsn_log(logdata, *pm, AF_INET6, pg->idx, st->cur.off);
-	} else
-		logdata = NULL;
-
-	action = nat64_do_handle_ip6(*pm, aaddr, aport, &cfg->stats, logdata);
-	if (action == NAT64SKIP)
-		return (IP_FW_PASS);
-	if (action == NAT64MFREE)
-		m_freem(*pm);
-	*pm = NULL;	/* mark mbuf as consumed */
-	return (IP_FW_DENY);
-}
-
-/*
- * Main dataplane entry point.
- */
-int
-ipfw_nat64lsn(struct ip_fw_chain *ch, struct ip_fw_args *args,
-    ipfw_insn *cmd, int *done)
-{
-	ipfw_insn *icmd;
-	struct nat64lsn_cfg *cfg;
-	int ret;
-
-	IPFW_RLOCK_ASSERT(ch);
-
-	*done = 1; /* terminate the search */
-	icmd = cmd + 1;
-	if (cmd->opcode != O_EXTERNAL_ACTION ||
-	    cmd->arg1 != V_nat64lsn_eid ||
-	    icmd->opcode != O_EXTERNAL_INSTANCE ||
-	    (cfg = NAT64_LOOKUP(ch, icmd)) == NULL)
-		return (0);
-
-	switch (args->f_id.addr_type) {
-	case 4:
-		ret = nat64lsn_translate4(cfg, &args->f_id, &args->m);
-		break;
-	case 6:
-		ret = nat64lsn_translate6(cfg, &args->f_id, &args->m);
-		break;
-	default:
-		return (0);
-	}
-	return (ret);
-}
-
-static int
-nat64lsn_ctor_host(void *mem, int size, void *arg, int flags)
-{
-	struct nat64lsn_host *nh;
-
-	nh = (struct nat64lsn_host *)mem;
-	memset(nh->pg_ptr, 0, sizeof(nh->pg_ptr));
-	memset(nh->phash, 0, sizeof(nh->phash));
-	return (0);
-}
-
-static int
-nat64lsn_ctor_pgidx(void *mem, int size, void *arg, int flags)
-{
-
-	memset(mem, 0, size);
-	return (0);
-}
-
-void
-nat64lsn_init_internal(void)
-{
-
-	memset(nat64lsn_proto_map, 0, sizeof(nat64lsn_proto_map));
-	/* Set up supported protocol map */
-	nat64lsn_proto_map[IPPROTO_TCP] = NAT_PROTO_TCP;
-	nat64lsn_proto_map[IPPROTO_UDP] = NAT_PROTO_UDP;
-	nat64lsn_proto_map[IPPROTO_ICMP] = NAT_PROTO_ICMP;
-	nat64lsn_proto_map[IPPROTO_ICMPV6] = NAT_PROTO_ICMP;
-	/* Fill in reverse proto map */
-	memset(nat64lsn_rproto_map, 0, sizeof(nat64lsn_rproto_map));
-	nat64lsn_rproto_map[NAT_PROTO_TCP] = IPPROTO_TCP;
-	nat64lsn_rproto_map[NAT_PROTO_UDP] = IPPROTO_UDP;
-	nat64lsn_rproto_map[NAT_PROTO_ICMP] = IPPROTO_ICMPV6;
-
-	JQUEUE_LOCK_INIT();
-	nat64lsn_host_zone = uma_zcreate("NAT64 hosts zone",
-	    sizeof(struct nat64lsn_host), nat64lsn_ctor_host, NULL,
-	    NULL, NULL, UMA_ALIGN_PTR, 0);
-	nat64lsn_pg_zone = uma_zcreate("NAT64 portgroups zone",
-	    sizeof(struct nat64lsn_portgroup), NULL, NULL, NULL, NULL,
-	    UMA_ALIGN_PTR, 0);
-	nat64lsn_pgidx_zone = uma_zcreate("NAT64 portgroup indexes zone",
-	    sizeof(struct nat64lsn_portgroup *) * NAT64LSN_PGIDX_CHUNK,
-	    nat64lsn_ctor_pgidx, NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
-}
-
-void
-nat64lsn_uninit_internal(void)
-{
-
-	JQUEUE_LOCK_DESTROY();
-	uma_zdestroy(nat64lsn_host_zone);
-	uma_zdestroy(nat64lsn_pg_zone);
-	uma_zdestroy(nat64lsn_pgidx_zone);
-}
-
-void
-nat64lsn_start_instance(struct nat64lsn_cfg *cfg)
-{
-
-	callout_reset(&cfg->periodic, hz * PERIODIC_DELAY,
-	    nat64lsn_periodic, cfg);
-}
-
-struct nat64lsn_cfg *
-nat64lsn_init_instance(struct ip_fw_chain *ch, size_t numaddr)
-{
-	struct nat64lsn_cfg *cfg;
-
-	cfg = malloc(sizeof(struct nat64lsn_cfg), M_IPFW, M_WAITOK | M_ZERO);
-	TAILQ_INIT(&cfg->jhead);
-	cfg->vp = curvnet;
-	cfg->ch = ch;
-	COUNTER_ARRAY_ALLOC(cfg->stats.stats, NAT64STATS, M_WAITOK);
-
-	cfg->ihsize = NAT64LSN_HSIZE;
-	cfg->ih = malloc(sizeof(void *) * cfg->ihsize, M_IPFW,
-	    M_WAITOK | M_ZERO);
-
-	cfg->pg = malloc(sizeof(void *) * numaddr * _ADDR_PG_COUNT, M_IPFW,
-	    M_WAITOK | M_ZERO);
-
-        callout_init(&cfg->periodic, CALLOUT_MPSAFE);
-        callout_init(&cfg->jcallout, CALLOUT_MPSAFE);
-
-	return (cfg);
-}
-
-/*
- * Destroy all hosts callback.
- * Called on module unload when all activity already finished, so
- * can work without any locks.
- */
-static NAT64NOINLINE int
-nat64lsn_destroy_host(struct nat64lsn_host *nh, struct nat64lsn_cfg *cfg)
-{
-	struct nat64lsn_portgroup *pg;
-	int i;
-
-	for (i = nh->pg_used; i > 0; i--) {
-		pg = PORTGROUP_BYSIDX(cfg, nh, i);
-		if (pg == NULL)
-			continue;
-		cfg->pg[pg->idx] = NULL;
-		destroy_portgroup(pg);
-		nh->pg_used--;
-	}
-	destroy_host6(nh);
-	cfg->ihcount--;
-	return (0);
-}
-
-void
-nat64lsn_destroy_instance(struct nat64lsn_cfg *cfg)
-{
-	struct nat64lsn_host *nh, *tmp;
-
-	JQUEUE_LOCK();
-	callout_drain(&cfg->jcallout);
-	JQUEUE_UNLOCK();
-
-	callout_drain(&cfg->periodic);
-	I6HASH_FOREACH_SAFE(cfg, nh, tmp, nat64lsn_destroy_host, cfg);
-	DPRINTF(DP_OBJ, "instance %s: hosts %d", cfg->name, cfg->ihcount);
-
-	COUNTER_ARRAY_FREE(cfg->stats.stats, NAT64STATS);
-	free(cfg->ih, M_IPFW);
-	free(cfg->pg, M_IPFW);
-	free(cfg, M_IPFW);
-}
-
Index: eebsd/sys/netpfil/ipfw/nat64/nat64lsn.h
===================================================================
--- freebsd/sys/netpfil/ipfw/nat64/nat64lsn.h	(revision f62c62d2fe57ec02c1350144f7739f8e866ee6d4)
+++ 	(revision )
@@ -1,351 +1,0 @@
-/*-
- * Copyright (c) 2015 Yandex LLC
- * Copyright (c) 2015 Alexander V. Chernikov <melifaro@FreeBSD.org>
- * Copyright (c) 2016 Andrey V. Elsukov <ae@FreeBSD.org>
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
- *
- * $FreeBSD$
- */
-
-#ifndef	_IP_FW_NAT64LSN_H_
-#define	_IP_FW_NAT64LSN_H_
-
-#define	NAT64_CHUNK_SIZE_BITS	6	/* 64 ports */
-#define	NAT64_CHUNK_SIZE	(1 << NAT64_CHUNK_SIZE_BITS)
-
-#define	NAT64_MIN_PORT		1024
-#define	NAT64_MIN_CHUNK		(NAT64_MIN_PORT >> NAT64_CHUNK_SIZE_BITS)
-
-struct st_ptr {
-	uint8_t			idx;	/* index in nh->pg_ptr array.
-					 * NOTE: it starts from 1.
-					 */
-	uint8_t			off;
-};
-#define	NAT64LSN_MAXPGPTR	((1 << (sizeof(uint8_t) * NBBY)) - 1)
-#define	NAT64LSN_PGPTRMASKBITS	(sizeof(uint64_t) * NBBY)
-#define	NAT64LSN_PGPTRNMASK	(roundup(NAT64LSN_MAXPGPTR,	\
-    NAT64LSN_PGPTRMASKBITS) / NAT64LSN_PGPTRMASKBITS)
-
-struct nat64lsn_portgroup;
-/* sizeof(struct nat64lsn_host) = 64 + 64x2 + 8x8 = 256 bytes */
-struct nat64lsn_host {
-	struct rwlock	h_lock;		/* Host states lock */
-
-	struct in6_addr	addr;
-	struct nat64lsn_host	*next;
-	uint16_t	timestamp;	/* Last altered */
-	uint16_t	hsize;		/* ports hash size */
-	uint16_t	pg_used;	/* Number of portgroups used */
-#define	NAT64LSN_REMAININGPG	8	/* Number of remaining PG before
-					 * requesting of new chunk of indexes.
-					 */
-	uint16_t	pg_allocated;	/* Number of portgroups indexes
-					 * allocated.
-					 */
-#define	NAT64LSN_HSIZE	64
-	struct st_ptr	phash[NAT64LSN_HSIZE]; /* XXX: hardcoded size */
-	/*
-	 * PG indexes are stored in chunks with 32 elements.
-	 * The maximum count is limited to 255 due to st_ptr->idx is uint8_t.
-	 */
-#define	NAT64LSN_PGIDX_CHUNK	32
-#define	NAT64LSN_PGNIDX		(roundup(NAT64LSN_MAXPGPTR, \
-    NAT64LSN_PGIDX_CHUNK) / NAT64LSN_PGIDX_CHUNK)
-	struct nat64lsn_portgroup **pg_ptr[NAT64LSN_PGNIDX]; /* PG indexes */
-};
-
-#define	NAT64_RLOCK_ASSERT(h)	rw_assert(&(h)->h_lock, RA_RLOCKED)
-#define	NAT64_WLOCK_ASSERT(h)	rw_assert(&(h)->h_lock, RA_WLOCKED)
-
-#define	NAT64_RLOCK(h)		rw_rlock(&(h)->h_lock)
-#define	NAT64_RUNLOCK(h)	rw_runlock(&(h)->h_lock)
-#define	NAT64_WLOCK(h)		rw_wlock(&(h)->h_lock)
-#define	NAT64_WUNLOCK(h)	rw_wunlock(&(h)->h_lock)
-#define	NAT64_LOCK(h)		NAT64_WLOCK(h)
-#define	NAT64_UNLOCK(h)		NAT64_WUNLOCK(h)
-#define	NAT64_LOCK_INIT(h) do {			\
-	rw_init(&(h)->h_lock, "NAT64 host lock");	\
-	} while (0)
-
-#define	NAT64_LOCK_DESTROY(h) do {			\
-	rw_destroy(&(h)->h_lock);			\
-	} while (0)
-
-/* Internal proto index */
-#define	NAT_PROTO_TCP	1
-#define	NAT_PROTO_UDP	2
-#define	NAT_PROTO_ICMP	3
-
-#define	NAT_MAX_PROTO	4
-extern uint8_t nat64lsn_rproto_map[NAT_MAX_PROTO];
-
-VNET_DECLARE(uint16_t, nat64lsn_eid);
-#define	V_nat64lsn_eid		VNET(nat64lsn_eid)
-#define	IPFW_TLV_NAT64LSN_NAME	IPFW_TLV_EACTION_NAME(V_nat64lsn_eid)
-
-/* Timestamp macro */
-#define	_CT		((int)time_uptime % 65536)
-#define	SET_AGE(x)	(x) = _CT
-#define	GET_AGE(x)	((_CT >= (x)) ? _CT - (x) :	\
-	(int)65536 + _CT - (x))
-
-#ifdef __LP64__
-/* ffsl() is capable of checking 64-bit ints */
-#define	_FFS64
-#endif
-
-/* 16 bytes */
-struct nat64lsn_state {
-	union {
-		struct {
-			in_addr_t	faddr;	/* Remote IPv4 address */
-			uint16_t	fport;	/* Remote IPv4 port */
-			uint16_t	lport;	/* Local IPv6 port */
-		}s;
-		uint64_t		hkey;
-	} u;
-	uint8_t		nat_proto;
-	uint8_t		flags;
-	uint16_t	timestamp;
-	struct st_ptr	cur; /* Index of portgroup in nat64lsn_host */
-	struct st_ptr	next; /* Next entry index */
-};
-
-/*
- * 1024+32 bytes per 64 states, used to store state
- * AND for outside-in state lookup 
- */
-struct nat64lsn_portgroup {
-	struct nat64lsn_host	*host;	/* IPv6 source host info */
-	in_addr_t		aaddr;	/* Alias addr, network format */
-	uint16_t		aport;	/* Base port */
-	uint16_t		timestamp;
-	uint8_t			nat_proto;
-	uint8_t			spare[3];
-	uint32_t		idx;
-#ifdef _FFS64
-	uint64_t		freemask;	/* Mask of free entries */
-#else
-	uint32_t		freemask[2];	/* Mask of free entries */
-#endif
-	struct nat64lsn_state	states[NAT64_CHUNK_SIZE]; /* State storage */
-};
-#ifdef _FFS64
-#define	PG_MARK_BUSY_IDX(_pg, _idx)	(_pg)->freemask &= ~((uint64_t)1<<(_idx))
-#define	PG_MARK_FREE_IDX(_pg, _idx)	(_pg)->freemask |= ((uint64_t)1<<(_idx))
-#define	PG_IS_FREE_IDX(_pg, _idx)	((_pg)->freemask & ((uint64_t)1<<(_idx)))
-#define	PG_IS_BUSY_IDX(_pg, _idx)	(PG_IS_FREE_IDX(_pg, _idx) == 0)
-#define	PG_GET_FREE_IDX(_pg)		(ffsll((_pg)->freemask))
-#define	PG_IS_EMPTY(_pg)		(((_pg)->freemask + 1) == 0)
-#else
-#define	PG_MARK_BUSY_IDX(_pg, _idx)	\
-	(_pg)->freemask[(_idx) / 32] &= ~((u_long)1<<((_idx) % 32))
-#define	PG_MARK_FREE_IDX(_pg, _idx)	\
-	(_pg)->freemask[(_idx) / 32] |= ((u_long)1<<((_idx)  % 32))
-#define	PG_IS_FREE_IDX(_pg, _idx)	\
-	((_pg)->freemask[(_idx) / 32] & ((u_long)1<<((_idx) % 32)))
-#define	PG_IS_BUSY_IDX(_pg, _idx)	(PG_IS_FREE_IDX(_pg, _idx) == 0)
-#define	PG_GET_FREE_IDX(_pg)		_pg_get_free_idx(_pg)
-#define	PG_IS_EMPTY(_pg)		\
-	((((_pg)->freemask[0] + 1) == 0 && ((_pg)->freemask[1] + 1) == 0))
-
-static inline int
-_pg_get_free_idx(const struct nat64lsn_portgroup *pg)
-{
-	int i;
-
-	if ((i = ffsl(pg->freemask[0])) != 0)
-		return (i);
-	if ((i = ffsl(pg->freemask[1])) != 0)
-		return (i + 32);
-	return (0);
-}
-
-#endif
-
-TAILQ_HEAD(nat64lsn_job_head, nat64lsn_job_item);
-
-#define	NAT64LSN_FLAGSMASK	(NAT64_LOG)
-struct nat64lsn_cfg {
-	struct named_object	no;
-	//struct nat64_exthost	*ex;	/* Pointer to external addr array */
-	struct nat64lsn_portgroup	**pg;	/* XXX: array of pointers */
-	struct nat64lsn_host	**ih;	/* Host hash */
-	uint32_t	prefix4;	/* IPv4 prefix */
-	uint32_t	pmask4;		/* IPv4 prefix mask */
-	uint32_t	ihsize;		/* IPv6 host hash size */
-	uint8_t		plen4;
-	uint8_t		plen6;
-	uint8_t		nomatch_verdict;/* What to return to ipfw on no-match */
-	uint8_t		nomatch_final;	/* Exit outer loop? */
-	struct in6_addr	prefix6;	/* IPv6 prefix to embed IPv4 hosts */
-
-	uint32_t	ihcount;	/* Number of items in host hash */
-	int		max_chunks;	/* Max chunks per client */
-	int		agg_prefix_len;	/* Prefix length to count */
-	int		agg_prefix_max;	/* Max hosts per agg prefix */
-	uint32_t	jmaxlen;	/* Max jobqueue length */
-	uint32_t	flags;
-	uint16_t	min_chunk;	/* Min port group # to use */
-	uint16_t	max_chunk;	/* Max port group # to use */
-	uint16_t	nh_delete_delay;	/* Stale host delete delay */
-	uint16_t	pg_delete_delay;	/* Stale portgroup del delay */
-	uint16_t	st_syn_ttl;	/* TCP syn expire */
-	uint16_t	st_close_ttl;	/* TCP fin expire */
-	uint16_t	st_estab_ttl;	/* TCP established expire */
-	uint16_t	st_udp_ttl;	/* UDP expire */
-	uint16_t	st_icmp_ttl;	/* ICMP expire */
-	uint32_t	protochunks[NAT_MAX_PROTO];/* Number of chunks used */
-
-	struct callout		periodic;
-	struct callout		jcallout;
-	struct ip_fw_chain	*ch;
-	struct vnet		*vp;
-	struct nat64lsn_job_head	jhead;
-	int			jlen;
-	char			name[64];	/* Nat instance name */
-	nat64_stats_block	stats;
-};
-
-struct nat64lsn_cfg *nat64lsn_init_instance(struct ip_fw_chain *ch,
-    size_t numaddr);
-void nat64lsn_destroy_instance(struct nat64lsn_cfg *cfg);
-void nat64lsn_start_instance(struct nat64lsn_cfg *cfg);
-void nat64lsn_init_internal(void);
-void nat64lsn_uninit_internal(void);
-int ipfw_nat64lsn(struct ip_fw_chain *ch, struct ip_fw_args *args,
-    ipfw_insn *cmd, int *done);
-
-void
-nat64lsn_dump_state(const struct nat64lsn_cfg *cfg,
-    const struct nat64lsn_portgroup *pg, const struct nat64lsn_state *st,
-    const char *px, int off);
-/*
- * Portgroup layout
- * addr x nat_proto x port_off
- *
- */
-
-#define	_ADDR_PG_PROTO_COUNT	(65536 >> NAT64_CHUNK_SIZE_BITS)
-#define	_ADDR_PG_COUNT		(_ADDR_PG_PROTO_COUNT * NAT_MAX_PROTO)
-
-#define	GET_ADDR_IDX(_cfg, _addr)	((_addr) - ((_cfg)->prefix4))
-#define	__GET_PORTGROUP_IDX(_proto, _port)	\
-    ((_proto - 1) * _ADDR_PG_PROTO_COUNT +	\
-	((_port) >> NAT64_CHUNK_SIZE_BITS))
-
-#define	_GET_PORTGROUP_IDX(_cfg, _addr, _proto, _port)	\
-    GET_ADDR_IDX(_cfg, _addr) * _ADDR_PG_COUNT +	\
-	__GET_PORTGROUP_IDX(_proto, _port)
-#define	GET_PORTGROUP(_cfg, _addr, _proto, _port)	\
-    ((_cfg)->pg[_GET_PORTGROUP_IDX(_cfg, _addr, _proto, _port)])
-
-#define	PORTGROUP_CHUNK(_nh, _idx)		\
-    ((_nh)->pg_ptr[(_idx)])
-#define	PORTGROUP_BYSIDX(_cfg, _nh, _idx)	\
-    (PORTGROUP_CHUNK(_nh, (_idx - 1) / NAT64LSN_PGIDX_CHUNK) \
-	[((_idx) - 1) % NAT64LSN_PGIDX_CHUNK])
-
-
-/* Chained hash table */
-#define CHT_FIND(_ph, _hsize, _PX, _x, _key) do {			\
-	unsigned int _buck = _PX##hash(_key) & (_hsize - 1);		\
-	_PX##lock(_ph, _buck);						\
-	_x = _PX##first(_ph, _buck);					\
-	for ( ; _x != NULL; _x = _PX##next(_x)) {			\
-		if (_PX##cmp(_key, _PX##val(_x)))			\
-			break;						\
-	}								\
-	if (_x == NULL)							\
-		_PX##unlock(_ph, _buck);				\
-} while(0)
-
-#define	CHT_UNLOCK_BUCK(_ph, _PX, _buck)				\
-	_PX##unlock(_ph, _buck);
-
-#define	CHT_UNLOCK_KEY(_ph, _hsize, _PX, _key) do {			\
-	unsigned int _buck = _PX##hash(_key) & (_hsize - 1);		\
-	_PX##unlock(_ph, _buck);					\
-} while(0)
-
-#define	CHT_INSERT_HEAD(_ph, _hsize, _PX, _i) do {			\
-	unsigned int _buck = _PX##hash(_PX##val(_i)) & (_hsize - 1);	\
-	_PX##lock(_ph, _buck);						\
-	_PX##next(_i) = _PX##first(_ph, _buck);				\
-	_PX##first(_ph, _buck) = _i;					\
-	_PX##unlock(_ph, _buck);					\
-} while(0)
-
-#define	CHT_REMOVE(_ph, _hsize, _PX, _x, _tmp, _key) do {		\
-	unsigned int _buck = _PX##hash(_key) & (_hsize - 1);		\
-	_PX##lock(_ph, _buck);						\
-	_x = _PX##first(_ph, _buck);					\
-	_tmp = NULL;							\
-	for ( ; _x != NULL; _tmp = _x, _x = _PX##next(_x)) {		\
-		if (_PX##cmp(_key, _PX##val(_x)))			\
-			break;						\
-	}								\
-	if (_x != NULL) {						\
-		if (_tmp == NULL)					\
-			_PX##first(_ph, _buck) = _PX##next(_x);		\
-		else							\
-			_PX##next(_tmp) = _PX##next(_x);		\
-	}								\
-	_PX##unlock(_ph, _buck);					\
-} while(0)
-
-#define	CHT_FOREACH_SAFE(_ph, _hsize, _PX, _x, _tmp, _cb, _arg) do {	\
-	for (unsigned int _i = 0; _i < _hsize; _i++) {			\
-		_PX##lock(_ph, _i);					\
-		_x = _PX##first(_ph, _i);				\
-		_tmp = NULL;						\
-		for (; _x != NULL; _tmp = _x, _x = _PX##next(_x)) {	\
-			if (_cb(_x, _arg) == 0)				\
-				continue;				\
-			if (_tmp == NULL)				\
-				_PX##first(_ph, _i) = _PX##next(_x);	\
-			else						\
-				_tmp = _PX##next(_x);			\
-		}							\
-		_PX##unlock(_ph, _i);					\
-	}								\
-} while(0)
-
-#define	CHT_RESIZE(_ph, _hsize, _nph, _nhsize, _PX, _x, _y) do {	\
-	unsigned int _buck;						\
-	for (unsigned int _i = 0; _i < _hsize; _i++) {			\
-		_x = _PX##first(_ph, _i);				\
-		_y = _x;						\
-		while (_y != NULL) {					\
-			_buck = _PX##hash(_PX##val(_x)) & (_nhsize - 1);\
-			_y = _PX##next(_x);				\
-			_PX##next(_x) = _PX##first(_nph, _buck);	\
-			_PX##first(_nph, _buck) = _x;			\
-		}							\
-	}								\
-} while(0)
-
-#endif /* _IP_FW_NAT64LSN_H_ */
-
Index: eebsd/sys/netpfil/ipfw/nat64/nat64lsn_control.c
===================================================================
--- freebsd/sys/netpfil/ipfw/nat64/nat64lsn_control.c	(revision f62c62d2fe57ec02c1350144f7739f8e866ee6d4)
+++ 	(revision )
@@ -1,919 +1,0 @@
-#include <machine/rtems-bsd-kernel-space.h>
-
-/*-
- * Copyright (c) 2015 Yandex LLC
- * Copyright (c) 2015 Alexander V. Chernikov <melifaro@FreeBSD.org>
- * Copyright (c) 2016 Andrey V. Elsukov <ae@FreeBSD.org>
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/counter.h>
-#include <sys/errno.h>
-#include <sys/kernel.h>
-#include <sys/lock.h>
-#include <sys/malloc.h>
-#include <sys/mbuf.h>
-#include <sys/module.h>
-#include <sys/rmlock.h>
-#include <sys/rwlock.h>
-#include <sys/socket.h>
-#include <sys/sockopt.h>
-#include <sys/queue.h>
-
-#include <net/if.h>
-#include <net/pfil.h>
-
-#include <netinet/in.h>
-#include <netinet/ip.h>
-#include <netinet/ip_var.h>
-#include <netinet/ip_fw.h>
-
-#include <netpfil/ipfw/ip_fw_private.h>
-#include <netpfil/ipfw/nat64/ip_fw_nat64.h>
-#include <netpfil/ipfw/nat64/nat64lsn.h>
-#include <netinet6/ip_fw_nat64.h>
-
-VNET_DEFINE(uint16_t, nat64lsn_eid) = 0;
-
-static struct nat64lsn_cfg *
-nat64lsn_find(struct namedobj_instance *ni, const char *name, uint8_t set)
-{
-	struct nat64lsn_cfg *cfg;
-
-	cfg = (struct nat64lsn_cfg *)ipfw_objhash_lookup_name_type(ni, set,
-	    IPFW_TLV_NAT64LSN_NAME, name);
-
-	return (cfg);
-}
-
-static void
-nat64lsn_default_config(ipfw_nat64lsn_cfg *uc)
-{
-
-	if (uc->max_ports == 0)
-		uc->max_ports = NAT64LSN_MAX_PORTS;
-	else
-		uc->max_ports = roundup(uc->max_ports, NAT64_CHUNK_SIZE);
-	if (uc->max_ports > NAT64_CHUNK_SIZE * NAT64LSN_MAXPGPTR)
-		uc->max_ports = NAT64_CHUNK_SIZE * NAT64LSN_MAXPGPTR;
-	if (uc->jmaxlen == 0)
-		uc->jmaxlen = NAT64LSN_JMAXLEN;
-	if (uc->jmaxlen > 65536)
-		uc->jmaxlen = 65536;
-	if (uc->nh_delete_delay == 0)
-		uc->nh_delete_delay = NAT64LSN_HOST_AGE;
-	if (uc->pg_delete_delay == 0)
-		uc->pg_delete_delay = NAT64LSN_PG_AGE;
-	if (uc->st_syn_ttl == 0)
-		uc->st_syn_ttl = NAT64LSN_TCP_SYN_AGE;
-	if (uc->st_close_ttl == 0)
-		uc->st_close_ttl = NAT64LSN_TCP_FIN_AGE;
-	if (uc->st_estab_ttl == 0)
-		uc->st_estab_ttl = NAT64LSN_TCP_EST_AGE;
-	if (uc->st_udp_ttl == 0)
-		uc->st_udp_ttl = NAT64LSN_UDP_AGE;
-	if (uc->st_icmp_ttl == 0)
-		uc->st_icmp_ttl = NAT64LSN_ICMP_AGE;
-}
-
-/*
- * Creates new nat64lsn instance.
- * Data layout (v0)(current):
- * Request: [ ipfw_obj_lheader ipfw_nat64lsn_cfg ]
- *
- * Returns 0 on success
- */
-static int
-nat64lsn_create(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
-    struct sockopt_data *sd)
-{
-	ipfw_obj_lheader *olh;
-	ipfw_nat64lsn_cfg *uc;
-	struct nat64lsn_cfg *cfg;
-	struct namedobj_instance *ni;
-	uint32_t addr4, mask4;
-
-	if (sd->valsize != sizeof(*olh) + sizeof(*uc))
-		return (EINVAL);
-
-	olh = (ipfw_obj_lheader *)sd->kbuf;
-	uc = (ipfw_nat64lsn_cfg *)(olh + 1);
-
-	if (ipfw_check_object_name_generic(uc->name) != 0)
-		return (EINVAL);
-
-	if (uc->agg_prefix_len > 127 || uc->set >= IPFW_MAX_SETS)
-		return (EINVAL);
-
-	if (uc->plen4 > 32)
-		return (EINVAL);
-	if (uc->plen6 > 128 || ((uc->plen6 % 8) != 0))
-		return (EINVAL);
-
-	/* XXX: Check prefix4 to be global */
-	addr4 = ntohl(uc->prefix4.s_addr);
-	mask4 = ~((1 << (32 - uc->plen4)) - 1);
-	if ((addr4 & mask4) != addr4)
-		return (EINVAL);
-
-	/* XXX: Check prefix6 */
-	if (uc->min_port == 0)
-		uc->min_port = NAT64_MIN_PORT;
-	if (uc->max_port == 0)
-		uc->max_port = 65535;
-	if (uc->min_port > uc->max_port)
-		return (EINVAL);
-	uc->min_port = roundup(uc->min_port, NAT64_CHUNK_SIZE);
-	uc->max_port = roundup(uc->max_port, NAT64_CHUNK_SIZE);
-
-	nat64lsn_default_config(uc);
-
-	ni = CHAIN_TO_SRV(ch);
-	IPFW_UH_RLOCK(ch);
-	if (nat64lsn_find(ni, uc->name, uc->set) != NULL) {
-		IPFW_UH_RUNLOCK(ch);
-		return (EEXIST);
-	}
-	IPFW_UH_RUNLOCK(ch);
-
-	cfg = nat64lsn_init_instance(ch, 1 << (32 - uc->plen4));
-	strlcpy(cfg->name, uc->name, sizeof(cfg->name));
-	cfg->no.name = cfg->name;
-	cfg->no.etlv = IPFW_TLV_NAT64LSN_NAME;
-	cfg->no.set = uc->set;
-
-	cfg->prefix4 = addr4;
-	cfg->pmask4 = addr4 | ~mask4;
-	/* XXX: Copy 96 bits */
-	cfg->plen6 = 96;
-	memcpy(&cfg->prefix6, &uc->prefix6, cfg->plen6 / 8);
-	cfg->plen4 = uc->plen4;
-	cfg->flags = uc->flags & NAT64LSN_FLAGSMASK;
-	cfg->max_chunks = uc->max_ports / NAT64_CHUNK_SIZE;
-	cfg->agg_prefix_len = uc->agg_prefix_len;
-	cfg->agg_prefix_max = uc->agg_prefix_max;
-
-	cfg->min_chunk = uc->min_port / NAT64_CHUNK_SIZE;
-	cfg->max_chunk = uc->max_port / NAT64_CHUNK_SIZE;
-
-	cfg->jmaxlen = uc->jmaxlen;
-	cfg->nh_delete_delay = uc->nh_delete_delay;
-	cfg->pg_delete_delay = uc->pg_delete_delay;
-	cfg->st_syn_ttl = uc->st_syn_ttl;
-	cfg->st_close_ttl = uc->st_close_ttl;
-	cfg->st_estab_ttl = uc->st_estab_ttl;
-	cfg->st_udp_ttl = uc->st_udp_ttl;
-	cfg->st_icmp_ttl = uc->st_icmp_ttl;
-
-	cfg->nomatch_verdict = IP_FW_DENY;
-	cfg->nomatch_final = 1;	/* Exit outer loop by default */
-
-	IPFW_UH_WLOCK(ch);
-
-	if (nat64lsn_find(ni, uc->name, uc->set) != NULL) {
-		IPFW_UH_WUNLOCK(ch);
-		nat64lsn_destroy_instance(cfg);
-		return (EEXIST);
-	}
-
-	if (ipfw_objhash_alloc_idx(CHAIN_TO_SRV(ch), &cfg->no.kidx) != 0) {
-		IPFW_UH_WUNLOCK(ch);
-		nat64lsn_destroy_instance(cfg);
-		return (ENOSPC);
-	}
-	ipfw_objhash_add(CHAIN_TO_SRV(ch), &cfg->no);
-
-	/* Okay, let's link data */
-	IPFW_WLOCK(ch);
-	SRV_OBJECT(ch, cfg->no.kidx) = cfg;
-	IPFW_WUNLOCK(ch);
-
-	nat64lsn_start_instance(cfg);
-
-	IPFW_UH_WUNLOCK(ch);
-	return (0);
-}
-
-static void
-nat64lsn_detach_config(struct ip_fw_chain *ch, struct nat64lsn_cfg *cfg)
-{
-
-	IPFW_UH_WLOCK_ASSERT(ch);
-
-	ipfw_objhash_del(CHAIN_TO_SRV(ch), &cfg->no);
-	ipfw_objhash_free_idx(CHAIN_TO_SRV(ch), cfg->no.kidx);
-}
-
-/*
- * Destroys nat64 instance.
- * Data layout (v0)(current):
- * Request: [ ipfw_obj_header ]
- *
- * Returns 0 on success
- */
-static int
-nat64lsn_destroy(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
-    struct sockopt_data *sd)
-{
-	struct nat64lsn_cfg *cfg;
-	ipfw_obj_header *oh;
-
-	if (sd->valsize != sizeof(*oh))
-		return (EINVAL);
-
-	oh = (ipfw_obj_header *)op3;
-
-	IPFW_UH_WLOCK(ch);
-	cfg = nat64lsn_find(CHAIN_TO_SRV(ch), oh->ntlv.name, oh->ntlv.set);
-	if (cfg == NULL) {
-		IPFW_UH_WUNLOCK(ch);
-		return (ESRCH);
-	}
-
-	if (cfg->no.refcnt > 0) {
-		IPFW_UH_WUNLOCK(ch);
-		return (EBUSY);
-	}
-
-	IPFW_WLOCK(ch);
-	SRV_OBJECT(ch, cfg->no.kidx) = NULL;
-	IPFW_WUNLOCK(ch);
-
-	nat64lsn_detach_config(ch, cfg);
-	IPFW_UH_WUNLOCK(ch);
-
-	nat64lsn_destroy_instance(cfg);
-	return (0);
-}
-
-#define	__COPY_STAT_FIELD(_cfg, _stats, _field)	\
-	(_stats)->_field = NAT64STAT_FETCH(&(_cfg)->stats, _field)
-static void
-export_stats(struct ip_fw_chain *ch, struct nat64lsn_cfg *cfg,
-    struct ipfw_nat64lsn_stats *stats)
-{
-
-	__COPY_STAT_FIELD(cfg, stats, opcnt64);
-	__COPY_STAT_FIELD(cfg, stats, opcnt46);
-	__COPY_STAT_FIELD(cfg, stats, ofrags);
-	__COPY_STAT_FIELD(cfg, stats, ifrags);
-	__COPY_STAT_FIELD(cfg, stats, oerrors);
-	__COPY_STAT_FIELD(cfg, stats, noroute4);
-	__COPY_STAT_FIELD(cfg, stats, noroute6);
-	__COPY_STAT_FIELD(cfg, stats, nomatch4);
-	__COPY_STAT_FIELD(cfg, stats, noproto);
-	__COPY_STAT_FIELD(cfg, stats, nomem);
-	__COPY_STAT_FIELD(cfg, stats, dropped);
-
-	__COPY_STAT_FIELD(cfg, stats, jcalls);
-	__COPY_STAT_FIELD(cfg, stats, jrequests);
-	__COPY_STAT_FIELD(cfg, stats, jhostsreq);
-	__COPY_STAT_FIELD(cfg, stats, jportreq);
-	__COPY_STAT_FIELD(cfg, stats, jhostfails);
-	__COPY_STAT_FIELD(cfg, stats, jportfails);
-	__COPY_STAT_FIELD(cfg, stats, jmaxlen);
-	__COPY_STAT_FIELD(cfg, stats, jnomem);
-	__COPY_STAT_FIELD(cfg, stats, jreinjected);
-	__COPY_STAT_FIELD(cfg, stats, screated);
-	__COPY_STAT_FIELD(cfg, stats, sdeleted);
-	__COPY_STAT_FIELD(cfg, stats, spgcreated);
-	__COPY_STAT_FIELD(cfg, stats, spgdeleted);
-
-	stats->hostcount = cfg->ihcount;
-	stats->tcpchunks = cfg->protochunks[NAT_PROTO_TCP];
-	stats->udpchunks = cfg->protochunks[NAT_PROTO_UDP];
-	stats->icmpchunks = cfg->protochunks[NAT_PROTO_ICMP];
-}
-#undef	__COPY_STAT_FIELD
-
-static void
-nat64lsn_export_config(struct ip_fw_chain *ch, struct nat64lsn_cfg *cfg,
-    ipfw_nat64lsn_cfg *uc)
-{
-
-	uc->flags = cfg->flags & NAT64LSN_FLAGSMASK;
-	uc->max_ports = cfg->max_chunks * NAT64_CHUNK_SIZE;
-	uc->agg_prefix_len = cfg->agg_prefix_len;
-	uc->agg_prefix_max = cfg->agg_prefix_max;
-
-	uc->jmaxlen = cfg->jmaxlen;
-	uc->nh_delete_delay = cfg->nh_delete_delay;
-	uc->pg_delete_delay = cfg->pg_delete_delay;
-	uc->st_syn_ttl = cfg->st_syn_ttl;
-	uc->st_close_ttl = cfg->st_close_ttl;
-	uc->st_estab_ttl = cfg->st_estab_ttl;
-	uc->st_udp_ttl = cfg->st_udp_ttl;
-	uc->st_icmp_ttl = cfg->st_icmp_ttl;
-	uc->prefix4.s_addr = htonl(cfg->prefix4);
-	uc->prefix6 = cfg->prefix6;
-	uc->plen4 = cfg->plen4;
-	uc->plen6 = cfg->plen6;
-	uc->set = cfg->no.set;
-	strlcpy(uc->name, cfg->no.name, sizeof(uc->name));
-}
-
-struct nat64_dump_arg {
-	struct ip_fw_chain *ch;
-	struct sockopt_data *sd;
-};
-
-static int
-export_config_cb(struct namedobj_instance *ni, struct named_object *no,
-    void *arg)
-{
-	struct nat64_dump_arg *da = (struct nat64_dump_arg *)arg;
-	ipfw_nat64lsn_cfg *uc;
-
-	uc = (struct _ipfw_nat64lsn_cfg *)ipfw_get_sopt_space(da->sd,
-	    sizeof(*uc));
-	nat64lsn_export_config(da->ch, (struct nat64lsn_cfg *)no, uc);
-	return (0);
-}
-
-/*
- * Lists all nat64 lsn instances currently available in kernel.
- * Data layout (v0)(current):
- * Request: [ ipfw_obj_lheader ]
- * Reply: [ ipfw_obj_lheader ipfw_nat64lsn_cfg x N ]
- *
- * Returns 0 on success
- */
-static int
-nat64lsn_list(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
-    struct sockopt_data *sd)
-{
-	ipfw_obj_lheader *olh;
-	struct nat64_dump_arg da;
-
-	/* Check minimum header size */
-	if (sd->valsize < sizeof(ipfw_obj_lheader))
-		return (EINVAL);
-
-	olh = (ipfw_obj_lheader *)ipfw_get_sopt_header(sd, sizeof(*olh));
-
-	IPFW_UH_RLOCK(ch);
-	olh->count = ipfw_objhash_count_type(CHAIN_TO_SRV(ch),
-	    IPFW_TLV_NAT64LSN_NAME);
-	olh->objsize = sizeof(ipfw_nat64lsn_cfg);
-	olh->size = sizeof(*olh) + olh->count * olh->objsize;
-
-	if (sd->valsize < olh->size) {
-		IPFW_UH_RUNLOCK(ch);
-		return (ENOMEM);
-	}
-	memset(&da, 0, sizeof(da));
-	da.ch = ch;
-	da.sd = sd;
-	ipfw_objhash_foreach_type(CHAIN_TO_SRV(ch), export_config_cb, &da,
-	    IPFW_TLV_NAT64LSN_NAME);
-	IPFW_UH_RUNLOCK(ch);
-
-	return (0);
-}
-
-/*
- * Change existing nat64lsn instance configuration.
- * Data layout (v0)(current):
- * Request: [ ipfw_obj_header ipfw_nat64lsn_cfg ]
- * Reply: [ ipfw_obj_header ipfw_nat64lsn_cfg ]
- *
- * Returns 0 on success
- */
-static int
-nat64lsn_config(struct ip_fw_chain *ch, ip_fw3_opheader *op,
-    struct sockopt_data *sd)
-{
-	ipfw_obj_header *oh;
-	ipfw_nat64lsn_cfg *uc;
-	struct nat64lsn_cfg *cfg;
-	struct namedobj_instance *ni;
-
-	if (sd->valsize != sizeof(*oh) + sizeof(*uc))
-		return (EINVAL);
-
-	oh = (ipfw_obj_header *)ipfw_get_sopt_space(sd,
-	    sizeof(*oh) + sizeof(*uc));
-	uc = (ipfw_nat64lsn_cfg *)(oh + 1);
-
-	if (ipfw_check_object_name_generic(oh->ntlv.name) != 0 ||
-	    oh->ntlv.set >= IPFW_MAX_SETS)
-		return (EINVAL);
-
-	ni = CHAIN_TO_SRV(ch);
-	if (sd->sopt->sopt_dir == SOPT_GET) {
-		IPFW_UH_RLOCK(ch);
-		cfg = nat64lsn_find(ni, oh->ntlv.name, oh->ntlv.set);
-		if (cfg == NULL) {
-			IPFW_UH_RUNLOCK(ch);
-			return (EEXIST);
-		}
-		nat64lsn_export_config(ch, cfg, uc);
-		IPFW_UH_RUNLOCK(ch);
-		return (0);
-	}
-
-	nat64lsn_default_config(uc);
-
-	IPFW_UH_WLOCK(ch);
-	cfg = nat64lsn_find(ni, oh->ntlv.name, oh->ntlv.set);
-	if (cfg == NULL) {
-		IPFW_UH_WUNLOCK(ch);
-		return (EEXIST);
-	}
-
-	/*
-	 * For now allow to change only following values:
-	 *  jmaxlen, nh_del_age, pg_del_age, tcp_syn_age, tcp_close_age,
-	 *  tcp_est_age, udp_age, icmp_age, flags, max_ports.
-	 */
-
-	cfg->max_chunks = uc->max_ports / NAT64_CHUNK_SIZE;
-	cfg->jmaxlen = uc->jmaxlen;
-	cfg->nh_delete_delay = uc->nh_delete_delay;
-	cfg->pg_delete_delay = uc->pg_delete_delay;
-	cfg->st_syn_ttl = uc->st_syn_ttl;
-	cfg->st_close_ttl = uc->st_close_ttl;
-	cfg->st_estab_ttl = uc->st_estab_ttl;
-	cfg->st_udp_ttl = uc->st_udp_ttl;
-	cfg->st_icmp_ttl = uc->st_icmp_ttl;
-	cfg->flags = uc->flags & NAT64LSN_FLAGSMASK;
-
-	IPFW_UH_WUNLOCK(ch);
-
-	return (0);
-}
-
-/*
- * Get nat64lsn statistics.
- * Data layout (v0)(current):
- * Request: [ ipfw_obj_header ]
- * Reply: [ ipfw_obj_header ipfw_counter_tlv ]
- *
- * Returns 0 on success
- */
-static int
-nat64lsn_stats(struct ip_fw_chain *ch, ip_fw3_opheader *op,
-    struct sockopt_data *sd)
-{
-	struct ipfw_nat64lsn_stats stats;
-	struct nat64lsn_cfg *cfg;
-	ipfw_obj_header *oh;
-	ipfw_obj_ctlv *ctlv;
-	size_t sz;
-
-	sz = sizeof(ipfw_obj_header) + sizeof(ipfw_obj_ctlv) + sizeof(stats);
-	if (sd->valsize % sizeof(uint64_t))
-		return (EINVAL);
-	if (sd->valsize < sz)
-		return (ENOMEM);
-	oh = (ipfw_obj_header *)ipfw_get_sopt_header(sd, sz);
-	if (oh == NULL)
-		return (EINVAL);
-	memset(&stats, 0, sizeof(stats));
-
-	IPFW_UH_RLOCK(ch);
-	cfg = nat64lsn_find(CHAIN_TO_SRV(ch), oh->ntlv.name, oh->ntlv.set);
-	if (cfg == NULL) {
-		IPFW_UH_RUNLOCK(ch);
-		return (ESRCH);
-	}
-
-	export_stats(ch, cfg, &stats);
-	IPFW_UH_RUNLOCK(ch);
-
-	ctlv = (ipfw_obj_ctlv *)(oh + 1);
-	memset(ctlv, 0, sizeof(*ctlv));
-	ctlv->head.type = IPFW_TLV_COUNTERS;
-	ctlv->head.length = sz - sizeof(ipfw_obj_header);
-	ctlv->count = sizeof(stats) / sizeof(uint64_t);
-	ctlv->objsize = sizeof(uint64_t);
-	ctlv->version = IPFW_NAT64_VERSION;
-	memcpy(ctlv + 1, &stats, sizeof(stats));
-	return (0);
-}
-
-/*
- * Reset nat64lsn statistics.
- * Data layout (v0)(current):
- * Request: [ ipfw_obj_header ]
- *
- * Returns 0 on success
- */
-static int
-nat64lsn_reset_stats(struct ip_fw_chain *ch, ip_fw3_opheader *op,
-    struct sockopt_data *sd)
-{
-	struct nat64lsn_cfg *cfg;
-	ipfw_obj_header *oh;
-
-	if (sd->valsize != sizeof(*oh))
-		return (EINVAL);
-	oh = (ipfw_obj_header *)sd->kbuf;
-	if (ipfw_check_object_name_generic(oh->ntlv.name) != 0 ||
-	    oh->ntlv.set >= IPFW_MAX_SETS)
-		return (EINVAL);
-
-	IPFW_UH_WLOCK(ch);
-	cfg = nat64lsn_find(CHAIN_TO_SRV(ch), oh->ntlv.name, oh->ntlv.set);
-	if (cfg == NULL) {
-		IPFW_UH_WUNLOCK(ch);
-		return (ESRCH);
-	}
-	COUNTER_ARRAY_ZERO(cfg->stats.stats, NAT64STATS);
-	IPFW_UH_WUNLOCK(ch);
-	return (0);
-}
-
-/*
- * Reply: [ ipfw_obj_header ipfw_obj_data [ ipfw_nat64lsn_stg
- *	ipfw_nat64lsn_state x count, ... ] ]
- */
-static int
-export_pg_states(struct nat64lsn_cfg *cfg, struct nat64lsn_portgroup *pg,
-    ipfw_nat64lsn_stg *stg, struct sockopt_data *sd)
-{
-	ipfw_nat64lsn_state *ste;
-	struct nat64lsn_state *st;
-	int i, count;
-
-	NAT64_LOCK(pg->host);
-	count = 0;
-	for (i = 0; i < 64; i++) {
-		if (PG_IS_BUSY_IDX(pg, i))
-			count++;
-	}
-	DPRINTF(DP_STATE, "EXPORT PG %d, count %d", pg->idx, count);
-
-	if (count == 0) {
-		stg->count = 0;
-		NAT64_UNLOCK(pg->host);
-		return (0);
-	}
-	ste = (ipfw_nat64lsn_state *)ipfw_get_sopt_space(sd,
-	    count * sizeof(ipfw_nat64lsn_state));
-	if (ste == NULL) {
-		NAT64_UNLOCK(pg->host);
-		return (1);
-	}
-
-	stg->alias4.s_addr = pg->aaddr;
-	stg->proto = nat64lsn_rproto_map[pg->nat_proto];
-	stg->flags = 0;
-	stg->host6 = pg->host->addr;
-	stg->count = count;
-	for (i = 0; i < 64; i++) {
-		if (PG_IS_FREE_IDX(pg, i))
-			continue;
-		st = &pg->states[i];
-		ste->daddr.s_addr = st->u.s.faddr;
-		ste->dport = st->u.s.fport;
-		ste->aport = pg->aport + i;
-		ste->sport = st->u.s.lport;
-		ste->flags = st->flags; /* XXX filter flags */
-		ste->idle = GET_AGE(st->timestamp);
-		ste++;
-	}
-	NAT64_UNLOCK(pg->host);
-
-	return (0);
-}
-
-static int
-get_next_idx(struct nat64lsn_cfg *cfg, uint32_t *addr, uint8_t *nat_proto,
-    uint16_t *port)
-{
-
-	if (*port < 65536 - NAT64_CHUNK_SIZE) {
-		*port += NAT64_CHUNK_SIZE;
-		return (0);
-	}
-	*port = 0;
-
-	if (*nat_proto < NAT_MAX_PROTO - 1) {
-		*nat_proto += 1;
-		return (0);
-	}
-	*nat_proto = 1;
-
-	if (*addr < cfg->pmask4) {
-		*addr += 1;
-		return (0);
-	}
-
-	/* End of space. */
-	return (1);
-}
-
-#define	PACK_IDX(addr, proto, port)	\
-	((uint64_t)addr << 32) | ((uint32_t)port << 16) | (proto << 8)
-#define	UNPACK_IDX(idx, addr, proto, port)		\
-	(addr) = (uint32_t)((idx) >> 32);		\
-	(port) = (uint16_t)(((idx) >> 16) & 0xFFFF);	\
-	(proto) = (uint8_t)(((idx) >> 8) & 0xFF)
-
-static struct nat64lsn_portgroup *
-get_next_pg(struct nat64lsn_cfg *cfg, uint32_t *addr, uint8_t *nat_proto,
-  uint16_t *port)
-{
-	struct nat64lsn_portgroup *pg;
-	uint64_t pre_pack, post_pack;
-
-	pg = NULL;
-	pre_pack = PACK_IDX(*addr, *nat_proto, *port);
-	for (;;) {
-		if (get_next_idx(cfg, addr, nat_proto, port) != 0) {
-			/* End of states */
-			return (pg);
-		}
-
-		pg = GET_PORTGROUP(cfg, *addr, *nat_proto, *port);
-		if (pg != NULL)
-			break;
-	}
-
-	post_pack = PACK_IDX(*addr, *nat_proto, *port);
-	if (pre_pack == post_pack)
-		DPRINTF(DP_STATE, "XXX: PACK_IDX %u %d %d",
-		    *addr, *nat_proto, *port);
-	return (pg);
-}
-
-static NAT64NOINLINE struct nat64lsn_portgroup *
-get_first_pg(struct nat64lsn_cfg *cfg, uint32_t *addr, uint8_t *nat_proto,
-  uint16_t *port)
-{
-	struct nat64lsn_portgroup *pg;
-
-	pg = GET_PORTGROUP(cfg, *addr, *nat_proto, *port);
-	if (pg == NULL)
-		pg = get_next_pg(cfg, addr, nat_proto, port);
-
-	return (pg);
-}
-
-/*
- * Lists nat64lsn states.
- * Data layout (v0)(current):
- * Request: [ ipfw_obj_header ipfw_obj_data [ uint64_t ]]
- * Reply: [ ipfw_obj_header ipfw_obj_data [
- *		ipfw_nat64lsn_stg ipfw_nat64lsn_state x N] ]
- *
- * Returns 0 on success
- */
-static int
-nat64lsn_states(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
-    struct sockopt_data *sd)
-{
-	ipfw_obj_header *oh;
-	ipfw_obj_data *od;
-	ipfw_nat64lsn_stg *stg;
-	struct nat64lsn_cfg *cfg;
-	struct nat64lsn_portgroup *pg, *pg_next;
-	uint64_t next_idx;
-	size_t sz;
-	uint32_t addr, states;
-	uint16_t port;
-	uint8_t nat_proto;
-
-	sz = sizeof(ipfw_obj_header) + sizeof(ipfw_obj_data) +
-	    sizeof(uint64_t);
-	/* Check minimum header size */
-	if (sd->valsize < sz)
-		return (EINVAL);
-
-	oh = (ipfw_obj_header *)sd->kbuf;
-	od = (ipfw_obj_data *)(oh + 1);
-	if (od->head.type != IPFW_TLV_OBJDATA ||
-	    od->head.length != sz - sizeof(ipfw_obj_header))
-		return (EINVAL);
-
-	next_idx = *(uint64_t *)(od + 1);
-	/* Translate index to the request position to start from */
-	UNPACK_IDX(next_idx, addr, nat_proto, port);
-	if (nat_proto >= NAT_MAX_PROTO)
-		return (EINVAL);
-	if (nat_proto == 0 && addr != 0)
-		return (EINVAL);
-
-	IPFW_UH_RLOCK(ch);
-	cfg = nat64lsn_find(CHAIN_TO_SRV(ch), oh->ntlv.name, oh->ntlv.set);
-	if (cfg == NULL) {
-		IPFW_UH_RUNLOCK(ch);
-		return (ESRCH);
-	}
-	/* Fill in starting point */
-	if (addr == 0) {
-		addr = cfg->prefix4;
-		nat_proto = 1;
-		port = 0;
-	}
-	if (addr < cfg->prefix4 || addr > cfg->pmask4) {
-		IPFW_UH_RUNLOCK(ch);
-		DPRINTF(DP_GENERIC | DP_STATE, "XXX: %ju %u %u",
-		    (uintmax_t)next_idx, addr, cfg->pmask4);
-		return (EINVAL);
-	}
-
-	sz = sizeof(ipfw_obj_header) + sizeof(ipfw_obj_data) +
-	    sizeof(ipfw_nat64lsn_stg);
-	if (sd->valsize < sz)
-		return (ENOMEM);
-	oh = (ipfw_obj_header *)ipfw_get_sopt_space(sd, sz);
-	od = (ipfw_obj_data *)(oh + 1);
-	od->head.type = IPFW_TLV_OBJDATA;
-	od->head.length = sz - sizeof(ipfw_obj_header);
-	stg = (ipfw_nat64lsn_stg *)(od + 1);
-
-	pg = get_first_pg(cfg, &addr, &nat_proto, &port);
-	if (pg == NULL) {
-		/* No states */
-		stg->next_idx = 0xFF;
-		stg->count = 0;
-		IPFW_UH_RUNLOCK(ch);
-		return (0);
-	}
-	states = 0;
-	pg_next = NULL;
-	while (pg != NULL) {
-		pg_next = get_next_pg(cfg, &addr, &nat_proto, &port);
-		if (pg_next == NULL)
-			stg->next_idx = 0xFF;
-		else
-			stg->next_idx = PACK_IDX(addr, nat_proto, port);
-
-		if (export_pg_states(cfg, pg, stg, sd) != 0) {
-			IPFW_UH_RUNLOCK(ch);
-			return (states == 0 ? ENOMEM: 0);
-		}
-		states += stg->count;
-		od->head.length += stg->count * sizeof(ipfw_nat64lsn_state);
-		sz += stg->count * sizeof(ipfw_nat64lsn_state);
-		if (pg_next != NULL) {
-			sz += sizeof(ipfw_nat64lsn_stg);
-			if (sd->valsize < sz)
-				break;
-			stg = (ipfw_nat64lsn_stg *)ipfw_get_sopt_space(sd,
-			    sizeof(ipfw_nat64lsn_stg));
-		}
-		pg = pg_next;
-	}
-	IPFW_UH_RUNLOCK(ch);
-	return (0);
-}
-
-static struct ipfw_sopt_handler	scodes[] = {
-	{ IP_FW_NAT64LSN_CREATE, 0,	HDIR_BOTH,	nat64lsn_create },
-	{ IP_FW_NAT64LSN_DESTROY,0,	HDIR_SET,	nat64lsn_destroy },
-	{ IP_FW_NAT64LSN_CONFIG, 0,	HDIR_BOTH,	nat64lsn_config },
-	{ IP_FW_NAT64LSN_LIST,	 0,	HDIR_GET,	nat64lsn_list },
-	{ IP_FW_NAT64LSN_STATS,	 0,	HDIR_GET,	nat64lsn_stats },
-	{ IP_FW_NAT64LSN_RESET_STATS,0,	HDIR_SET,	nat64lsn_reset_stats },
-	{ IP_FW_NAT64LSN_LIST_STATES,0,	HDIR_GET,	nat64lsn_states },
-};
-
-static int
-nat64lsn_classify(ipfw_insn *cmd, uint16_t *puidx, uint8_t *ptype)
-{
-	ipfw_insn *icmd;
-
-	icmd = cmd - 1;
-	if (icmd->opcode != O_EXTERNAL_ACTION ||
-	    icmd->arg1 != V_nat64lsn_eid)
-		return (1);
-
-	*puidx = cmd->arg1;
-	*ptype = 0;
-	return (0);
-}
-
-static void
-nat64lsn_update_arg1(ipfw_insn *cmd, uint16_t idx)
-{
-
-	cmd->arg1 = idx;
-}
-
-static int
-nat64lsn_findbyname(struct ip_fw_chain *ch, struct tid_info *ti,
-    struct named_object **pno)
-{
-	int err;
-
-	err = ipfw_objhash_find_type(CHAIN_TO_SRV(ch), ti,
-	    IPFW_TLV_NAT64LSN_NAME, pno);
-	return (err);
-}
-
-static struct named_object *
-nat64lsn_findbykidx(struct ip_fw_chain *ch, uint16_t idx)
-{
-	struct namedobj_instance *ni;
-	struct named_object *no;
-
-	IPFW_UH_WLOCK_ASSERT(ch);
-	ni = CHAIN_TO_SRV(ch);
-	no = ipfw_objhash_lookup_kidx(ni, idx);
-	KASSERT(no != NULL, ("NAT64LSN with index %d not found", idx));
-
-	return (no);
-}
-
-static int
-nat64lsn_manage_sets(struct ip_fw_chain *ch, uint16_t set, uint8_t new_set,
-    enum ipfw_sets_cmd cmd)
-{
-
-	return (ipfw_obj_manage_sets(CHAIN_TO_SRV(ch), IPFW_TLV_NAT64LSN_NAME,
-	    set, new_set, cmd));
-}
-
-static struct opcode_obj_rewrite opcodes[] = {
-	{
-		.opcode = O_EXTERNAL_INSTANCE,
-		.etlv = IPFW_TLV_EACTION /* just show it isn't table */,
-		.classifier = nat64lsn_classify,
-		.update = nat64lsn_update_arg1,
-		.find_byname = nat64lsn_findbyname,
-		.find_bykidx = nat64lsn_findbykidx,
-		.manage_sets = nat64lsn_manage_sets,
-	},
-};
-
-static int
-destroy_config_cb(struct namedobj_instance *ni, struct named_object *no,
-    void *arg)
-{
-	struct nat64lsn_cfg *cfg;
-	struct ip_fw_chain *ch;
-
-	ch = (struct ip_fw_chain *)arg;
-	cfg = (struct nat64lsn_cfg *)SRV_OBJECT(ch, no->kidx);
-	SRV_OBJECT(ch, no->kidx) = NULL;
-	nat64lsn_detach_config(ch, cfg);
-	nat64lsn_destroy_instance(cfg);
-	return (0);
-}
-
-int
-nat64lsn_init(struct ip_fw_chain *ch, int first)
-{
-
-	if (first != 0)
-		nat64lsn_init_internal();
-	V_nat64lsn_eid = ipfw_add_eaction(ch, ipfw_nat64lsn, "nat64lsn");
-	if (V_nat64lsn_eid == 0)
-		return (ENXIO);
-	IPFW_ADD_SOPT_HANDLER(first, scodes);
-	IPFW_ADD_OBJ_REWRITER(first, opcodes);
-	return (0);
-}
-
-void
-nat64lsn_uninit(struct ip_fw_chain *ch, int last)
-{
-
-	IPFW_DEL_OBJ_REWRITER(last, opcodes);
-	IPFW_DEL_SOPT_HANDLER(last, scodes);
-	ipfw_del_eaction(ch, V_nat64lsn_eid);
-	/*
-	 * Since we already have deregistered external action,
-	 * our named objects become unaccessible via rules, because
-	 * all rules were truncated by ipfw_del_eaction().
-	 * So, we can unlink and destroy our named objects without holding
-	 * IPFW_WLOCK().
-	 */
-	IPFW_UH_WLOCK(ch);
-	ipfw_objhash_foreach_type(CHAIN_TO_SRV(ch), destroy_config_cb, ch,
-	    IPFW_TLV_NAT64LSN_NAME);
-	V_nat64lsn_eid = 0;
-	IPFW_UH_WUNLOCK(ch);
-	if (last != 0)
-		nat64lsn_uninit_internal();
-}
-
Index: eebsd/sys/netpfil/ipfw/nat64/nat64stl.c
===================================================================
--- freebsd/sys/netpfil/ipfw/nat64/nat64stl.c	(revision f62c62d2fe57ec02c1350144f7739f8e866ee6d4)
+++ 	(revision )
@@ -1,264 +1,0 @@
-#include <machine/rtems-bsd-kernel-space.h>
-
-/*-
- * Copyright (c) 2015-2016 Yandex LLC
- * Copyright (c) 2015-2016 Andrey V. Elsukov <ae@FreeBSD.org>
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/counter.h>
-#include <sys/kernel.h>
-#include <sys/lock.h>
-#include <sys/mbuf.h>
-#include <sys/module.h>
-#include <sys/rmlock.h>
-#include <sys/rwlock.h>
-#include <sys/socket.h>
-#include <sys/sysctl.h>
-
-#include <net/if.h>
-#include <net/if_var.h>
-#include <net/if_pflog.h>
-#include <net/pfil.h>
-
-#include <netinet/in.h>
-#include <netinet/ip.h>
-#include <netinet/ip_icmp.h>
-#include <netinet/ip_var.h>
-#include <netinet/ip_fw.h>
-#include <netinet/ip6.h>
-#include <netinet/icmp6.h>
-#include <netinet6/ip_fw_nat64.h>
-
-#include <netpfil/ipfw/ip_fw_private.h>
-#include <netpfil/ipfw/nat64/ip_fw_nat64.h>
-#include <netpfil/ipfw/nat64/nat64_translate.h>
-#include <netpfil/ipfw/nat64/nat64stl.h>
-#include <netpfil/pf/pf.h>
-
-#define	NAT64_LOOKUP(chain, cmd)	\
-	(struct nat64stl_cfg *)SRV_OBJECT((chain), (cmd)->arg1)
-
-static void
-nat64stl_log(struct pfloghdr *plog, struct mbuf *m, sa_family_t family,
-    uint32_t kidx)
-{
-	static uint32_t pktid = 0;
-
-	memset(plog, 0, sizeof(*plog));
-	plog->length = PFLOG_REAL_HDRLEN;
-	plog->af = family;
-	plog->action = PF_NAT;
-	plog->dir = PF_IN;
-	plog->rulenr = htonl(kidx);
-	plog->subrulenr = htonl(++pktid);
-	plog->ruleset[0] = '\0';
-	strlcpy(plog->ifname, "NAT64STL", sizeof(plog->ifname));
-	ipfw_bpf_mtap2(plog, PFLOG_HDRLEN, m);
-}
-
-static int
-nat64stl_handle_ip4(struct ip_fw_chain *chain, struct nat64stl_cfg *cfg,
-    struct mbuf *m, uint32_t tablearg)
-{
-	struct pfloghdr loghdr, *logdata;
-	struct in6_addr saddr, daddr;
-	struct ip *ip;
-
-	ip = mtod(m, struct ip*);
-	if (nat64_check_ip4(ip->ip_src.s_addr) != 0 ||
-	    nat64_check_ip4(ip->ip_dst.s_addr) != 0 ||
-	    nat64_check_private_ip4(ip->ip_src.s_addr) != 0 ||
-	    nat64_check_private_ip4(ip->ip_dst.s_addr) != 0)
-		return (NAT64SKIP);
-
-	daddr = TARG_VAL(chain, tablearg, nh6);
-	if (nat64_check_ip6(&daddr) != 0)
-		return (NAT64MFREE);
-	saddr = cfg->prefix6;
-	nat64_set_ip4(&saddr, ip->ip_src.s_addr);
-
-	if (cfg->flags & NAT64_LOG) {
-		logdata = &loghdr;
-		nat64stl_log(logdata, m, AF_INET, cfg->no.kidx);
-	} else
-		logdata = NULL;
-	return (nat64_do_handle_ip4(m, &saddr, &daddr, 0, &cfg->stats,
-	    logdata));
-}
-
-static int
-nat64stl_handle_ip6(struct ip_fw_chain *chain, struct nat64stl_cfg *cfg,
-    struct mbuf *m, uint32_t tablearg)
-{
-	struct pfloghdr loghdr, *logdata;
-	struct ip6_hdr *ip6;
-	uint32_t aaddr;
-
-	aaddr = htonl(TARG_VAL(chain, tablearg, nh4));
-
-	/*
-	 * NOTE: we expect ipfw_chk() did m_pullup() up to upper level
-	 * protocol's headers. Also we skip some checks, that ip6_input(),
-	 * ip6_forward(), ip6_fastfwd() and ipfw_chk() already did.
-	 */
-	ip6 = mtod(m, struct ip6_hdr *);
-	/* Check ip6_dst matches configured prefix */
-	if (bcmp(&ip6->ip6_dst, &cfg->prefix6, cfg->plen6 / 8) != 0)
-		return (NAT64SKIP);
-
-	if (cfg->flags & NAT64_LOG) {
-		logdata = &loghdr;
-		nat64stl_log(logdata, m, AF_INET6, cfg->no.kidx);
-	} else
-		logdata = NULL;
-	return (nat64_do_handle_ip6(m, aaddr, 0, &cfg->stats, logdata));
-}
-
-static int
-nat64stl_handle_icmp6(struct ip_fw_chain *chain, struct nat64stl_cfg *cfg,
-    struct mbuf *m)
-{
-	struct pfloghdr loghdr, *logdata;
-	nat64_stats_block *stats;
-	struct ip6_hdr *ip6i;
-	struct icmp6_hdr *icmp6;
-	uint32_t tablearg;
-	int hlen, proto;
-
-	hlen = 0;
-	stats = &cfg->stats;
-	proto = nat64_getlasthdr(m, &hlen);
-	if (proto != IPPROTO_ICMPV6) {
-		NAT64STAT_INC(stats, dropped);
-		return (NAT64MFREE);
-	}
-	icmp6 = mtodo(m, hlen);
-	switch (icmp6->icmp6_type) {
-	case ICMP6_DST_UNREACH:
-	case ICMP6_PACKET_TOO_BIG:
-	case ICMP6_TIME_EXCEED_TRANSIT:
-	case ICMP6_PARAM_PROB:
-		break;
-	default:
-		NAT64STAT_INC(stats, dropped);
-		return (NAT64MFREE);
-	}
-	hlen += sizeof(struct icmp6_hdr);
-	if (m->m_pkthdr.len < hlen + sizeof(struct ip6_hdr) + ICMP_MINLEN) {
-		NAT64STAT_INC(stats, dropped);
-		return (NAT64MFREE);
-	}
-	if (m->m_len < hlen + sizeof(struct ip6_hdr) + ICMP_MINLEN)
-		m = m_pullup(m, hlen + sizeof(struct ip6_hdr) + ICMP_MINLEN);
-	if (m == NULL) {
-		NAT64STAT_INC(stats, nomem);
-		return (NAT64RETURN);
-	}
-	/*
-	 * Use destination address from inner IPv6 header to determine
-	 * IPv4 mapped address.
-	 */
-	ip6i = mtodo(m, hlen);
-	if (ipfw_lookup_table(chain, cfg->map64,
-	    sizeof(struct in6_addr), &ip6i->ip6_dst, &tablearg) == 0) {
-		m_freem(m);
-		return (NAT64RETURN);
-	}
-	if (cfg->flags & NAT64_LOG) {
-		logdata = &loghdr;
-		nat64stl_log(logdata, m, AF_INET6, cfg->no.kidx);
-	} else
-		logdata = NULL;
-	return (nat64_handle_icmp6(m, 0,
-	    htonl(TARG_VAL(chain, tablearg, nh4)), 0, stats, logdata));
-}
-
-int
-ipfw_nat64stl(struct ip_fw_chain *chain, struct ip_fw_args *args,
-    ipfw_insn *cmd, int *done)
-{
-	ipfw_insn *icmd;
-	struct nat64stl_cfg *cfg;
-	in_addr_t dst4;
-	uint32_t tablearg;
-	int ret;
-
-	IPFW_RLOCK_ASSERT(chain);
-
-	*done = 0; /* try next rule if not matched */
-	icmd = cmd + 1;
-	if (cmd->opcode != O_EXTERNAL_ACTION ||
-	    cmd->arg1 != V_nat64stl_eid ||
-	    icmd->opcode != O_EXTERNAL_INSTANCE ||
-	    (cfg = NAT64_LOOKUP(chain, icmd)) == NULL)
-		return (0);
-
-	switch (args->f_id.addr_type) {
-	case 4:
-		dst4 = htonl(args->f_id.dst_ip);
-		ret = ipfw_lookup_table(chain, cfg->map46, sizeof(in_addr_t),
-		    &dst4, &tablearg);
-		break;
-	case 6:
-		ret = ipfw_lookup_table(chain, cfg->map64,
-		    sizeof(struct in6_addr), &args->f_id.src_ip6, &tablearg);
-		break;
-	default:
-		return (0);
-	}
-	if (ret == 0) {
-		/*
-		 * In case when packet is ICMPv6 message from an intermediate
-		 * router, the source address of message will not match the
-		 * addresses from our map64 table.
-		 */
-		if (args->f_id.proto != IPPROTO_ICMPV6)
-			return (0);
-
-		ret = nat64stl_handle_icmp6(chain, cfg, args->m);
-	} else {
-		if (args->f_id.addr_type == 4)
-			ret = nat64stl_handle_ip4(chain, cfg, args->m,
-			    tablearg);
-		else
-			ret = nat64stl_handle_ip6(chain, cfg, args->m,
-			    tablearg);
-	}
-	if (ret == NAT64SKIP)
-		return (0);
-
-	*done = 1; /* terminate the search */
-	if (ret == NAT64MFREE)
-		m_freem(args->m);
-	args->m = NULL;
-	return (IP_FW_DENY);
-}
-
-
Index: eebsd/sys/netpfil/ipfw/nat64/nat64stl.h
===================================================================
--- freebsd/sys/netpfil/ipfw/nat64/nat64stl.h	(revision f62c62d2fe57ec02c1350144f7739f8e866ee6d4)
+++ 	(revision )
@@ -1,58 +1,0 @@
-/*-
- * Copyright (c) 2015-2016 Yandex LLC
- * Copyright (c) 2015-2016 Andrey V. Elsukov <ae@FreeBSD.org>
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
- *
- * $FreeBSD$
- */
-
-#ifndef	_IP_FW_NAT64STL_H_
-#define	_IP_FW_NAT64STL_H_
-
-struct nat64stl_cfg {
-	struct named_object	no;
-
-	uint16_t		map64;	/* table with 6to4 mapping */
-	uint16_t		map46;	/* table with 4to6 mapping */
-
-	struct in6_addr		prefix6;/* IPv6 prefix */
-	uint8_t			plen6;	/* prefix length */
-	uint8_t			flags;	/* flags for internal use */
-#define	NAT64STL_KIDX		0x0100
-#define	NAT64STL_46T		0x0200
-#define	NAT64STL_64T		0x0400
-#define	NAT64STL_FLAGSMASK	(NAT64_LOG) /* flags to pass to userland */
-	char			name[64];
-	nat64_stats_block	stats;
-};
-
-VNET_DECLARE(uint16_t, nat64stl_eid);
-#define	V_nat64stl_eid	VNET(nat64stl_eid)
-#define	IPFW_TLV_NAT64STL_NAME	IPFW_TLV_EACTION_NAME(V_nat64stl_eid)
-
-int ipfw_nat64stl(struct ip_fw_chain *chain, struct ip_fw_args *args,
-    ipfw_insn *cmd, int *done);
-
-#endif
-
Index: eebsd/sys/netpfil/ipfw/nat64/nat64stl_control.c
===================================================================
--- freebsd/sys/netpfil/ipfw/nat64/nat64stl_control.c	(revision f62c62d2fe57ec02c1350144f7739f8e866ee6d4)
+++ 	(revision )
@@ -1,623 +1,0 @@
-#include <machine/rtems-bsd-kernel-space.h>
-
-/*-
- * Copyright (c) 2015-2016 Yandex LLC
- * Copyright (c) 2015-2016 Andrey V. Elsukov <ae@FreeBSD.org>
- * Copyright (c) 2015 Alexander V. Chernikov <melifaro@FreeBSD.org>
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/counter.h>
-#include <sys/errno.h>
-#include <sys/kernel.h>
-#include <sys/lock.h>
-#include <sys/malloc.h>
-#include <sys/mbuf.h>
-#include <sys/module.h>
-#include <sys/rmlock.h>
-#include <sys/rwlock.h>
-#include <sys/socket.h>
-#include <sys/sockopt.h>
-#include <sys/queue.h>
-#include <sys/syslog.h>
-#include <sys/sysctl.h>
-
-#include <net/if.h>
-#include <net/if_var.h>
-#include <net/pfil.h>
-#include <net/route.h>
-#include <net/vnet.h>
-
-#include <netinet/in.h>
-#include <netinet/ip_var.h>
-#include <netinet/ip_fw.h>
-#include <netinet6/in6_var.h>
-#include <netinet6/ip6_var.h>
-
-#include <netpfil/ipfw/ip_fw_private.h>
-#include <netpfil/ipfw/nat64/ip_fw_nat64.h>
-#include <netpfil/ipfw/nat64/nat64stl.h>
-#include <netinet6/ip_fw_nat64.h>
-
-VNET_DEFINE(uint16_t, nat64stl_eid) = 0;
-
-static struct nat64stl_cfg *nat64stl_alloc_config(const char *name, uint8_t set);
-static void nat64stl_free_config(struct nat64stl_cfg *cfg);
-static struct nat64stl_cfg *nat64stl_find(struct namedobj_instance *ni,
-    const char *name, uint8_t set);
-
-static struct nat64stl_cfg *
-nat64stl_alloc_config(const char *name, uint8_t set)
-{
-	struct nat64stl_cfg *cfg;
-
-	cfg = malloc(sizeof(struct nat64stl_cfg), M_IPFW, M_WAITOK | M_ZERO);
-	COUNTER_ARRAY_ALLOC(cfg->stats.stats, NAT64STATS, M_WAITOK);
-	cfg->no.name = cfg->name;
-	cfg->no.etlv = IPFW_TLV_NAT64STL_NAME;
-	cfg->no.set = set;
-	strlcpy(cfg->name, name, sizeof(cfg->name));
-	return (cfg);
-}
-
-static void
-nat64stl_free_config(struct nat64stl_cfg *cfg)
-{
-
-	COUNTER_ARRAY_FREE(cfg->stats.stats, NAT64STATS);
-	free(cfg, M_IPFW);
-}
-
-static void
-nat64stl_export_config(struct ip_fw_chain *ch, struct nat64stl_cfg *cfg,
-    ipfw_nat64stl_cfg *uc)
-{
-	struct named_object *no;
-
-	uc->prefix6 = cfg->prefix6;
-	uc->plen6 = cfg->plen6;
-	uc->flags = cfg->flags & NAT64STL_FLAGSMASK;
-	uc->set = cfg->no.set;
-	strlcpy(uc->name, cfg->no.name, sizeof(uc->name));
-
-	no = ipfw_objhash_lookup_table_kidx(ch, cfg->map64);
-	ipfw_export_obj_ntlv(no, &uc->ntlv6);
-	no = ipfw_objhash_lookup_table_kidx(ch, cfg->map46);
-	ipfw_export_obj_ntlv(no, &uc->ntlv4);
-}
-
-struct nat64stl_dump_arg {
-	struct ip_fw_chain *ch;
-	struct sockopt_data *sd;
-};
-
-static int
-export_config_cb(struct namedobj_instance *ni, struct named_object *no,
-    void *arg)
-{
-	struct nat64stl_dump_arg *da = (struct nat64stl_dump_arg *)arg;
-	ipfw_nat64stl_cfg *uc;
-
-	uc = (ipfw_nat64stl_cfg *)ipfw_get_sopt_space(da->sd, sizeof(*uc));
-	nat64stl_export_config(da->ch, (struct nat64stl_cfg *)no, uc);
-	return (0);
-}
-
-static struct nat64stl_cfg *
-nat64stl_find(struct namedobj_instance *ni, const char *name, uint8_t set)
-{
-	struct nat64stl_cfg *cfg;
-
-	cfg = (struct nat64stl_cfg *)ipfw_objhash_lookup_name_type(ni, set,
-	    IPFW_TLV_NAT64STL_NAME, name);
-
-	return (cfg);
-}
-
-
-static int
-nat64stl_create_internal(struct ip_fw_chain *ch, struct nat64stl_cfg *cfg,
-    ipfw_nat64stl_cfg *i)
-{
-
-	IPFW_UH_WLOCK_ASSERT(ch);
-
-	if (ipfw_objhash_alloc_idx(CHAIN_TO_SRV(ch), &cfg->no.kidx) != 0)
-		return (ENOSPC);
-	cfg->flags |= NAT64STL_KIDX;
-
-	if (ipfw_ref_table(ch, &i->ntlv4, &cfg->map46) != 0)
-		return (EINVAL);
-	cfg->flags |= NAT64STL_46T;
-
-	if (ipfw_ref_table(ch, &i->ntlv6, &cfg->map64) != 0)
-		return (EINVAL);
-	cfg->flags |= NAT64STL_64T;
-
-	ipfw_objhash_add(CHAIN_TO_SRV(ch), &cfg->no);
-
-	return (0);
-}
-
-/*
- * Creates new nat64 instance.
- * Data layout (v0)(current):
- * Request: [ ipfw_obj_lheader ipfw_nat64stl_cfg ]
- *
- * Returns 0 on success
- */
-static int
-nat64stl_create(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
-    struct sockopt_data *sd)
-{
-	ipfw_obj_lheader *olh;
-	ipfw_nat64stl_cfg *uc;
-	struct namedobj_instance *ni;
-	struct nat64stl_cfg *cfg;
-	int error;
-
-	if (sd->valsize != sizeof(*olh) + sizeof(*uc))
-		return (EINVAL);
-
-	olh = (ipfw_obj_lheader *)sd->kbuf;
-	uc = (ipfw_nat64stl_cfg *)(olh + 1);
-
-	if (ipfw_check_object_name_generic(uc->name) != 0)
-		return (EINVAL);
-	if (!IN6_IS_ADDR_WKPFX(&uc->prefix6))
-		return (EINVAL);
-	if (uc->plen6 != 96 || uc->set >= IPFW_MAX_SETS)
-		return (EINVAL);
-
-	/* XXX: check types of tables */
-
-	ni = CHAIN_TO_SRV(ch);
-	error = 0;
-
-	IPFW_UH_RLOCK(ch);
-	if (nat64stl_find(ni, uc->name, uc->set) != NULL) {
-		IPFW_UH_RUNLOCK(ch);
-		return (EEXIST);
-	}
-	IPFW_UH_RUNLOCK(ch);
-
-	cfg = nat64stl_alloc_config(uc->name, uc->set);
-	cfg->prefix6 = uc->prefix6;
-	cfg->plen6 = uc->plen6;
-	cfg->flags = uc->flags & NAT64STL_FLAGSMASK;
-
-	IPFW_UH_WLOCK(ch);
-
-	if (nat64stl_find(ni, uc->name, uc->set) != NULL) {
-		IPFW_UH_WUNLOCK(ch);
-		nat64stl_free_config(cfg);
-		return (EEXIST);
-	}
-	error = nat64stl_create_internal(ch, cfg, uc);
-	if (error == 0) {
-		/* Okay, let's link data */
-		IPFW_WLOCK(ch);
-		SRV_OBJECT(ch, cfg->no.kidx) = cfg;
-		IPFW_WUNLOCK(ch);
-
-		IPFW_UH_WUNLOCK(ch);
-		return (0);
-	}
-
-	if (cfg->flags & NAT64STL_KIDX)
-		ipfw_objhash_free_idx(ni, cfg->no.kidx);
-	if (cfg->flags & NAT64STL_46T)
-		ipfw_unref_table(ch, cfg->map46);
-	if (cfg->flags & NAT64STL_64T)
-		ipfw_unref_table(ch, cfg->map64);
-
-	IPFW_UH_WUNLOCK(ch);
-	nat64stl_free_config(cfg);
-	return (error);
-}
-
-/*
- * Change existing nat64stl instance configuration.
- * Data layout (v0)(current):
- * Request: [ ipfw_obj_header ipfw_nat64stl_cfg ]
- * Reply: [ ipfw_obj_header ipfw_nat64stl_cfg ]
- *
- * Returns 0 on success
- */
-static int
-nat64stl_config(struct ip_fw_chain *ch, ip_fw3_opheader *op,
-    struct sockopt_data *sd)
-{
-	ipfw_obj_header *oh;
-	ipfw_nat64stl_cfg *uc;
-	struct nat64stl_cfg *cfg;
-	struct namedobj_instance *ni;
-
-	if (sd->valsize != sizeof(*oh) + sizeof(*uc))
-		return (EINVAL);
-
-	oh = (ipfw_obj_header *)ipfw_get_sopt_space(sd,
-	    sizeof(*oh) + sizeof(*uc));
-	uc = (ipfw_nat64stl_cfg *)(oh + 1);
-
-	if (ipfw_check_object_name_generic(oh->ntlv.name) != 0 ||
-	    oh->ntlv.set >= IPFW_MAX_SETS)
-		return (EINVAL);
-
-	ni = CHAIN_TO_SRV(ch);
-	if (sd->sopt->sopt_dir == SOPT_GET) {
-		IPFW_UH_RLOCK(ch);
-		cfg = nat64stl_find(ni, oh->ntlv.name, oh->ntlv.set);
-		if (cfg == NULL) {
-			IPFW_UH_RUNLOCK(ch);
-			return (EEXIST);
-		}
-		nat64stl_export_config(ch, cfg, uc);
-		IPFW_UH_RUNLOCK(ch);
-		return (0);
-	}
-
-	IPFW_UH_WLOCK(ch);
-	cfg = nat64stl_find(ni, oh->ntlv.name, oh->ntlv.set);
-	if (cfg == NULL) {
-		IPFW_UH_WUNLOCK(ch);
-		return (EEXIST);
-	}
-
-	/*
-	 * For now allow to change only following values:
-	 *  flags.
-	 */
-
-	cfg->flags = uc->flags & NAT64STL_FLAGSMASK;
-	IPFW_UH_WUNLOCK(ch);
-	return (0);
-}
-
-static void
-nat64stl_detach_config(struct ip_fw_chain *ch, struct nat64stl_cfg *cfg)
-{
-
-	IPFW_UH_WLOCK_ASSERT(ch);
-
-	ipfw_objhash_del(CHAIN_TO_SRV(ch), &cfg->no);
-	ipfw_objhash_free_idx(CHAIN_TO_SRV(ch), cfg->no.kidx);
-	ipfw_unref_table(ch, cfg->map46);
-	ipfw_unref_table(ch, cfg->map64);
-}
-
-/*
- * Destroys nat64 instance.
- * Data layout (v0)(current):
- * Request: [ ipfw_obj_header ]
- *
- * Returns 0 on success
- */
-static int
-nat64stl_destroy(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
-    struct sockopt_data *sd)
-{
-	ipfw_obj_header *oh;
-	struct nat64stl_cfg *cfg;
-
-	if (sd->valsize != sizeof(*oh))
-		return (EINVAL);
-
-	oh = (ipfw_obj_header *)sd->kbuf;
-	if (ipfw_check_object_name_generic(oh->ntlv.name) != 0)
-		return (EINVAL);
-
-	IPFW_UH_WLOCK(ch);
-	cfg = nat64stl_find(CHAIN_TO_SRV(ch), oh->ntlv.name, oh->ntlv.set);
-	if (cfg == NULL) {
-		IPFW_UH_WUNLOCK(ch);
-		return (ESRCH);
-	}
-	if (cfg->no.refcnt > 0) {
-		IPFW_UH_WUNLOCK(ch);
-		return (EBUSY);
-	}
-
-	IPFW_WLOCK(ch);
-	SRV_OBJECT(ch, cfg->no.kidx) = NULL;
-	IPFW_WUNLOCK(ch);
-
-	nat64stl_detach_config(ch, cfg);
-	IPFW_UH_WUNLOCK(ch);
-
-	nat64stl_free_config(cfg);
-	return (0);
-}
-
-/*
- * Lists all nat64stl instances currently available in kernel.
- * Data layout (v0)(current):
- * Request: [ ipfw_obj_lheader ]
- * Reply: [ ipfw_obj_lheader ipfw_nat64stl_cfg x N ]
- *
- * Returns 0 on success
- */
-static int
-nat64stl_list(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
-    struct sockopt_data *sd)
-{
-	ipfw_obj_lheader *olh;
-	struct nat64stl_dump_arg da;
-
-	/* Check minimum header size */
-	if (sd->valsize < sizeof(ipfw_obj_lheader))
-		return (EINVAL);
-
-	olh = (ipfw_obj_lheader *)ipfw_get_sopt_header(sd, sizeof(*olh));
-
-	IPFW_UH_RLOCK(ch);
-	olh->count = ipfw_objhash_count_type(CHAIN_TO_SRV(ch),
-	    IPFW_TLV_NAT64STL_NAME);
-	olh->objsize = sizeof(ipfw_nat64stl_cfg);
-	olh->size = sizeof(*olh) + olh->count * olh->objsize;
-
-	if (sd->valsize < olh->size) {
-		IPFW_UH_RUNLOCK(ch);
-		return (ENOMEM);
-	}
-	memset(&da, 0, sizeof(da));
-	da.ch = ch;
-	da.sd = sd;
-	ipfw_objhash_foreach_type(CHAIN_TO_SRV(ch), export_config_cb,
-	    &da, IPFW_TLV_NAT64STL_NAME);
-	IPFW_UH_RUNLOCK(ch);
-
-	return (0);
-}
-
-#define	__COPY_STAT_FIELD(_cfg, _stats, _field)	\
-	(_stats)->_field = NAT64STAT_FETCH(&(_cfg)->stats, _field)
-static void
-export_stats(struct ip_fw_chain *ch, struct nat64stl_cfg *cfg,
-    struct ipfw_nat64stl_stats *stats)
-{
-
-	__COPY_STAT_FIELD(cfg, stats, opcnt64);
-	__COPY_STAT_FIELD(cfg, stats, opcnt46);
-	__COPY_STAT_FIELD(cfg, stats, ofrags);
-	__COPY_STAT_FIELD(cfg, stats, ifrags);
-	__COPY_STAT_FIELD(cfg, stats, oerrors);
-	__COPY_STAT_FIELD(cfg, stats, noroute4);
-	__COPY_STAT_FIELD(cfg, stats, noroute6);
-	__COPY_STAT_FIELD(cfg, stats, noproto);
-	__COPY_STAT_FIELD(cfg, stats, nomem);
-	__COPY_STAT_FIELD(cfg, stats, dropped);
-}
-
-/*
- * Get nat64stl statistics.
- * Data layout (v0)(current):
- * Request: [ ipfw_obj_header ]
- * Reply: [ ipfw_obj_header ipfw_obj_ctlv [ uint64_t x N ]]
- *
- * Returns 0 on success
- */
-static int
-nat64stl_stats(struct ip_fw_chain *ch, ip_fw3_opheader *op,
-    struct sockopt_data *sd)
-{
-	struct ipfw_nat64stl_stats stats;
-	struct nat64stl_cfg *cfg;
-	ipfw_obj_header *oh;
-	ipfw_obj_ctlv *ctlv;
-	size_t sz;
-
-	sz = sizeof(ipfw_obj_header) + sizeof(ipfw_obj_ctlv) + sizeof(stats);
-	if (sd->valsize % sizeof(uint64_t))
-		return (EINVAL);
-	if (sd->valsize < sz)
-		return (ENOMEM);
-	oh = (ipfw_obj_header *)ipfw_get_sopt_header(sd, sz);
-	if (oh == NULL)
-		return (EINVAL);
-	memset(&stats, 0, sizeof(stats));
-
-	IPFW_UH_RLOCK(ch);
-	cfg = nat64stl_find(CHAIN_TO_SRV(ch), oh->ntlv.name, oh->ntlv.set);
-	if (cfg == NULL) {
-		IPFW_UH_RUNLOCK(ch);
-		return (ESRCH);
-	}
-	export_stats(ch, cfg, &stats);
-	IPFW_UH_RUNLOCK(ch);
-
-	ctlv = (ipfw_obj_ctlv *)(oh + 1);
-	memset(ctlv, 0, sizeof(*ctlv));
-	ctlv->head.type = IPFW_TLV_COUNTERS;
-	ctlv->head.length = sz - sizeof(ipfw_obj_header);
-	ctlv->count = sizeof(stats) / sizeof(uint64_t);
-	ctlv->objsize = sizeof(uint64_t);
-	ctlv->version = IPFW_NAT64_VERSION;
-	memcpy(ctlv + 1, &stats, sizeof(stats));
-	return (0);
-}
-
-/*
- * Reset nat64stl statistics.
- * Data layout (v0)(current):
- * Request: [ ipfw_obj_header ]
- *
- * Returns 0 on success
- */
-static int
-nat64stl_reset_stats(struct ip_fw_chain *ch, ip_fw3_opheader *op,
-    struct sockopt_data *sd)
-{
-	struct nat64stl_cfg *cfg;
-	ipfw_obj_header *oh;
-
-	if (sd->valsize != sizeof(*oh))
-		return (EINVAL);
-	oh = (ipfw_obj_header *)sd->kbuf;
-	if (ipfw_check_object_name_generic(oh->ntlv.name) != 0 ||
-	    oh->ntlv.set >= IPFW_MAX_SETS)
-		return (EINVAL);
-
-	IPFW_UH_WLOCK(ch);
-	cfg = nat64stl_find(CHAIN_TO_SRV(ch), oh->ntlv.name, oh->ntlv.set);
-	if (cfg == NULL) {
-		IPFW_UH_WUNLOCK(ch);
-		return (ESRCH);
-	}
-	COUNTER_ARRAY_ZERO(cfg->stats.stats, NAT64STATS);
-	IPFW_UH_WUNLOCK(ch);
-	return (0);
-}
-
-static struct ipfw_sopt_handler	scodes[] = {
-
-	{ IP_FW_NAT64STL_CREATE, 0,	HDIR_SET,	nat64stl_create },
-	{ IP_FW_NAT64STL_DESTROY,0,	HDIR_SET,	nat64stl_destroy },
-	{ IP_FW_NAT64STL_CONFIG, 0,	HDIR_BOTH,	nat64stl_config },
-	{ IP_FW_NAT64STL_LIST,   0,	HDIR_GET,	nat64stl_list },
-	{ IP_FW_NAT64STL_STATS,  0,	HDIR_GET,	nat64stl_stats },
-	{ IP_FW_NAT64STL_RESET_STATS,0,	HDIR_SET,	nat64stl_reset_stats },
-};
-
-static int
-nat64stl_classify(ipfw_insn *cmd, uint16_t *puidx, uint8_t *ptype)
-{
-	ipfw_insn *icmd;
-
-	icmd = cmd - 1;
-	if (icmd->opcode != O_EXTERNAL_ACTION ||
-	    icmd->arg1 != V_nat64stl_eid)
-		return (1);
-
-	*puidx = cmd->arg1;
-	*ptype = 0;
-	return (0);
-}
-
-static void
-nat64stl_update_arg1(ipfw_insn *cmd, uint16_t idx)
-{
-
-	cmd->arg1 = idx;
-}
-
-static int
-nat64stl_findbyname(struct ip_fw_chain *ch, struct tid_info *ti,
-    struct named_object **pno)
-{
-	int err;
-
-	err = ipfw_objhash_find_type(CHAIN_TO_SRV(ch), ti,
-	    IPFW_TLV_NAT64STL_NAME, pno);
-	return (err);
-}
-
-static struct named_object *
-nat64stl_findbykidx(struct ip_fw_chain *ch, uint16_t idx)
-{
-	struct namedobj_instance *ni;
-	struct named_object *no;
-
-	IPFW_UH_WLOCK_ASSERT(ch);
-	ni = CHAIN_TO_SRV(ch);
-	no = ipfw_objhash_lookup_kidx(ni, idx);
-	KASSERT(no != NULL, ("NAT with index %d not found", idx));
-
-	return (no);
-}
-
-static int
-nat64stl_manage_sets(struct ip_fw_chain *ch, uint16_t set, uint8_t new_set,
-    enum ipfw_sets_cmd cmd)
-{
-
-	return (ipfw_obj_manage_sets(CHAIN_TO_SRV(ch), IPFW_TLV_NAT64STL_NAME,
-	    set, new_set, cmd));
-}
-
-static struct opcode_obj_rewrite opcodes[] = {
-	{
-		.opcode = O_EXTERNAL_INSTANCE,
-		.etlv = IPFW_TLV_EACTION /* just show it isn't table */,
-		.classifier = nat64stl_classify,
-		.update = nat64stl_update_arg1,
-		.find_byname = nat64stl_findbyname,
-		.find_bykidx = nat64stl_findbykidx,
-		.manage_sets = nat64stl_manage_sets,
-	},
-};
-
-static int
-destroy_config_cb(struct namedobj_instance *ni, struct named_object *no,
-    void *arg)
-{
-	struct nat64stl_cfg *cfg;
-	struct ip_fw_chain *ch;
-
-	ch = (struct ip_fw_chain *)arg;
-	cfg = (struct nat64stl_cfg *)SRV_OBJECT(ch, no->kidx);
-	SRV_OBJECT(ch, no->kidx) = NULL;
-	nat64stl_detach_config(ch, cfg);
-	nat64stl_free_config(cfg);
-	return (0);
-}
-
-int
-nat64stl_init(struct ip_fw_chain *ch, int first)
-{
-
-	V_nat64stl_eid = ipfw_add_eaction(ch, ipfw_nat64stl, "nat64stl");
-	if (V_nat64stl_eid == 0)
-		return (ENXIO);
-	IPFW_ADD_SOPT_HANDLER(first, scodes);
-	IPFW_ADD_OBJ_REWRITER(first, opcodes);
-	return (0);
-}
-
-void
-nat64stl_uninit(struct ip_fw_chain *ch, int last)
-{
-
-	IPFW_DEL_OBJ_REWRITER(last, opcodes);
-	IPFW_DEL_SOPT_HANDLER(last, scodes);
-	ipfw_del_eaction(ch, V_nat64stl_eid);
-	/*
-	 * Since we already have deregistered external action,
-	 * our named objects become unaccessible via rules, because
-	 * all rules were truncated by ipfw_del_eaction().
-	 * So, we can unlink and destroy our named objects without holding
-	 * IPFW_WLOCK().
-	 */
-	IPFW_UH_WLOCK(ch);
-	ipfw_objhash_foreach_type(CHAIN_TO_SRV(ch), destroy_config_cb, ch,
-	    IPFW_TLV_NAT64STL_NAME);
-	V_nat64stl_eid = 0;
-	IPFW_UH_WUNLOCK(ch);
-}
-
Index: eebsd/sys/netpfil/ipfw/nptv6/ip_fw_nptv6.c
===================================================================
--- freebsd/sys/netpfil/ipfw/nptv6/ip_fw_nptv6.c	(revision f62c62d2fe57ec02c1350144f7739f8e866ee6d4)
+++ 	(revision )
@@ -1,101 +1,0 @@
-#include <machine/rtems-bsd-kernel-space.h>
-
-/*-
- * Copyright (c) 2016 Yandex LLC
- * Copyright (c) 2016 Andrey V. Elsukov <ae@FreeBSD.org>
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/kernel.h>
-#include <sys/lock.h>
-#include <sys/malloc.h>
-#include <sys/module.h>
-#include <sys/rwlock.h>
-#include <sys/socket.h>
-
-#include <net/if.h>
-#include <net/vnet.h>
-
-#include <netinet/in.h>
-#include <netinet/ip_var.h>
-#include <netinet/ip_fw.h>
-
-#include <netpfil/ipfw/ip_fw_private.h>
-#include <netpfil/ipfw/nptv6/nptv6.h>
-
-static int
-vnet_ipfw_nptv6_init(const void *arg __unused)
-{
-
-	return (nptv6_init(&V_layer3_chain, IS_DEFAULT_VNET(curvnet)));
-}
-
-static int
-vnet_ipfw_nptv6_uninit(const void *arg __unused)
-{
-
-	nptv6_uninit(&V_layer3_chain, IS_DEFAULT_VNET(curvnet));
-	return (0);
-}
-
-static int
-ipfw_nptv6_modevent(module_t mod, int type, void *unused)
-{
-
-	switch (type) {
-	case MOD_LOAD:
-	case MOD_UNLOAD:
-		break;
-	default:
-		return (EOPNOTSUPP);
-	}
-	return (0);
-}
-
-static moduledata_t ipfw_nptv6_mod = {
-	"ipfw_nptv6",
-	ipfw_nptv6_modevent,
-	0
-};
-
-/* Define startup order. */
-#define	IPFW_NPTV6_SI_SUB_FIREWALL	SI_SUB_PROTO_IFATTACHDOMAIN
-#define	IPFW_NPTV6_MODEVENT_ORDER	(SI_ORDER_ANY - 128) /* after ipfw */
-#define	IPFW_NPTV6_MODULE_ORDER		(IPFW_NPTV6_MODEVENT_ORDER + 1)
-#define	IPFW_NPTV6_VNET_ORDER		(IPFW_NPTV6_MODEVENT_ORDER + 2)
-
-DECLARE_MODULE(ipfw_nptv6, ipfw_nptv6_mod, IPFW_NPTV6_SI_SUB_FIREWALL,
-    IPFW_NPTV6_MODULE_ORDER);
-MODULE_DEPEND(ipfw_nptv6, ipfw, 3, 3, 3);
-MODULE_VERSION(ipfw_nptv6, 1);
-
-VNET_SYSINIT(vnet_ipfw_nptv6_init, IPFW_NPTV6_SI_SUB_FIREWALL,
-    IPFW_NPTV6_VNET_ORDER, vnet_ipfw_nptv6_init, NULL);
-VNET_SYSUNINIT(vnet_ipfw_nptv6_uninit, IPFW_NPTV6_SI_SUB_FIREWALL,
-    IPFW_NPTV6_VNET_ORDER, vnet_ipfw_nptv6_uninit, NULL);
Index: eebsd/sys/netpfil/ipfw/nptv6/nptv6.c
===================================================================
--- freebsd/sys/netpfil/ipfw/nptv6/nptv6.c	(revision f62c62d2fe57ec02c1350144f7739f8e866ee6d4)
+++ 	(revision )
@@ -1,896 +1,0 @@
-#include <machine/rtems-bsd-kernel-space.h>
-
-/*-
- * Copyright (c) 2016 Yandex LLC
- * Copyright (c) 2016 Andrey V. Elsukov <ae@FreeBSD.org>
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/counter.h>
-#include <sys/errno.h>
-#include <sys/kernel.h>
-#include <sys/lock.h>
-#include <sys/malloc.h>
-#include <sys/mbuf.h>
-#include <sys/module.h>
-#include <sys/rmlock.h>
-#include <sys/rwlock.h>
-#include <sys/socket.h>
-#include <sys/queue.h>
-#include <sys/syslog.h>
-#include <sys/sysctl.h>
-
-#include <net/if.h>
-#include <net/if_var.h>
-#include <net/netisr.h>
-#include <net/pfil.h>
-#include <net/vnet.h>
-
-#include <netinet/in.h>
-#include <netinet/ip_var.h>
-#include <netinet/ip_fw.h>
-#include <netinet/ip6.h>
-#include <netinet/icmp6.h>
-#include <netinet6/in6_var.h>
-#include <netinet6/ip6_var.h>
-
-#include <netpfil/ipfw/ip_fw_private.h>
-#include <netpfil/ipfw/nptv6/nptv6.h>
-
-static VNET_DEFINE(uint16_t, nptv6_eid) = 0;
-#define	V_nptv6_eid	VNET(nptv6_eid)
-#define	IPFW_TLV_NPTV6_NAME	IPFW_TLV_EACTION_NAME(V_nptv6_eid)
-
-static struct nptv6_cfg *nptv6_alloc_config(const char *name, uint8_t set);
-static void nptv6_free_config(struct nptv6_cfg *cfg);
-static struct nptv6_cfg *nptv6_find(struct namedobj_instance *ni,
-    const char *name, uint8_t set);
-static int nptv6_rewrite_internal(struct nptv6_cfg *cfg, struct mbuf **mp,
-    int offset);
-static int nptv6_rewrite_external(struct nptv6_cfg *cfg, struct mbuf **mp,
-    int offset);
-
-#define	NPTV6_LOOKUP(chain, cmd)	\
-    (struct nptv6_cfg *)SRV_OBJECT((chain), (cmd)->arg1)
-
-#ifndef IN6_MASK_ADDR
-#define IN6_MASK_ADDR(a, m)	do { \
-	(a)->s6_addr32[0] &= (m)->s6_addr32[0]; \
-	(a)->s6_addr32[1] &= (m)->s6_addr32[1]; \
-	(a)->s6_addr32[2] &= (m)->s6_addr32[2]; \
-	(a)->s6_addr32[3] &= (m)->s6_addr32[3]; \
-} while (0)
-#endif
-#ifndef IN6_ARE_MASKED_ADDR_EQUAL
-#define IN6_ARE_MASKED_ADDR_EQUAL(d, a, m)	(	\
-	(((d)->s6_addr32[0] ^ (a)->s6_addr32[0]) & (m)->s6_addr32[0]) == 0 && \
-	(((d)->s6_addr32[1] ^ (a)->s6_addr32[1]) & (m)->s6_addr32[1]) == 0 && \
-	(((d)->s6_addr32[2] ^ (a)->s6_addr32[2]) & (m)->s6_addr32[2]) == 0 && \
-	(((d)->s6_addr32[3] ^ (a)->s6_addr32[3]) & (m)->s6_addr32[3]) == 0 )
-#endif
-
-#if 0
-#define	NPTV6_DEBUG(fmt, ...)	do {			\
-	printf("%s: " fmt "\n", __func__, ## __VA_ARGS__);	\
-} while (0)
-#define	NPTV6_IPDEBUG(fmt, ...)	do {			\
-	char _s[INET6_ADDRSTRLEN], _d[INET6_ADDRSTRLEN];	\
-	printf("%s: " fmt "\n", __func__, ## __VA_ARGS__);	\
-} while (0)
-#else
-#define	NPTV6_DEBUG(fmt, ...)
-#define	NPTV6_IPDEBUG(fmt, ...)
-#endif
-
-static int
-nptv6_getlasthdr(struct nptv6_cfg *cfg, struct mbuf *m, int *offset)
-{
-	struct ip6_hdr *ip6;
-	struct ip6_hbh *hbh;
-	int proto, hlen;
-
-	hlen = (offset == NULL) ? 0: *offset;
-	if (m->m_len < hlen)
-		return (-1);
-	ip6 = mtodo(m, hlen);
-	hlen += sizeof(*ip6);
-	proto = ip6->ip6_nxt;
-	while (proto == IPPROTO_HOPOPTS || proto == IPPROTO_ROUTING ||
-	    proto == IPPROTO_DSTOPTS) {
-		hbh = mtodo(m, hlen);
-		if (m->m_len < hlen)
-			return (-1);
-		proto = hbh->ip6h_nxt;
-		hlen += hbh->ip6h_len << 3;
-	}
-	if (offset != NULL)
-		*offset = hlen;
-	return (proto);
-}
-
-static int
-nptv6_translate_icmpv6(struct nptv6_cfg *cfg, struct mbuf **mp, int offset)
-{
-	struct icmp6_hdr *icmp6;
-	struct ip6_hdr *ip6;
-	struct mbuf *m;
-
-	m = *mp;
-	if (offset > m->m_len)
-		return (-1);
-	icmp6 = mtodo(m, offset);
-	NPTV6_DEBUG("ICMPv6 type %d", icmp6->icmp6_type);
-	switch (icmp6->icmp6_type) {
-	case ICMP6_DST_UNREACH:
-	case ICMP6_PACKET_TOO_BIG:
-	case ICMP6_TIME_EXCEEDED:
-	case ICMP6_PARAM_PROB:
-		break;
-	case ICMP6_ECHO_REQUEST:
-	case ICMP6_ECHO_REPLY:
-		/* nothing to translate */
-		return (0);
-	default:
-		/*
-		 * XXX: We can add some checks to not translate NDP and MLD
-		 * messages. Currently user must explicitly allow these message
-		 * types, otherwise packets will be dropped.
-		 */
-		return (-1);
-	}
-	offset += sizeof(*icmp6);
-	if (offset + sizeof(*ip6) > m->m_pkthdr.len)
-		return (-1);
-	if (offset + sizeof(*ip6) > m->m_len)
-		*mp = m = m_pullup(m, offset + sizeof(*ip6));
-	if (m == NULL)
-		return (-1);
-	ip6 = mtodo(m, offset);
-	NPTV6_IPDEBUG("offset %d, %s -> %s %d", offset,
-	    inet_ntop(AF_INET6, &ip6->ip6_src, _s, sizeof(_s)),
-	    inet_ntop(AF_INET6, &ip6->ip6_dst, _d, sizeof(_d)),
-	    ip6->ip6_nxt);
-	if (IN6_ARE_MASKED_ADDR_EQUAL(&ip6->ip6_src,
-	    &cfg->external, &cfg->mask))
-		return (nptv6_rewrite_external(cfg, mp, offset));
-	else if (IN6_ARE_MASKED_ADDR_EQUAL(&ip6->ip6_dst,
-	    &cfg->internal, &cfg->mask))
-		return (nptv6_rewrite_internal(cfg, mp, offset));
-	/*
-	 * Addresses in the inner IPv6 header doesn't matched to
-	 * our prefixes.
-	 */
-	return (-1);
-}
-
-static int
-nptv6_search_index(struct nptv6_cfg *cfg, struct in6_addr *a)
-{
-	int idx;
-
-	if (cfg->flags & NPTV6_48PLEN)
-		return (3);
-
-	/* Search suitable word index for adjustment */
-	for (idx = 4; idx < 8; idx++)
-		if (a->s6_addr16[idx] != 0xffff)
-			break;
-	/*
-	 * RFC 6296 p3.7: If an NPTv6 Translator discovers a datagram with
-	 * an IID of all-zeros while performing address mapping, that
-	 * datagram MUST be dropped, and an ICMPv6 Parameter Problem error
-	 * SHOULD be generated.
-	 */
-	if (idx == 8 ||
-	    (a->s6_addr32[2] == 0 && a->s6_addr32[3] == 0))
-		return (-1);
-	return (idx);
-}
-
-static void
-nptv6_copy_addr(struct in6_addr *src, struct in6_addr *dst,
-    struct in6_addr *mask)
-{
-	int i;
-
-	for (i = 0; i < 8 && mask->s6_addr8[i] != 0; i++) {
-		dst->s6_addr8[i] &=  ~mask->s6_addr8[i];
-		dst->s6_addr8[i] |= src->s6_addr8[i] & mask->s6_addr8[i];
-	}
-}
-
-static int
-nptv6_rewrite_internal(struct nptv6_cfg *cfg, struct mbuf **mp, int offset)
-{
-	struct in6_addr *addr;
-	struct ip6_hdr *ip6;
-	int idx, proto;
-	uint16_t adj;
-
-	ip6 = mtodo(*mp, offset);
-	NPTV6_IPDEBUG("offset %d, %s -> %s %d", offset,
-	    inet_ntop(AF_INET6, &ip6->ip6_src, _s, sizeof(_s)),
-	    inet_ntop(AF_INET6, &ip6->ip6_dst, _d, sizeof(_d)),
-	    ip6->ip6_nxt);
-	if (offset == 0)
-		addr = &ip6->ip6_src;
-	else {
-		/*
-		 * When we rewriting inner IPv6 header, we need to rewrite
-		 * destination address back to external prefix. The datagram in
-		 * the ICMPv6 payload should looks like it was send from
-		 * external prefix.
-		 */
-		addr = &ip6->ip6_dst;
-	}
-	idx = nptv6_search_index(cfg, addr);
-	if (idx < 0) {
-		/*
-		 * Do not send ICMPv6 error when offset isn't zero.
-		 * This means we are rewriting inner IPv6 header in the
-		 * ICMPv6 error message.
-		 */
-		if (offset == 0) {
-			icmp6_error2(*mp, ICMP6_DST_UNREACH,
-			    ICMP6_DST_UNREACH_ADDR, 0, (*mp)->m_pkthdr.rcvif);
-			*mp = NULL;
-		}
-		return (IP_FW_DENY);
-	}
-	adj = addr->s6_addr16[idx];
-	nptv6_copy_addr(&cfg->external, addr, &cfg->mask);
-	adj = cksum_add(adj, cfg->adjustment);
-	if (adj == 0xffff)
-		adj = 0;
-	addr->s6_addr16[idx] = adj;
-	if (offset == 0) {
-		/*
-		 * We may need to translate addresses in the inner IPv6
-		 * header for ICMPv6 error messages.
-		 */
-		proto = nptv6_getlasthdr(cfg, *mp, &offset);
-		if (proto < 0 || (proto == IPPROTO_ICMPV6 &&
-		    nptv6_translate_icmpv6(cfg, mp, offset) != 0))
-			return (IP_FW_DENY);
-		NPTV6STAT_INC(cfg, in2ex);
-	}
-	return (0);
-}
-
-static int
-nptv6_rewrite_external(struct nptv6_cfg *cfg, struct mbuf **mp, int offset)
-{
-	struct in6_addr *addr;
-	struct ip6_hdr *ip6;
-	int idx, proto;
-	uint16_t adj;
-
-	ip6 = mtodo(*mp, offset);
-	NPTV6_IPDEBUG("offset %d, %s -> %s %d", offset,
-	    inet_ntop(AF_INET6, &ip6->ip6_src, _s, sizeof(_s)),
-	    inet_ntop(AF_INET6, &ip6->ip6_dst, _d, sizeof(_d)),
-	    ip6->ip6_nxt);
-	if (offset == 0)
-		addr = &ip6->ip6_dst;
-	else {
-		/*
-		 * When we rewriting inner IPv6 header, we need to rewrite
-		 * source address back to internal prefix. The datagram in
-		 * the ICMPv6 payload should looks like it was send from
-		 * internal prefix.
-		 */
-		addr = &ip6->ip6_src;
-	}
-	idx = nptv6_search_index(cfg, addr);
-	if (idx < 0) {
-		/*
-		 * Do not send ICMPv6 error when offset isn't zero.
-		 * This means we are rewriting inner IPv6 header in the
-		 * ICMPv6 error message.
-		 */
-		if (offset == 0) {
-			icmp6_error2(*mp, ICMP6_DST_UNREACH,
-			    ICMP6_DST_UNREACH_ADDR, 0, (*mp)->m_pkthdr.rcvif);
-			*mp = NULL;
-		}
-		return (IP_FW_DENY);
-	}
-	adj = addr->s6_addr16[idx];
-	nptv6_copy_addr(&cfg->internal, addr, &cfg->mask);
-	adj = cksum_add(adj, ~cfg->adjustment);
-	if (adj == 0xffff)
-		adj = 0;
-	addr->s6_addr16[idx] = adj;
-	if (offset == 0) {
-		/*
-		 * We may need to translate addresses in the inner IPv6
-		 * header for ICMPv6 error messages.
-		 */
-		proto = nptv6_getlasthdr(cfg, *mp, &offset);
-		if (proto < 0 || (proto == IPPROTO_ICMPV6 &&
-		    nptv6_translate_icmpv6(cfg, mp, offset) != 0))
-			return (IP_FW_DENY);
-		NPTV6STAT_INC(cfg, ex2in);
-	}
-	return (0);
-}
-
-/*
- * ipfw external action handler.
- */
-static int
-ipfw_nptv6(struct ip_fw_chain *chain, struct ip_fw_args *args,
-    ipfw_insn *cmd, int *done)
-{
-	struct ip6_hdr *ip6;
-	struct nptv6_cfg *cfg;
-	ipfw_insn *icmd;
-	int ret;
-
-	*done = 0; /* try next rule if not matched */
-	ret = IP_FW_DENY;
-	icmd = cmd + 1;
-	if (cmd->opcode != O_EXTERNAL_ACTION ||
-	    cmd->arg1 != V_nptv6_eid ||
-	    icmd->opcode != O_EXTERNAL_INSTANCE ||
-	    (cfg = NPTV6_LOOKUP(chain, icmd)) == NULL)
-		return (ret);
-	/*
-	 * We need act as router, so when forwarding is disabled -
-	 * do nothing.
-	 */
-	if (V_ip6_forwarding == 0 || args->f_id.addr_type != 6)
-		return (ret);
-	/*
-	 * NOTE: we expect ipfw_chk() did m_pullup() up to upper level
-	 * protocol's headers. Also we skip some checks, that ip6_input(),
-	 * ip6_forward(), ip6_fastfwd() and ipfw_chk() already did.
-	 */
-	ip6 = mtod(args->m, struct ip6_hdr *);
-	NPTV6_IPDEBUG("eid %u, oid %u, %s -> %s %d",
-	    cmd->arg1, icmd->arg1,
-	    inet_ntop(AF_INET6, &ip6->ip6_src, _s, sizeof(_s)),
-	    inet_ntop(AF_INET6, &ip6->ip6_dst, _d, sizeof(_d)),
-	    ip6->ip6_nxt);
-	if (IN6_ARE_MASKED_ADDR_EQUAL(&ip6->ip6_src,
-	    &cfg->internal, &cfg->mask)) {
-		/*
-		 * XXX: Do not translate packets when both src and dst
-		 * are from internal prefix.
-		 */
-		if (IN6_ARE_MASKED_ADDR_EQUAL(&ip6->ip6_dst,
-		    &cfg->internal, &cfg->mask))
-			return (ret);
-		ret = nptv6_rewrite_internal(cfg, &args->m, 0);
-	} else if (IN6_ARE_MASKED_ADDR_EQUAL(&ip6->ip6_dst,
-	    &cfg->external, &cfg->mask))
-		ret = nptv6_rewrite_external(cfg, &args->m, 0);
-	else
-		return (ret);
-	/*
-	 * If address wasn't rewrited - free mbuf and terminate the search.
-	 */
-	if (ret != 0) {
-		if (args->m != NULL) {
-			m_freem(args->m);
-			args->m = NULL; /* mark mbuf as consumed */
-		}
-		NPTV6STAT_INC(cfg, dropped);
-		*done = 1;
-	} else {
-		/* Terminate the search if one_pass is set */
-		*done = V_fw_one_pass;
-		/* Update args->f_id when one_pass is off */
-		if (*done == 0) {
-			ip6 = mtod(args->m, struct ip6_hdr *);
-			args->f_id.src_ip6 = ip6->ip6_src;
-			args->f_id.dst_ip6 = ip6->ip6_dst;
-		}
-	}
-	return (ret);
-}
-
-static struct nptv6_cfg *
-nptv6_alloc_config(const char *name, uint8_t set)
-{
-	struct nptv6_cfg *cfg;
-
-	cfg = malloc(sizeof(struct nptv6_cfg), M_IPFW, M_WAITOK | M_ZERO);
-	COUNTER_ARRAY_ALLOC(cfg->stats, NPTV6STATS, M_WAITOK);
-	cfg->no.name = cfg->name;
-	cfg->no.etlv = IPFW_TLV_NPTV6_NAME;
-	cfg->no.set = set;
-	strlcpy(cfg->name, name, sizeof(cfg->name));
-	return (cfg);
-}
-
-static void
-nptv6_free_config(struct nptv6_cfg *cfg)
-{
-
-	COUNTER_ARRAY_FREE(cfg->stats, NPTV6STATS);
-	free(cfg, M_IPFW);
-}
-
-static void
-nptv6_export_config(struct ip_fw_chain *ch, struct nptv6_cfg *cfg,
-    ipfw_nptv6_cfg *uc)
-{
-
-	uc->internal = cfg->internal;
-	uc->external = cfg->external;
-	uc->plen = cfg->plen;
-	uc->flags = cfg->flags & NPTV6_FLAGSMASK;
-	uc->set = cfg->no.set;
-	strlcpy(uc->name, cfg->no.name, sizeof(uc->name));
-}
-
-struct nptv6_dump_arg {
-	struct ip_fw_chain *ch;
-	struct sockopt_data *sd;
-};
-
-static int
-export_config_cb(struct namedobj_instance *ni, struct named_object *no,
-    void *arg)
-{
-	struct nptv6_dump_arg *da = (struct nptv6_dump_arg *)arg;
-	ipfw_nptv6_cfg *uc;
-
-	uc = (ipfw_nptv6_cfg *)ipfw_get_sopt_space(da->sd, sizeof(*uc));
-	nptv6_export_config(da->ch, (struct nptv6_cfg *)no, uc);
-	return (0);
-}
-
-static struct nptv6_cfg *
-nptv6_find(struct namedobj_instance *ni, const char *name, uint8_t set)
-{
-	struct nptv6_cfg *cfg;
-
-	cfg = (struct nptv6_cfg *)ipfw_objhash_lookup_name_type(ni, set,
-	    IPFW_TLV_NPTV6_NAME, name);
-
-	return (cfg);
-}
-
-static void
-nptv6_calculate_adjustment(struct nptv6_cfg *cfg)
-{
-	uint16_t i, e;
-	uint16_t *p;
-
-	/* Calculate checksum of internal prefix */
-	for (i = 0, p = (uint16_t *)&cfg->internal;
-	    p < (uint16_t *)(&cfg->internal + 1); p++)
-		i = cksum_add(i, *p);
-
-	/* Calculate checksum of external prefix */
-	for (e = 0, p = (uint16_t *)&cfg->external;
-	    p < (uint16_t *)(&cfg->external + 1); p++)
-		e = cksum_add(e, *p);
-
-	/* Adjustment value for Int->Ext direction */
-	cfg->adjustment = cksum_add(~e, i);
-}
-
-/*
- * Creates new NPTv6 instance.
- * Data layout (v0)(current):
- * Request: [ ipfw_obj_lheader ipfw_nptv6_cfg ]
- *
- * Returns 0 on success
- */
-static int
-nptv6_create(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
-    struct sockopt_data *sd)
-{
-	struct in6_addr mask;
-	ipfw_obj_lheader *olh;
-	ipfw_nptv6_cfg *uc;
-	struct namedobj_instance *ni;
-	struct nptv6_cfg *cfg;
-
-	if (sd->valsize != sizeof(*olh) + sizeof(*uc))
-		return (EINVAL);
-
-	olh = (ipfw_obj_lheader *)sd->kbuf;
-	uc = (ipfw_nptv6_cfg *)(olh + 1);
-	if (ipfw_check_object_name_generic(uc->name) != 0)
-		return (EINVAL);
-	if (uc->plen < 8 || uc->plen > 64 || uc->set >= IPFW_MAX_SETS)
-		return (EINVAL);
-	if (IN6_IS_ADDR_MULTICAST(&uc->internal) ||
-	    IN6_IS_ADDR_MULTICAST(&uc->external) ||
-	    IN6_IS_ADDR_UNSPECIFIED(&uc->internal) ||
-	    IN6_IS_ADDR_UNSPECIFIED(&uc->external) ||
-	    IN6_IS_ADDR_LINKLOCAL(&uc->internal) ||
-	    IN6_IS_ADDR_LINKLOCAL(&uc->external))
-		return (EINVAL);
-	in6_prefixlen2mask(&mask, uc->plen);
-	if (IN6_ARE_MASKED_ADDR_EQUAL(&uc->internal, &uc->external, &mask))
-		return (EINVAL);
-
-	ni = CHAIN_TO_SRV(ch);
-	IPFW_UH_RLOCK(ch);
-	if (nptv6_find(ni, uc->name, uc->set) != NULL) {
-		IPFW_UH_RUNLOCK(ch);
-		return (EEXIST);
-	}
-	IPFW_UH_RUNLOCK(ch);
-
-	cfg = nptv6_alloc_config(uc->name, uc->set);
-	cfg->plen = uc->plen;
-	if (cfg->plen <= 48)
-		cfg->flags |= NPTV6_48PLEN;
-	cfg->internal = uc->internal;
-	cfg->external = uc->external;
-	cfg->mask = mask;
-	IN6_MASK_ADDR(&cfg->internal, &mask);
-	IN6_MASK_ADDR(&cfg->external, &mask);
-	nptv6_calculate_adjustment(cfg);
-
-	IPFW_UH_WLOCK(ch);
-	if (ipfw_objhash_alloc_idx(ni, &cfg->no.kidx) != 0) {
-		IPFW_UH_WUNLOCK(ch);
-		nptv6_free_config(cfg);
-		return (ENOSPC);
-	}
-	ipfw_objhash_add(ni, &cfg->no);
-	IPFW_WLOCK(ch);
-	SRV_OBJECT(ch, cfg->no.kidx) = cfg;
-	IPFW_WUNLOCK(ch);
-	IPFW_UH_WUNLOCK(ch);
-	return (0);
-}
-
-/*
- * Destroys NPTv6 instance.
- * Data layout (v0)(current):
- * Request: [ ipfw_obj_header ]
- *
- * Returns 0 on success
- */
-static int
-nptv6_destroy(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
-    struct sockopt_data *sd)
-{
-	ipfw_obj_header *oh;
-	struct nptv6_cfg *cfg;
-
-	if (sd->valsize != sizeof(*oh))
-		return (EINVAL);
-
-	oh = (ipfw_obj_header *)sd->kbuf;
-	if (ipfw_check_object_name_generic(oh->ntlv.name) != 0)
-		return (EINVAL);
-
-	IPFW_UH_WLOCK(ch);
-	cfg = nptv6_find(CHAIN_TO_SRV(ch), oh->ntlv.name, oh->ntlv.set);
-	if (cfg == NULL) {
-		IPFW_UH_WUNLOCK(ch);
-		return (ESRCH);
-	}
-	if (cfg->no.refcnt > 0) {
-		IPFW_UH_WUNLOCK(ch);
-		return (EBUSY);
-	}
-
-	IPFW_WLOCK(ch);
-	SRV_OBJECT(ch, cfg->no.kidx) = NULL;
-	IPFW_WUNLOCK(ch);
-
-	ipfw_objhash_del(CHAIN_TO_SRV(ch), &cfg->no);
-	ipfw_objhash_free_idx(CHAIN_TO_SRV(ch), cfg->no.kidx);
-	IPFW_UH_WUNLOCK(ch);
-
-	nptv6_free_config(cfg);
-	return (0);
-}
-
-/*
- * Get or change nptv6 instance config.
- * Request: [ ipfw_obj_header [ ipfw_nptv6_cfg ] ]
- */
-static int
-nptv6_config(struct ip_fw_chain *chain, ip_fw3_opheader *op,
-    struct sockopt_data *sd)
-{
-
-	return (EOPNOTSUPP);
-}
-
-/*
- * Lists all NPTv6 instances currently available in kernel.
- * Data layout (v0)(current):
- * Request: [ ipfw_obj_lheader ]
- * Reply: [ ipfw_obj_lheader ipfw_nptv6_cfg x N ]
- *
- * Returns 0 on success
- */
-static int
-nptv6_list(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
-    struct sockopt_data *sd)
-{
-	ipfw_obj_lheader *olh;
-	struct nptv6_dump_arg da;
-
-	/* Check minimum header size */
-	if (sd->valsize < sizeof(ipfw_obj_lheader))
-		return (EINVAL);
-
-	olh = (ipfw_obj_lheader *)ipfw_get_sopt_header(sd, sizeof(*olh));
-
-	IPFW_UH_RLOCK(ch);
-	olh->count = ipfw_objhash_count_type(CHAIN_TO_SRV(ch),
-	    IPFW_TLV_NPTV6_NAME);
-	olh->objsize = sizeof(ipfw_nptv6_cfg);
-	olh->size = sizeof(*olh) + olh->count * olh->objsize;
-
-	if (sd->valsize < olh->size) {
-		IPFW_UH_RUNLOCK(ch);
-		return (ENOMEM);
-	}
-	memset(&da, 0, sizeof(da));
-	da.ch = ch;
-	da.sd = sd;
-	ipfw_objhash_foreach_type(CHAIN_TO_SRV(ch), export_config_cb,
-	    &da, IPFW_TLV_NPTV6_NAME);
-	IPFW_UH_RUNLOCK(ch);
-
-	return (0);
-}
-
-#define	__COPY_STAT_FIELD(_cfg, _stats, _field)	\
-	(_stats)->_field = NPTV6STAT_FETCH(_cfg, _field)
-static void
-export_stats(struct ip_fw_chain *ch, struct nptv6_cfg *cfg,
-    struct ipfw_nptv6_stats *stats)
-{
-
-	__COPY_STAT_FIELD(cfg, stats, in2ex);
-	__COPY_STAT_FIELD(cfg, stats, ex2in);
-	__COPY_STAT_FIELD(cfg, stats, dropped);
-}
-
-/*
- * Get NPTv6 statistics.
- * Data layout (v0)(current):
- * Request: [ ipfw_obj_header ]
- * Reply: [ ipfw_obj_header ipfw_obj_ctlv [ uint64_t x N ]]
- *
- * Returns 0 on success
- */
-static int
-nptv6_stats(struct ip_fw_chain *ch, ip_fw3_opheader *op,
-    struct sockopt_data *sd)
-{
-	struct ipfw_nptv6_stats stats;
-	struct nptv6_cfg *cfg;
-	ipfw_obj_header *oh;
-	ipfw_obj_ctlv *ctlv;
-	size_t sz;
-
-	sz = sizeof(ipfw_obj_header) + sizeof(ipfw_obj_ctlv) + sizeof(stats);
-	if (sd->valsize % sizeof(uint64_t))
-		return (EINVAL);
-	if (sd->valsize < sz)
-		return (ENOMEM);
-	oh = (ipfw_obj_header *)ipfw_get_sopt_header(sd, sz);
-	if (oh == NULL)
-		return (EINVAL);
-	if (ipfw_check_object_name_generic(oh->ntlv.name) != 0 ||
-	    oh->ntlv.set >= IPFW_MAX_SETS)
-		return (EINVAL);
-	memset(&stats, 0, sizeof(stats));
-
-	IPFW_UH_RLOCK(ch);
-	cfg = nptv6_find(CHAIN_TO_SRV(ch), oh->ntlv.name, oh->ntlv.set);
-	if (cfg == NULL) {
-		IPFW_UH_RUNLOCK(ch);
-		return (ESRCH);
-	}
-	export_stats(ch, cfg, &stats);
-	IPFW_UH_RUNLOCK(ch);
-
-	ctlv = (ipfw_obj_ctlv *)(oh + 1);
-	memset(ctlv, 0, sizeof(*ctlv));
-	ctlv->head.type = IPFW_TLV_COUNTERS;
-	ctlv->head.length = sz - sizeof(ipfw_obj_header);
-	ctlv->count = sizeof(stats) / sizeof(uint64_t);
-	ctlv->objsize = sizeof(uint64_t);
-	ctlv->version = 1;
-	memcpy(ctlv + 1, &stats, sizeof(stats));
-	return (0);
-}
-
-/*
- * Reset NPTv6 statistics.
- * Data layout (v0)(current):
- * Request: [ ipfw_obj_header ]
- *
- * Returns 0 on success
- */
-static int
-nptv6_reset_stats(struct ip_fw_chain *ch, ip_fw3_opheader *op,
-    struct sockopt_data *sd)
-{
-	struct nptv6_cfg *cfg;
-	ipfw_obj_header *oh;
-
-	if (sd->valsize != sizeof(*oh))
-		return (EINVAL);
-	oh = (ipfw_obj_header *)sd->kbuf;
-	if (ipfw_check_object_name_generic(oh->ntlv.name) != 0 ||
-	    oh->ntlv.set >= IPFW_MAX_SETS)
-		return (EINVAL);
-
-	IPFW_UH_WLOCK(ch);
-	cfg = nptv6_find(CHAIN_TO_SRV(ch), oh->ntlv.name, oh->ntlv.set);
-	if (cfg == NULL) {
-		IPFW_UH_WUNLOCK(ch);
-		return (ESRCH);
-	}
-	COUNTER_ARRAY_ZERO(cfg->stats, NPTV6STATS);
-	IPFW_UH_WUNLOCK(ch);
-	return (0);
-}
-
-static struct ipfw_sopt_handler	scodes[] = {
-	{ IP_FW_NPTV6_CREATE, 0,	HDIR_SET,	nptv6_create },
-	{ IP_FW_NPTV6_DESTROY,0,	HDIR_SET,	nptv6_destroy },
-	{ IP_FW_NPTV6_CONFIG, 0,	HDIR_BOTH,	nptv6_config },
-	{ IP_FW_NPTV6_LIST,   0,	HDIR_GET,	nptv6_list },
-	{ IP_FW_NPTV6_STATS,  0,	HDIR_GET,	nptv6_stats },
-	{ IP_FW_NPTV6_RESET_STATS,0,	HDIR_SET,	nptv6_reset_stats },
-};
-
-static int
-nptv6_classify(ipfw_insn *cmd, uint16_t *puidx, uint8_t *ptype)
-{
-	ipfw_insn *icmd;
-
-	icmd = cmd - 1;
-	NPTV6_DEBUG("opcode %d, arg1 %d, opcode0 %d, arg1 %d",
-	    cmd->opcode, cmd->arg1, icmd->opcode, icmd->arg1);
-	if (icmd->opcode != O_EXTERNAL_ACTION ||
-	    icmd->arg1 != V_nptv6_eid)
-		return (1);
-
-	*puidx = cmd->arg1;
-	*ptype = 0;
-	return (0);
-}
-
-static void
-nptv6_update_arg1(ipfw_insn *cmd, uint16_t idx)
-{
-
-	cmd->arg1 = idx;
-	NPTV6_DEBUG("opcode %d, arg1 -> %d", cmd->opcode, cmd->arg1);
-}
-
-static int
-nptv6_findbyname(struct ip_fw_chain *ch, struct tid_info *ti,
-    struct named_object **pno)
-{
-	int err;
-
-	err = ipfw_objhash_find_type(CHAIN_TO_SRV(ch), ti,
-	    IPFW_TLV_NPTV6_NAME, pno);
-	NPTV6_DEBUG("uidx %u, type %u, err %d", ti->uidx, ti->type, err);
-	return (err);
-}
-
-static struct named_object *
-nptv6_findbykidx(struct ip_fw_chain *ch, uint16_t idx)
-{
-	struct namedobj_instance *ni;
-	struct named_object *no;
-
-	IPFW_UH_WLOCK_ASSERT(ch);
-	ni = CHAIN_TO_SRV(ch);
-	no = ipfw_objhash_lookup_kidx(ni, idx);
-	KASSERT(no != NULL, ("NPT with index %d not found", idx));
-
-	NPTV6_DEBUG("kidx %u -> %s", idx, no->name);
-	return (no);
-}
-
-static int
-nptv6_manage_sets(struct ip_fw_chain *ch, uint16_t set, uint8_t new_set,
-    enum ipfw_sets_cmd cmd)
-{
-
-	return (ipfw_obj_manage_sets(CHAIN_TO_SRV(ch), IPFW_TLV_NPTV6_NAME,
-	    set, new_set, cmd));
-}
-
-static struct opcode_obj_rewrite opcodes[] = {
-	{
-		.opcode	= O_EXTERNAL_INSTANCE,
-		.etlv = IPFW_TLV_EACTION /* just show it isn't table */,
-		.classifier = nptv6_classify,
-		.update = nptv6_update_arg1,
-		.find_byname = nptv6_findbyname,
-		.find_bykidx = nptv6_findbykidx,
-		.manage_sets = nptv6_manage_sets,
-	},
-};
-
-static int
-destroy_config_cb(struct namedobj_instance *ni, struct named_object *no,
-    void *arg)
-{
-	struct nptv6_cfg *cfg;
-	struct ip_fw_chain *ch;
-
-	ch = (struct ip_fw_chain *)arg;
-	IPFW_UH_WLOCK_ASSERT(ch);
-
-	cfg = (struct nptv6_cfg *)SRV_OBJECT(ch, no->kidx);
-	SRV_OBJECT(ch, no->kidx) = NULL;
-	ipfw_objhash_del(ni, &cfg->no);
-	ipfw_objhash_free_idx(ni, cfg->no.kidx);
-	nptv6_free_config(cfg);
-	return (0);
-}
-
-int
-nptv6_init(struct ip_fw_chain *ch, int first)
-{
-
-	V_nptv6_eid = ipfw_add_eaction(ch, ipfw_nptv6, "nptv6");
-	if (V_nptv6_eid == 0)
-		return (ENXIO);
-	IPFW_ADD_SOPT_HANDLER(first, scodes);
-	IPFW_ADD_OBJ_REWRITER(first, opcodes);
-	return (0);
-}
-
-void
-nptv6_uninit(struct ip_fw_chain *ch, int last)
-{
-
-	IPFW_DEL_OBJ_REWRITER(last, opcodes);
-	IPFW_DEL_SOPT_HANDLER(last, scodes);
-	ipfw_del_eaction(ch, V_nptv6_eid);
-	/*
-	 * Since we already have deregistered external action,
-	 * our named objects become unaccessible via rules, because
-	 * all rules were truncated by ipfw_del_eaction().
-	 * So, we can unlink and destroy our named objects without holding
-	 * IPFW_WLOCK().
-	 */
-	IPFW_UH_WLOCK(ch);
-	ipfw_objhash_foreach_type(CHAIN_TO_SRV(ch), destroy_config_cb, ch,
-	    IPFW_TLV_NPTV6_NAME);
-	V_nptv6_eid = 0;
-	IPFW_UH_WUNLOCK(ch);
-}
-
Index: eebsd/sys/netpfil/ipfw/nptv6/nptv6.h
===================================================================
--- freebsd/sys/netpfil/ipfw/nptv6/nptv6.h	(revision f62c62d2fe57ec02c1350144f7739f8e866ee6d4)
+++ 	(revision )
@@ -1,65 +1,0 @@
-/*-
- * Copyright (c) 2016 Yandex LLC
- * Copyright (c) 2016 Andrey V. Elsukov <ae@FreeBSD.org>
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
- *
- * $FreeBSD$
- */
-
-#ifndef	_IP_FW_NPTV6_H_
-#define	_IP_FW_NPTV6_H_
-
-#include <netinet6/ip_fw_nptv6.h>
-
-#ifdef _KERNEL
-#define	NPTV6STATS	(sizeof(struct ipfw_nptv6_stats) / sizeof(uint64_t))
-#define	NPTV6STAT_ADD(c, f, v)		\
-    counter_u64_add((c)->stats[		\
-	offsetof(struct ipfw_nptv6_stats, f) / sizeof(uint64_t)], (v))
-#define	NPTV6STAT_INC(c, f)	NPTV6STAT_ADD(c, f, 1)
-#define	NPTV6STAT_FETCH(c, f)		\
-    counter_u64_fetch((c)->stats[	\
-	offsetof(struct ipfw_nptv6_stats, f) / sizeof(uint64_t)])
-
-struct nptv6_cfg {
-	struct named_object	no;
-
-	struct in6_addr		internal;   /* Internal IPv6 prefix */
-	struct in6_addr		external;   /* External IPv6 prefix */
-	struct in6_addr		mask;	    /* IPv6 prefix mask */
-	uint16_t		adjustment; /* Checksum adjustment value */
-	uint8_t			plen;	    /* Prefix length */
-	uint8_t			flags;	    /* Flags for internal use */
-#define	NPTV6_48PLEN		0x0001
-	char			name[64];   /* Instance name */
-	counter_u64_t		stats[NPTV6STATS]; /* Statistics counters */
-};
-#define	NPTV6_FLAGSMASK		0
-
-int nptv6_init(struct ip_fw_chain *ch, int first);
-void nptv6_uninit(struct ip_fw_chain *ch, int last);
-#endif /* _KERNEL */
-
-#endif /* _IP_FW_NPTV6_H_ */
-
Index: libbsd.py
===================================================================
--- libbsd.py	(revision f62c62d2fe57ec02c1350144f7739f8e866ee6d4)
+++ libbsd.py	(revision 63084c1988e3c8c0858fd747485f250a2160f434)
@@ -2441,4 +2441,5 @@
                 'sys/net/if_pfsync.h',
                 'sys/net/pfvar.h',
+                'sys/netpfil/ipfw/ip_fw_private.h',
                 'sys/netpfil/pf/pf_altq.h',
                 'sys/netpfil/pf/pf.h',
@@ -2459,58 +2460,4 @@
                 'sys/netpfil/pf/pf_ruleset.c',
                 'sys/netpfil/pf/pf_table.c',
-            ],
-            mm.generator['source']()
-        )
-
-class ipfw(builder.Module):
-
-    def __init__(self, manager):
-        super(ipfw, self).__init__(manager, type(self).__name__)
-
-    def generate(self):
-        mm = self.manager
-        self.addKernelSpaceHeaderFiles(
-            [
-                'sys/netinet6/ip_fw_nat64.h',
-                'sys/netinet6/ip_fw_nptv6.h',
-                'sys/netpfil/ipfw/dn_aqm_codel.h',
-                'sys/netpfil/ipfw/dn_aqm.h',
-                'sys/netpfil/ipfw/dn_aqm_pie.h',
-                'sys/netpfil/ipfw/dn_heap.h',
-                'sys/netpfil/ipfw/dn_sched_fq_codel.h',
-                'sys/netpfil/ipfw/dn_sched_fq_codel_helper.h',
-                'sys/netpfil/ipfw/dn_sched.h',
-                'sys/netpfil/ipfw/ip_dn_private.h',
-                'sys/netpfil/ipfw/ip_fw_private.h',
-                'sys/netpfil/ipfw/ip_fw_table.h',
-                'sys/netpfil/ipfw/nat64/ip_fw_nat64.h',
-                'sys/netpfil/ipfw/nat64/nat64lsn.h',
-                'sys/netpfil/ipfw/nat64/nat64stl.h',
-                'sys/netpfil/ipfw/nat64/nat64_translate.h',
-                'sys/netpfil/ipfw/nptv6/nptv6.h',
-            ]
-        )
-        self.addKernelSpaceSourceFiles(
-            [
-                'sys/netpfil/ipfw/ip_fw2.c',
-                'sys/netpfil/ipfw/ip_fw_bpf.c',
-                'sys/netpfil/ipfw/ip_fw_dynamic.c',
-                'sys/netpfil/ipfw/ip_fw_eaction.c',
-                'sys/netpfil/ipfw/ip_fw_iface.c',
-                'sys/netpfil/ipfw/ip_fw_log.c',
-                'sys/netpfil/ipfw/ip_fw_nat.c',
-                'sys/netpfil/ipfw/ip_fw_pfil.c',
-                'sys/netpfil/ipfw/ip_fw_sockopt.c',
-                'sys/netpfil/ipfw/ip_fw_table_algo.c',
-                'sys/netpfil/ipfw/ip_fw_table.c',
-                'sys/netpfil/ipfw/ip_fw_table_value.c',
-                'sys/netpfil/ipfw/nat64/ip_fw_nat64.c',
-                'sys/netpfil/ipfw/nat64/nat64lsn.c',
-                'sys/netpfil/ipfw/nat64/nat64lsn_control.c',
-                'sys/netpfil/ipfw/nat64/nat64stl.c',
-                'sys/netpfil/ipfw/nat64/nat64stl_control.c',
-                'sys/netpfil/ipfw/nat64/nat64_translate.c',
-                'sys/netpfil/ipfw/nptv6/ip_fw_nptv6.c',
-                'sys/netpfil/ipfw/nptv6/nptv6.c',
             ],
             mm.generator['source']()
@@ -4967,5 +4914,4 @@
     mm.addModule(altq(mm))
     mm.addModule(pf(mm))
-    mm.addModule(ipfw(mm))
     mm.addModule(dev_net(mm))
 
Index: rtemsbsd/include/machine/rtems-bsd-kernel-namespace.h
===================================================================
--- rtemsbsd/include/machine/rtems-bsd-kernel-namespace.h	(revision f62c62d2fe57ec02c1350144f7739f8e866ee6d4)
+++ rtemsbsd/include/machine/rtems-bsd-kernel-namespace.h	(revision 63084c1988e3c8c0858fd747485f250a2160f434)
@@ -11,11 +11,6 @@
 #define	AddLink _bsd_AddLink
 #define	AddPptp _bsd_AddPptp
-#define	addr_hash _bsd_addr_hash
-#define	addr_kfib _bsd_addr_kfib
-#define	addr_radix _bsd_addr_radix
 #define	addrsel_policy_init _bsd_addrsel_policy_init
 #define	AddSeq _bsd_AddSeq
-#define	add_table_entry _bsd_add_table_entry
-#define	add_toperation_state _bsd_add_toperation_state
 #define	AES_GMAC_Final _bsd_AES_GMAC_Final
 #define	AES_GMAC_Init _bsd_AES_GMAC_Init
@@ -90,5 +85,4 @@
 #define	auth_hash_nist_gmac_aes_256 _bsd_auth_hash_nist_gmac_aes_256
 #define	auth_hash_null _bsd_auth_hash_null
-#define	autoinc_step _bsd_autoinc_step
 #define	badport_bandlim _bsd_badport_bandlim
 #define	bcd2bin_data _bsd_bcd2bin_data
@@ -544,5 +538,4 @@
 #define	cdevpriv_mtx _bsd_cdevpriv_mtx
 #define	cgem_set_ref_clk _bsd_cgem_set_ref_clk
-#define	classify_opcode_kidx _bsd_classify_opcode_kidx
 #define	clean_unrhdr _bsd_clean_unrhdr
 #define	clean_unrhdrl _bsd_clean_unrhdrl
@@ -551,6 +544,4 @@
 #define	comp_algo_deflate _bsd_comp_algo_deflate
 #define	comp_algorithm_lookup _bsd_comp_algorithm_lookup
-#define	compare_ifidx _bsd_compare_ifidx
-#define	compare_numarray _bsd_compare_numarray
 #define	config_intrhook_disestablish _bsd_config_intrhook_disestablish
 #define	config_intrhook_establish _bsd_config_intrhook_establish
@@ -562,5 +553,4 @@
 #define	counter_u64_zero _bsd_counter_u64_zero
 #define	crc32_tab _bsd_crc32_tab
-#define	create_objects_compat _bsd_create_objects_compat
 #define	crypto_apply _bsd_crypto_apply
 #define	crypto_copyback _bsd_crypto_copyback
@@ -589,6 +579,4 @@
 #define	crypto_unregister_all _bsd_crypto_unregister_all
 #define	crypto_userasymcrypto _bsd_crypto_userasymcrypto
-#define	ctl3_lock _bsd_ctl3_lock
-#define	ctl3_rewriters _bsd_ctl3_rewriters
 #define	ctl_subtype_name _bsd_ctl_subtype_name
 #define	cuio_apply _bsd_cuio_apply
@@ -606,5 +594,4 @@
 #define	deembed_scopeid _bsd_deembed_scopeid
 #define	default_cc_ptr _bsd_default_cc_ptr
-#define	default_eaction_typename _bsd_default_eaction_typename
 #define	deflate_global _bsd_deflate_global
 #define	defrouter_del _bsd_defrouter_del
@@ -621,6 +608,4 @@
 #define	delete_unrhdr _bsd_delete_unrhdr
 #define	delist_dev _bsd_delist_dev
-#define	del_table_entry _bsd_del_table_entry
-#define	del_toperation_state _bsd_del_toperation_state
 #define	deregister_tcp_functions _bsd_deregister_tcp_functions
 #define	des_check_key _bsd_des_check_key
@@ -744,5 +729,4 @@
 #define	drbr_needs_enqueue_drv _bsd_drbr_needs_enqueue_drv
 #define	driver_module_handler _bsd_driver_module_handler
-#define	dummy_def _bsd_dummy_def
 #define	dwc_driver _bsd_dwc_driver
 #define	dwc_otg_attach _bsd_dwc_otg_attach
@@ -1237,6 +1221,4 @@
 #define	firmware_unregister _bsd_firmware_unregister
 #define	first_handler _bsd_first_handler
-#define	flow_hash _bsd_flow_hash
-#define	flush_table _bsd_flush_table
 #define	frag6_drain _bsd_frag6_drain
 #define	frag6_init _bsd_frag6_init
@@ -1244,8 +1226,4 @@
 #define	frag6_slowtimo _bsd_frag6_slowtimo
 #define	free_unr _bsd_free_unr
-#define	fw_one_pass _bsd_fw_one_pass
-#define	fw_tables_max _bsd_fw_tables_max
-#define	fw_tables_sets _bsd_fw_tables_sets
-#define	fw_verbose _bsd_fw_verbose
 #define	genkbd_commonioctl _bsd_genkbd_commonioctl
 #define	genkbd_diag _bsd_genkbd_diag
@@ -1775,5 +1753,4 @@
 #define	ifa_add_loopback_route _bsd_ifa_add_loopback_route
 #define	ifa_alloc _bsd_ifa_alloc
-#define	iface_idx _bsd_iface_idx
 #define	if_addgroup _bsd_if_addgroup
 #define	if_addmulti _bsd_if_addmulti
@@ -2260,120 +2237,6 @@
 #define	ipforwarding _bsd_ipforwarding
 #define	ip_fragment _bsd_ip_fragment
-#define	ipfw_add_eaction _bsd_ipfw_add_eaction
-#define	ipfw_add_obj_rewriter _bsd_ipfw_add_obj_rewriter
-#define	ipfw_add_sopt_handler _bsd_ipfw_add_sopt_handler
-#define	ipfw_add_table_algo _bsd_ipfw_add_table_algo
-#define	ipfw_alloc_rule _bsd_ipfw_alloc_rule
-#define	ipfw_attach_hooks _bsd_ipfw_attach_hooks
-#define	ipfw_bpf_init _bsd_ipfw_bpf_init
-#define	ipfw_bpf_mtap2 _bsd_ipfw_bpf_mtap2
-#define	ipfw_bpf_uninit _bsd_ipfw_bpf_uninit
-#define	ipfw_check_frame _bsd_ipfw_check_frame
-#define	ipfw_check_object_name_generic _bsd_ipfw_check_object_name_generic
-#define	ipfw_check_packet _bsd_ipfw_check_packet
-#define	ipfw_chg_hook _bsd_ipfw_chg_hook
-#define	ipfw_chk _bsd_ipfw_chk
 #define	ip_fw_chk_ptr _bsd_ip_fw_chk_ptr
-#define	ipfw_count_table _bsd_ipfw_count_table
-#define	ipfw_count_xtable _bsd_ipfw_count_xtable
-#define	ipfw_ctl3 _bsd_ipfw_ctl3
 #define	ip_fw_ctl_ptr _bsd_ip_fw_ctl_ptr
-#define	ipfw_del_eaction _bsd_ipfw_del_eaction
-#define	ipfw_del_obj_rewriter _bsd_ipfw_del_obj_rewriter
-#define	ipfw_del_sopt_handler _bsd_ipfw_del_sopt_handler
-#define	ipfw_del_table_algo _bsd_ipfw_del_table_algo
-#define	ipfw_destroy_counters _bsd_ipfw_destroy_counters
-#define	ipfw_destroy_obj_rewriter _bsd_ipfw_destroy_obj_rewriter
-#define	ipfw_destroy_skipto_cache _bsd_ipfw_destroy_skipto_cache
-#define	ipfw_destroy_sopt_handler _bsd_ipfw_destroy_sopt_handler
-#define	ipfw_destroy_srv _bsd_ipfw_destroy_srv
-#define	ipfw_destroy_tables _bsd_ipfw_destroy_tables
-#define	ipfw_dump_states _bsd_ipfw_dump_states
-#define	ipfw_dump_table_legacy _bsd_ipfw_dump_table_legacy
-#define	ipfw_dyn_get_count _bsd_ipfw_dyn_get_count
-#define	ipfw_dyn_init _bsd_ipfw_dyn_init
-#define	ipfw_dyn_len _bsd_ipfw_dyn_len
-#define	ipfw_dyn_uninit _bsd_ipfw_dyn_uninit
-#define	ipfw_dyn_unlock _bsd_ipfw_dyn_unlock
-#define	ipfw_eaction_init _bsd_ipfw_eaction_init
-#define	ipfw_eaction_uninit _bsd_ipfw_eaction_uninit
-#define	ipfw_expire_dyn_rules _bsd_ipfw_expire_dyn_rules
-#define	ipfw_export_obj_ntlv _bsd_ipfw_export_obj_ntlv
-#define	ipfw_export_table_ntlv _bsd_ipfw_export_table_ntlv
-#define	ipfw_export_table_value_legacy _bsd_ipfw_export_table_value_legacy
-#define	ipfw_export_table_value_v1 _bsd_ipfw_export_table_value_v1
-#define	ipfw_find_name_tlv_type _bsd_ipfw_find_name_tlv_type
-#define	ipfw_find_rule _bsd_ipfw_find_rule
-#define	ipfw_foreach_table_tentry _bsd_ipfw_foreach_table_tentry
-#define	ipfw_garbage_table_values _bsd_ipfw_garbage_table_values
-#define	ipfw_get_dynamic _bsd_ipfw_get_dynamic
-#define	ipfw_get_sopt_header _bsd_ipfw_get_sopt_header
-#define	ipfw_get_sopt_space _bsd_ipfw_get_sopt_space
-#define	ipfw_get_table_objhash _bsd_ipfw_get_table_objhash
-#define	ipfw_iface_add_notify _bsd_ipfw_iface_add_notify
-#define	ipfw_iface_del_notify _bsd_ipfw_iface_del_notify
-#define	ipfw_iface_destroy _bsd_ipfw_iface_destroy
-#define	ipfw_iface_init _bsd_ipfw_iface_init
-#define	ipfw_iface_ref _bsd_ipfw_iface_ref
-#define	ipfw_iface_unref _bsd_ipfw_iface_unref
-#define	ipfw_import_table_value_legacy _bsd_ipfw_import_table_value_legacy
-#define	ipfw_import_table_value_v1 _bsd_ipfw_import_table_value_v1
-#define	ipfw_init_counters _bsd_ipfw_init_counters
-#define	ipfw_init_obj_rewriter _bsd_ipfw_init_obj_rewriter
-#define	ipfw_init_skipto_cache _bsd_ipfw_init_skipto_cache
-#define	ipfw_init_sopt_handler _bsd_ipfw_init_sopt_handler
-#define	ipfw_init_srv _bsd_ipfw_init_srv
-#define	ipfw_init_tables _bsd_ipfw_init_tables
-#define	ipfw_install_state _bsd_ipfw_install_state
-#define	ipfw_is_dyn_rule _bsd_ipfw_is_dyn_rule
-#define	ipfw_link_table_values _bsd_ipfw_link_table_values
-#define	ipfw_log _bsd_ipfw_log
-#define	ipfw_lookup_dyn_rule _bsd_ipfw_lookup_dyn_rule
-#define	ipfw_lookup_table _bsd_ipfw_lookup_table
-#define	ipfw_match_range _bsd_ipfw_match_range
-#define	ipfw_nat64lsn _bsd_ipfw_nat64lsn
-#define	ipfw_nat64stl _bsd_ipfw_nat64stl
-#define	ipfw_nat_cfg_ptr _bsd_ipfw_nat_cfg_ptr
-#define	ipfw_nat_del_ptr _bsd_ipfw_nat_del_ptr
-#define	ipfw_nat_get_cfg_ptr _bsd_ipfw_nat_get_cfg_ptr
-#define	ipfw_nat_get_log_ptr _bsd_ipfw_nat_get_log_ptr
-#define	ipfw_nat_ptr _bsd_ipfw_nat_ptr
-#define	ipfw_nat_ready _bsd_ipfw_nat_ready
-#define	ipfw_objhash_add _bsd_ipfw_objhash_add
-#define	ipfw_objhash_alloc_idx _bsd_ipfw_objhash_alloc_idx
-#define	ipfw_objhash_bitmap_alloc _bsd_ipfw_objhash_bitmap_alloc
-#define	ipfw_objhash_bitmap_free _bsd_ipfw_objhash_bitmap_free
-#define	ipfw_objhash_bitmap_merge _bsd_ipfw_objhash_bitmap_merge
-#define	ipfw_objhash_bitmap_swap _bsd_ipfw_objhash_bitmap_swap
-#define	ipfw_objhash_count _bsd_ipfw_objhash_count
-#define	ipfw_objhash_count_type _bsd_ipfw_objhash_count_type
-#define	ipfw_objhash_create _bsd_ipfw_objhash_create
-#define	ipfw_objhash_del _bsd_ipfw_objhash_del
-#define	ipfw_objhash_destroy _bsd_ipfw_objhash_destroy
-#define	ipfw_objhash_find_type _bsd_ipfw_objhash_find_type
-#define	ipfw_objhash_foreach _bsd_ipfw_objhash_foreach
-#define	ipfw_objhash_foreach_type _bsd_ipfw_objhash_foreach_type
-#define	ipfw_objhash_free_idx _bsd_ipfw_objhash_free_idx
-#define	ipfw_objhash_lookup_kidx _bsd_ipfw_objhash_lookup_kidx
-#define	ipfw_objhash_lookup_name _bsd_ipfw_objhash_lookup_name
-#define	ipfw_objhash_lookup_name_type _bsd_ipfw_objhash_lookup_name_type
-#define	ipfw_objhash_lookup_table_kidx _bsd_ipfw_objhash_lookup_table_kidx
-#define	ipfw_objhash_same_name _bsd_ipfw_objhash_same_name
-#define	ipfw_objhash_set_funcs _bsd_ipfw_objhash_set_funcs
-#define	ipfw_obj_manage_sets _bsd_ipfw_obj_manage_sets
-#define	ipfw_reap_add _bsd_ipfw_reap_add
-#define	ipfw_reap_rules _bsd_ipfw_reap_rules
-#define	ipfw_ref_table _bsd_ipfw_ref_table
-#define	ipfw_resize_tables _bsd_ipfw_resize_tables
-#define	ipfw_run_eaction _bsd_ipfw_run_eaction
-#define	ipfw_send_pkt _bsd_ipfw_send_pkt
-#define	ipfw_switch_tables_namespace _bsd_ipfw_switch_tables_namespace
-#define	ipfw_table_algo_destroy _bsd_ipfw_table_algo_destroy
-#define	ipfw_table_algo_init _bsd_ipfw_table_algo_init
-#define	ipfw_table_value_destroy _bsd_ipfw_table_value_destroy
-#define	ipfw_table_value_init _bsd_ipfw_table_value_init
-#define	ipfw_unref_table _bsd_ipfw_unref_table
-#define	ipfw_unref_table_values _bsd_ipfw_unref_table_values
-#define	ipfw_vnet_ready _bsd_ipfw_vnet_ready
 #define	ip_gre_ttl _bsd_ip_gre_ttl
 #define	ip_init _bsd_ip_init
@@ -2628,5 +2491,4 @@
 #define	lagg_linkstate_p _bsd_lagg_linkstate_p
 #define	lagg_list _bsd_lagg_list
-#define	layer3_chain _bsd_layer3_chain
 #define	led_create _bsd_led_create
 #define	led_create_state _bsd_led_create_state
@@ -2713,5 +2575,4 @@
 #define	loif _bsd_loif
 #define	loioctl _bsd_loioctl
-#define	lookup_nat_ptr _bsd_lookup_nat_ptr
 #define	looutput _bsd_looutput
 #define	lpc_pwr_read _bsd_lpc_pwr_read
@@ -2810,6 +2671,4 @@
 #define	M_IOV _bsd_M_IOV
 #define	M_IP6NDP _bsd_M_IP6NDP
-#define	M_IPFW _bsd_M_IPFW
-#define	M_IPFW_TBL _bsd_M_IPFW_TBL
 #define	M_IPSEC_INPCB _bsd_M_IPSEC_INPCB
 #define	M_IPSEC_MISC _bsd_M_IPSEC_MISC
@@ -2842,5 +2701,4 @@
 #define	m_megapullup _bsd_m_megapullup
 #define	m_move_pkthdr _bsd_m_move_pkthdr
-#define	M_NAT64LSN _bsd_M_NAT64LSN
 #define	module_lookupbyname _bsd_module_lookupbyname
 #define	module_register _bsd_module_register
@@ -2906,23 +2764,4 @@
 #define	mutex_init _bsd_mutex_init
 #define	M_XDATA _bsd_M_XDATA
-#define	nat64_allow_private _bsd_nat64_allow_private
-#define	nat64_debug _bsd_nat64_debug
-#define	nat64_do_handle_ip4 _bsd_nat64_do_handle_ip4
-#define	nat64_do_handle_ip6 _bsd_nat64_do_handle_ip6
-#define	nat64_getlasthdr _bsd_nat64_getlasthdr
-#define	nat64_handle_icmp6 _bsd_nat64_handle_icmp6
-#define	nat64lsn_destroy_instance _bsd_nat64lsn_destroy_instance
-#define	nat64lsn_dump_state _bsd_nat64lsn_dump_state
-#define	nat64lsn_eid _bsd_nat64lsn_eid
-#define	nat64lsn_init _bsd_nat64lsn_init
-#define	nat64lsn_init_instance _bsd_nat64lsn_init_instance
-#define	nat64lsn_init_internal _bsd_nat64lsn_init_internal
-#define	nat64lsn_rproto_map _bsd_nat64lsn_rproto_map
-#define	nat64lsn_start_instance _bsd_nat64lsn_start_instance
-#define	nat64lsn_uninit _bsd_nat64lsn_uninit
-#define	nat64lsn_uninit_internal _bsd_nat64lsn_uninit_internal
-#define	nat64stl_eid _bsd_nat64stl_eid
-#define	nat64stl_init _bsd_nat64stl_init
-#define	nat64stl_uninit _bsd_nat64stl_uninit
 #define	natt_cksum_policy _bsd_natt_cksum_policy
 #define	nd6_add_ifa_lle _bsd_nd6_add_ifa_lle
@@ -3005,12 +2844,8 @@
 #define	ng_gif_input_p _bsd_ng_gif_input_p
 #define	ng_ipfw_input_p _bsd_ng_ipfw_input_p
-#define	norule_counter _bsd_norule_counter
 #define	nousrreqs _bsd_nousrreqs
-#define	nptv6_init _bsd_nptv6_init
-#define	nptv6_uninit _bsd_nptv6_uninit
 #define	null_class _bsd_null_class
 #define	null_filtops _bsd_null_filtops
 #define	nullop _bsd_nullop
-#define	number_array _bsd_number_array
 #define	OF_call_method _bsd_OF_call_method
 #define	OF_canon _bsd_OF_canon
@@ -3852,6 +3687,4 @@
 #define	rn_walktree _bsd_rn_walktree
 #define	rn_walktree_from _bsd_rn_walktree_from
-#define	rollback_table_values _bsd_rollback_table_values
-#define	rollback_toperation_state _bsd_rollback_toperation_state
 #define	root_bus _bsd_root_bus
 #define	root_bus_configure _bsd_root_bus_configure
@@ -4479,5 +4312,4 @@
 #define	SetDefaultAliasAddress _bsd_SetDefaultAliasAddress
 #define	SetDestCallId _bsd_SetDestCallId
-#define	set_disable _bsd_set_disable
 #define	SetExpire _bsd_SetExpire
 #define	SetFragmentAddr _bsd_SetFragmentAddr
@@ -4762,5 +4594,4 @@
 #define	sysctl___net_inet6_icmp6 _bsd_sysctl___net_inet6_icmp6
 #define	sysctl___net_inet6_ip6 _bsd_sysctl___net_inet6_ip6
-#define	sysctl___net_inet6_ip6_fw _bsd_sysctl___net_inet6_ip6_fw
 #define	sysctl___net_inet6_ipsec6 _bsd_sysctl___net_inet6_ipsec6
 #define	sysctl___net_inet6_mld _bsd_sysctl___net_inet6_mld
@@ -4776,5 +4607,4 @@
 #define	sysctl___net_inet_ip_alias _bsd_sysctl___net_inet_ip_alias
 #define	sysctl___net_inet_ipcomp _bsd_sysctl___net_inet_ipcomp
-#define	sysctl___net_inet_ip_fw _bsd_sysctl___net_inet_ip_fw
 #define	sysctl___net_inet_ipip _bsd_sysctl___net_inet_ipip
 #define	sysctl___net_inet_ipsec _bsd_sysctl___net_inet_ipsec
@@ -4956,8 +4786,6 @@
 #define	tcp_v6mssdflt _bsd_tcp_v6mssdflt
 #define	tcp_xmit_timer _bsd_tcp_xmit_timer
-#define	tc_ref _bsd_tc_ref
 #define	tc_tick_bt _bsd_tc_tick_bt
 #define	tc_tick_sbt _bsd_tc_tick_sbt
-#define	tc_unref _bsd_tc_unref
 #define	t_functions _bsd_t_functions
 #define	t_functions_inited _bsd_t_functions_inited
@@ -5153,5 +4981,4 @@
 #define	uma_zsecond_create _bsd_uma_zsecond_create
 #define	untimeout _bsd_untimeout
-#define	update_opcode_kidx _bsd_update_opcode_kidx
 #define	usb_alloc_device _bsd_usb_alloc_device
 #define	usb_alloc_mbufs _bsd_usb_alloc_mbufs
@@ -5432,5 +5259,4 @@
 #define	uuid_ether_add _bsd_uuid_ether_add
 #define	uuid_ether_del _bsd_uuid_ether_del
-#define	verbose_limit _bsd_verbose_limit
 #define	vht80_chan_ranges _bsd_vht80_chan_ranges
 #define	vlan_cookie_p _bsd_vlan_cookie_p
@@ -5444,5 +5270,4 @@
 #define	vlog _bsd_vlog
 #define	vnet_if_clone_init _bsd_vnet_if_clone_init
-#define	vnet_ipfw_iface_destroy _bsd_vnet_ipfw_iface_destroy
 #define	vprintf _bsd_vprintf
 #define	vsnprintf _bsd_vsnprintf
