[Midnightbsd-cvs] src: pf/net: Update pf

laffer1 at midnightbsd.org laffer1 at midnightbsd.org
Thu Nov 20 13:44:31 EST 2008


Log Message:
-----------
Update pf

Modified Files:
--------------
    src/sys/contrib/pf/net:
        if_pflog.c (r1.2 -> r1.3)
        if_pflog.h (r1.2 -> r1.3)
        if_pfsync.c (r1.1.1.1 -> r1.2)
        if_pfsync.h (r1.1.1.1 -> r1.2)
        pf.c (r1.1.1.2 -> r1.2)
        pf_if.c (r1.1.1.1 -> r1.2)
        pf_ioctl.c (r1.2 -> r1.3)
        pf_norm.c (r1.2 -> r1.3)
        pf_osfp.c (r1.1.1.1 -> r1.2)
        pf_subr.c (r1.1.1.1 -> r1.2)
        pf_table.c (r1.1.1.1 -> r1.2)
        pfvar.h (r1.1.1.2 -> r1.2)

Added Files:
-----------
    src/sys/contrib/pf/net:
        pf_mtag.h (r1.1)
        pf_ruleset.c (r1.1)

-------------- next part --------------
Index: pfvar.h
===================================================================
RCS file: /home/cvs/src/sys/contrib/pf/net/pfvar.h,v
retrieving revision 1.1.1.2
retrieving revision 1.2
diff -L sys/contrib/pf/net/pfvar.h -L sys/contrib/pf/net/pfvar.h -u -r1.1.1.2 -r1.2
--- sys/contrib/pf/net/pfvar.h
+++ sys/contrib/pf/net/pfvar.h
@@ -1,5 +1,5 @@
-/*	$FreeBSD: src/sys/contrib/pf/net/pfvar.h,v 1.11.2.2 2005/12/30 00:50:18 mlaier Exp $	*/
-/*	$OpenBSD: pfvar.h,v 1.213 2005/03/03 07:13:39 dhartmei Exp $ */
+/*	$FreeBSD: src/sys/contrib/pf/net/pfvar.h,v 1.16 2007/07/03 12:58:33 mlaier Exp $	*/
+/*	$OpenBSD: pfvar.h,v 1.244 2007/02/23 21:31:51 deraadt Exp $ */
 
 /*
  * Copyright (c) 2001 Daniel Hartmeier
@@ -38,11 +38,18 @@
 #include <sys/types.h>
 #include <sys/queue.h>
 #include <sys/tree.h>
+#ifdef __FreeBSD__
+#include <sys/lock.h>
+#include <sys/sx.h>
+#else
+#include <sys/rwlock.h>
+#endif
 
 #include <net/radix.h>
 #include <net/route.h>
 #ifdef __FreeBSD__
 #include <net/if_clone.h>
+#include <net/pf_mtag.h>
 #include <vm/uma.h>
 #else
 #include <netinet/ip_ipsp.h>
@@ -55,6 +62,7 @@
 #include <netinet/tcp_fsm.h>
 
 struct ip;
+struct ip6_hdr;
 #ifdef __FreeBSD__
 struct inpcb;
 #endif
@@ -62,6 +70,13 @@
 #define	PF_TCPS_PROXY_SRC	((TCP_NSTATES)+0)
 #define	PF_TCPS_PROXY_DST	((TCP_NSTATES)+1)
 
+#define	PF_MD5_DIGEST_LENGTH	16
+#ifdef MD5_DIGEST_LENGTH
+#if PF_MD5_DIGEST_LENGTH != MD5_DIGEST_LENGTH
+#error
+#endif
+#endif
+
 enum	{ PF_INOUT, PF_IN, PF_OUT };
 enum	{ PF_LAN_EXT, PF_EXT_GWY, PF_ID };
 enum	{ PF_PASS, PF_DROP, PF_SCRUB, PF_NOSCRUB, PF_NAT, PF_NONAT,
@@ -74,6 +89,8 @@
 enum	{ PF_CHANGE_NONE, PF_CHANGE_ADD_HEAD, PF_CHANGE_ADD_TAIL,
 	  PF_CHANGE_ADD_BEFORE, PF_CHANGE_ADD_AFTER,
 	  PF_CHANGE_REMOVE, PF_CHANGE_GET_TICKET };
+enum	{ PF_GET_NONE, PF_GET_CLR_CNTR };
+
 /*
  * Note about PFTM_*: real indices into pf_rule.timeout[] come before
  * PFTM_MAX, special cases afterwards. See pf_state_expires().
@@ -85,7 +102,8 @@
 	  PFTM_OTHER_FIRST_PACKET, PFTM_OTHER_SINGLE,
 	  PFTM_OTHER_MULTIPLE, PFTM_FRAG, PFTM_INTERVAL,
 	  PFTM_ADAPTIVE_START, PFTM_ADAPTIVE_END, PFTM_SRC_NODE,
-	  PFTM_TS_DIFF, PFTM_MAX, PFTM_PURGE, PFTM_UNTIL_PACKET };
+	  PFTM_TS_DIFF, PFTM_MAX, PFTM_PURGE, PFTM_UNLINKED,
+	  PFTM_UNTIL_PACKET };
 
 /* PFTM default values */
 #define PFTM_TCP_FIRST_PACKET_VAL	120	/* First TCP packet */
@@ -108,17 +126,22 @@
 #define PFTM_TS_DIFF_VAL		30	/* Allowed TS diff */
 
 enum	{ PF_NOPFROUTE, PF_FASTROUTE, PF_ROUTETO, PF_DUPTO, PF_REPLYTO };
-enum	{ PF_LIMIT_STATES, PF_LIMIT_SRC_NODES, PF_LIMIT_FRAGS, PF_LIMIT_MAX };
+enum	{ PF_LIMIT_STATES, PF_LIMIT_SRC_NODES, PF_LIMIT_FRAGS,
+	  PF_LIMIT_TABLES, PF_LIMIT_TABLE_ENTRIES, PF_LIMIT_MAX };
 #define PF_POOL_IDMASK		0x0f
 enum	{ PF_POOL_NONE, PF_POOL_BITMASK, PF_POOL_RANDOM,
 	  PF_POOL_SRCHASH, PF_POOL_ROUNDROBIN };
 enum	{ PF_ADDR_ADDRMASK, PF_ADDR_NOROUTE, PF_ADDR_DYNIFTL,
-	  PF_ADDR_TABLE, PF_ADDR_RTLABEL };
+	  PF_ADDR_TABLE, PF_ADDR_RTLABEL, PF_ADDR_URPFFAILED };
 #define PF_POOL_TYPEMASK	0x0f
 #define PF_POOL_STICKYADDR	0x20
 #define	PF_WSCALE_FLAG		0x80
 #define	PF_WSCALE_MASK		0x0f
 
+#define	PF_LOG			0x01
+#define	PF_LOG_ALL		0x02
+#define	PF_LOG_SOCKET_LOOKUP	0x04
+
 struct pf_addr {
 	union {
 		struct in_addr		v4;
@@ -169,18 +192,19 @@
 #ifdef _KERNEL
 
 struct pfi_dynaddr {
-	struct pf_addr		 pfid_addr4;
-	struct pf_addr		 pfid_mask4;
-	struct pf_addr		 pfid_addr6;
-	struct pf_addr		 pfid_mask6;
-	struct pfr_ktable	*pfid_kt;
-	struct pfi_kif		*pfid_kif;
-	void			*pfid_hook_cookie;
-	int			 pfid_net;	/* optional mask, or 128 */
-	int			 pfid_acnt4;	/* address count, IPv4 */
-	int			 pfid_acnt6;	/* address count, IPv6 */
-	sa_family_t		 pfid_af;	/* rule address family */
-	u_int8_t		 pfid_iflags;	/* PFI_AFLAG_* */
+	TAILQ_ENTRY(pfi_dynaddr)	 entry;
+	struct pf_addr			 pfid_addr4;
+	struct pf_addr			 pfid_mask4;
+	struct pf_addr			 pfid_addr6;
+	struct pf_addr			 pfid_mask6;
+	struct pfr_ktable		*pfid_kt;
+	struct pfi_kif			*pfid_kif;
+	void				*pfid_hook_cookie;
+	int				 pfid_net;	/* mask or 128 */
+	int				 pfid_acnt4;	/* address count IPv4 */
+	int				 pfid_acnt6;	/* address count IPv6 */
+	sa_family_t			 pfid_af;	/* rule af */
+	u_int8_t			 pfid_iflags;	/* PFI_AFLAG_* */
 };
 
 /*
@@ -246,21 +270,6 @@
 #define PFSYNC_MINVER	1
 #define PFSYNC_PREFVER	PFSYNC_MODVER
 #define PFSYNC_MAXVER	1
-
-/* prototyped for pf_subr.c */
-struct hook_desc {
-	TAILQ_ENTRY(hook_desc) hd_list;
-	void	(*hd_fn)(void *);
-	void	*hd_arg;
-};
-TAILQ_HEAD(hook_desc_head, hook_desc);
-
-void *hook_establish(struct hook_desc_head *, int, void (*)(void *), void *);
-void hook_disestablish(struct hook_desc_head *, void *);
-void dohooks(struct hook_desc_head *, int);
-
-#define HOOK_REMOVE     0x01
-#define HOOK_FREE       0x02
 #endif	/* __FreeBSD__ */
 
 #ifdef INET
@@ -392,23 +401,26 @@
 #endif /* PF_INET6_ONLY */
 #endif /* PF_INET_INET6 */
 
-#define	PF_MISMATCHAW(aw, x, af, neg)				\
-	(							\
-		(((aw)->type == PF_ADDR_NOROUTE &&		\
-		    pf_routable((x), (af))) ||			\
-		((aw)->type == PF_ADDR_RTLABEL &&		\
-		    !pf_rtlabel_match((x), (af), (aw))) ||	\
-		((aw)->type == PF_ADDR_TABLE &&			\
-		    !pfr_match_addr((aw)->p.tbl, (x), (af))) ||	\
-		((aw)->type == PF_ADDR_DYNIFTL &&		\
-		    !pfi_match_addr((aw)->p.dyn, (x), (af))) || \
-		((aw)->type == PF_ADDR_ADDRMASK &&		\
-		    !PF_AZERO(&(aw)->v.a.mask, (af)) &&		\
-		    !PF_MATCHA(0, &(aw)->v.a.addr,		\
-		    &(aw)->v.a.mask, (x), (af)))) !=		\
-		(neg)						\
+#define	PF_MISMATCHAW(aw, x, af, neg, ifp)				\
+	(								\
+		(((aw)->type == PF_ADDR_NOROUTE &&			\
+		    pf_routable((x), (af), NULL)) ||			\
+		(((aw)->type == PF_ADDR_URPFFAILED && (ifp) != NULL &&	\
+		    pf_routable((x), (af), (ifp))) ||			\
+		((aw)->type == PF_ADDR_RTLABEL &&			\
+		    !pf_rtlabel_match((x), (af), (aw))) ||		\
+		((aw)->type == PF_ADDR_TABLE &&				\
+		    !pfr_match_addr((aw)->p.tbl, (x), (af))) ||		\
+		((aw)->type == PF_ADDR_DYNIFTL &&			\
+		    !pfi_match_addr((aw)->p.dyn, (x), (af))) || 	\
+		((aw)->type == PF_ADDR_ADDRMASK &&			\
+		    !PF_AZERO(&(aw)->v.a.mask, (af)) &&			\
+		    !PF_MATCHA(0, &(aw)->v.a.addr,			\
+		    &(aw)->v.a.mask, (x), (af))))) !=			\
+		(neg)							\
 	)
 
+
 struct pf_rule_uid {
 	uid_t		 uid[2];
 	u_int8_t	 op;
@@ -526,6 +538,7 @@
 #define PF_OSFP_MSS_DC		0x0800		/* TCP MSS dont-care */
 #define PF_OSFP_DF		0x1000		/* IPv4 don't fragment bit */
 #define PF_OSFP_TS0		0x2000		/* Zero timestamp */
+#define PF_OSFP_INET6		0x4000		/* IPv6 */
 	u_int8_t		fp_optcnt;	/* TCP option count */
 	u_int8_t		fp_wscale;	/* TCP window scaling */
 	u_int8_t		fp_ttl;		/* IPv4 TTL */
@@ -581,11 +594,11 @@
 	union pf_rule_ptr	 skip[PF_SKIP_COUNT];
 #define PF_RULE_LABEL_SIZE	 64
 	char			 label[PF_RULE_LABEL_SIZE];
-#define PF_QNAME_SIZE		 16
+#define PF_QNAME_SIZE		 64
 	char			 ifname[IFNAMSIZ];
 	char			 qname[PF_QNAME_SIZE];
 	char			 pqname[PF_QNAME_SIZE];
-#define	PF_TAG_NAME_SIZE	 16
+#define	PF_TAG_NAME_SIZE	 64
 	char			 tagname[PF_TAG_NAME_SIZE];
 	char			 match_tagname[PF_TAG_NAME_SIZE];
 
@@ -595,8 +608,8 @@
 	struct pf_pool		 rpool;
 
 	u_int64_t		 evaluations;
-	u_int64_t		 packets;
-	u_int64_t		 bytes;
+	u_int64_t		 packets[2];
+	u_int64_t		 bytes[2];
 
 	struct pfi_kif		*kif;
 	struct pf_anchor	*anchor;
@@ -604,12 +617,14 @@
 
 	pf_osfp_t		 os_fingerprint;
 
+	int			 rtableid;
 	u_int32_t		 timeout[PFTM_MAX];
 	u_int32_t		 states;
 	u_int32_t		 max_states;
 	u_int32_t		 src_nodes;
 	u_int32_t		 max_src_nodes;
 	u_int32_t		 max_src_states;
+	u_int32_t		 spare1;		/* netgraph */
 	u_int32_t		 max_src_conn;
 	struct {
 		u_int32_t		limit;
@@ -620,12 +635,15 @@
 	u_int32_t		 rt_listid;
 	u_int32_t		 nr;
 	u_int32_t		 prob;
+	uid_t			 cuid;
+	pid_t			 cpid;
 
 	u_int16_t		 return_icmp;
 	u_int16_t		 return_icmp6;
 	u_int16_t		 max_mss;
 	u_int16_t		 tag;
 	u_int16_t		 match_tag;
+	u_int16_t		 spare2;		/* netgraph */
 
 	struct pf_rule_uid	 uid;
 	struct pf_rule_gid	 gid;
@@ -634,6 +652,7 @@
 	u_int8_t		 action;
 	u_int8_t		 direction;
 	u_int8_t		 log;
+	u_int8_t		 logif;
 	u_int8_t		 quick;
 	u_int8_t		 ifnot;
 	u_int8_t		 match_tag_not;
@@ -681,9 +700,10 @@
 
 /* rule flags again */
 #define PFRULE_IFBOUND		0x00010000	/* if-bound */
-#define PFRULE_GRBOUND		0x00020000	/* group-bound */
 
 #define PFSTATE_HIWAT		10000	/* default state table size */
+#define PFSTATE_ADAPT_START	6000	/* default adaptive timeout start */
+#define PFSTATE_ADAPT_END	12000	/* default adaptive timeout end */
 
 
 struct pf_threshold {
@@ -701,8 +721,8 @@
 	struct pf_addr	 raddr;
 	union pf_rule_ptr rule;
 	struct pfi_kif	*kif;
-	u_int32_t	 bytes;
-	u_int32_t	 packets;
+	u_int64_t	 bytes[2];
+	u_int64_t	 packets[2];
 	u_int32_t	 states;
 	u_int32_t	 conn;
 	struct pf_threshold	conn_rate;
@@ -744,26 +764,58 @@
 	u_int8_t	state;		/* active state level		*/
 	u_int8_t	wscale;		/* window scaling factor	*/
 	u_int16_t	mss;		/* Maximum segment size option	*/
+	u_int8_t	tcp_est;	/* Did we reach TCPS_ESTABLISHED */
 	struct pf_state_scrub	*scrub;	/* state is scrubbed		*/
+	u_int8_t	pad[3];
 };
 
 TAILQ_HEAD(pf_state_queue, pf_state);
 
+/* keep synced with struct pf_state, used in RB_FIND */
+struct pf_state_cmp {
+	u_int64_t	 id;
+	u_int32_t	 creatorid;
+	struct pf_state_host lan;
+	struct pf_state_host gwy;
+	struct pf_state_host ext;
+	sa_family_t	 af;
+	u_int8_t	 proto;
+	u_int8_t	 direction;
+	u_int8_t	 pad;
+};
+
 struct pf_state {
 	u_int64_t	 id;
+	u_int32_t	 creatorid;
+	struct pf_state_host lan;
+	struct pf_state_host gwy;
+	struct pf_state_host ext;
+	sa_family_t	 af;
+	u_int8_t	 proto;
+	u_int8_t	 direction;
+#ifdef __FreeBSD__
+	u_int8_t	 local_flags;
+#define	PFSTATE_EXPIRING 0x01
+#else
+	u_int8_t	 pad;
+#endif
+	u_int8_t	 log;
+	u_int8_t	 allow_opts;
+	u_int8_t	 timeout;
+	u_int8_t	 sync_flags;
+#define	PFSTATE_NOSYNC	 0x01
+#define	PFSTATE_FROMSYNC 0x02
+#define	PFSTATE_STALE	 0x04
 	union {
 		struct {
 			RB_ENTRY(pf_state)	 entry_lan_ext;
 			RB_ENTRY(pf_state)	 entry_ext_gwy;
 			RB_ENTRY(pf_state)	 entry_id;
-			TAILQ_ENTRY(pf_state)	 entry_updates;
+			TAILQ_ENTRY(pf_state)	 entry_list;
 			struct pfi_kif		*kif;
 		} s;
 		char	 ifname[IFNAMSIZ];
 	} u;
-	struct pf_state_host lan;
-	struct pf_state_host gwy;
-	struct pf_state_host ext;
 	struct pf_state_peer src;
 	struct pf_state_peer dst;
 	union pf_rule_ptr rule;
@@ -773,30 +825,12 @@
 	struct pfi_kif	*rt_kif;
 	struct pf_src_node	*src_node;
 	struct pf_src_node	*nat_src_node;
+	u_int64_t	 packets[2];
+	u_int64_t	 bytes[2];
 	u_int32_t	 creation;
 	u_int32_t	 expire;
 	u_int32_t	 pfsync_time;
-	u_int32_t	 packets[2];
-	u_int32_t	 bytes[2];
-	u_int32_t	 creatorid;
 	u_int16_t	 tag;
-	sa_family_t	 af;
-	u_int8_t	 proto;
-	u_int8_t	 direction;
-	u_int8_t	 log;
-	u_int8_t	 allow_opts;
-	u_int8_t	 timeout;
-	u_int8_t	 sync_flags;
-#define	PFSTATE_NOSYNC	 0x01
-#define	PFSTATE_FROMSYNC 0x02
-#define	PFSTATE_STALE	 0x04
-#ifdef __FreeBSD__
-	u_int8_t	 local_flags;
-#define	PFSTATE_EXPIRING 0x01
-#define	PFSTATE_SRC_CONN 0x02
-#else
-	u_int8_t	 pad;
-#endif
 };
 
 TAILQ_HEAD(pf_rulequeue, pf_rule);
@@ -808,6 +842,8 @@
 		struct pf_rulequeue	 queues[2];
 		struct {
 			struct pf_rulequeue	*ptr;
+			struct pf_rule		**ptr_array;
+			u_int32_t		 rcount;
 			u_int32_t		 ticket;
 			int			 open;
 		}			 active, inactive;
@@ -829,6 +865,7 @@
 	char			 path[MAXPATHLEN];
 	struct pf_ruleset	 ruleset;
 	int			 refcnt;	/* anchor rules */
+	int			 match;
 };
 RB_PROTOTYPE(pf_anchor_global, pf_anchor, entry_global, pf_anchor_compare);
 RB_PROTOTYPE(pf_anchor_node, pf_anchor, entry_node, pf_anchor_compare);
@@ -954,56 +991,52 @@
 RB_PROTOTYPE(pf_state_tree_ext_gwy, pf_state,
     u.s.entry_ext_gwy, pf_state_compare_ext_gwy);
 
-struct pfi_if {
-	char				 pfif_name[IFNAMSIZ];
-	u_int64_t			 pfif_packets[2][2][2];
-	u_int64_t			 pfif_bytes[2][2][2];
-	u_int64_t			 pfif_addcnt;
-	u_int64_t			 pfif_delcnt;
-	long				 pfif_tzero;
-	int				 pfif_states;
-	int				 pfif_rules;
-	int				 pfif_flags;
-};
-
-TAILQ_HEAD(pfi_grouphead, pfi_kif);
 TAILQ_HEAD(pfi_statehead, pfi_kif);
 RB_HEAD(pfi_ifhead, pfi_kif);
+
+/* keep synced with pfi_kif, used in RB_FIND */
+struct pfi_kif_cmp {
+	char				 pfik_name[IFNAMSIZ];
+};
+
 struct pfi_kif {
-	struct pfi_if			 pfik_if;
+	char				 pfik_name[IFNAMSIZ];
 	RB_ENTRY(pfi_kif)		 pfik_tree;
+	u_int64_t			 pfik_packets[2][2][2];
+	u_int64_t			 pfik_bytes[2][2][2];
+	u_int32_t			 pfik_tzero;
+	int				 pfik_flags;
 	struct pf_state_tree_lan_ext	 pfik_lan_ext;
 	struct pf_state_tree_ext_gwy	 pfik_ext_gwy;
-	struct pfi_grouphead		 pfik_grouphead;
-	TAILQ_ENTRY(pfi_kif)		 pfik_instances;
 	TAILQ_ENTRY(pfi_kif)		 pfik_w_states;
-	struct hook_desc_head		*pfik_ah_head;
+#ifndef __FreeBSD__
 	void				*pfik_ah_cookie;
-	struct pfi_kif			*pfik_parent;
+#endif
 	struct ifnet			*pfik_ifp;
+	struct ifg_group		*pfik_group;
 	int				 pfik_states;
 	int				 pfik_rules;
+	TAILQ_HEAD(, pfi_dynaddr)	 pfik_dynaddrs;
 };
-#define pfik_name	pfik_if.pfif_name
-#define pfik_packets	pfik_if.pfif_packets
-#define pfik_bytes	pfik_if.pfif_bytes
-#define pfik_tzero	pfik_if.pfif_tzero
-#define pfik_flags	pfik_if.pfif_flags
-#define pfik_addcnt	pfik_if.pfif_addcnt
-#define pfik_delcnt	pfik_if.pfif_delcnt
-#define pfik_states	pfik_if.pfif_states
-#define pfik_rules	pfik_if.pfif_rules
-
-#define PFI_IFLAG_GROUP		0x0001	/* group of interfaces */
-#define PFI_IFLAG_INSTANCE	0x0002	/* single instance */
-#define PFI_IFLAG_CLONABLE	0x0010	/* clonable group */
-#define PFI_IFLAG_DYNAMIC	0x0020	/* dynamic group */
-#define PFI_IFLAG_ATTACHED	0x0040	/* interface attached */
+
+enum pfi_kif_refs {
+	PFI_KIF_REF_NONE,
+	PFI_KIF_REF_STATE,
+	PFI_KIF_REF_RULE
+};
+
 #define PFI_IFLAG_SKIP		0x0100	/* skip filtering on interface */
+/* XXX: revisist */
 #define PFI_IFLAG_SETABLE_MASK	0x0100	/* setable via DIOC{SET,CLR}IFFLAG */
 #define PFI_IFLAG_PLACEHOLDER	0x8000	/* placeholder group/interface */
 
 struct pf_pdesc {
+	struct {
+		int	 done;
+		uid_t	 uid;
+		gid_t	 gid;
+		pid_t	 pid;
+	}		 lookup;
 	u_int64_t	 tot_len;	/* Make Mickey money */
 	union {
 		struct tcphdr		*tcp;
@@ -1021,6 +1054,7 @@
 	struct pf_addr	*dst;
 	struct ether_header
 			*eh;
+	struct pf_mtag	*pf_mtag;
 	u_int16_t	*ip_sum;
 	u_int32_t	 p_len;		/* total length of payload */
 	u_int16_t	 flags;		/* Let SCRUB trigger behavior in
@@ -1161,6 +1195,7 @@
 	u_int32_t	debug;
 	u_int32_t	hostid;
 	char		ifname[IFNAMSIZ];
+	u_int8_t	pf_chksum[PF_MD5_DIGEST_LENGTH];
 };
 
 struct cbq_opts {
@@ -1223,6 +1258,23 @@
 	u_int32_t		 qid;		/* return value */
 };
 
+#ifndef __FreeBSD__
+
+#define	PF_TAG_GENERATED		0x01
+#define	PF_TAG_FRAGCACHE		0x02
+#define	PF_TAG_TRANSLATE_LOCALHOST	0x04
+
+struct pf_mtag {
+	void		*hdr;		/* saved hdr pos in mbuf, for ECN */
+	u_int		 rtableid;	/* alternate routing table id */
+	u_int32_t	 qid;		/* queue id */
+	u_int16_t	 tag;		/* tag id */
+	u_int8_t	 flags;
+	u_int8_t	 routed;
+	sa_family_t	 af;		/* for ECN */
+};
+#endif
+
 struct pf_tag {
 	u_int16_t	tag;		/* tag id */
 };
@@ -1239,6 +1291,10 @@
 #define PFFRAG_FRCENT_HIWAT	50000	/* Number of fragment cache entries */
 #define PFFRAG_FRCACHE_HIWAT	10000	/* Number of fragment descriptors */
 
+#define PFR_KTABLE_HIWAT	1000	/* Number of tables */
+#define PFR_KENTRY_HIWAT	200000	/* Number of table entries */
+#define PFR_KENTRY_HIWAT_SMALL	100000	/* Number of table entries (tiny hosts) */
+
 /*
  * ioctl parameter structures
  */
@@ -1284,6 +1340,13 @@
 	struct pf_state	 state;
 };
 
+struct pfioc_src_node_kill {
+	/* XXX returns the number of src nodes killed in psnk_af */
+	sa_family_t psnk_af;
+	struct pf_rule_addr psnk_src;
+	struct pf_rule_addr psnk_dst;
+};
+
 struct pfioc_state_kill {
 	/* XXX returns the number of states killed in psk_af */
 	sa_family_t		psk_af;
@@ -1391,11 +1454,6 @@
 #define pfrio_setflag	pfrio_size2
 #define pfrio_clrflag	pfrio_nadd
 
-
-#define PFI_FLAG_GROUP		0x0001	/* gets groups of interfaces */
-#define PFI_FLAG_INSTANCE	0x0002	/* gets single interfaces */
-#define PFI_FLAG_ALLMASK	0x0003
-
 struct pfioc_iface {
 	char	 pfiio_name[IFNAMSIZ];
 	void	*pfiio_buffer;
@@ -1474,15 +1532,15 @@
 #define DIOCCLRSRCNODES	_IO('D', 85)
 #define DIOCSETHOSTID	_IOWR('D', 86, u_int32_t)
 #define DIOCIGETIFACES	_IOWR('D', 87, struct pfioc_iface)
-#define DIOCICLRISTATS  _IOWR('D', 88, struct pfioc_iface)
 #define DIOCSETIFFLAG	_IOWR('D', 89, struct pfioc_iface)
 #define DIOCCLRIFFLAG	_IOWR('D', 90, struct pfioc_iface)
+#define DIOCKILLSRCNODES	_IOWR('D', 91, struct pfioc_src_node_kill)
 #ifdef __FreeBSD__
 struct pf_ifspeed {
 	char			ifname[IFNAMSIZ];
 	u_int32_t		baudrate;
 };
-#define DIOCGIFSPEED	_IOWR('D', 91, struct pf_ifspeed)
+#define DIOCGIFSPEED	_IOWR('D', 92, struct pf_ifspeed)
 #endif
 
 #ifdef _KERNEL
@@ -1494,16 +1552,13 @@
 RB_PROTOTYPE(pf_state_tree_id, pf_state,
     entry_id, pf_state_compare_id);
 extern struct pf_state_tree_id tree_id;
-extern struct pf_state_queue state_updates;
+extern struct pf_state_queue state_list;
 
-extern struct pf_anchor_global		  pf_anchors;
-extern struct pf_ruleset		  pf_main_ruleset;
 TAILQ_HEAD(pf_poolqueue, pf_pool);
 extern struct pf_poolqueue		  pf_pools[2];
 TAILQ_HEAD(pf_altqqueue, pf_altq);
 extern struct pf_altqqueue		  pf_altqs[2];
 extern struct pf_palist			  pf_pabuf;
-extern struct pfi_kif			**pfi_index2kif;
 
 extern u_int32_t		 ticket_altqs_active;
 extern u_int32_t		 ticket_altqs_inactive;
@@ -1530,26 +1585,22 @@
 extern struct pool		 pf_state_pl, pf_altq_pl, pf_pooladdr_pl;
 extern struct pool		 pf_state_scrub_pl;
 #endif
-extern void			 pf_purge_timeout(void *);
-extern void			 pf_purge_expired_src_nodes(void);
-extern void			 pf_purge_expired_states(void);
-extern void			 pf_purge_expired_state(struct pf_state *);
+extern void			 pf_purge_thread(void *);
+extern void			 pf_purge_expired_src_nodes(int);
+extern void			 pf_purge_expired_states(u_int32_t);
+extern void			 pf_unlink_state(struct pf_state *);
+extern void			 pf_free_state(struct pf_state *);
 extern int			 pf_insert_state(struct pfi_kif *,
 				    struct pf_state *);
 extern int			 pf_insert_src_node(struct pf_src_node **,
 				    struct pf_rule *, struct pf_addr *,
 				    sa_family_t);
 void				 pf_src_tree_remove_state(struct pf_state *);
-extern struct pf_state		*pf_find_state_byid(struct pf_state *);
-extern struct pf_state		*pf_find_state_all(struct pf_state *key,
+extern struct pf_state		*pf_find_state_byid(struct pf_state_cmp *);
+extern struct pf_state		*pf_find_state_all(struct pf_state_cmp *key,
 				    u_int8_t tree, int *more);
 extern void			 pf_print_state(struct pf_state *);
 extern void			 pf_print_flags(u_int8_t);
-extern struct pf_anchor		*pf_find_anchor(const char *);
-extern struct pf_ruleset	*pf_find_ruleset(const char *);
-extern struct pf_ruleset	*pf_find_or_create_ruleset(const char *);
-extern void			 pf_remove_if_empty_ruleset(
-				    struct pf_ruleset *);
 extern u_int16_t		 pf_cksum_fixup(u_int16_t, u_int16_t, u_int16_t,
 				    u_int8_t);
 
@@ -1581,11 +1632,15 @@
 void	pf_addr_inc(struct pf_addr *, sa_family_t);
 #endif /* INET6 */
 
+#ifdef __FreeBSD__
+u_int32_t	pf_new_isn(struct pf_state *);
+#endif
 void   *pf_pull_hdr(struct mbuf *, int, void *, int, u_short *, u_short *,
 	    sa_family_t);
 void	pf_change_a(void *, u_int16_t *, u_int32_t, u_int8_t);
 int	pflog_packet(struct pfi_kif *, struct mbuf *, sa_family_t, u_int8_t,
-	    u_int8_t, struct pf_rule *, struct pf_rule *, struct pf_ruleset *);
+	    u_int8_t, struct pf_rule *, struct pf_rule *, struct pf_ruleset *,
+	    struct pf_pdesc *);
 int	pf_match_addr(u_int8_t, struct pf_addr *, struct pf_addr *,
 	    struct pf_addr *, sa_family_t);
 int	pf_match(u_int8_t, u_int32_t, u_int32_t, u_int32_t);
@@ -1609,8 +1664,13 @@
 u_int32_t
 	pf_state_expires(const struct pf_state *);
 void	pf_purge_expired_fragments(void);
-int	pf_routable(struct pf_addr *addr, sa_family_t af);
+int	pf_routable(struct pf_addr *addr, sa_family_t af, struct pfi_kif *);
 int	pf_rtlabel_match(struct pf_addr *, sa_family_t, struct pf_addr_wrap *);
+#ifdef __FreeBSD__
+int	pf_socket_lookup(int, struct pf_pdesc *, struct inpcb *);
+#else
+int	pf_socket_lookup(int, struct pf_pdesc *);
+#endif
 void	pfr_initialize(void);
 int	pfr_match_addr(struct pfr_ktable *, struct pf_addr *, sa_family_t);
 void	pfr_update_stats(struct pfr_ktable *, struct pf_addr *, sa_family_t,
@@ -1635,7 +1695,7 @@
 int	pfr_del_addrs(struct pfr_table *, struct pfr_addr *, int, int *,
 	    int);
 int	pfr_set_addrs(struct pfr_table *, struct pfr_addr *, int, int *,
-	    int *, int *, int *, int);
+	    int *, int *, int *, int, u_int32_t);
 int	pfr_get_addrs(struct pfr_table *, struct pfr_addr *, int *, int);
 int	pfr_get_astats(struct pfr_table *, struct pfr_astats *, int *, int);
 int	pfr_clr_astats(struct pfr_table *, struct pfr_addr *, int, int *,
@@ -1648,48 +1708,54 @@
 int	pfr_ina_define(struct pfr_table *, struct pfr_addr *, int, int *,
 	    int *, u_int32_t, int);
 
+extern struct pfi_statehead	 pfi_statehead;
+extern struct pfi_kif		*pfi_all;
+
 void		 pfi_initialize(void);
 #ifdef __FreeBSD__
 void		 pfi_cleanup(void);
 #endif
-void		 pfi_attach_clone(struct if_clone *);
+struct pfi_kif	*pfi_kif_get(const char *);
+void		 pfi_kif_ref(struct pfi_kif *, enum pfi_kif_refs);
+void		 pfi_kif_unref(struct pfi_kif *, enum pfi_kif_refs);
+int		 pfi_kif_match(struct pfi_kif *, struct pfi_kif *);
 void		 pfi_attach_ifnet(struct ifnet *);
 void		 pfi_detach_ifnet(struct ifnet *);
-struct pfi_kif	*pfi_lookup_create(const char *);
-struct pfi_kif	*pfi_lookup_if(const char *);
-int		 pfi_maybe_destroy(struct pfi_kif *);
-struct pfi_kif	*pfi_attach_rule(const char *);
-void		 pfi_detach_rule(struct pfi_kif *);
-void		 pfi_attach_state(struct pfi_kif *);
-void		 pfi_detach_state(struct pfi_kif *);
+void		 pfi_attach_ifgroup(struct ifg_group *);
+void		 pfi_detach_ifgroup(struct ifg_group *);
+void		 pfi_group_change(const char *);
+int		 pfi_match_addr(struct pfi_dynaddr *, struct pf_addr *,
+		    sa_family_t);
 int		 pfi_dynaddr_setup(struct pf_addr_wrap *, sa_family_t);
-void		 pfi_dynaddr_copyout(struct pf_addr_wrap *);
 void		 pfi_dynaddr_remove(struct pf_addr_wrap *);
+void		 pfi_dynaddr_copyout(struct pf_addr_wrap *);
 void		 pfi_fill_oldstatus(struct pf_status *);
-int		 pfi_clr_istats(const char *, int *, int);
-int		 pfi_get_ifaces(const char *, struct pfi_if *, int *, int);
+int		 pfi_clr_istats(const char *);
+int		 pfi_get_ifaces(const char *, struct pfi_kif *, int *);
 int		 pfi_set_flags(const char *, int);
 int		 pfi_clear_flags(const char *, int);
-int		 pfi_match_addr(struct pfi_dynaddr *, struct pf_addr *,
-		    sa_family_t);
 
-extern struct pfi_statehead	pfi_statehead;
-
-u_int16_t	pf_tagname2tag(char *);
-void		pf_tag2tagname(u_int16_t, char *);
-void		pf_tag_ref(u_int16_t);
-void		pf_tag_unref(u_int16_t);
-int		pf_tag_packet(struct mbuf *, struct pf_tag *, int);
-u_int32_t	pf_qname2qid(char *);
-void		pf_qid2qname(u_int32_t, char *);
-void		pf_qid_unref(u_int32_t);
+u_int16_t	 pf_tagname2tag(char *);
+void		 pf_tag2tagname(u_int16_t, char *);
+void		 pf_tag_ref(u_int16_t);
+void		 pf_tag_unref(u_int16_t);
+int		 pf_tag_packet(struct mbuf *, struct pf_mtag *, int, int);
+u_int32_t	 pf_qname2qid(char *);
+void		 pf_qid2qname(u_int32_t, char *);
+void		 pf_qid_unref(u_int32_t);
+#ifndef __FreeBSD__
+struct pf_mtag	*pf_find_mtag(struct mbuf *);
+struct pf_mtag	*pf_get_mtag(struct mbuf *);
+#endif
 
 extern struct pf_status	pf_status;
 
 #ifdef __FreeBSD__
 extern uma_zone_t	pf_frent_pl, pf_frag_pl;
+extern struct sx	pf_consistency_lock;
 #else
 extern struct pool	pf_frent_pl, pf_frag_pl;
+extern struct rwlock	pf_consistency_lock;
 #endif
 
 struct pf_pool_limit {
@@ -1732,6 +1798,34 @@
 
 #endif /* _KERNEL */
 
+extern struct pf_anchor_global  pf_anchors;
+extern struct pf_anchor        pf_main_anchor;
+#define pf_main_ruleset	pf_main_anchor.ruleset
+
+/* these ruleset functions can be linked into userland programs (pfctl) */
+int			 pf_get_ruleset_number(u_int8_t);
+void			 pf_init_ruleset(struct pf_ruleset *);
+int			 pf_anchor_setup(struct pf_rule *,
+			    const struct pf_ruleset *, const char *);
+int			 pf_anchor_copyout(const struct pf_ruleset *,
+			    const struct pf_rule *, struct pfioc_rule *);
+void			 pf_anchor_remove(struct pf_rule *);
+void			 pf_remove_if_empty_ruleset(struct pf_ruleset *);
+struct pf_anchor	*pf_find_anchor(const char *);
+struct pf_ruleset	*pf_find_ruleset(const char *);
+struct pf_ruleset	*pf_find_or_create_ruleset(const char *);
+void			 pf_rs_initialize(void);
+
+#ifndef __FreeBSD__
+/* ?!? */
+#ifdef _KERNEL
+int			 pf_anchor_copyout(const struct pf_ruleset *,
+			    const struct pf_rule *, struct pfioc_rule *);
+void			 pf_anchor_remove(struct pf_rule *);
+
+#endif /* _KERNEL */
+#endif
+
 /* The fingerprint functions can be linked into userland programs (tcpdump) */
 int	pf_osfp_add(struct pf_osfp_ioctl *);
 #ifdef _KERNEL
@@ -1740,7 +1834,8 @@
 	    const struct tcphdr *);
 #endif /* _KERNEL */
 struct pf_osfp_enlist *
-	pf_osfp_fingerprint_hdr(const struct ip *, const struct tcphdr *);
+	pf_osfp_fingerprint_hdr(const struct ip *, const struct ip6_hdr *,
+	    const struct tcphdr *);
 void	pf_osfp_flush(void);
 int	pf_osfp_get(struct pf_osfp_ioctl *);
 #ifdef __FreeBSD__
Index: pf_ioctl.c
===================================================================
RCS file: /home/cvs/src/sys/contrib/pf/net/pf_ioctl.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -L sys/contrib/pf/net/pf_ioctl.c -L sys/contrib/pf/net/pf_ioctl.c -u -r1.2 -r1.3
--- sys/contrib/pf/net/pf_ioctl.c
+++ sys/contrib/pf/net/pf_ioctl.c
@@ -1,5 +1,4 @@
-/*	$FreeBSD: src/sys/contrib/pf/net/pf_ioctl.c,v 1.20.2.2 2006/03/06 16:10:18 mlaier Exp $	*/
-/*	$OpenBSD: pf_ioctl.c,v 1.139 2005/03/03 07:13:39 dhartmei Exp $ */
+/*	$OpenBSD: pf_ioctl.c,v 1.175 2007/02/26 22:47:43 deraadt Exp $ */
 
 /*
  * Copyright (c) 2001 Daniel Hartmeier
@@ -39,15 +38,34 @@
 #ifdef __FreeBSD__
 #include "opt_inet.h"
 #include "opt_inet6.h"
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/sys/contrib/pf/net/pf_ioctl.c,v 1.28.2.1 2007/11/25 19:26:46 mlaier Exp $");
 #endif
 
 #ifdef __FreeBSD__
 #include "opt_bpf.h"
 #include "opt_pf.h"
+
+#ifdef DEV_BPF
 #define	NBPFILTER	DEV_BPF
+#else
+#define	NBPFILTER	0
+#endif
+
+#ifdef DEV_PFLOG
 #define	NPFLOG		DEV_PFLOG
+#else
+#define	NPFLOG		0
+#endif
+
+#ifdef DEV_PFSYNC
 #define	NPFSYNC		DEV_PFSYNC
 #else
+#define	NPFSYNC		0
+#endif
+
+#else
 #include "bpfilter.h"
 #include "pflog.h"
 #include "pfsync.h"
@@ -67,10 +85,18 @@
 #include <sys/module.h>
 #include <sys/conf.h>
 #include <sys/proc.h>
+#include <sys/sysctl.h>
 #else
 #include <sys/timeout.h>
 #include <sys/pool.h>
 #endif
+#include <sys/proc.h>
+#include <sys/malloc.h>
+#include <sys/kthread.h>
+#ifndef __FreeBSD__
+#include <sys/rwlock.h>
+#include <uvm/uvm_extern.h>
+#endif
 
 #include <net/if.h>
 #include <net/if_types.h>
@@ -83,8 +109,11 @@
 #include <netinet/ip_var.h>
 #include <netinet/ip_icmp.h>
 
-#ifndef __FreeBSD__
+#ifdef __FreeBSD__
+#include <sys/md5.h>
+#else
 #include <dev/rndvar.h>
+#include <crypto/md5.h>
 #endif
 #include <net/pfvar.h>
 
@@ -92,9 +121,7 @@
 #include <net/if_pfsync.h>
 #endif /* NPFSYNC > 0 */
 
-#ifdef __FreeBSD__
 #include <net/if_pflog.h>
-#endif
 
 #ifdef INET6
 #include <netinet/ip6.h>
@@ -118,18 +145,12 @@
 int			 pfattach(void);
 #else
 void			 pfattach(int);
+void			 pf_thread_create(void *);
 int			 pfopen(dev_t, int, int, struct proc *);
 int			 pfclose(dev_t, int, int, struct proc *);
 #endif
 struct pf_pool		*pf_get_pool(char *, u_int32_t, u_int8_t, u_int32_t,
 			    u_int8_t, u_int8_t, u_int8_t);
-int			 pf_get_ruleset_number(u_int8_t);
-void			 pf_init_ruleset(struct pf_ruleset *);
-int			 pf_anchor_setup(struct pf_rule *,
-			    const struct pf_ruleset *, const char *);
-int			 pf_anchor_copyout(const struct pf_ruleset *,
-			    const struct pf_rule *, struct pfioc_rule *);
-void			 pf_anchor_remove(struct pf_rule *);
 
 void			 pf_mv_pool(struct pf_palist *, struct pf_palist *);
 void			 pf_empty_pool(struct pf_palist *);
@@ -147,15 +168,18 @@
 #endif /* ALTQ */
 int			 pf_begin_rules(u_int32_t *, int, const char *);
 int			 pf_rollback_rules(u_int32_t, int, char *);
+int			 pf_setup_pfsync_matching(struct pf_ruleset *);
+void			 pf_hash_rule(MD5_CTX *, struct pf_rule *);
+void			 pf_hash_rule_addr(MD5_CTX *, struct pf_rule_addr *);
 int			 pf_commit_rules(u_int32_t, int, char *);
 
+struct pf_rule		 pf_default_rule;
 #ifdef __FreeBSD__
-extern struct callout	 pf_expire_to;
+struct sx		 pf_consistency_lock;
+SX_SYSINIT(pf_consistency_lock, &pf_consistency_lock, "pf_statetbl_lock");
 #else
-extern struct timeout	 pf_expire_to;
+struct rwlock		 pf_consistency_lock = RWLOCK_INITIALIZER;
 #endif
-
-struct pf_rule		 pf_default_rule;
 #ifdef ALTQ
 static int		 pf_altq_running;
 #endif
@@ -167,9 +191,9 @@
 #if (PF_QNAME_SIZE != PF_TAG_NAME_SIZE)
 #error PF_QNAME_SIZE must be equal to PF_TAG_NAME_SIZE
 #endif
-static u_int16_t	 tagname2tag(struct pf_tags *, char *);
-static void		 tag2tagname(struct pf_tags *, u_int16_t, char *);
-static void		 tag_unref(struct pf_tags *, u_int16_t);
+u_int16_t		 tagname2tag(struct pf_tags *, char *);
+void			 tag2tagname(struct pf_tags *, u_int16_t, char *);
+void			 tag_unref(struct pf_tags *, u_int16_t);
 int			 pf_rtlabel_add(struct pf_addr_wrap *);
 void			 pf_rtlabel_remove(struct pf_addr_wrap *);
 void			 pf_rtlabel_copyout(struct pf_addr_wrap *);
@@ -217,9 +241,14 @@
 };
 
 static volatile int pf_pfil_hooked = 0;
+int pf_end_threads = 0;
 struct mtx pf_task_mtx;
 pflog_packet_t *pflog_packet_ptr = NULL;
 
+int debug_pfugidhack = 0;
+SYSCTL_INT(_debug, OID_AUTO, pfugidhack, CTLFLAG_RW, &debug_pfugidhack, 0,
+    "Enable/disable pf user/group rules mpsafe hack");
+
 void
 init_pf_mutex(void)
 {
@@ -255,6 +284,7 @@
 	UMA_DESTROY(pf_cache_pl);
 	UMA_DESTROY(pf_cent_pl);
 	UMA_DESTROY(pfr_ktable_pl);
+	UMA_DESTROY(pfr_kentry_pl2);
 	UMA_DESTROY(pfr_kentry_pl);
 	UMA_DESTROY(pf_state_scrub_pl);
 	UMA_DESTROY(pfi_addr_pl);
@@ -302,6 +332,10 @@
 	pf_pool_limits[PF_LIMIT_SRC_NODES].limit = PFSNODE_HIWAT;
 	pf_pool_limits[PF_LIMIT_FRAGS].pp = pf_frent_pl;
 	pf_pool_limits[PF_LIMIT_FRAGS].limit = PFFRAG_FRENT_HIWAT;
+	pf_pool_limits[PF_LIMIT_TABLES].pp = pfr_ktable_pl;
+	pf_pool_limits[PF_LIMIT_TABLES].limit = PFR_KTABLE_HIWAT;
+	pf_pool_limits[PF_LIMIT_TABLE_ENTRIES].pp = pfr_kentry_pl;
+	pf_pool_limits[PF_LIMIT_TABLE_ENTRIES].limit = PFR_KENTRY_HIWAT;
 	uma_zone_set_max(pf_pool_limits[PF_LIMIT_STATES].pp,
 		pf_pool_limits[PF_LIMIT_STATES].limit);
 
@@ -313,12 +347,13 @@
 	TAILQ_INIT(&pf_pabuf);
 	pf_altqs_active = &pf_altqs[0];
 	pf_altqs_inactive = &pf_altqs[1];
-	TAILQ_INIT(&state_updates);
+	TAILQ_INIT(&state_list);
 
 	/* default rule should never be garbage collected */
 	pf_default_rule.entries.tqe_prev = &pf_default_rule.entries.tqe_next;
 	pf_default_rule.action = PF_PASS;
 	pf_default_rule.nr = -1;
+	pf_default_rule.rtableid = -1;
 
 	/* initialize default timeouts */
 	my_timeout[PFTM_TCP_FIRST_PACKET] = PFTM_TCP_FIRST_PACKET_VAL;
@@ -339,18 +374,21 @@
 	my_timeout[PFTM_INTERVAL] = PFTM_INTERVAL_VAL;
 	my_timeout[PFTM_SRC_NODE] = PFTM_SRC_NODE_VAL;
 	my_timeout[PFTM_TS_DIFF] = PFTM_TS_DIFF_VAL;
-
-	callout_init(&pf_expire_to, NET_CALLOUT_MPSAFE);
-	callout_reset(&pf_expire_to, my_timeout[PFTM_INTERVAL] * hz,
-	    pf_purge_timeout, &pf_expire_to);
+	my_timeout[PFTM_ADAPTIVE_START] = PFSTATE_ADAPT_START;
+	my_timeout[PFTM_ADAPTIVE_END] = PFSTATE_ADAPT_END;
 
 	pf_normalize_init();
 	bzero(&pf_status, sizeof(pf_status));
+	pf_status.debug = PF_DEBUG_URGENT;
+
 	pf_pfil_hooked = 0;
 
 	/* XXX do our best to avoid a conflict */
 	pf_status.hostid = arc4random();
 
+	if (kthread_create(pf_purge_thread, NULL, NULL, 0, 0, "pfpurge"))
+		return (ENXIO);
+
 	return (error);
 }
 #else /* !__FreeBSD__ */
@@ -376,6 +414,10 @@
 	pool_sethardlimit(pf_pool_limits[PF_LIMIT_STATES].pp,
 	    pf_pool_limits[PF_LIMIT_STATES].limit, NULL, 0);
 
+	if (ctob(physmem) <= 100*1024*1024)
+		pf_pool_limits[PF_LIMIT_TABLE_ENTRIES].limit =
+		    PFR_KENTRY_HIWAT_SMALL;
+
 	RB_INIT(&tree_src_tracking);
 	RB_INIT(&pf_anchors);
 	pf_init_ruleset(&pf_main_ruleset);
@@ -384,12 +426,13 @@
 	TAILQ_INIT(&pf_pabuf);
 	pf_altqs_active = &pf_altqs[0];
 	pf_altqs_inactive = &pf_altqs[1];
-	TAILQ_INIT(&state_updates);
+	TAILQ_INIT(&state_list);
 
 	/* default rule should never be garbage collected */
 	pf_default_rule.entries.tqe_prev = &pf_default_rule.entries.tqe_next;
 	pf_default_rule.action = PF_PASS;
 	pf_default_rule.nr = -1;
+	pf_default_rule.rtableid = -1;
 
 	/* initialize default timeouts */
 	timeout[PFTM_TCP_FIRST_PACKET] = PFTM_TCP_FIRST_PACKET_VAL;
@@ -410,9 +453,8 @@
 	timeout[PFTM_INTERVAL] = PFTM_INTERVAL_VAL;
 	timeout[PFTM_SRC_NODE] = PFTM_SRC_NODE_VAL;
 	timeout[PFTM_TS_DIFF] = PFTM_TS_DIFF_VAL;
-
-	timeout_set(&pf_expire_to, pf_purge_timeout, &pf_expire_to);
-	timeout_add(&pf_expire_to, timeout[PFTM_INTERVAL] * hz);
+	timeout[PFTM_ADAPTIVE_START] = PFSTATE_ADAPT_START;
+	timeout[PFTM_ADAPTIVE_END] = PFSTATE_ADAPT_END;
 
 	pf_normalize_init();
 	bzero(&pf_status, sizeof(pf_status));
@@ -420,6 +462,16 @@
 
 	/* XXX do our best to avoid a conflict */
 	pf_status.hostid = arc4random();
+
+	/* require process context to purge states, so perform in a thread */
+	kthread_create_deferred(pf_thread_create, NULL);
+}
+
+void
+pf_thread_create(void *v)
+{
+	if (kthread_create(pf_purge_thread, NULL, NULL, "pfpurge"))
+		panic("pfpurge thread");
 }
 
 int
@@ -483,312 +535,6 @@
 	return (&rule->rpool);
 }
 
-int
-pf_get_ruleset_number(u_int8_t action)
-{
-	switch (action) {
-	case PF_SCRUB:
-	case PF_NOSCRUB:
-		return (PF_RULESET_SCRUB);
-		break;
-	case PF_PASS:
-	case PF_DROP:
-		return (PF_RULESET_FILTER);
-		break;
-	case PF_NAT:
-	case PF_NONAT:
-		return (PF_RULESET_NAT);
-		break;
-	case PF_BINAT:
-	case PF_NOBINAT:
-		return (PF_RULESET_BINAT);
-		break;
-	case PF_RDR:
-	case PF_NORDR:
-		return (PF_RULESET_RDR);
-		break;
-	default:
-		return (PF_RULESET_MAX);
-		break;
-	}
-}
-
-void
-pf_init_ruleset(struct pf_ruleset *ruleset)
-{
-	int	i;
-
-	memset(ruleset, 0, sizeof(struct pf_ruleset));
-	for (i = 0; i < PF_RULESET_MAX; i++) {
-		TAILQ_INIT(&ruleset->rules[i].queues[0]);
-		TAILQ_INIT(&ruleset->rules[i].queues[1]);
-		ruleset->rules[i].active.ptr = &ruleset->rules[i].queues[0];
-		ruleset->rules[i].inactive.ptr = &ruleset->rules[i].queues[1];
-	}
-}
-
-struct pf_anchor *
-pf_find_anchor(const char *path)
-{
-	static struct pf_anchor	 key;
-
-	memset(&key, 0, sizeof(key));
-	strlcpy(key.path, path, sizeof(key.path));
-	return (RB_FIND(pf_anchor_global, &pf_anchors, &key));
-}
-
-struct pf_ruleset *
-pf_find_ruleset(const char *path)
-{
-	struct pf_anchor	*anchor;
-
-	while (*path == '/')
-		path++;
-	if (!*path)
-		return (&pf_main_ruleset);
-	anchor = pf_find_anchor(path);
-	if (anchor == NULL)
-		return (NULL);
-	else
-		return (&anchor->ruleset);
-}
-
-struct pf_ruleset *
-pf_find_or_create_ruleset(const char *path)
-{
-	static char		 p[MAXPATHLEN];
-	char			*q = NULL, *r;	/* make the compiler happy */
-	struct pf_ruleset	*ruleset;
-	struct pf_anchor	*anchor = NULL, *dup, *parent = NULL;
-
-	while (*path == '/')
-		path++;
-	ruleset = pf_find_ruleset(path);
-	if (ruleset != NULL)
-		return (ruleset);
-	strlcpy(p, path, sizeof(p));
-#ifdef __FreeBSD__
-	while (parent == NULL && (q = rindex(p, '/')) != NULL) {
-#else
-	while (parent == NULL && (q = strrchr(p, '/')) != NULL) {
-#endif
-		*q = 0;
-		if ((ruleset = pf_find_ruleset(p)) != NULL) {
-			parent = ruleset->anchor;
-			break;
-		}
-	}
-	if (q == NULL)
-		q = p;
-	else
-		q++;
-	strlcpy(p, path, sizeof(p));
-	if (!*q)
-		return (NULL);
-#ifdef __FreeBSD__
-	while ((r = index(q, '/')) != NULL || *q) {
-#else
-	while ((r = strchr(q, '/')) != NULL || *q) {
-#endif
-		if (r != NULL)
-			*r = 0;
-		if (!*q || strlen(q) >= PF_ANCHOR_NAME_SIZE ||
-		    (parent != NULL && strlen(parent->path) >=
-		    MAXPATHLEN - PF_ANCHOR_NAME_SIZE - 1))
-			return (NULL);
-		anchor = (struct pf_anchor *)malloc(sizeof(*anchor), M_TEMP,
-		    M_NOWAIT);
-		if (anchor == NULL)
-			return (NULL);
-		memset(anchor, 0, sizeof(*anchor));
-		RB_INIT(&anchor->children);
-		strlcpy(anchor->name, q, sizeof(anchor->name));
-		if (parent != NULL) {
-			strlcpy(anchor->path, parent->path,
-			    sizeof(anchor->path));
-			strlcat(anchor->path, "/", sizeof(anchor->path));
-		}
-		strlcat(anchor->path, anchor->name, sizeof(anchor->path));
-		if ((dup = RB_INSERT(pf_anchor_global, &pf_anchors, anchor)) !=
-		    NULL) {
-			printf("pf_find_or_create_ruleset: RB_INSERT1 "
-			    "'%s' '%s' collides with '%s' '%s'\n",
-			    anchor->path, anchor->name, dup->path, dup->name);
-			free(anchor, M_TEMP);
-			return (NULL);
-		}
-		if (parent != NULL) {
-			anchor->parent = parent;
-			if ((dup = RB_INSERT(pf_anchor_node, &parent->children,
-			    anchor)) != NULL) {
-				printf("pf_find_or_create_ruleset: "
-				    "RB_INSERT2 '%s' '%s' collides with "
-				    "'%s' '%s'\n", anchor->path, anchor->name,
-				    dup->path, dup->name);
-				RB_REMOVE(pf_anchor_global, &pf_anchors,
-				    anchor);
-				free(anchor, M_TEMP);
-				return (NULL);
-			}
-		}
-		pf_init_ruleset(&anchor->ruleset);
-		anchor->ruleset.anchor = anchor;
-		parent = anchor;
-		if (r != NULL)
-			q = r + 1;
-		else
-			*q = 0;
-	}
-	return (&anchor->ruleset);
-}
-
-void
-pf_remove_if_empty_ruleset(struct pf_ruleset *ruleset)
-{
-	struct pf_anchor	*parent;
-	int			 i;
-
-	while (ruleset != NULL) {
-		if (ruleset == &pf_main_ruleset || ruleset->anchor == NULL ||
-		    !RB_EMPTY(&ruleset->anchor->children) ||
-		    ruleset->anchor->refcnt > 0 || ruleset->tables > 0 ||
-		    ruleset->topen)
-			return;
-		for (i = 0; i < PF_RULESET_MAX; ++i)
-			if (!TAILQ_EMPTY(ruleset->rules[i].active.ptr) ||
-			    !TAILQ_EMPTY(ruleset->rules[i].inactive.ptr) ||
-			    ruleset->rules[i].inactive.open)
-				return;
-		RB_REMOVE(pf_anchor_global, &pf_anchors, ruleset->anchor);
-		if ((parent = ruleset->anchor->parent) != NULL)
-			RB_REMOVE(pf_anchor_node, &parent->children,
-			    ruleset->anchor);
-		free(ruleset->anchor, M_TEMP);
-		if (parent == NULL)
-			return;
-		ruleset = &parent->ruleset;
-	}
-}
-
-int
-pf_anchor_setup(struct pf_rule *r, const struct pf_ruleset *s,
-    const char *name)
-{
-	static char		*p, path[MAXPATHLEN];
-	struct pf_ruleset	*ruleset;
-
-	r->anchor = NULL;
-	r->anchor_relative = 0;
-	r->anchor_wildcard = 0;
-	if (!name[0])
-		return (0);
-	if (name[0] == '/')
-		strlcpy(path, name + 1, sizeof(path));
-	else {
-		/* relative path */
-		r->anchor_relative = 1;
-		if (s->anchor == NULL || !s->anchor->path[0])
-			path[0] = 0;
-		else
-			strlcpy(path, s->anchor->path, sizeof(path));
-		while (name[0] == '.' && name[1] == '.' && name[2] == '/') {
-			if (!path[0]) {
-				printf("pf_anchor_setup: .. beyond root\n");
-				return (1);
-			}
-#ifdef __FreeBSD__
-			if ((p = rindex(path, '/')) != NULL)
-#else
-			if ((p = strrchr(path, '/')) != NULL)
-#endif
-				*p = 0;
-			else
-				path[0] = 0;
-			r->anchor_relative++;
-			name += 3;
-		}
-		if (path[0])
-			strlcat(path, "/", sizeof(path));
-		strlcat(path, name, sizeof(path));
-	}
-#ifdef __FreeBSD__
-	if ((p = rindex(path, '/')) != NULL && !strcmp(p, "/*")) {
-#else
-	if ((p = strrchr(path, '/')) != NULL && !strcmp(p, "/*")) {
-#endif
-		r->anchor_wildcard = 1;
-		*p = 0;
-	}
-	ruleset = pf_find_or_create_ruleset(path);
-	if (ruleset == NULL || ruleset->anchor == NULL) {
-		printf("pf_anchor_setup: ruleset\n");
-		return (1);
-	}
-	r->anchor = ruleset->anchor;
-	r->anchor->refcnt++;
-	return (0);
-}
-
-int
-pf_anchor_copyout(const struct pf_ruleset *rs, const struct pf_rule *r,
-    struct pfioc_rule *pr)
-{
-	pr->anchor_call[0] = 0;
-	if (r->anchor == NULL)
-		return (0);
-	if (!r->anchor_relative) {
-		strlcpy(pr->anchor_call, "/", sizeof(pr->anchor_call));
-		strlcat(pr->anchor_call, r->anchor->path,
-		    sizeof(pr->anchor_call));
-	} else {
-		char a[MAXPATHLEN], b[MAXPATHLEN], *p;
-		int i;
-
-		if (rs->anchor == NULL)
-			a[0] = 0;
-		else
-			strlcpy(a, rs->anchor->path, sizeof(a));
-		strlcpy(b, r->anchor->path, sizeof(b));
-		for (i = 1; i < r->anchor_relative; ++i) {
-#ifdef __FreeBSD__
-			if ((p = rindex(a, '/')) == NULL)
-#else
-			if ((p = strrchr(a, '/')) == NULL)
-#endif
-				p = a;
-			*p = 0;
-			strlcat(pr->anchor_call, "../",
-			    sizeof(pr->anchor_call));
-		}
-		if (strncmp(a, b, strlen(a))) {
-			printf("pf_anchor_copyout: '%s' '%s'\n", a, b);
-			return (1);
-		}
-		if (strlen(b) > strlen(a))
-			strlcat(pr->anchor_call, b + (a[0] ? strlen(a) + 1 : 0),
-			    sizeof(pr->anchor_call));
-	}
-	if (r->anchor_wildcard)
-		strlcat(pr->anchor_call, pr->anchor_call[0] ? "/*" : "*",
-		    sizeof(pr->anchor_call));
-	return (0);
-}
-
-void
-pf_anchor_remove(struct pf_rule *r)
-{
-	if (r->anchor == NULL)
-		return;
-	if (r->anchor->refcnt <= 0) {
-		printf("pf_anchor_remove: broken refcount");
-		r->anchor = NULL;
-		return;
-	}
-	if (!--r->anchor->refcnt)
-		pf_remove_if_empty_ruleset(&r->anchor->ruleset);
-	r->anchor = NULL;
-}
-
 void
 pf_mv_pool(struct pf_palist *poola, struct pf_palist *poolb)
 {
@@ -808,7 +554,7 @@
 	while ((empty_pool_pa = TAILQ_FIRST(poola)) != NULL) {
 		pfi_dynaddr_remove(&empty_pool_pa->addr);
 		pf_tbladdr_remove(&empty_pool_pa->addr);
-		pfi_detach_rule(empty_pool_pa->kif);
+		pfi_kif_unref(empty_pool_pa->kif, PFI_KIF_REF_RULE);
 		TAILQ_REMOVE(poola, empty_pool_pa, entries);
 		pool_put(&pf_pooladdr_pl, empty_pool_pa);
 	}
@@ -854,13 +600,13 @@
 		if (rule->overload_tbl)
 			pfr_detach_table(rule->overload_tbl);
 	}
-	pfi_detach_rule(rule->kif);
+	pfi_kif_unref(rule->kif, PFI_KIF_REF_RULE);
 	pf_anchor_remove(rule);
 	pf_empty_pool(&rule->rpool.list);
 	pool_put(&pf_rule_pl, rule);
 }
 
-static	u_int16_t
+u_int16_t
 tagname2tag(struct pf_tags *head, char *tagname)
 {
 	struct pf_tagname	*tag, *p = NULL;
@@ -905,7 +651,7 @@
 	return (tag->tag);
 }
 
-static	void
+void
 tag2tagname(struct pf_tags *head, u_int16_t tagid, char *p)
 {
 	struct pf_tagname	*tag;
@@ -917,7 +663,7 @@
 		}
 }
 
-static	void
+void
 tag_unref(struct pf_tags *head, u_int16_t tag)
 {
 	struct pf_tagname	*p, *next;
@@ -946,7 +692,7 @@
 void
 pf_tag2tagname(u_int16_t tagid, char *p)
 {
-	return (tag2tagname(&pf_tags, tagid, p));
+	tag2tagname(&pf_tags, tagid, p);
 }
 
 void
@@ -964,7 +710,7 @@
 void
 pf_tag_unref(u_int16_t tag)
 {
-	return (tag_unref(&pf_tags, tag));
+	tag_unref(&pf_tags, tag);
 }
 
 int
@@ -1023,13 +769,13 @@
 void
 pf_qid2qname(u_int32_t qid, char *p)
 {
-	return (tag2tagname(&pf_qids, (u_int16_t)qid, p));
+	tag2tagname(&pf_qids, (u_int16_t)qid, p);
 }
 
 void
 pf_qid_unref(u_int32_t qid)
 {
-	return (tag_unref(&pf_qids, (u_int16_t)qid));
+	tag_unref(&pf_qids, (u_int16_t)qid);
 }
 
 int
@@ -1148,7 +894,7 @@
 	if (error == 0 && ifp != NULL && ALTQ_IS_ENABLED(&ifp->if_snd)) {
 		tb.rate = altq->ifbandwidth;
 		tb.depth = altq->tbrsize;
-		s = splimp();
+		s = splnet();
 #ifdef __FreeBSD__
 		PF_UNLOCK();
 #endif
@@ -1184,7 +930,7 @@
 	if (error == 0) {
 		/* clear tokenbucket regulator */
 		tb.rate = 0;
-		s = splimp();
+		s = splnet();
 #ifdef __FreeBSD__
 		PF_UNLOCK();
 #endif
@@ -1210,8 +956,10 @@
 	rs = pf_find_or_create_ruleset(anchor);
 	if (rs == NULL)
 		return (EINVAL);
-	while ((rule = TAILQ_FIRST(rs->rules[rs_num].inactive.ptr)) != NULL)
+	while ((rule = TAILQ_FIRST(rs->rules[rs_num].inactive.ptr)) != NULL) {
 		pf_rm_rule(rs->rules[rs_num].inactive.ptr, rule);
+		rs->rules[rs_num].inactive.rcount--;
+	}
 	*ticket = ++rs->rules[rs_num].inactive.ticket;
 	rs->rules[rs_num].inactive.open = 1;
 	return (0);
@@ -1229,19 +977,105 @@
 	if (rs == NULL || !rs->rules[rs_num].inactive.open ||
 	    rs->rules[rs_num].inactive.ticket != ticket)
 		return (0);
-	while ((rule = TAILQ_FIRST(rs->rules[rs_num].inactive.ptr)) != NULL)
+	while ((rule = TAILQ_FIRST(rs->rules[rs_num].inactive.ptr)) != NULL) {
 		pf_rm_rule(rs->rules[rs_num].inactive.ptr, rule);
+		rs->rules[rs_num].inactive.rcount--;
+	}
 	rs->rules[rs_num].inactive.open = 0;
 	return (0);
 }
 
+#define PF_MD5_UPD(st, elm)						\
+		MD5Update(ctx, (u_int8_t *) &(st)->elm, sizeof((st)->elm))
+
+#define PF_MD5_UPD_STR(st, elm)						\
+		MD5Update(ctx, (u_int8_t *) (st)->elm, strlen((st)->elm))
+
+#define PF_MD5_UPD_HTONL(st, elm, stor) do {				\
+		(stor) = htonl((st)->elm);				\
+		MD5Update(ctx, (u_int8_t *) &(stor), sizeof(u_int32_t));\
+} while (0)
+
+#define PF_MD5_UPD_HTONS(st, elm, stor) do {				\
+		(stor) = htons((st)->elm);				\
+		MD5Update(ctx, (u_int8_t *) &(stor), sizeof(u_int16_t));\
+} while (0)
+
+void
+pf_hash_rule_addr(MD5_CTX *ctx, struct pf_rule_addr *pfr)
+{
+	PF_MD5_UPD(pfr, addr.type);
+	switch (pfr->addr.type) {
+		case PF_ADDR_DYNIFTL:
+			PF_MD5_UPD(pfr, addr.v.ifname);
+			PF_MD5_UPD(pfr, addr.iflags);
+			break;
+		case PF_ADDR_TABLE:
+			PF_MD5_UPD(pfr, addr.v.tblname);
+			break;
+		case PF_ADDR_ADDRMASK:
+			/* XXX ignore af? */
+			PF_MD5_UPD(pfr, addr.v.a.addr.addr32);
+			PF_MD5_UPD(pfr, addr.v.a.mask.addr32);
+			break;
+		case PF_ADDR_RTLABEL:
+			PF_MD5_UPD(pfr, addr.v.rtlabelname);
+			break;
+	}
+
+	PF_MD5_UPD(pfr, port[0]);
+	PF_MD5_UPD(pfr, port[1]);
+	PF_MD5_UPD(pfr, neg);
+	PF_MD5_UPD(pfr, port_op);
+}
+
+void
+pf_hash_rule(MD5_CTX *ctx, struct pf_rule *rule)
+{
+	u_int16_t x;
+	u_int32_t y;
+
+	pf_hash_rule_addr(ctx, &rule->src);
+	pf_hash_rule_addr(ctx, &rule->dst);
+	PF_MD5_UPD_STR(rule, label);
+	PF_MD5_UPD_STR(rule, ifname);
+	PF_MD5_UPD_STR(rule, match_tagname);
+	PF_MD5_UPD_HTONS(rule, match_tag, x); /* dup? */
+	PF_MD5_UPD_HTONL(rule, os_fingerprint, y);
+	PF_MD5_UPD_HTONL(rule, prob, y);
+	PF_MD5_UPD_HTONL(rule, uid.uid[0], y);
+	PF_MD5_UPD_HTONL(rule, uid.uid[1], y);
+	PF_MD5_UPD(rule, uid.op);
+	PF_MD5_UPD_HTONL(rule, gid.gid[0], y);
+	PF_MD5_UPD_HTONL(rule, gid.gid[1], y);
+	PF_MD5_UPD(rule, gid.op);
+	PF_MD5_UPD_HTONL(rule, rule_flag, y);
+	PF_MD5_UPD(rule, action);
+	PF_MD5_UPD(rule, direction);
+	PF_MD5_UPD(rule, af);
+	PF_MD5_UPD(rule, quick);
+	PF_MD5_UPD(rule, ifnot);
+	PF_MD5_UPD(rule, match_tag_not);
+	PF_MD5_UPD(rule, natpass);
+	PF_MD5_UPD(rule, keep_state);
+	PF_MD5_UPD(rule, proto);
+	PF_MD5_UPD(rule, type);
+	PF_MD5_UPD(rule, code);
+	PF_MD5_UPD(rule, flags);
+	PF_MD5_UPD(rule, flagset);
+	PF_MD5_UPD(rule, allow_opts);
+	PF_MD5_UPD(rule, rt);
+	PF_MD5_UPD(rule, tos);
+}
+
 int
 pf_commit_rules(u_int32_t ticket, int rs_num, char *anchor)
 {
 	struct pf_ruleset	*rs;
-	struct pf_rule		*rule;
+	struct pf_rule		*rule, **old_array;
 	struct pf_rulequeue	*old_rules;
-	int			 s;
+	int			 s, error;
+	u_int32_t		 old_rcount;
 
 	if (rs_num < 0 || rs_num >= PF_RULESET_MAX)
 		return (EINVAL);
@@ -1250,31 +1084,92 @@
 	    ticket != rs->rules[rs_num].inactive.ticket)
 		return (EBUSY);
 
+	/* Calculate checksum for the main ruleset */
+	if (rs == &pf_main_ruleset) {
+		error = pf_setup_pfsync_matching(rs);
+		if (error != 0)
+			return (error);
+	}
+
 	/* Swap rules, keep the old. */
 	s = splsoftnet();
 	old_rules = rs->rules[rs_num].active.ptr;
+	old_rcount = rs->rules[rs_num].active.rcount;
+	old_array = rs->rules[rs_num].active.ptr_array;
+
 	rs->rules[rs_num].active.ptr =
 	    rs->rules[rs_num].inactive.ptr;
+	rs->rules[rs_num].active.ptr_array =
+	    rs->rules[rs_num].inactive.ptr_array;
+	rs->rules[rs_num].active.rcount =
+	    rs->rules[rs_num].inactive.rcount;
 	rs->rules[rs_num].inactive.ptr = old_rules;
+	rs->rules[rs_num].inactive.ptr_array = old_array;
+	rs->rules[rs_num].inactive.rcount = old_rcount;
+
 	rs->rules[rs_num].active.ticket =
 	    rs->rules[rs_num].inactive.ticket;
 	pf_calc_skip_steps(rs->rules[rs_num].active.ptr);
 
+
 	/* Purge the old rule list. */
 	while ((rule = TAILQ_FIRST(old_rules)) != NULL)
 		pf_rm_rule(old_rules, rule);
+	if (rs->rules[rs_num].inactive.ptr_array)
+		free(rs->rules[rs_num].inactive.ptr_array, M_TEMP);
+	rs->rules[rs_num].inactive.ptr_array = NULL;
+	rs->rules[rs_num].inactive.rcount = 0;
 	rs->rules[rs_num].inactive.open = 0;
 	pf_remove_if_empty_ruleset(rs);
 	splx(s);
 	return (0);
 }
 
-#ifdef __FreeBSD__
 int
+pf_setup_pfsync_matching(struct pf_ruleset *rs)
+{
+	MD5_CTX			 ctx;
+	struct pf_rule		*rule;
+	int			 rs_cnt;
+	u_int8_t		 digest[PF_MD5_DIGEST_LENGTH];
+
+	MD5Init(&ctx);
+	for (rs_cnt = 0; rs_cnt < PF_RULESET_MAX; rs_cnt++) {
+		/* XXX PF_RULESET_SCRUB as well? */
+		if (rs_cnt == PF_RULESET_SCRUB)
+			continue;
+
+		if (rs->rules[rs_cnt].inactive.ptr_array)
+			free(rs->rules[rs_cnt].inactive.ptr_array, M_TEMP);
+		rs->rules[rs_cnt].inactive.ptr_array = NULL;
+
+		if (rs->rules[rs_cnt].inactive.rcount) {
+			rs->rules[rs_cnt].inactive.ptr_array =
+			    malloc(sizeof(caddr_t) *
+			    rs->rules[rs_cnt].inactive.rcount,
+			    M_TEMP, M_NOWAIT);
+
+			if (!rs->rules[rs_cnt].inactive.ptr_array)
+				return (ENOMEM);
+		}
+
+		TAILQ_FOREACH(rule, rs->rules[rs_cnt].inactive.ptr,
+		    entries) {
+			pf_hash_rule(&ctx, rule);
+			(rs->rules[rs_cnt].inactive.ptr_array)[rule->nr] = rule;
+		}
+	}
+
+	MD5Final(digest, &ctx);
+	memcpy(pf_status.pf_chksum, digest, sizeof(pf_status.pf_chksum));
+	return (0);
+}
+
+int
+#ifdef __FreeBSD__
 pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td)
 #else
-int
-pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
+pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
 #endif
 {
 	struct pf_pooladdr	*pa = NULL;
@@ -1325,7 +1220,6 @@
 		case DIOCGETSRCNODES:
 		case DIOCCLRSRCNODES:
 		case DIOCIGETIFACES:
-		case DIOCICLRISTATS:
 #ifdef __FreeBSD__
 		case DIOCGIFSPEED:
 #endif
@@ -1347,7 +1241,6 @@
 	if (!(flags & FWRITE))
 		switch (cmd) {
 		case DIOCGETRULES:
-		case DIOCGETRULE:
 		case DIOCGETADDRS:
 		case DIOCGETADDR:
 		case DIOCGETSTATE:
@@ -1360,6 +1253,7 @@
 		case DIOCGETQSTATS:
 		case DIOCGETRULESETS:
 		case DIOCGETRULESET:
+		case DIOCNATLOOK:
 		case DIOCRGETTABLES:
 		case DIOCRGETTSTATS:
 		case DIOCRGETADDRS:
@@ -1382,13 +1276,30 @@
 		case DIOCRSETADDRS:
 		case DIOCRSETTFLAGS:
 			if (((struct pfioc_table *)addr)->pfrio_flags &
-			    PFR_FLAG_DUMMY)
+			    PFR_FLAG_DUMMY) {
+				flags |= FWRITE; /* need write lock for dummy */
 				break; /* dummy operation ok */
+			}
 			return (EACCES);
+		case DIOCGETRULE:
+			if (((struct pfioc_rule *)addr)->action == PF_GET_CLR_CNTR)
+				return (EACCES);
+			break;
 		default:
 			return (EACCES);
 		}
 
+	if (flags & FWRITE)
+#ifdef __FreeBSD__
+		sx_xlock(&pf_consistency_lock);
+	else
+		sx_slock(&pf_consistency_lock);
+#else
+		rw_enter_write(&pf_consistency_lock);
+	else
+		rw_enter_read(&pf_consistency_lock);
+#endif
+
 #ifdef __FreeBSD__
 	PF_LOCK();
 #else
@@ -1463,14 +1374,20 @@
 			break;
 		}
 		if (pr->ticket != ruleset->rules[rs_num].inactive.ticket) {
-			printf("ticket: %d != [%d]%d\n", pr->ticket,
-			    rs_num, ruleset->rules[rs_num].inactive.ticket);
+#ifdef __FreeBSD__
+			DPFPRINTF(PF_DEBUG_MISC,
+			    ("ticket: %d != [%d]%d\n", pr->ticket, rs_num,
+			    ruleset->rules[rs_num].inactive.ticket));
+#endif
 			error = EBUSY;
 			break;
 		}
 		if (pr->pool_ticket != ticket_pabuf) {
-			printf("pool_ticket: %d != %d\n", pr->pool_ticket,
-			    ticket_pabuf);
+#ifdef __FreeBSD__
+			DPFPRINTF(PF_DEBUG_MISC,
+			    ("pool_ticket: %d != %d\n", pr->pool_ticket,
+			    ticket_pabuf));
+#endif
 			error = EBUSY;
 			break;
 		}
@@ -1480,6 +1397,13 @@
 			break;
 		}
 		bcopy(&pr->rule, rule, sizeof(struct pf_rule));
+#ifdef __FreeBSD__
+		rule->cuid = td->td_ucred->cr_ruid;
+		rule->cpid = td->td_proc ? td->td_proc->p_pid : 0;
+#else
+		rule->cuid = p->p_cred->p_ruid;
+		rule->cpid = p->p_pid;
+#endif
 		rule->anchor = NULL;
 		rule->kif = NULL;
 		TAILQ_INIT(&rule->rpool.list);
@@ -1508,14 +1432,22 @@
 		else
 			rule->nr = 0;
 		if (rule->ifname[0]) {
-			rule->kif = pfi_attach_rule(rule->ifname);
+			rule->kif = pfi_kif_get(rule->ifname);
 			if (rule->kif == NULL) {
 				pool_put(&pf_rule_pl, rule);
 				error = EINVAL;
 				break;
 			}
+			pfi_kif_ref(rule->kif, PFI_KIF_REF_RULE);
 		}
 
+#ifdef __FreeBSD__ /* ROUTEING */
+		if (rule->rtableid > 0)
+#else
+		if (rule->rtableid > 0 && !rtable_exists(rule->rtableid))
+#endif
+			error = EBUSY;
+
 #ifdef ALTQ
 		/* set queue IDs */
 		if (rule->qname[0] != 0) {
@@ -1538,6 +1470,14 @@
 				error = EBUSY;
 		if (rule->rt && !rule->direction)
 			error = EINVAL;
+#if NPFLOG > 0
+#ifdef __FreeBSD__
+		if (!rule->log)
+			rule->logif = 0;
+#endif
+		if (rule->logif >= PFLOGIFS_MAX)
+			error = EINVAL;
+#endif
 		if (pf_rtlabel_add(&rule->src.addr) ||
 		    pf_rtlabel_add(&rule->dst.addr))
 			error = EBUSY;
@@ -1575,10 +1515,22 @@
 			pf_rm_rule(NULL, rule);
 			break;
 		}
+
+#ifdef __FreeBSD__
+		if (!debug_pfugidhack && (rule->uid.op || rule->gid.op ||
+		    rule->log & PF_LOG_SOCKET_LOOKUP)) {
+			DPFPRINTF(PF_DEBUG_MISC,
+			    ("pf: debug.pfugidhack enabled\n"));
+			debug_pfugidhack = 1;
+		}
+#endif
+
 		rule->rpool.cur = TAILQ_FIRST(&rule->rpool.list);
-		rule->evaluations = rule->packets = rule->bytes = 0;
+		rule->evaluations = rule->packets[0] = rule->packets[1] =
+		    rule->bytes[0] = rule->bytes[1] = 0;
 		TAILQ_INSERT_TAIL(ruleset->rules[rs_num].inactive.ptr,
 		    rule, entries);
+		ruleset->rules[rs_num].inactive.rcount++;
 		break;
 	}
 
@@ -1654,6 +1606,12 @@
 			else
 				pr->rule.skip[i].nr =
 				    rule->skip[i].ptr->nr;
+
+		if (pr->action == PF_GET_CLR_CNTR) {
+			rule->evaluations = 0;
+			rule->packets[0] = rule->packets[1] = 0;
+			rule->bytes[0] = rule->bytes[1] = 0;
+		}
 		break;
 	}
 
@@ -1709,6 +1667,13 @@
 				break;
 			}
 			bcopy(&pcr->rule, newrule, sizeof(struct pf_rule));
+#ifdef __FreeBSD__
+			newrule->cuid = td->td_ucred->cr_ruid;
+			newrule->cpid = td->td_proc ? td->td_proc->p_pid : 0;
+#else
+			newrule->cuid = p->p_cred->p_ruid;
+			newrule->cpid = p->p_pid;
+#endif
 			TAILQ_INIT(&newrule->rpool.list);
 			/* initialize refcounting */
 			newrule->states = 0;
@@ -1728,15 +1693,24 @@
 			}
 #endif /* INET6 */
 			if (newrule->ifname[0]) {
-				newrule->kif = pfi_attach_rule(newrule->ifname);
+				newrule->kif = pfi_kif_get(newrule->ifname);
 				if (newrule->kif == NULL) {
 					pool_put(&pf_rule_pl, newrule);
 					error = EINVAL;
 					break;
 				}
+				pfi_kif_ref(newrule->kif, PFI_KIF_REF_RULE);
 			} else
 				newrule->kif = NULL;
 
+			if (newrule->rtableid > 0 &&
+#ifdef __FreeBSD__ /* ROUTING */
+			    1)
+#else
+			    !rtable_exists(newrule->rtableid))
+#endif
+				error = EBUSY;
+
 #ifdef ALTQ
 			/* set queue IDs */
 			if (newrule->qname[0] != 0) {
@@ -1761,6 +1735,14 @@
 					error = EBUSY;
 			if (newrule->rt && !newrule->direction)
 				error = EINVAL;
+#ifdef __FreeBSD__
+#if NPFLOG > 0
+			if (!newrule->log)
+				newrule->logif = 0;
+			if (newrule->logif >= PFLOGIFS_MAX)
+				error = EINVAL;
+#endif
+#endif
 			if (pf_rtlabel_add(&newrule->src.addr) ||
 			    pf_rtlabel_add(&newrule->dst.addr))
 				error = EBUSY;
@@ -1793,7 +1775,7 @@
 			    (newrule->action == PF_RDR) ||
 			    (newrule->action == PF_BINAT) ||
 			    (newrule->rt > PF_FASTROUTE)) &&
-			    !pcr->anchor[0])) &&
+			    !newrule->anchor)) &&
 			    (TAILQ_FIRST(&newrule->rpool.list) == NULL))
 				error = EINVAL;
 
@@ -1801,9 +1783,21 @@
 				pf_rm_rule(NULL, newrule);
 				break;
 			}
+
+#ifdef __FreeBSD__
+			if (!debug_pfugidhack && (newrule->uid.op ||
+			    newrule->gid.op ||
+			    newrule->log & PF_LOG_SOCKET_LOOKUP)) {
+				DPFPRINTF(PF_DEBUG_MISC,
+				    ("pf: debug.pfugidhack enabled\n"));
+				debug_pfugidhack = 1;
+			}
+#endif
+
 			newrule->rpool.cur = TAILQ_FIRST(&newrule->rpool.list);
-			newrule->evaluations = newrule->packets = 0;
-			newrule->bytes = 0;
+			newrule->evaluations = 0;
+			newrule->packets[0] = newrule->packets[1] = 0;
+			newrule->bytes[0] = newrule->bytes[1] = 0;
 		}
 		pf_empty_pool(&pf_pabuf);
 
@@ -1826,9 +1820,10 @@
 			}
 		}
 
-		if (pcr->action == PF_CHANGE_REMOVE)
+		if (pcr->action == PF_CHANGE_REMOVE) {
 			pf_rm_rule(ruleset->rules[rs_num].active.ptr, oldrule);
-		else {
+			ruleset->rules[rs_num].active.rcount--;
+		} else {
 			if (oldrule == NULL)
 				TAILQ_INSERT_TAIL(
 				    ruleset->rules[rs_num].active.ptr,
@@ -1840,6 +1835,7 @@
 				TAILQ_INSERT_AFTER(
 				    ruleset->rules[rs_num].active.ptr,
 				    oldrule, newrule, entries);
+			ruleset->rules[rs_num].active.rcount++;
 		}
 
 		nr = 0;
@@ -1856,23 +1852,24 @@
 	}
 
 	case DIOCCLRSTATES: {
-		struct pf_state		*state;
+		struct pf_state		*state, *nexts;
 		struct pfioc_state_kill *psk = (struct pfioc_state_kill *)addr;
 		int			 killed = 0;
 
-		RB_FOREACH(state, pf_state_tree_id, &tree_id) {
+		for (state = RB_MIN(pf_state_tree_id, &tree_id); state;
+		    state = nexts) {
+			nexts = RB_NEXT(pf_state_tree_id, &tree_id, state);
+
 			if (!psk->psk_ifname[0] || !strcmp(psk->psk_ifname,
 			    state->u.s.kif->pfik_name)) {
-				state->timeout = PFTM_PURGE;
 #if NPFSYNC
 				/* don't send out individual delete messages */
 				state->sync_flags = PFSTATE_NOSYNC;
 #endif
+				pf_unlink_state(state);
 				killed++;
 			}
 		}
-		pf_purge_expired_states();
-		pf_status.states = 0;
 		psk->psk_af = killed;
 #if NPFSYNC
 		pfsync_clear_states(pf_status.hostid, psk->psk_ifname);
@@ -1881,37 +1878,52 @@
 	}
 
 	case DIOCKILLSTATES: {
-		struct pf_state		*state;
+		struct pf_state		*state, *nexts;
+		struct pf_state_host	*src, *dst;
 		struct pfioc_state_kill	*psk = (struct pfioc_state_kill *)addr;
 		int			 killed = 0;
 
-		RB_FOREACH(state, pf_state_tree_id, &tree_id) {
+		for (state = RB_MIN(pf_state_tree_id, &tree_id); state;
+		    state = nexts) {
+			nexts = RB_NEXT(pf_state_tree_id, &tree_id, state);
+
+			if (state->direction == PF_OUT) {
+				src = &state->lan;
+				dst = &state->ext;
+			} else {
+				src = &state->ext;
+				dst = &state->lan;
+			}
 			if ((!psk->psk_af || state->af == psk->psk_af)
 			    && (!psk->psk_proto || psk->psk_proto ==
 			    state->proto) &&
 			    PF_MATCHA(psk->psk_src.neg,
 			    &psk->psk_src.addr.v.a.addr,
 			    &psk->psk_src.addr.v.a.mask,
-			    &state->lan.addr, state->af) &&
+			    &src->addr, state->af) &&
 			    PF_MATCHA(psk->psk_dst.neg,
 			    &psk->psk_dst.addr.v.a.addr,
 			    &psk->psk_dst.addr.v.a.mask,
-			    &state->ext.addr, state->af) &&
+			    &dst->addr, state->af) &&
 			    (psk->psk_src.port_op == 0 ||
 			    pf_match_port(psk->psk_src.port_op,
 			    psk->psk_src.port[0], psk->psk_src.port[1],
-			    state->lan.port)) &&
+			    src->port)) &&
 			    (psk->psk_dst.port_op == 0 ||
 			    pf_match_port(psk->psk_dst.port_op,
 			    psk->psk_dst.port[0], psk->psk_dst.port[1],
-			    state->ext.port)) &&
+			    dst->port)) &&
 			    (!psk->psk_ifname[0] || !strcmp(psk->psk_ifname,
 			    state->u.s.kif->pfik_name))) {
-				state->timeout = PFTM_PURGE;
+#if NPFSYNC > 0
+				/* send immediate delete of state */
+				pfsync_delete_state(state);
+				state->sync_flags |= PFSTATE_NOSYNC;
+#endif
+				pf_unlink_state(state);
 				killed++;
 			}
 		}
-		pf_purge_expired_states();
 		psk->psk_af = killed;
 		break;
 	}
@@ -1931,7 +1943,7 @@
 			error = ENOMEM;
 			break;
 		}
-		kif = pfi_lookup_create(ps->state.u.ifname);
+		kif = pfi_kif_get(ps->state.u.ifname);
 		if (kif == NULL) {
 			pool_put(&pf_state_pl, state);
 			error = ENOENT;
@@ -1949,7 +1961,7 @@
 		state->bytes[0] = state->bytes[1] = 0;
 
 		if (pf_insert_state(kif, state)) {
-			pfi_maybe_destroy(kif);
+			pfi_kif_unref(kif, PFI_KIF_REF_NONE);
 			pool_put(&pf_state_pl, state);
 			error = ENOMEM;
 		}
@@ -1960,6 +1972,7 @@
 		struct pfioc_state	*ps = (struct pfioc_state *)addr;
 		struct pf_state		*state;
 		u_int32_t		 nr;
+		int			 secs;
 
 		nr = 0;
 		RB_FOREACH(state, pf_state_tree_id, &tree_id) {
@@ -1971,15 +1984,19 @@
 			error = EBUSY;
 			break;
 		}
-		bcopy(state, &ps->state, sizeof(struct pf_state));
+		secs = time_second;
+		bcopy(state, &ps->state, sizeof(ps->state));
+		strlcpy(ps->state.u.ifname, state->u.s.kif->pfik_name,
+		    sizeof(ps->state.u.ifname));
 		ps->state.rule.nr = state->rule.ptr->nr;
 		ps->state.nat_rule.nr = (state->nat_rule.ptr == NULL) ?
 		    -1 : state->nat_rule.ptr->nr;
 		ps->state.anchor.nr = (state->anchor.ptr == NULL) ?
 		    -1 : state->anchor.ptr->nr;
+		ps->state.creation = secs - ps->state.creation;
 		ps->state.expire = pf_state_expires(state);
-		if (ps->state.expire > time_second)
-			ps->state.expire -= time_second;
+		if (ps->state.expire > secs)
+			ps->state.expire -= secs;
 		else
 			ps->state.expire = 0;
 		break;
@@ -1988,52 +2005,67 @@
 	case DIOCGETSTATES: {
 		struct pfioc_states	*ps = (struct pfioc_states *)addr;
 		struct pf_state		*state;
-		struct pf_state		*p, pstore;
-		struct pfi_kif		*kif;
+		struct pf_state		*p, *pstore;
 		u_int32_t		 nr = 0;
 		int			 space = ps->ps_len;
 
 		if (space == 0) {
-			TAILQ_FOREACH(kif, &pfi_statehead, pfik_w_states)
-				nr += kif->pfik_states;
+			nr = pf_status.states;
 			ps->ps_len = sizeof(struct pf_state) * nr;
 			break;
 		}
 
+#ifdef __FreeBSD__
+		PF_UNLOCK();
+#endif
+		pstore = malloc(sizeof(*pstore), M_TEMP, M_WAITOK);
+#ifdef __FreeBSD__
+		PF_LOCK();
+#endif
+
 		p = ps->ps_states;
-		TAILQ_FOREACH(kif, &pfi_statehead, pfik_w_states)
-			RB_FOREACH(state, pf_state_tree_ext_gwy,
-			    &kif->pfik_ext_gwy) {
+
+		state = TAILQ_FIRST(&state_list);
+		while (state) {
+			if (state->timeout != PFTM_UNLINKED) {
 				int	secs = time_second;
 
 				if ((nr+1) * sizeof(*p) > (unsigned)ps->ps_len)
 					break;
 
-				bcopy(state, &pstore, sizeof(pstore));
-				strlcpy(pstore.u.ifname, kif->pfik_name,
-				    sizeof(pstore.u.ifname));
-				pstore.rule.nr = state->rule.ptr->nr;
-				pstore.nat_rule.nr = (state->nat_rule.ptr ==
+				bcopy(state, pstore, sizeof(*pstore));
+				strlcpy(pstore->u.ifname,
+				    state->u.s.kif->pfik_name,
+				    sizeof(pstore->u.ifname));
+				pstore->rule.nr = state->rule.ptr->nr;
+				pstore->nat_rule.nr = (state->nat_rule.ptr ==
 				    NULL) ? -1 : state->nat_rule.ptr->nr;
-				pstore.anchor.nr = (state->anchor.ptr ==
+				pstore->anchor.nr = (state->anchor.ptr ==
 				    NULL) ? -1 : state->anchor.ptr->nr;
-				pstore.creation = secs - pstore.creation;
-				pstore.expire = pf_state_expires(state);
-				if (pstore.expire > secs)
-					pstore.expire -= secs;
+				pstore->creation = secs - pstore->creation;
+				pstore->expire = pf_state_expires(state);
+				if (pstore->expire > secs)
+					pstore->expire -= secs;
 				else
-					pstore.expire = 0;
+					pstore->expire = 0;
 #ifdef __FreeBSD__
-				PF_COPYOUT(&pstore, p, sizeof(*p), error);
+				PF_COPYOUT(pstore, p, sizeof(*p), error);
 #else
-				error = copyout(&pstore, p, sizeof(*p));
+				error = copyout(pstore, p, sizeof(*p));
 #endif
-				if (error)
+				if (error) {
+					free(pstore, M_TEMP);
 					goto fail;
+				}
 				p++;
 				nr++;
 			}
+			state = TAILQ_NEXT(state, u.s.entry_list);
+		}
+
 		ps->ps_len = sizeof(struct pf_state) * nr;
+
+		free(pstore, M_TEMP);
 		break;
 	}
 
@@ -2063,16 +2095,16 @@
 		bzero(pf_status.counters, sizeof(pf_status.counters));
 		bzero(pf_status.fcounters, sizeof(pf_status.fcounters));
 		bzero(pf_status.scounters, sizeof(pf_status.scounters));
+		pf_status.since = time_second;
 		if (*pf_status.ifname)
-			pfi_clr_istats(pf_status.ifname, NULL,
-			    PFI_FLAG_INSTANCE);
+			pfi_clr_istats(pf_status.ifname);
 		break;
 	}
 
 	case DIOCNATLOOK: {
 		struct pfioc_natlook	*pnl = (struct pfioc_natlook *)addr;
 		struct pf_state		*state;
-		struct pf_state		 key;
+		struct pf_state_cmp	 key;
 		int			 m = 0, direction = pnl->direction;
 
 		key.af = pnl->af;
@@ -2081,7 +2113,9 @@
 		if (!pnl->proto ||
 		    PF_AZERO(&pnl->saddr, pnl->af) ||
 		    PF_AZERO(&pnl->daddr, pnl->af) ||
-		    !pnl->dport || !pnl->sport)
+		    ((pnl->proto == IPPROTO_TCP ||
+		    pnl->proto == IPPROTO_UDP) &&
+		    (!pnl->dport || !pnl->sport)))
 			error = EINVAL;
 		else {
 			/*
@@ -2137,7 +2171,11 @@
 			goto fail;
 		}
 		old = pf_default_rule.timeout[pt->timeout];
+		if (pt->timeout == PFTM_INTERVAL && pt->seconds == 0)
+			pt->seconds = 1;
 		pf_default_rule.timeout[pt->timeout] = pt->seconds;
+		if (pt->timeout == PFTM_INTERVAL && pt->seconds < old)
+			wakeup(pf_purge_thread);
 		pt->seconds = old;
 		break;
 	}
@@ -2196,13 +2234,16 @@
 	}
 
 	case DIOCCLRRULECTRS: {
+		/* obsoleted by DIOCGETRULE with action=PF_GET_CLR_CNTR */
 		struct pf_ruleset	*ruleset = &pf_main_ruleset;
 		struct pf_rule		*rule;
 
 		TAILQ_FOREACH(rule,
-		    ruleset->rules[PF_RULESET_FILTER].active.ptr, entries)
-			rule->evaluations = rule->packets =
-			    rule->bytes = 0;
+		    ruleset->rules[PF_RULESET_FILTER].active.ptr, entries) {
+			rule->evaluations = 0;
+			rule->packets[0] = rule->packets[1] = 0;
+			rule->bytes[0] = rule->bytes[1] = 0;
+		}
 		break;
 	}
 
@@ -2427,16 +2468,17 @@
 		}
 		bcopy(&pp->addr, pa, sizeof(struct pf_pooladdr));
 		if (pa->ifname[0]) {
-			pa->kif = pfi_attach_rule(pa->ifname);
+			pa->kif = pfi_kif_get(pa->ifname);
 			if (pa->kif == NULL) {
 				pool_put(&pf_pooladdr_pl, pa);
 				error = EINVAL;
 				break;
 			}
+			pfi_kif_ref(pa->kif, PFI_KIF_REF_RULE);
 		}
 		if (pfi_dynaddr_setup(&pa->addr, pp->af)) {
 			pfi_dynaddr_remove(&pa->addr);
-			pfi_detach_rule(pa->kif);
+			pfi_kif_unref(pa->kif, PFI_KIF_REF_RULE);
 			pool_put(&pf_pooladdr_pl, pa);
 			error = EINVAL;
 			break;
@@ -2536,18 +2578,19 @@
 			}
 #endif /* INET6 */
 			if (newpa->ifname[0]) {
-				newpa->kif = pfi_attach_rule(newpa->ifname);
+				newpa->kif = pfi_kif_get(newpa->ifname);
 				if (newpa->kif == NULL) {
 					pool_put(&pf_pooladdr_pl, newpa);
 					error = EINVAL;
 					break;
 				}
+				pfi_kif_ref(newpa->kif, PFI_KIF_REF_RULE);
 			} else
 				newpa->kif = NULL;
 			if (pfi_dynaddr_setup(&newpa->addr, pca->af) ||
 			    pf_tbladdr_setup(ruleset, &newpa->addr)) {
 				pfi_dynaddr_remove(&newpa->addr);
-				pfi_detach_rule(newpa->kif);
+				pfi_kif_unref(newpa->kif, PFI_KIF_REF_RULE);
 				pool_put(&pf_pooladdr_pl, newpa);
 				error = EINVAL;
 				break;
@@ -2576,7 +2619,7 @@
 			TAILQ_REMOVE(&pool->list, oldpa, entries);
 			pfi_dynaddr_remove(&oldpa->addr);
 			pf_tbladdr_remove(&oldpa->addr);
-			pfi_detach_rule(oldpa->kif);
+			pfi_kif_unref(oldpa->kif, PFI_KIF_REF_RULE);
 			pool_put(&pf_pooladdr_pl, oldpa);
 		} else {
 			if (oldpa == NULL)
@@ -2786,7 +2829,7 @@
 		error = pfr_set_addrs(&io->pfrio_table, io->pfrio_buffer,
 		    io->pfrio_size, &io->pfrio_size2, &io->pfrio_nadd,
 		    &io->pfrio_ndel, &io->pfrio_nchange, io->pfrio_flags |
-		    PFR_FLAG_USERIOCTL);
+		    PFR_FLAG_USERIOCTL, 0);
 		break;
 	}
 
@@ -2866,171 +2909,242 @@
 	}
 
 	case DIOCXBEGIN: {
-		struct pfioc_trans		*io = (struct pfioc_trans *)
-						    addr;
-		static struct pfioc_trans_e	 ioe;
-		static struct pfr_table		 table;
-		int				 i;
+		struct pfioc_trans	*io = (struct pfioc_trans *)addr;
+		struct pfioc_trans_e	*ioe;
+		struct pfr_table	*table;
+		int			 i;
 
-		if (io->esize != sizeof(ioe)) {
+		if (io->esize != sizeof(*ioe)) {
 			error = ENODEV;
 			goto fail;
 		}
+#ifdef __FreeBSD__
+		PF_UNLOCK();
+#endif
+		ioe = (struct pfioc_trans_e *)malloc(sizeof(*ioe),
+		    M_TEMP, M_WAITOK);
+		table = (struct pfr_table *)malloc(sizeof(*table),
+		    M_TEMP, M_WAITOK);
+#ifdef __FreeBSD__
+		PF_LOCK();
+#endif
 		for (i = 0; i < io->size; i++) {
 #ifdef __FreeBSD__
-			PF_COPYIN(io->array+i, &ioe, sizeof(ioe), error);
+			PF_COPYIN(io->array+i, ioe, sizeof(*ioe), error);
 			if (error) {
 #else
-			if (copyin(io->array+i, &ioe, sizeof(ioe))) {
+			if (copyin(io->array+i, ioe, sizeof(*ioe))) {
 #endif
+				free(table, M_TEMP);
+				free(ioe, M_TEMP);
 				error = EFAULT;
 				goto fail;
 			}
-			switch (ioe.rs_num) {
+			switch (ioe->rs_num) {
 #ifdef ALTQ
 			case PF_RULESET_ALTQ:
-				if (ioe.anchor[0]) {
+				if (ioe->anchor[0]) {
+					free(table, M_TEMP);
+					free(ioe, M_TEMP);
 					error = EINVAL;
 					goto fail;
 				}
-				if ((error = pf_begin_altq(&ioe.ticket)))
+				if ((error = pf_begin_altq(&ioe->ticket))) {
+					free(table, M_TEMP);
+					free(ioe, M_TEMP);
 					goto fail;
+				}
 				break;
 #endif /* ALTQ */
 			case PF_RULESET_TABLE:
-				bzero(&table, sizeof(table));
-				strlcpy(table.pfrt_anchor, ioe.anchor,
-				    sizeof(table.pfrt_anchor));
-				if ((error = pfr_ina_begin(&table,
-				    &ioe.ticket, NULL, 0)))
+				bzero(table, sizeof(*table));
+				strlcpy(table->pfrt_anchor, ioe->anchor,
+				    sizeof(table->pfrt_anchor));
+				if ((error = pfr_ina_begin(table,
+				    &ioe->ticket, NULL, 0))) {
+					free(table, M_TEMP);
+					free(ioe, M_TEMP);
 					goto fail;
+				}
 				break;
 			default:
-				if ((error = pf_begin_rules(&ioe.ticket,
-				    ioe.rs_num, ioe.anchor)))
+				if ((error = pf_begin_rules(&ioe->ticket,
+				    ioe->rs_num, ioe->anchor))) {
+					free(table, M_TEMP);
+					free(ioe, M_TEMP);
 					goto fail;
+				}
 				break;
 			}
 #ifdef __FreeBSD__
-			PF_COPYOUT(&ioe, io->array+i, sizeof(io->array[i]),
+			PF_COPYOUT(ioe, io->array+i, sizeof(io->array[i]),
 			    error);
 			if (error) {
 #else
-			if (copyout(&ioe, io->array+i, sizeof(io->array[i]))) {
+			if (copyout(ioe, io->array+i, sizeof(io->array[i]))) {
 #endif
+				free(table, M_TEMP);
+				free(ioe, M_TEMP);
 				error = EFAULT;
 				goto fail;
 			}
 		}
+		free(table, M_TEMP);
+		free(ioe, M_TEMP);
 		break;
 	}
 
 	case DIOCXROLLBACK: {
-		struct pfioc_trans		*io = (struct pfioc_trans *)
-						    addr;
-		static struct pfioc_trans_e	 ioe;
-		static struct pfr_table		 table;
-		int				 i;
+		struct pfioc_trans	*io = (struct pfioc_trans *)addr;
+		struct pfioc_trans_e	*ioe;
+		struct pfr_table	*table;
+		int			 i;
 
-		if (io->esize != sizeof(ioe)) {
+		if (io->esize != sizeof(*ioe)) {
 			error = ENODEV;
 			goto fail;
 		}
+#ifdef __FreeBSD__
+		PF_UNLOCK();
+#endif
+		ioe = (struct pfioc_trans_e *)malloc(sizeof(*ioe),
+		    M_TEMP, M_WAITOK);
+		table = (struct pfr_table *)malloc(sizeof(*table),
+		    M_TEMP, M_WAITOK);
+#ifdef __FreeBSD__
+		PF_LOCK();
+#endif
 		for (i = 0; i < io->size; i++) {
 #ifdef __FreeBSD__
-			PF_COPYIN(io->array+i, &ioe, sizeof(ioe), error);
+			PF_COPYIN(io->array+i, ioe, sizeof(*ioe), error);
 			if (error) {
 #else
-			if (copyin(io->array+i, &ioe, sizeof(ioe))) {
+			if (copyin(io->array+i, ioe, sizeof(*ioe))) {
 #endif
+				free(table, M_TEMP);
+				free(ioe, M_TEMP);
 				error = EFAULT;
 				goto fail;
 			}
-			switch (ioe.rs_num) {
+			switch (ioe->rs_num) {
 #ifdef ALTQ
 			case PF_RULESET_ALTQ:
-				if (ioe.anchor[0]) {
+				if (ioe->anchor[0]) {
+					free(table, M_TEMP);
+					free(ioe, M_TEMP);
 					error = EINVAL;
 					goto fail;
 				}
-				if ((error = pf_rollback_altq(ioe.ticket)))
+				if ((error = pf_rollback_altq(ioe->ticket))) {
+					free(table, M_TEMP);
+					free(ioe, M_TEMP);
 					goto fail; /* really bad */
+				}
 				break;
 #endif /* ALTQ */
 			case PF_RULESET_TABLE:
-				bzero(&table, sizeof(table));
-				strlcpy(table.pfrt_anchor, ioe.anchor,
-				    sizeof(table.pfrt_anchor));
-				if ((error = pfr_ina_rollback(&table,
-				    ioe.ticket, NULL, 0)))
+				bzero(table, sizeof(*table));
+				strlcpy(table->pfrt_anchor, ioe->anchor,
+				    sizeof(table->pfrt_anchor));
+				if ((error = pfr_ina_rollback(table,
+				    ioe->ticket, NULL, 0))) {
+					free(table, M_TEMP);
+					free(ioe, M_TEMP);
 					goto fail; /* really bad */
+				}
 				break;
 			default:
-				if ((error = pf_rollback_rules(ioe.ticket,
-				    ioe.rs_num, ioe.anchor)))
+				if ((error = pf_rollback_rules(ioe->ticket,
+				    ioe->rs_num, ioe->anchor))) {
+					free(table, M_TEMP);
+					free(ioe, M_TEMP);
 					goto fail; /* really bad */
+				}
 				break;
 			}
 		}
+		free(table, M_TEMP);
+		free(ioe, M_TEMP);
 		break;
 	}
 
 	case DIOCXCOMMIT: {
-		struct pfioc_trans		*io = (struct pfioc_trans *)
-						    addr;
-		static struct pfioc_trans_e	 ioe;
-		static struct pfr_table		 table;
-		struct pf_ruleset		*rs;
-		int				 i;
+		struct pfioc_trans	*io = (struct pfioc_trans *)addr;
+		struct pfioc_trans_e	*ioe;
+		struct pfr_table	*table;
+		struct pf_ruleset	*rs;
+		int			 i;
 
-		if (io->esize != sizeof(ioe)) {
+		if (io->esize != sizeof(*ioe)) {
 			error = ENODEV;
 			goto fail;
 		}
+#ifdef __FreeBSD__
+		PF_UNLOCK();
+#endif
+		ioe = (struct pfioc_trans_e *)malloc(sizeof(*ioe),
+		    M_TEMP, M_WAITOK);
+		table = (struct pfr_table *)malloc(sizeof(*table),
+		    M_TEMP, M_WAITOK);
+#ifdef __FreeBSD__
+		PF_LOCK();
+#endif
 		/* first makes sure everything will succeed */
 		for (i = 0; i < io->size; i++) {
 #ifdef __FreeBSD__
-			PF_COPYIN(io->array+i, &ioe, sizeof(ioe), error);
+			PF_COPYIN(io->array+i, ioe, sizeof(*ioe), error);
 			if (error) {
 #else
-			if (copyin(io->array+i, &ioe, sizeof(ioe))) {
+			if (copyin(io->array+i, ioe, sizeof(*ioe))) {
 #endif
+				free(table, M_TEMP);
+				free(ioe, M_TEMP);
 				error = EFAULT;
 				goto fail;
 			}
-			switch (ioe.rs_num) {
+			switch (ioe->rs_num) {
 #ifdef ALTQ
 			case PF_RULESET_ALTQ:
-				if (ioe.anchor[0]) {
+				if (ioe->anchor[0]) {
+					free(table, M_TEMP);
+					free(ioe, M_TEMP);
 					error = EINVAL;
 					goto fail;
 				}
-				if (!altqs_inactive_open || ioe.ticket !=
+				if (!altqs_inactive_open || ioe->ticket !=
 				    ticket_altqs_inactive) {
+					free(table, M_TEMP);
+					free(ioe, M_TEMP);
 					error = EBUSY;
 					goto fail;
 				}
 				break;
 #endif /* ALTQ */
 			case PF_RULESET_TABLE:
-				rs = pf_find_ruleset(ioe.anchor);
-				if (rs == NULL || !rs->topen || ioe.ticket !=
+				rs = pf_find_ruleset(ioe->anchor);
+				if (rs == NULL || !rs->topen || ioe->ticket !=
 				     rs->tticket) {
+					free(table, M_TEMP);
+					free(ioe, M_TEMP);
 					error = EBUSY;
 					goto fail;
 				}
 				break;
 			default:
-				if (ioe.rs_num < 0 || ioe.rs_num >=
+				if (ioe->rs_num < 0 || ioe->rs_num >=
 				    PF_RULESET_MAX) {
+					free(table, M_TEMP);
+					free(ioe, M_TEMP);
 					error = EINVAL;
 					goto fail;
 				}
-				rs = pf_find_ruleset(ioe.anchor);
+				rs = pf_find_ruleset(ioe->anchor);
 				if (rs == NULL ||
-				    !rs->rules[ioe.rs_num].inactive.open ||
-				    rs->rules[ioe.rs_num].inactive.ticket !=
-				    ioe.ticket) {
+				    !rs->rules[ioe->rs_num].inactive.open ||
+				    rs->rules[ioe->rs_num].inactive.ticket !=
+				    ioe->ticket) {
+					free(table, M_TEMP);
+					free(ioe, M_TEMP);
 					error = EBUSY;
 					goto fail;
 				}
@@ -3040,43 +3154,55 @@
 		/* now do the commit - no errors should happen here */
 		for (i = 0; i < io->size; i++) {
 #ifdef __FreeBSD__
-			PF_COPYIN(io->array+i, &ioe, sizeof(ioe), error);
+			PF_COPYIN(io->array+i, ioe, sizeof(*ioe), error);
 			if (error) {
 #else
-			if (copyin(io->array+i, &ioe, sizeof(ioe))) {
+			if (copyin(io->array+i, ioe, sizeof(*ioe))) {
 #endif
+				free(table, M_TEMP);
+				free(ioe, M_TEMP);
 				error = EFAULT;
 				goto fail;
 			}
-			switch (ioe.rs_num) {
+			switch (ioe->rs_num) {
 #ifdef ALTQ
 			case PF_RULESET_ALTQ:
-				if ((error = pf_commit_altq(ioe.ticket)))
+				if ((error = pf_commit_altq(ioe->ticket))) {
+					free(table, M_TEMP);
+					free(ioe, M_TEMP);
 					goto fail; /* really bad */
+				}
 				break;
 #endif /* ALTQ */
 			case PF_RULESET_TABLE:
-				bzero(&table, sizeof(table));
-				strlcpy(table.pfrt_anchor, ioe.anchor,
-				    sizeof(table.pfrt_anchor));
-				if ((error = pfr_ina_commit(&table, ioe.ticket,
-				    NULL, NULL, 0)))
+				bzero(table, sizeof(*table));
+				strlcpy(table->pfrt_anchor, ioe->anchor,
+				    sizeof(table->pfrt_anchor));
+				if ((error = pfr_ina_commit(table, ioe->ticket,
+				    NULL, NULL, 0))) {
+					free(table, M_TEMP);
+					free(ioe, M_TEMP);
 					goto fail; /* really bad */
+				}
 				break;
 			default:
-				if ((error = pf_commit_rules(ioe.ticket,
-				    ioe.rs_num, ioe.anchor)))
+				if ((error = pf_commit_rules(ioe->ticket,
+				    ioe->rs_num, ioe->anchor))) {
+					free(table, M_TEMP);
+					free(ioe, M_TEMP);
 					goto fail; /* really bad */
+				}
 				break;
 			}
 		}
+		free(table, M_TEMP);
+		free(ioe, M_TEMP);
 		break;
 	}
 
 	case DIOCGETSRCNODES: {
 		struct pfioc_src_nodes	*psn = (struct pfioc_src_nodes *)addr;
-		struct pf_src_node	*n;
-		struct pf_src_node *p, pstore;
+		struct pf_src_node	*n, *p, *pstore;
 		u_int32_t		 nr = 0;
 		int			 space = psn->psn_len;
 
@@ -3087,6 +3213,14 @@
 			break;
 		}
 
+#ifdef __FreeBSD__
+		PF_UNLOCK();
+#endif
+		pstore = malloc(sizeof(*pstore), M_TEMP, M_WAITOK);
+#ifdef __FreeBSD__
+		PF_LOCK();
+#endif
+
 		p = psn->psn_src_nodes;
 		RB_FOREACH(n, pf_src_tree, &tree_src_tracking) {
 			int	secs = time_second, diff;
@@ -3094,35 +3228,39 @@
 			if ((nr + 1) * sizeof(*p) > (unsigned)psn->psn_len)
 				break;
 
-			bcopy(n, &pstore, sizeof(pstore));
+			bcopy(n, pstore, sizeof(*pstore));
 			if (n->rule.ptr != NULL)
-				pstore.rule.nr = n->rule.ptr->nr;
-			pstore.creation = secs - pstore.creation;
-			if (pstore.expire > secs)
-				pstore.expire -= secs;
+				pstore->rule.nr = n->rule.ptr->nr;
+			pstore->creation = secs - pstore->creation;
+			if (pstore->expire > secs)
+				pstore->expire -= secs;
 			else
-				pstore.expire = 0;
+				pstore->expire = 0;
 
 			/* adjust the connection rate estimate */
 			diff = secs - n->conn_rate.last;
 			if (diff >= n->conn_rate.seconds)
-				pstore.conn_rate.count = 0;
+				pstore->conn_rate.count = 0;
 			else
-				pstore.conn_rate.count -=
+				pstore->conn_rate.count -=
 				    n->conn_rate.count * diff /
 				    n->conn_rate.seconds;
 
 #ifdef __FreeBSD__
-			PF_COPYOUT(&pstore, p, sizeof(*p), error);
+			PF_COPYOUT(pstore, p, sizeof(*p), error);
 #else
-			error = copyout(&pstore, p, sizeof(*p));
+			error = copyout(pstore, p, sizeof(*p));
 #endif
-			if (error)
+			if (error) {
+				free(pstore, M_TEMP);
 				goto fail;
+			}
 			p++;
 			nr++;
 		}
 		psn->psn_len = sizeof(struct pf_src_node) * nr;
+
+		free(pstore, M_TEMP);
 		break;
 	}
 
@@ -3138,11 +3276,50 @@
 			n->expire = 1;
 			n->states = 0;
 		}
-		pf_purge_expired_src_nodes();
+		pf_purge_expired_src_nodes(1);
 		pf_status.src_nodes = 0;
 		break;
 	}
 
+	case DIOCKILLSRCNODES: {
+		struct pf_src_node	*sn;
+		struct pf_state		*s;
+		struct pfioc_src_node_kill *psnk = \
+			(struct pfioc_src_node_kill *) addr;
+		int			killed = 0;
+
+		RB_FOREACH(sn, pf_src_tree, &tree_src_tracking) {
+        		if (PF_MATCHA(psnk->psnk_src.neg, \
+				      &psnk->psnk_src.addr.v.a.addr, \
+				      &psnk->psnk_src.addr.v.a.mask, \
+				      &sn->addr, sn->af) &&
+			    PF_MATCHA(psnk->psnk_dst.neg, \
+				      &psnk->psnk_dst.addr.v.a.addr, \
+				      &psnk->psnk_dst.addr.v.a.mask, \
+				      &sn->raddr, sn->af)) {
+				/* Handle state to src_node linkage */
+				if (sn->states != 0) {
+					RB_FOREACH(s, pf_state_tree_id, 
+					    &tree_id) {
+						if (s->src_node == sn)
+							s->src_node = NULL;
+						if (s->nat_src_node == sn)
+							s->nat_src_node = NULL;
+					}
+					sn->states = 0;
+				}
+				sn->expire = 1;
+				killed++;
+			}
+		}
+
+		if (killed > 0)
+			pf_purge_expired_src_nodes(1);
+
+		psnk->psnk_af = killed;
+		break;
+	}
+
 	case DIOCSETHOSTID: {
 		u_int32_t	*hostid = (u_int32_t *)addr;
 
@@ -3160,20 +3337,12 @@
 	case DIOCIGETIFACES: {
 		struct pfioc_iface *io = (struct pfioc_iface *)addr;
 
-		if (io->pfiio_esize != sizeof(struct pfi_if)) {
+		if (io->pfiio_esize != sizeof(struct pfi_kif)) {
 			error = ENODEV;
 			break;
 		}
 		error = pfi_get_ifaces(io->pfiio_name, io->pfiio_buffer,
-		    &io->pfiio_size, io->pfiio_flags);
-		break;
-	}
-
-	case DIOCICLRISTATS: {
-		struct pfioc_iface *io = (struct pfioc_iface *)addr;
-
-		error = pfi_clr_istats(io->pfiio_name, &io->pfiio_nzero,
-		    io->pfiio_flags);
+		    &io->pfiio_size);
 		break;
 	}
 
@@ -3198,8 +3367,18 @@
 fail:
 #ifdef __FreeBSD__
 	PF_UNLOCK();
+
+	if (flags & FWRITE)
+		sx_xunlock(&pf_consistency_lock);
+	else
+		sx_sunlock(&pf_consistency_lock);
 #else
 	splx(s);
+	/* XXX: Lock order? */
+	if (flags & FWRITE)
+		rw_exit_write(&pf_consistency_lock);
+	else
+		rw_exit_read(&pf_consistency_lock);
 #endif
 	return (error);
 }
@@ -3219,9 +3398,9 @@
 		/* don't send out individual delete messages */
 		state->sync_flags = PFSTATE_NOSYNC;
 #endif
+		pf_unlink_state(state);
 	}
-	pf_purge_expired_states();
-	pf_status.states = 0;
+
 #if 0 /* NPFSYNC */
 /*
  * XXX This is called on module unload, we do not want to sync that over? */
@@ -3258,8 +3437,6 @@
 		n->expire = 1;
 		n->states = 0;
 	}
-	pf_purge_expired_src_nodes();
-	pf_status.src_nodes = 0;
 }
 /*
  * XXX - Check for version missmatch!!!
@@ -3275,8 +3452,6 @@
 	u_int32_t t[5];
 	char nn = '\0';
 
-	callout_stop(&pf_expire_to);
-
 	pf_status.running = 0;
 	do {
 		if ((error = pf_begin_rules(&t[0], PF_RULESET_SCRUB, &nn))
@@ -3415,11 +3590,17 @@
     struct inpcb *inp)
 {
 	/*
-	 * IPv6 does not affected ip_len/ip_off byte order changes.
+	 * IPv6 is not affected by ip_len/ip_off byte order changes.
 	 */
 	int chk;
 
-	chk = pf_test6(PF_IN, ifp, m, NULL, inp);
+	/*
+	 * In case of loopback traffic IPv6 uses the real interface in
+	 * order to support scoped addresses. In order to support stateful
+	 * filtering we have change this to lo0 as it is the case in IPv4.
+	 */
+	chk = pf_test6(PF_IN, (*m)->m_flags & M_LOOP ? &loif[0] : ifp, m,
+	    NULL, inp);
 	if (chk && *m) {
 		m_freem(*m);
 		*m = NULL;
@@ -3553,6 +3734,11 @@
 	}
 	PF_LOCK();
 	shutdown_pf();
+	pf_end_threads = 1;
+	while (pf_end_threads < 2) {
+		wakeup_one(pf_purge_thread);
+		msleep(pf_purge_thread, &pf_task_mtx, 0, "pftmo", hz);
+	}
 	pfi_cleanup();
 	pf_osfp_flush();
 	pf_osfp_cleanup();
Index: if_pflog.h
===================================================================
RCS file: /home/cvs/src/sys/contrib/pf/net/if_pflog.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -L sys/contrib/pf/net/if_pflog.h -L sys/contrib/pf/net/if_pflog.h -u -r1.2 -r1.3
--- sys/contrib/pf/net/if_pflog.h
+++ sys/contrib/pf/net/if_pflog.h
@@ -1,6 +1,5 @@
-/*	$FreeBSD: src/sys/contrib/pf/net/if_pflog.h,v 1.6.2.2 2006/03/22 15:18:04 yar Exp $	*/
-/* $OpenBSD: if_pflog.h,v 1.11 2004/05/19 17:50:51 dhartmei Exp $ */
-
+/* $FreeBSD: src/sys/contrib/pf/net/if_pflog.h,v 1.9 2007/07/03 12:16:07 mlaier Exp $ */
+/* $OpenBSD: if_pflog.h,v 1.14 2006/10/25 11:27:01 henning Exp $ */
 /*
  * Copyright 2001 Niels Provos <provos at citi.umich.edu>
  * All rights reserved.
@@ -29,14 +28,19 @@
 #ifndef _NET_IF_PFLOG_H_
 #define _NET_IF_PFLOG_H_
 
+#define	PFLOGIFS_MAX	16
+
+#ifdef _KERNEL
 struct pflog_softc {
 #ifdef __FreeBSD__
-	struct ifnet	*sc_ifp;  /* the interface */
-	LIST_ENTRY(pflog_softc) sc_next;
+	struct ifnet		*sc_ifp;	/* the interface pointer */
 #else
-	struct ifnet	sc_if;  /* the interface */
+	struct ifnet		sc_if;		/* the interface */
 #endif
+	int			sc_unit;
+	LIST_ENTRY(pflog_softc)	sc_list;
 };
+#endif /* _KERNEL */
 
 #define PFLOG_RULESET_NAME_SIZE	16
 
@@ -49,6 +53,10 @@
 	char		ruleset[PFLOG_RULESET_NAME_SIZE];
 	u_int32_t	rulenr;
 	u_int32_t	subrulenr;
+	uid_t		uid;
+	pid_t		pid;
+	uid_t		rule_uid;
+	pid_t		rule_pid;
 	u_int8_t	dir;
 	u_int8_t	pad[3];
 };
@@ -74,20 +82,21 @@
 struct pf_rule;
 struct pf_ruleset;
 struct pfi_kif;
+struct pf_pdesc;
 
 typedef int pflog_packet_t(struct pfi_kif *, struct mbuf *, sa_family_t,
     u_int8_t, u_int8_t, struct pf_rule *, struct pf_rule *,
-    struct pf_ruleset *);
+    struct pf_ruleset *, struct pf_pdesc *);
 extern pflog_packet_t *pflog_packet_ptr;
-#define	PFLOG_PACKET(i,x,a,b,c,d,e,f,g) do {		\
-	if (pflog_packet_ptr != NULL)			\
-		pflog_packet_ptr(i,a,b,c,d,e,f,g);	\
+#define	PFLOG_PACKET(i,x,a,b,c,d,e,f,g,h) do {	\
+	if (pflog_packet_ptr != NULL)		\
+	pflog_packet_ptr(i,a,b,c,d,e,f,g,h);	\
 } while (0)
-#else
+#else /* ! __FreeBSD__ */
 #if NPFLOG > 0
-#define	PFLOG_PACKET(i,x,a,b,c,d,e,f,g) pflog_packet(i,a,b,c,d,e,f,g)
+#define	PFLOG_PACKET(i,x,a,b,c,d,e,f,g,h) pflog_packet(i,a,b,c,d,e,f,g,h)
 #else
-#define	PFLOG_PACKET(i,x,a,b,c,d,e,f,g)	((void)0)
+#define	PFLOG_PACKET(i,x,a,b,c,d,e,f,g,h) ((void)0)
 #endif /* NPFLOG > 0 */
 #endif /* __FreeBSD__ */
 #endif /* _KERNEL */
Index: pf_table.c
===================================================================
RCS file: /home/cvs/src/sys/contrib/pf/net/pf_table.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/contrib/pf/net/pf_table.c -L sys/contrib/pf/net/pf_table.c -u -r1.1.1.1 -r1.2
--- sys/contrib/pf/net/pf_table.c
+++ sys/contrib/pf/net/pf_table.c
@@ -1,5 +1,4 @@
-/*	$FreeBSD: src/sys/contrib/pf/net/pf_table.c,v 1.7 2005/05/04 15:29:28 mlaier Exp $	*/
-/*	$OpenBSD: pf_table.c,v 1.62 2004/12/07 18:02:04 mcbride Exp $	*/
+/*	$OpenBSD: pf_table.c,v 1.68 2006/05/02 10:08:45 dhartmei Exp $	*/
 
 /*
  * Copyright (c) 2002 Cedric Berger
@@ -34,6 +33,9 @@
 #ifdef __FreeBSD__
 #include "opt_inet.h"
 #include "opt_inet6.h"
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/sys/contrib/pf/net/pf_table.c,v 1.8.2.1 2007/10/28 19:46:30 mlaier Exp $");
 #endif
 
 #include <sys/param.h>
@@ -465,7 +467,8 @@
 
 int
 pfr_set_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
-    int *size2, int *nadd, int *ndel, int *nchange, int flags)
+    int *size2, int *nadd, int *ndel, int *nchange, int flags,
+    u_int32_t ignore_pfrt_flags)
 {
 	struct pfr_ktable	*kt, *tmpkt;
 	struct pfr_kentryworkq	 addq, delq, changeq;
@@ -475,7 +478,8 @@
 	long			 tzero = time_second;
 
 	ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY+PFR_FLAG_FEEDBACK);
-	if (pfr_validate_table(tbl, 0, flags & PFR_FLAG_USERIOCTL))
+	if (pfr_validate_table(tbl, ignore_pfrt_flags, flags &
+	    PFR_FLAG_USERIOCTL))
 		return (EINVAL);
 	kt = pfr_lookup_table(tbl);
 	if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
@@ -875,13 +879,10 @@
 	if (ADDR_NETWORK(ad)) {
 		pfr_prepare_network(&mask, ad->pfra_af, ad->pfra_net);
 		s = splsoftnet(); /* rn_lookup makes use of globals */
-#if defined(__FreeBSD__) && (__FreeBSD_version >= 500100)
-		RADIX_NODE_HEAD_LOCK(head);
+#ifdef __FreeBSD__
+		PF_ASSERT(MA_OWNED);
 #endif
 		ke = (struct pfr_kentry *)rn_lookup(&sa, &mask, head);
-#if defined(__FreeBSD__) && (__FreeBSD_version >= 500100)
-		RADIX_NODE_HEAD_UNLOCK(head);
-#endif
 		splx(s);
 		if (ke && KENTRY_RNF_ROOT(ke))
 			ke = NULL;
@@ -1079,17 +1080,14 @@
 		head = kt->pfrkt_ip6;
 
 	s = splsoftnet();
-#if defined(__FreeBSD__) && (__FreeBSD_version >= 500100)
-	RADIX_NODE_HEAD_LOCK(head);
+#ifdef __FreeBSD__
+	PF_ASSERT(MA_OWNED);
 #endif
 	if (KENTRY_NETWORK(ke)) {
 		pfr_prepare_network(&mask, ke->pfrke_af, ke->pfrke_net);
 		rn = rn_addroute(&ke->pfrke_sa, &mask, head, ke->pfrke_node);
 	} else
 		rn = rn_addroute(&ke->pfrke_sa, NULL, head, ke->pfrke_node);
-#if defined(__FreeBSD__) && (__FreeBSD_version >= 500100)
-	RADIX_NODE_HEAD_UNLOCK(head);
-#endif
 	splx(s);
 
 	return (rn == NULL ? -1 : 0);
@@ -1109,8 +1107,8 @@
 		head = kt->pfrkt_ip6;
 
 	s = splsoftnet();
-#if defined(__FreeBSD__) && (__FreeBSD_version >= 500100)
-	RADIX_NODE_HEAD_LOCK(head);
+#ifdef __FreeBSD__
+	PF_ASSERT(MA_OWNED);
 #endif
 	if (KENTRY_NETWORK(ke)) {
 		pfr_prepare_network(&mask, ke->pfrke_af, ke->pfrke_net);
@@ -1125,9 +1123,6 @@
 #else
 		rn = rn_delete(&ke->pfrke_sa, NULL, head, NULL);
 #endif
-#if defined(__FreeBSD__) && (__FreeBSD_version >= 500100)
-	RADIX_NODE_HEAD_UNLOCK(head);
-#endif
 	splx(s);
 
 	if (rn == NULL) {
@@ -1176,7 +1171,7 @@
 			struct pfr_addr ad;
 
 			pfr_copyout_addr(&ad, ke);
-			if (copyout(&ad, w->pfrw_addr, sizeof(ad)))
+			if (COPYOUT(&ad, w->pfrw_addr, sizeof(ad)))
 				return (EFAULT);
 			w->pfrw_addr++;
 		}
@@ -2182,7 +2177,7 @@
 	bzero(&tbl, sizeof(tbl));
 	strlcpy(tbl.pfrt_name, name, sizeof(tbl.pfrt_name));
 	if (ac != NULL)
-		strlcpy(tbl.pfrt_anchor, ac->name, sizeof(tbl.pfrt_anchor));
+		strlcpy(tbl.pfrt_anchor, ac->path, sizeof(tbl.pfrt_anchor));
 	kt = pfr_lookup_table(&tbl);
 	if (kt == NULL) {
 		kt = pfr_create_ktable(&tbl, time_second, 1);
Index: if_pfsync.h
===================================================================
RCS file: /home/cvs/src/sys/contrib/pf/net/if_pfsync.h,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/contrib/pf/net/if_pfsync.h -L sys/contrib/pf/net/if_pfsync.h -u -r1.1.1.1 -r1.2
--- sys/contrib/pf/net/if_pfsync.h
+++ sys/contrib/pf/net/if_pfsync.h
@@ -1,5 +1,5 @@
-/*	$FreeBSD: src/sys/contrib/pf/net/if_pfsync.h,v 1.7 2005/06/10 17:23:49 mlaier Exp $	*/
-/*	$OpenBSD: if_pfsync.h,v 1.19 2005/01/20 17:47:38 mcbride Exp $	*/
+/*	$FreeBSD: src/sys/contrib/pf/net/if_pfsync.h,v 1.9 2007/07/03 12:16:07 mlaier Exp $	*/
+/*	$OpenBSD: if_pfsync.h,v 1.30 2006/10/31 14:49:01 henning Exp $	*/
 
 /*
  * Copyright (c) 2001 Michael Shalayeff
@@ -36,6 +36,7 @@
 struct pfsync_state_scrub {
 	u_int16_t	pfss_flags;
 	u_int8_t	pfss_ttl;	/* stashed TTL		*/
+#define PFSYNC_SCRUB_FLAG_VALID 	0x01
 	u_int8_t	scrub_flag;
 	u_int32_t	pfss_ts_mod;	/* timestamp modulation	*/
 } __packed;
@@ -55,8 +56,7 @@
 	u_int16_t	mss;		/* Maximum segment size option	*/
 	u_int8_t	state;		/* active state level		*/
 	u_int8_t	wscale;		/* window scaling factor	*/
-	u_int8_t	scrub_flag;
-	u_int8_t	pad[5];
+	u_int8_t	pad[6];
 } __packed;
 
 struct pfsync_state {
@@ -73,8 +73,8 @@
 	u_int32_t	 nat_rule;
 	u_int32_t	 creation;
 	u_int32_t	 expire;
-	u_int32_t	 packets[2];
-	u_int32_t	 bytes[2];
+	u_int32_t	 packets[2][2];
+	u_int32_t	 bytes[2][2];
 	u_int32_t	 creatorid;
 	sa_family_t	 af;
 	u_int8_t	 proto;
@@ -89,6 +89,18 @@
 #define PFSYNC_FLAG_COMPRESS 	0x01
 #define PFSYNC_FLAG_STALE	0x02
 
+#ifdef PFSYNC_TDB
+struct pfsync_tdb {
+	u_int32_t	spi;
+	union sockaddr_union dst;
+	u_int32_t	rpl;
+	u_int64_t	cur_bytes;
+	u_int8_t	sproto;
+	u_int8_t	updates;
+	u_int8_t	pad[2];
+} __packed;
+#endif
+
 struct pfsync_state_upd {
 	u_int32_t		id[2];
 	struct pfsync_state_peer	src;
@@ -144,6 +156,12 @@
 	struct pfsync_state_upd_req	*r;
 };
 
+#ifdef PFSYNC_TDB
+union sc_tdb_statep {
+	struct pfsync_tdb	*t;
+};
+#endif
+
 extern int	pfsync_sync_ok;
 
 struct pfsync_softc {
@@ -157,10 +175,14 @@
 	struct ip_moptions	 sc_imo;
 #ifdef __FreeBSD__
 	struct callout		 sc_tmo;
+#ifdef PFSYNC_TDB
+	struct callout		 sc_tdb_tmo;
+#endif
 	struct callout		 sc_bulk_tmo;
 	struct callout		 sc_bulkfail_tmo;
 #else
 	struct timeout		 sc_tmo;
+	struct timeout		 sc_tdb_tmo;
 	struct timeout		 sc_bulk_tmo;
 	struct timeout		 sc_bulkfail_tmo;
 #endif
@@ -168,27 +190,37 @@
 	struct in_addr		 sc_sendaddr;
 	struct mbuf		*sc_mbuf;	/* current cumulative mbuf */
 	struct mbuf		*sc_mbuf_net;	/* current cumulative mbuf */
+#ifdef PFSYNC_TDB
+    	struct mbuf		*sc_mbuf_tdb;	/* dito for TDB updates */
+#endif
 #ifdef __FreeBSD__
 	struct ifqueue		 sc_ifq;
-	struct callout		 sc_send_tmo;
+	struct task		 sc_send_task;
 #endif
 	union sc_statep		 sc_statep;
 	union sc_statep		 sc_statep_net;
+#ifdef PFSYNC_TDB
+	union sc_tdb_statep	 sc_statep_tdb;
+#endif
 	u_int32_t		 sc_ureq_received;
 	u_int32_t		 sc_ureq_sent;
+	struct pf_state		*sc_bulk_send_next;
+	struct pf_state		*sc_bulk_terminator;
 	int			 sc_bulk_tries;
 	int			 sc_maxcount;	/* number of states in mtu */
 	int			 sc_maxupdates;	/* number of updates/state */
 #ifdef __FreeBSD__
-	LIST_ENTRY(pfsync_softc) sc_next;
+	eventhandler_tag	 sc_detachtag;
 #endif
 };
+
+extern struct pfsync_softc	*pfsyncif;
 #endif
 
 
 struct pfsync_header {
 	u_int8_t version;
-#define	PFSYNC_VERSION	2
+#define	PFSYNC_VERSION	3
 	u_int8_t af;
 	u_int8_t action;
 #define	PFSYNC_ACT_CLR		0	/* clear all states */
@@ -201,8 +233,10 @@
 #define	PFSYNC_ACT_DEL_F	7	/* delete fragments */
 #define	PFSYNC_ACT_UREQ		8	/* request "uncompressed" state */
 #define PFSYNC_ACT_BUS		9	/* Bulk Update Status */
-#define	PFSYNC_ACT_MAX		10
+#define PFSYNC_ACT_TDB_UPD	10	/* TDB replay counter update */
+#define	PFSYNC_ACT_MAX		11
 	u_int8_t count;
+	u_int8_t pf_chksum[PF_MD5_DIGEST_LENGTH];
 } __packed;
 
 #define PFSYNC_BULKPACKETS	1	/* # of packets per timeout */
@@ -211,7 +245,7 @@
 #define	PFSYNC_ACTIONS \
 	"CLR ST", "INS ST", "UPD ST", "DEL ST", \
 	"UPD ST COMP", "DEL ST COMP", "INS FR", "DEL FR", \
-	"UPD REQ", "BLK UPD STAT"
+	"UPD REQ", "BLK UPD STAT", "TDB UPD"
 
 #define PFSYNC_DFLTTL		255
 
@@ -258,6 +292,13 @@
 	(d)->mss = htons((s)->mss);		\
 	(d)->state = (s)->state;		\
 	(d)->wscale = (s)->wscale;		\
+	if ((s)->scrub) {						\
+		(d)->scrub.pfss_flags = 				\
+		    htons((s)->scrub->pfss_flags & PFSS_TIMESTAMP);	\
+		(d)->scrub.pfss_ttl = (s)->scrub->pfss_ttl;		\
+		(d)->scrub.pfss_ts_mod = htonl((s)->scrub->pfss_ts_mod);\
+		(d)->scrub.scrub_flag = PFSYNC_SCRUB_FLAG_VALID;	\
+	}								\
 } while (0)
 
 #define pf_state_peer_ntoh(s,d) do {		\
@@ -268,6 +309,13 @@
 	(d)->mss = ntohs((s)->mss);		\
 	(d)->state = (s)->state;		\
 	(d)->wscale = (s)->wscale;		\
+	if ((s)->scrub.scrub_flag == PFSYNC_SCRUB_FLAG_VALID && 	\
+	    (d)->scrub != NULL) {					\
+		(d)->scrub->pfss_flags =				\
+		    ntohs((s)->scrub.pfss_flags) & PFSS_TIMESTAMP;	\
+		(d)->scrub->pfss_ttl = (s)->scrub.pfss_ttl;		\
+		(d)->scrub->pfss_ts_mod = ntohl((s)->scrub.pfss_ts_mod);\
+	}								\
 } while (0)
 
 #define pf_state_host_hton(s,d) do {				\
@@ -280,6 +328,17 @@
 	(d)->port = (s)->port;					\
 } while (0)
 
+#define pf_state_counter_hton(s,d) do {				\
+	d[0] = htonl((s>>32)&0xffffffff);			\
+	d[1] = htonl(s&0xffffffff);				\
+} while (0)
+
+#define pf_state_counter_ntoh(s,d) do {				\
+	d = ntohl(s[0]);					\
+	d = d<<32;						\
+	d += ntohl(s[1]);					\
+} while (0)
+
 #ifdef _KERNEL
 #ifdef __FreeBSD__
 void pfsync_input(struct mbuf *, __unused int);
@@ -293,7 +352,8 @@
 	    (st->proto == IPPROTO_PFSYNC))			\
 		st->sync_flags |= PFSTATE_NOSYNC;		\
 	else if (!st->sync_flags)				\
-		pfsync_pack_state(PFSYNC_ACT_INS, (st), 1);	\
+		pfsync_pack_state(PFSYNC_ACT_INS, (st), 	\
+		    PFSYNC_FLAG_COMPRESS);			\
 	st->sync_flags &= ~PFSTATE_FROMSYNC;			\
 } while (0)
 #define pfsync_update_state(st) do {				\
@@ -306,8 +366,10 @@
 	if (!st->sync_flags)					\
 		pfsync_pack_state(PFSYNC_ACT_DEL, (st),		\
 		    PFSYNC_FLAG_COMPRESS);			\
-	st->sync_flags &= ~PFSTATE_FROMSYNC;			\
 } while (0)
+#ifdef PFSYNC_TDB
+int pfsync_update_tdb(struct tdb *, int);
+#endif
 #endif
 
 #endif /* _NET_IF_PFSYNC_H_ */
Index: pf_if.c
===================================================================
RCS file: /home/cvs/src/sys/contrib/pf/net/pf_if.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/contrib/pf/net/pf_if.c -L sys/contrib/pf/net/pf_if.c -u -r1.1.1.1 -r1.2
--- sys/contrib/pf/net/pf_if.c
+++ sys/contrib/pf/net/pf_if.c
@@ -1,7 +1,8 @@
-/*	$FreeBSD: src/sys/contrib/pf/net/pf_if.c,v 1.10 2005/05/03 16:43:32 mlaier Exp $ */
-/*	$OpenBSD: pf_if.c,v 1.23 2004/12/22 17:17:55 dhartmei Exp $ */
+/*	$OpenBSD: pf_if.c,v 1.46 2006/12/13 09:01:59 itojun Exp $ */
 
 /*
+ * Copyright 2005 Henning Brauer <henning at openbsd.org>
+ * Copyright 2005 Ryan McBride <mcbride at openbsd.org>
  * Copyright (c) 2001 Daniel Hartmeier
  * Copyright (c) 2003 Cedric Berger
  * All rights reserved.
@@ -34,6 +35,9 @@
 #if defined(__FreeBSD__)
 #include "opt_inet.h"
 #include "opt_inet6.h"
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/sys/contrib/pf/net/pf_if.c,v 1.11.2.2 2007/11/25 19:26:46 mlaier Exp $");
 #endif
 
 #include <sys/param.h>
@@ -66,74 +70,58 @@
 #include <netinet/ip6.h>
 #endif /* INET6 */
 
-#define ACCEPT_FLAGS(oklist)			\
-	do {					\
-		if ((flags & ~(oklist)) &	\
-		    PFI_FLAG_ALLMASK)		\
-			return (EINVAL);	\
-	} while (0)
-
-#define senderr(e)      do { rv = (e); goto _bad; } while (0)
-
-struct pfi_kif		**pfi_index2kif;
-struct pfi_kif		 *pfi_self, *pfi_dummy;
-int			  pfi_indexlim;
-struct pfi_ifhead	  pfi_ifs;
+struct pfi_kif		 *pfi_all = NULL;
 struct pfi_statehead	  pfi_statehead;
-int			  pfi_ifcnt;
 #ifdef __FreeBSD__
 uma_zone_t		  pfi_addr_pl;
 #else
 struct pool		  pfi_addr_pl;
 #endif
+struct pfi_ifhead	  pfi_ifs;
 long			  pfi_update = 1;
 struct pfr_addr		 *pfi_buffer;
 int			  pfi_buffer_cnt;
 int			  pfi_buffer_max;
 #ifdef __FreeBSD__
-eventhandler_tag	 pfi_clone_cookie = NULL;
-eventhandler_tag	 pfi_attach_cookie = NULL;
-eventhandler_tag	 pfi_detach_cookie = NULL;
+eventhandler_tag	  pfi_attach_cookie = NULL;
+eventhandler_tag	  pfi_detach_cookie = NULL;
+eventhandler_tag	  pfi_attach_group_cookie = NULL;
+eventhandler_tag	  pfi_change_group_cookie = NULL;
+eventhandler_tag	  pfi_detach_group_cookie = NULL;
+eventhandler_tag	  pfi_ifaddr_event_cookie = NULL;
 #endif
 
-void		 pfi_dynaddr_update(void *);
-void		 pfi_kifaddr_update(void *);
+void		 pfi_kif_update(struct pfi_kif *);
+void		 pfi_dynaddr_update(struct pfi_dynaddr *dyn);
 void		 pfi_table_update(struct pfr_ktable *, struct pfi_kif *,
 		    int, int);
+void		 pfi_kifaddr_update(void *);
 void		 pfi_instance_add(struct ifnet *, int, int);
 void		 pfi_address_add(struct sockaddr *, int, int);
 int		 pfi_if_compare(struct pfi_kif *, struct pfi_kif *);
-struct pfi_kif	*pfi_if_create(const char *, struct pfi_kif *, int);
-void		 pfi_copy_group(char *, const char *, int);
-void		 pfi_newgroup(const char *, int);
-int		 pfi_skip_if(const char *, struct pfi_kif *, int);
+int		 pfi_skip_if(const char *, struct pfi_kif *);
 int		 pfi_unmask(void *);
-void		 pfi_dohooks(struct pfi_kif *);
 #ifdef __FreeBSD__
-void		 pfi_kifaddr_update_event(void *, struct ifnet *);
-void		 pfi_attach_clone_event(void * __unused, struct if_clone *);
 void		 pfi_attach_ifnet_event(void * __unused, struct ifnet *);
 void		 pfi_detach_ifnet_event(void * __unused, struct ifnet *);
+void		 pfi_attach_group_event(void * __unused, struct ifg_group *);
+void		 pfi_change_group_event(void * __unused, char *);
+void		 pfi_detach_group_event(void * __unused, struct ifg_group *);
+void		 pfi_ifaddr_event(void * __unused, struct ifnet *);
+
+extern struct ifgrouphead ifg_head;
 #endif
 
 RB_PROTOTYPE(pfi_ifhead, pfi_kif, pfik_tree, pfi_if_compare);
 RB_GENERATE(pfi_ifhead, pfi_kif, pfik_tree, pfi_if_compare);
 
 #define PFI_BUFFER_MAX		0x10000
-#ifdef __FreeBSD__
-MALLOC_DEFINE(PFI_MTYPE, "pf_if", "pf interface table");
-#else
 #define PFI_MTYPE		M_IFADDR
-#endif
 
 void
 pfi_initialize(void)
 {
-#ifdef __FreeBSD__
-	struct ifnet	*ifp;
-#endif
-
-	if (pfi_self != NULL)	/* already initialized */
+	if (pfi_all != NULL)	/* already initialized */
 		return;
 
 	TAILQ_INIT(&pfi_statehead);
@@ -144,26 +132,33 @@
 	pfi_buffer_max = 64;
 	pfi_buffer = malloc(pfi_buffer_max * sizeof(*pfi_buffer),
 	    PFI_MTYPE, M_WAITOK);
-	pfi_self = pfi_if_create("self", NULL, PFI_IFLAG_GROUP);
+
+	if ((pfi_all = pfi_kif_get(IFG_ALL)) == NULL)
+		panic("pfi_kif_get for pfi_all failed");
+
 #ifdef __FreeBSD__
-	/* XXX_IMPORT */
-	PF_LOCK();
+	struct ifg_group *ifg;
+	struct ifnet *ifp;
+
 	IFNET_RLOCK();
-	TAILQ_FOREACH(ifp, &ifnet, if_link) {
-		IFNET_RUNLOCK();
+	TAILQ_FOREACH(ifg, &ifg_head, ifg_next)
+		pfi_attach_ifgroup(ifg);
+	TAILQ_FOREACH(ifp, &ifnet, if_link)
 		pfi_attach_ifnet(ifp);
-		IFNET_RLOCK();
-	}
 	IFNET_RUNLOCK();
-	PF_UNLOCK();
-	pfi_dummy = pfi_if_create("notyet", pfi_self,
-	    PFI_IFLAG_GROUP | PFI_IFLAG_DYNAMIC);
+
 	pfi_attach_cookie = EVENTHANDLER_REGISTER(ifnet_arrival_event,
 	    pfi_attach_ifnet_event, NULL, EVENTHANDLER_PRI_ANY);
 	pfi_detach_cookie = EVENTHANDLER_REGISTER(ifnet_departure_event,
 	    pfi_detach_ifnet_event, NULL, EVENTHANDLER_PRI_ANY);
-	pfi_clone_cookie = EVENTHANDLER_REGISTER(if_clone_event,
-	    pfi_attach_clone_event, NULL, EVENTHANDLER_PRI_ANY);
+	pfi_attach_group_cookie = EVENTHANDLER_REGISTER(group_attach_event,
+	    pfi_attach_group_event, NULL, EVENTHANDLER_PRI_ANY);
+	pfi_change_group_cookie = EVENTHANDLER_REGISTER(group_change_event,
+	    pfi_change_group_event, NULL, EVENTHANDLER_PRI_ANY);
+	pfi_detach_group_cookie = EVENTHANDLER_REGISTER(group_detach_event,
+	    pfi_detach_group_event, NULL, EVENTHANDLER_PRI_ANY);
+	pfi_ifaddr_event_cookie = EVENTHANDLER_REGISTER(ifaddr_event,
+	    pfi_ifaddr_event, NULL, EVENTHANDLER_PRI_ANY);
 #endif
 }
 
@@ -171,335 +166,275 @@
 void
 pfi_cleanup(void)
 {
-	struct pfi_kif *p, key;
-	struct ifnet *ifp;
-
-	PF_ASSERT(MA_OWNED);
+	struct pfi_kif *p;
 
 	PF_UNLOCK();
 	EVENTHANDLER_DEREGISTER(ifnet_arrival_event, pfi_attach_cookie);
 	EVENTHANDLER_DEREGISTER(ifnet_departure_event, pfi_detach_cookie);
-	EVENTHANDLER_DEREGISTER(if_clone_event, pfi_clone_cookie);
+	EVENTHANDLER_DEREGISTER(group_attach_event, pfi_attach_group_cookie);
+	EVENTHANDLER_DEREGISTER(group_change_event, pfi_change_group_cookie);
+	EVENTHANDLER_DEREGISTER(group_detach_event, pfi_detach_group_cookie);
+	EVENTHANDLER_DEREGISTER(ifaddr_event, pfi_ifaddr_event_cookie);
 	PF_LOCK();
 
-	IFNET_RLOCK();
-	/* release PFI_IFLAG_INSTANCE */
-	TAILQ_FOREACH(ifp, &ifnet, if_link) {
-		strlcpy(key.pfik_name, ifp->if_xname, sizeof(key.pfik_name));
-		p = RB_FIND(pfi_ifhead, &pfi_ifs, &key);
-		if (p != NULL) {
-			IFNET_RUNLOCK();
-			pfi_detach_ifnet(ifp);
-			IFNET_RLOCK();
+	pfi_all = NULL;
+	while ((p = RB_MIN(pfi_ifhead, &pfi_ifs))) {
+		if (p->pfik_rules || p->pfik_states) {
+			printf("pfi_cleanup: dangling refs for %s\n",
+			    p->pfik_name);
 		}
-	}
-	IFNET_RUNLOCK();
 
-	/* XXX clear all other interface group */
-	while ((p = RB_MIN(pfi_ifhead, &pfi_ifs))) {
 		RB_REMOVE(pfi_ifhead, &pfi_ifs, p);
-
-		free(p->pfik_ah_head, PFI_MTYPE);
 		free(p, PFI_MTYPE);
 	}
-	free(pfi_index2kif, PFI_MTYPE);
+
 	free(pfi_buffer, PFI_MTYPE);
-	pfi_index2kif = NULL;
-	pfi_buffer = NULL;
-	pfi_self = NULL;
 }
+#endif
 
-/*
- * Wrapper functions for FreeBSD eventhandler
- */
-void
-pfi_kifaddr_update_event(void *arg, struct ifnet *ifp)
+struct pfi_kif *
+pfi_kif_get(const char *kif_name)
 {
-	struct pfi_kif *p = arg;
-	
-	PF_LOCK();
-	/* 
-	 * Check to see if it is 'our' interface as we do not have per
-	 * interface hooks and thus get an update for every interface.
+	struct pfi_kif		*kif;
+	struct pfi_kif_cmp	 s;
+
+	bzero(&s, sizeof(s));
+	strlcpy(s.pfik_name, kif_name, sizeof(s.pfik_name));
+	if ((kif = RB_FIND(pfi_ifhead, &pfi_ifs, (struct pfi_kif *)&s)) != NULL)
+		return (kif);
+
+	/* create new one */
+#ifdef __FreeBSD__
+	if ((kif = malloc(sizeof(*kif), PFI_MTYPE, M_NOWAIT)) == NULL)
+#else
+	if ((kif = malloc(sizeof(*kif), PFI_MTYPE, M_DONTWAIT)) == NULL)
+#endif
+		return (NULL);
+
+	bzero(kif, sizeof(*kif));
+	strlcpy(kif->pfik_name, kif_name, sizeof(kif->pfik_name));
+#ifdef __FreeBSD__
+	/*
+	 * It seems that the value of time_second is in unintialzied state
+	 * when pf sets interface statistics clear time in boot phase if pf
+	 * was statically linked to kernel. Instead of setting the bogus
+	 * time value have pfi_get_ifaces handle this case. In
+	 * pfi_get_ifaces it uses boottime.tv_sec if it sees the time is 0.
 	 */
-	if (p && p->pfik_ifp == ifp)
-		pfi_kifaddr_update(p);
-	PF_UNLOCK();
-}
+	kif->pfik_tzero = time_second > 1 ? time_second : 0;
+#else
+	kif->pfik_tzero = time_second;
+#endif
+	TAILQ_INIT(&kif->pfik_dynaddrs);
 
-void
-pfi_attach_clone_event(void *arg __unused, struct if_clone *ifc)
-{
-	PF_LOCK();
-	pfi_attach_clone(ifc);
-	PF_UNLOCK();
+	RB_INSERT(pfi_ifhead, &pfi_ifs, kif);
+	return (kif);
 }
 
 void
-pfi_attach_ifnet_event(void *arg __unused, struct ifnet *ifp)
+pfi_kif_ref(struct pfi_kif *kif, enum pfi_kif_refs what)
 {
-	PF_LOCK();
-	pfi_attach_ifnet(ifp);
-	PF_UNLOCK();
+	switch (what) {
+	case PFI_KIF_REF_RULE:
+		kif->pfik_rules++;
+		break;
+	case PFI_KIF_REF_STATE:
+		if (!kif->pfik_states++)
+			TAILQ_INSERT_TAIL(&pfi_statehead, kif, pfik_w_states);
+		break;
+	default:
+		panic("pfi_kif_ref with unknown type");
+	}
 }
 
 void
-pfi_detach_ifnet_event(void *arg __unused, struct ifnet *ifp)
+pfi_kif_unref(struct pfi_kif *kif, enum pfi_kif_refs what)
 {
-	PF_LOCK();
-	pfi_detach_ifnet(ifp);
-	PF_UNLOCK();
+	if (kif == NULL)
+		return;
+
+	switch (what) {
+	case PFI_KIF_REF_NONE:
+		break;
+	case PFI_KIF_REF_RULE:
+		if (kif->pfik_rules <= 0) {
+			printf("pfi_kif_unref: rules refcount <= 0\n");
+			return;
+		}
+		kif->pfik_rules--;
+		break;
+	case PFI_KIF_REF_STATE:
+		if (kif->pfik_states <= 0) {
+			printf("pfi_kif_unref: state refcount <= 0\n");
+			return;
+		}
+		if (!--kif->pfik_states)
+			TAILQ_REMOVE(&pfi_statehead, kif, pfik_w_states);
+		break;
+	default:
+		panic("pfi_kif_unref with unknown type");
+	}
+
+	if (kif->pfik_ifp != NULL || kif->pfik_group != NULL || kif == pfi_all)
+		return;
+
+	if (kif->pfik_rules || kif->pfik_states)
+		return;
+
+	RB_REMOVE(pfi_ifhead, &pfi_ifs, kif);
+	free(kif, PFI_MTYPE);
 }
-#endif /* __FreeBSD__ */
 
-void
-pfi_attach_clone(struct if_clone *ifc)
+int
+pfi_kif_match(struct pfi_kif *rule_kif, struct pfi_kif *packet_kif)
 {
-	pfi_initialize();
-	pfi_newgroup(ifc->ifc_name, PFI_IFLAG_CLONABLE);
+	struct ifg_list	*p;
+
+	if (rule_kif == NULL || rule_kif == packet_kif)
+		return (1);
+
+	if (rule_kif->pfik_group != NULL)
+		TAILQ_FOREACH(p, &packet_kif->pfik_ifp->if_groups, ifgl_next)
+			if (p->ifgl_group == rule_kif->pfik_group)
+				return (1);
+
+	return (0);
 }
 
 void
 pfi_attach_ifnet(struct ifnet *ifp)
 {
-	struct pfi_kif	*p, *q, key;
-	int		 s;
-#ifdef __FreeBSD__
-	int		 realname;
-#endif
+	struct pfi_kif		*kif;
+	int			 s;
 
 	pfi_initialize();
 	s = splsoftnet();
 	pfi_update++;
-	if (ifp->if_index >= pfi_indexlim) {
-		/*
-		 * grow pfi_index2kif,  similar to ifindex2ifnet code in if.c
-		 */
-		size_t m, n, oldlim;
-		struct pfi_kif **mp, **np;
+	if ((kif = pfi_kif_get(ifp->if_xname)) == NULL)
+		panic("pfi_kif_get failed");
 
-		oldlim = pfi_indexlim;
-		if (pfi_indexlim == 0)
-			pfi_indexlim = 64;
-		while (ifp->if_index >= pfi_indexlim)
-			pfi_indexlim <<= 1;
-
-		m = oldlim * sizeof(struct pfi_kif *);
-		mp = pfi_index2kif;
-		n = pfi_indexlim * sizeof(struct pfi_kif *);
-#ifdef __FreeBSD__
-		np = malloc(n, PFI_MTYPE, M_NOWAIT);
-#else
-		np = malloc(n, PFI_MTYPE, M_DONTWAIT);
-#endif
-		if (np == NULL)
-			panic("pfi_attach_ifnet: "
-			    "cannot allocate translation table");
-		bzero(np, n);
-		if (mp != NULL)
-			bcopy(mp, np, m);
-		pfi_index2kif = np;
-		if (mp != NULL)
-			free(mp, PFI_MTYPE);
-	}
+	kif->pfik_ifp = ifp;
+	ifp->if_pf_kif = (caddr_t)kif;
 
-	strlcpy(key.pfik_name, ifp->if_xname, sizeof(key.pfik_name));
-	p = RB_FIND(pfi_ifhead, &pfi_ifs, &key);
-#ifdef __FreeBSD__
-	/* some additional trickery for placeholders */
-	if ((p == NULL) || (p->pfik_parent == pfi_dummy)) {
-		/* are we looking at a renamed instance or not? */
-		pfi_copy_group(key.pfik_name, ifp->if_xname,
-		    sizeof(key.pfik_name));
-		realname = (strncmp(key.pfik_name, ifp->if_dname,
-		    sizeof(key.pfik_name)) == 0);
-		/* add group */
-		/* we can change if_xname, hence use if_dname as group id */
-		pfi_copy_group(key.pfik_name, ifp->if_dname,
-		    sizeof(key.pfik_name));
-		q = RB_FIND(pfi_ifhead, &pfi_ifs, &key);
-		if (q == NULL)
-		    q = pfi_if_create(key.pfik_name, pfi_self,
-		        PFI_IFLAG_GROUP|PFI_IFLAG_DYNAMIC);
-		else if (q->pfik_parent == pfi_dummy) {
-			q->pfik_parent = pfi_self;
-			q->pfik_flags = (PFI_IFLAG_GROUP | PFI_IFLAG_DYNAMIC);
-		}
-		if (q == NULL)
-			panic("pfi_attach_ifnet: "
-			    "cannot allocate '%s' group", key.pfik_name);
-
-		/* add/modify interface */
-		if (p == NULL)
-			p = pfi_if_create(ifp->if_xname, q, PFI_IFLAG_INSTANCE |
-			    (realname?0:PFI_IFLAG_PLACEHOLDER));
-		else {
-			/* remove from the dummy group */
-			/* XXX: copy stats? We should not have any!!! */
-			pfi_dummy->pfik_delcnt++;
-			TAILQ_REMOVE(&pfi_dummy->pfik_grouphead, p,
-			    pfik_instances);
-			/* move to the right group */
-			p->pfik_parent = q;
-			q->pfik_addcnt++;
-			TAILQ_INSERT_TAIL(&q->pfik_grouphead, p,
-			    pfik_instances);
-			if (realname)
-				p->pfik_flags &= ~PFI_IFLAG_PLACEHOLDER;
-			p->pfik_flags |= PFI_IFLAG_INSTANCE;
-		}
-		if (p == NULL)
-			panic("pfi_attach_ifnet: "
-			    "cannot allocate '%s' interface", ifp->if_xname);
-#else
-	if (p == NULL) {
-		/* add group */
-		pfi_copy_group(key.pfik_name, ifp->if_xname,
-		    sizeof(key.pfik_name));
-		q = RB_FIND(pfi_ifhead, &pfi_ifs, &key);
-		if (q == NULL)
-		    q = pfi_if_create(key.pfik_name, pfi_self, PFI_IFLAG_GROUP);
-		else if (q->pfik_parent == pfi_dummy) {
-			q->pfik_parent = pfi_self;
-			q->pfik_flags = (PFI_IFLAG_GROUP | PFI_IFLAG_DYNAMIC);
-		}
-		if (q == NULL)
-			panic("pfi_attach_ifnet: "
-			    "cannot allocate '%s' group", key.pfik_name);
-
-		/* add interface */
-		p = pfi_if_create(ifp->if_xname, q, PFI_IFLAG_INSTANCE);
-		if (p == NULL)
-			panic("pfi_attach_ifnet: "
-			    "cannot allocate '%s' interface", ifp->if_xname);
-#endif
-	} else
-		q = p->pfik_parent;
-	p->pfik_ifp = ifp;
-	p->pfik_flags |= PFI_IFLAG_ATTACHED;
-#ifdef __FreeBSD__
-	PF_UNLOCK();
-	p->pfik_ah_cookie = EVENTHANDLER_REGISTER(ifaddr_event,
-	    pfi_kifaddr_update_event, p, EVENTHANDLER_PRI_ANY);
-	PF_LOCK();
-#else
-	p->pfik_ah_cookie =
-	    hook_establish(ifp->if_addrhooks, 1, pfi_kifaddr_update, p);
+#ifndef __FreeBSD__
+	if ((kif->pfik_ah_cookie = hook_establish(ifp->if_addrhooks, 1,
+	    pfi_kifaddr_update, kif)) == NULL)
+		panic("pfi_attach_ifnet: cannot allocate '%s' address hook",
+		    ifp->if_xname);
 #endif
-	pfi_index2kif[ifp->if_index] = p;
-	pfi_dohooks(p);
+
+	pfi_kif_update(kif);
+
 	splx(s);
 }
 
 void
 pfi_detach_ifnet(struct ifnet *ifp)
 {
-	struct pfi_kif	*p, *q, key;
-	int		 s;
+	int			 s;
+	struct pfi_kif		*kif;
 
-	strlcpy(key.pfik_name, ifp->if_xname, sizeof(key.pfik_name));
+	if ((kif = (struct pfi_kif *)ifp->if_pf_kif) == NULL)
+		return;
 
 	s = splsoftnet();
 	pfi_update++;
-	p = RB_FIND(pfi_ifhead, &pfi_ifs, &key);
-	if (p == NULL) {
-		printf("pfi_detach_ifnet: cannot find %s", ifp->if_xname);
-		splx(s);
-		return;
-	}
-#ifdef __FreeBSD__
-	PF_UNLOCK();
-	EVENTHANDLER_DEREGISTER(ifaddr_event, p->pfik_ah_cookie);
-	PF_LOCK();
-#else
-	hook_disestablish(p->pfik_ifp->if_addrhooks, p->pfik_ah_cookie);
+#ifndef __FreeBSD__
+	hook_disestablish(ifp->if_addrhooks, kif->pfik_ah_cookie);
 #endif
-	q = p->pfik_parent;
-	p->pfik_ifp = NULL;
-	p->pfik_flags &= ~PFI_IFLAG_ATTACHED;
-	pfi_index2kif[ifp->if_index] = NULL;
-	pfi_dohooks(p);
-	pfi_maybe_destroy(p);
+	pfi_kif_update(kif);
+
+	kif->pfik_ifp = NULL;
+	ifp->if_pf_kif = NULL;
+	pfi_kif_unref(kif, PFI_KIF_REF_NONE);
 	splx(s);
 }
 
-struct pfi_kif *
-pfi_lookup_create(const char *name)
+void
+pfi_attach_ifgroup(struct ifg_group *ifg)
 {
-	struct pfi_kif	*p, *q, key;
+	struct pfi_kif	*kif;
 	int		 s;
 
+	pfi_initialize();
 	s = splsoftnet();
-	p = pfi_lookup_if(name);
-	if (p == NULL) {
-		pfi_copy_group(key.pfik_name, name, sizeof(key.pfik_name));
-		q = pfi_lookup_if(key.pfik_name);
-#ifdef __FreeBSD__
-		/* XXX_IMPORT */
-		if ((q != NULL) && (q->pfik_parent != pfi_dummy))
-			p = pfi_if_create(name, q, PFI_IFLAG_INSTANCE);
-		else {
-			if (pfi_dummy == NULL)
-				panic("no 'notyet' dummy group");
-			p = pfi_if_create(name, pfi_dummy,
-			    PFI_IFLAG_PLACEHOLDER);
-		}
-#else
-		if (q == NULL) {
-			pfi_newgroup(key.pfik_name, PFI_IFLAG_DYNAMIC);
-			q = pfi_lookup_if(key.pfik_name);
-		}
-		p = pfi_lookup_if(name);
-		if (p == NULL && q != NULL)
-			p = pfi_if_create(name, q, PFI_IFLAG_INSTANCE);
-#endif
-	}
-	splx(s);
-	return (p);
-}
+	pfi_update++;
+	if ((kif = pfi_kif_get(ifg->ifg_group)) == NULL)
+		panic("pfi_kif_get failed");
 
-struct pfi_kif *
-pfi_attach_rule(const char *name)
-{
-	struct pfi_kif	*p;
+	kif->pfik_group = ifg;
+	ifg->ifg_pf_kif = (caddr_t)kif;
 
-	p = pfi_lookup_create(name);
-	if (p != NULL)
-		p->pfik_rules++;
-	return (p);
+	splx(s);
 }
 
 void
-pfi_detach_rule(struct pfi_kif *p)
+pfi_detach_ifgroup(struct ifg_group *ifg)
 {
-	if (p == NULL)
+	int		 s;
+	struct pfi_kif	*kif;
+
+	if ((kif = (struct pfi_kif *)ifg->ifg_pf_kif) == NULL)
 		return;
-	if (p->pfik_rules > 0)
-		p->pfik_rules--;
-	else
-		printf("pfi_detach_rule: reference count at 0\n");
-	pfi_maybe_destroy(p);
+
+	s = splsoftnet();
+	pfi_update++;
+
+	kif->pfik_group = NULL;
+	ifg->ifg_pf_kif = NULL;
+	pfi_kif_unref(kif, PFI_KIF_REF_NONE);
+	splx(s);
 }
 
 void
-pfi_attach_state(struct pfi_kif *p)
+pfi_group_change(const char *group)
 {
-	if (!p->pfik_states++)
-		TAILQ_INSERT_TAIL(&pfi_statehead, p, pfik_w_states);
+	struct pfi_kif		*kif;
+	int			 s;
+
+	s = splsoftnet();
+	pfi_update++;
+	if ((kif = pfi_kif_get(group)) == NULL)
+		panic("pfi_kif_get failed");
+
+	pfi_kif_update(kif);
+
+	splx(s);
 }
 
-void
-pfi_detach_state(struct pfi_kif *p)
+int
+pfi_match_addr(struct pfi_dynaddr *dyn, struct pf_addr *a, sa_family_t af)
 {
-	if (p == NULL)
-		return;
-	if (p->pfik_states <= 0) {
-		printf("pfi_detach_state: reference count <= 0\n");
-		return;
+	switch (af) {
+#ifdef INET
+	case AF_INET:
+		switch (dyn->pfid_acnt4) {
+		case 0:
+			return (0);
+		case 1:
+			return (PF_MATCHA(0, &dyn->pfid_addr4,
+			    &dyn->pfid_mask4, a, AF_INET));
+		default:
+			return (pfr_match_addr(dyn->pfid_kt, a, AF_INET));
+		}
+		break;
+#endif /* INET */
+#ifdef INET6
+	case AF_INET6:
+		switch (dyn->pfid_acnt6) {
+		case 0:
+			return (0);
+		case 1:
+			return (PF_MATCHA(0, &dyn->pfid_addr6,
+			    &dyn->pfid_mask6, a, AF_INET6));
+		default:
+			return (pfr_match_addr(dyn->pfid_kt, a, AF_INET6));
+		}
+		break;
+#endif /* INET6 */
+	default:
+		return (0);
 	}
-	if (!--p->pfik_states)
-		TAILQ_REMOVE(&pfi_statehead, p, pfik_w_states);
-	pfi_maybe_destroy(p);
 }
 
 int
@@ -512,15 +447,20 @@
 
 	if (aw->type != PF_ADDR_DYNIFTL)
 		return (0);
-	dyn = pool_get(&pfi_addr_pl, PR_NOWAIT);
-	if (dyn == NULL)
+	if ((dyn = pool_get(&pfi_addr_pl, PR_NOWAIT)) == NULL)
 		return (1);
 	bzero(dyn, sizeof(*dyn));
 
 	s = splsoftnet();
-	dyn->pfid_kif = pfi_attach_rule(aw->v.ifname);
-	if (dyn->pfid_kif == NULL)
-		senderr(1);
+	if (!strcmp(aw->v.ifname, "self"))
+		dyn->pfid_kif = pfi_kif_get(IFG_ALL);
+	else
+		dyn->pfid_kif = pfi_kif_get(aw->v.ifname);
+	if (dyn->pfid_kif == NULL) {
+		rv = 1;
+		goto _bad;
+	}
+	pfi_kif_ref(dyn->pfid_kif, PFI_KIF_REF_RULE);
 
 	dyn->pfid_net = pfi_unmask(&aw->v.a.mask);
 	if (af == AF_INET && dyn->pfid_net == 32)
@@ -537,24 +477,23 @@
 	if (dyn->pfid_net != 128)
 		snprintf(tblname + strlen(tblname),
 		    sizeof(tblname) - strlen(tblname), "/%d", dyn->pfid_net);
-	ruleset = pf_find_or_create_ruleset(PF_RESERVED_ANCHOR);
-	if (ruleset == NULL)
-		senderr(1);
-
-	dyn->pfid_kt = pfr_attach_table(ruleset, tblname);
-	if (dyn->pfid_kt == NULL)
-		senderr(1);
+	if ((ruleset = pf_find_or_create_ruleset(PF_RESERVED_ANCHOR)) == NULL) {
+		rv = 1;
+		goto _bad;
+	}
+
+	if ((dyn->pfid_kt = pfr_attach_table(ruleset, tblname)) == NULL) {
+		rv = 1;
+		goto _bad;
+	}
 
 	dyn->pfid_kt->pfrkt_flags |= PFR_TFLAG_ACTIVE;
 	dyn->pfid_iflags = aw->iflags;
 	dyn->pfid_af = af;
-	dyn->pfid_hook_cookie = hook_establish(dyn->pfid_kif->pfik_ah_head, 1,
-	    pfi_dynaddr_update, dyn);
-	if (dyn->pfid_hook_cookie == NULL)
-		senderr(1);
 
+	TAILQ_INSERT_TAIL(&dyn->pfid_kif->pfik_dynaddrs, dyn, entry);
 	aw->p.dyn = dyn;
-	pfi_dynaddr_update(aw->p.dyn);
+	pfi_kif_update(dyn->pfid_kif);
 	splx(s);
 	return (0);
 
@@ -564,16 +503,32 @@
 	if (ruleset != NULL)
 		pf_remove_if_empty_ruleset(ruleset);
 	if (dyn->pfid_kif != NULL)
-		pfi_detach_rule(dyn->pfid_kif);
+		pfi_kif_unref(dyn->pfid_kif, PFI_KIF_REF_RULE);
 	pool_put(&pfi_addr_pl, dyn);
 	splx(s);
 	return (rv);
 }
 
 void
-pfi_dynaddr_update(void *p)
+pfi_kif_update(struct pfi_kif *kif)
+{
+	struct ifg_list		*ifgl;
+	struct pfi_dynaddr	*p;
+
+	/* update all dynaddr */
+	TAILQ_FOREACH(p, &kif->pfik_dynaddrs, entry)
+		pfi_dynaddr_update(p);
+
+	/* again for all groups kif is member of */
+	if (kif->pfik_ifp != NULL)
+		TAILQ_FOREACH(ifgl, &kif->pfik_ifp->if_groups, ifgl_next)
+			pfi_kif_update((struct pfi_kif *)
+			    ifgl->ifgl_group->ifg_pf_kif);
+}
+
+void
+pfi_dynaddr_update(struct pfi_dynaddr *dyn)
 {
-	struct pfi_dynaddr	*dyn = (struct pfi_dynaddr *)p;
 	struct pfi_kif		*kif;
 	struct pfr_ktable	*kt;
 
@@ -582,6 +537,7 @@
 
 	kif = dyn->pfid_kif;
 	kt = dyn->pfid_kt;
+
 	if (kt->pfrkt_larg != pfi_update) {
 		/* this table needs to be brought up-to-date */
 		pfi_table_update(kt, kif, dyn->pfid_net, dyn->pfid_iflags);
@@ -594,28 +550,18 @@
 pfi_table_update(struct pfr_ktable *kt, struct pfi_kif *kif, int net, int flags)
 {
 	int			 e, size2 = 0;
-	struct pfi_kif		*p;
-	struct pfr_table	 t;
+	struct ifg_member	*ifgm;
 
-	if ((kif->pfik_flags & PFI_IFLAG_INSTANCE) && kif->pfik_ifp == NULL) {
-		pfr_clr_addrs(&kt->pfrkt_t, NULL, 0);
-		return;
-	}
 	pfi_buffer_cnt = 0;
-	if ((kif->pfik_flags & PFI_IFLAG_INSTANCE))
+
+	if (kif->pfik_ifp != NULL)
 		pfi_instance_add(kif->pfik_ifp, net, flags);
-	else if (strcmp(kif->pfik_name, "self")) {
-		TAILQ_FOREACH(p, &kif->pfik_grouphead, pfik_instances)
-			pfi_instance_add(p->pfik_ifp, net, flags);
-	} else {
-		RB_FOREACH(p, pfi_ifhead, &pfi_ifs)
-			if (p->pfik_flags & PFI_IFLAG_INSTANCE)
-				pfi_instance_add(p->pfik_ifp, net, flags);
-	}
-	t = kt->pfrkt_t;
-	t.pfrt_flags = 0;
-	if ((e = pfr_set_addrs(&t, pfi_buffer, pfi_buffer_cnt, &size2,
-	    NULL, NULL, NULL, 0)))
+	else if (kif->pfik_group != NULL)
+		TAILQ_FOREACH(ifgm, &kif->pfik_group->ifg_members, ifgm_next)
+			pfi_instance_add(ifgm->ifgm_ifp, net, flags);
+
+	if ((e = pfr_set_addrs(&kt->pfrkt_t, pfi_buffer, pfi_buffer_cnt, &size2,
+	    NULL, NULL, NULL, 0, PFR_TFLAG_ALLMASK)))
 		printf("pfi_table_update: cannot set %d new addresses "
 		    "into table %s: %d\n", pfi_buffer_cnt, kt->pfrkt_name, e);
 }
@@ -671,13 +617,12 @@
 			got6 = 1;
 		net2 = net;
 		if (net2 == 128 && (flags & PFI_AFLAG_NETWORK)) {
-			if (af == AF_INET) {
+			if (af == AF_INET)
 				net2 = pfi_unmask(&((struct sockaddr_in *)
 				    ia->ifa_netmask)->sin_addr);
-			} else if (af == AF_INET6) {
+			else if (af == AF_INET6)
 				net2 = pfi_unmask(&((struct sockaddr_in6 *)
 				    ia->ifa_netmask)->sin6_addr);
-			}
 		}
 		if (af == AF_INET && net2 > 32)
 			net2 = 32;
@@ -704,11 +649,10 @@
 			    pfi_buffer_cnt, PFI_BUFFER_MAX);
 			return;
 		}
-#ifdef __FreeBSD__
 		p = malloc(new_max * sizeof(*pfi_buffer), PFI_MTYPE,
+#ifdef __FreeBSD__
 		    M_NOWAIT);
 #else
-		p = malloc(new_max * sizeof(*pfi_buffer), PFI_MTYPE,
 		    M_DONTWAIT);
 #endif
 		if (p == NULL) {
@@ -730,9 +674,9 @@
 	p->pfra_net = net;
 	if (af == AF_INET)
 		p->pfra_ip4addr = ((struct sockaddr_in *)sa)->sin_addr;
-	if (af == AF_INET6) {
+	else if (af == AF_INET6) {
 		p->pfra_ip6addr = ((struct sockaddr_in6 *)sa)->sin6_addr;
-		if (IN6_IS_ADDR_LINKLOCAL(&p->pfra_ip6addr))
+		if (IN6_IS_SCOPE_EMBED(&p->pfra_ip6addr))
 			p->pfra_ip6addr.s6_addr16[1] = 0;
 	}
 	/* mask network address bits */
@@ -752,9 +696,8 @@
 		return;
 
 	s = splsoftnet();
-	hook_disestablish(aw->p.dyn->pfid_kif->pfik_ah_head,
-	    aw->p.dyn->pfid_hook_cookie);
-	pfi_detach_rule(aw->p.dyn->pfid_kif);
+	TAILQ_REMOVE(&aw->p.dyn->pfid_kif->pfik_dynaddrs, aw->p.dyn, entry);
+	pfi_kif_unref(aw->p.dyn->pfid_kif, PFI_KIF_REF_RULE);
 	aw->p.dyn->pfid_kif = NULL;
 	pfr_detach_table(aw->p.dyn->pfid_kt);
 	aw->p.dyn->pfid_kt = NULL;
@@ -775,11 +718,12 @@
 void
 pfi_kifaddr_update(void *v)
 {
-	int		 s;
+	int			 s;
+	struct pfi_kif		*kif = (struct pfi_kif *)v;
 
 	s = splsoftnet();
 	pfi_update++;
-	pfi_dohooks(v);
+	pfi_kif_update(kif);
 	splx(s);
 }
 
@@ -789,149 +733,16 @@
 	return (strncmp(p->pfik_name, q->pfik_name, IFNAMSIZ));
 }
 
-struct pfi_kif *
-pfi_if_create(const char *name, struct pfi_kif *q, int flags)
-{
-	struct pfi_kif *p;
-
-#ifdef __FreeBSD__
-	p = malloc(sizeof(*p), PFI_MTYPE, M_NOWAIT);
-#else
-	p = malloc(sizeof(*p), PFI_MTYPE, M_DONTWAIT);
-#endif
-	if (p == NULL)
-		return (NULL);
-	bzero(p, sizeof(*p));
-#ifdef __FreeBSD__
-	p->pfik_ah_head = malloc(sizeof(*p->pfik_ah_head), PFI_MTYPE,
-	    M_NOWAIT);
-#else
-	p->pfik_ah_head = malloc(sizeof(*p->pfik_ah_head), PFI_MTYPE,
-	    M_DONTWAIT);
-#endif
-	if (p->pfik_ah_head == NULL) {
-		free(p, PFI_MTYPE);
-		return (NULL);
-	}
-	bzero(p->pfik_ah_head, sizeof(*p->pfik_ah_head));
-	TAILQ_INIT(p->pfik_ah_head);
-	TAILQ_INIT(&p->pfik_grouphead);
-	strlcpy(p->pfik_name, name, sizeof(p->pfik_name));
-	RB_INIT(&p->pfik_lan_ext);
-	RB_INIT(&p->pfik_ext_gwy);
-	p->pfik_flags = flags;
-	p->pfik_parent = q;
-#ifdef __FreeBSD__
-	/*
-	 * It seems that the value of time_second is in unintialzied state when
-	 * pf sets interface statistics clear time in boot phase if pf was
-	 * statically linked to kernel. Instead of setting the bogus time value
-	 * have pfi_get_ifaces handle this case. In pfi_get_ifaces it uses
-	 * boottime.tv_sec if it sees the time is 0.
-	 */
-	p->pfik_tzero = time_second > 1 ? time_second : 0;
-#else
-	p->pfik_tzero = time_second;
-#endif
-
-	RB_INSERT(pfi_ifhead, &pfi_ifs, p);
-	if (q != NULL) {
-		q->pfik_addcnt++;
-		TAILQ_INSERT_TAIL(&q->pfik_grouphead, p, pfik_instances);
-	}
-	pfi_ifcnt++;
-	return (p);
-}
-
-int
-pfi_maybe_destroy(struct pfi_kif *p)
-{
-	int		 i, j, k, s;
-	struct pfi_kif	*q = p->pfik_parent;
-
-#ifdef __FreeBSD__
-	if ((p->pfik_flags & (PFI_IFLAG_ATTACHED | PFI_IFLAG_GROUP)) ||
-	    ((p->pfik_rules > 0 || p->pfik_states > 0) &&
-	     (p->pfik_flags & PFI_IFLAG_PLACEHOLDER) == 0))
-#else
-	if ((p->pfik_flags & (PFI_IFLAG_ATTACHED | PFI_IFLAG_GROUP)) ||
-	    p->pfik_rules > 0 || p->pfik_states > 0)
-#endif
-		return (0);
-
-	s = splsoftnet();
-	if (q != NULL) {
-		for (i = 0; i < 2; i++)
-			for (j = 0; j < 2; j++)
-				for (k = 0; k < 2; k++) {
-					q->pfik_bytes[i][j][k] +=
-					    p->pfik_bytes[i][j][k];
-					q->pfik_packets[i][j][k] +=
-					    p->pfik_packets[i][j][k];
-#ifdef __FreeBSD__
-			/* clear stats in case we return to the dummy group */
-					p->pfik_bytes[i][j][k] = 0;
-					p->pfik_packets[i][j][k] = 0;
-#endif
-				}
-		q->pfik_delcnt++;
-		TAILQ_REMOVE(&q->pfik_grouphead, p, pfik_instances);
-	}
-#ifdef __FreeBSD__
-	if (p->pfik_rules > 0 || p->pfik_states > 0) {
-		/* move back to the dummy group */
-		p->pfik_parent = pfi_dummy;
-		p->pfik_flags &= ~PFI_IFLAG_INSTANCE;
-		pfi_dummy->pfik_addcnt++;
-		TAILQ_INSERT_TAIL(&pfi_dummy->pfik_grouphead, p,
-		    pfik_instances);
-		return (0);
-	}
-#endif
-	pfi_ifcnt--;
-	RB_REMOVE(pfi_ifhead, &pfi_ifs, p);
-	splx(s);
-
-	free(p->pfik_ah_head, PFI_MTYPE);
-	free(p, PFI_MTYPE);
-	return (1);
-}
-
-void
-pfi_copy_group(char *p, const char *q, int m)
-{
-	while (m > 1 && *q && !(*q >= '0' && *q <= '9')) {
-		*p++ = *q++;
-		m--;
-	}
-	if (m > 0)
-		*p++ = '\0';
-}
-
-void
-pfi_newgroup(const char *name, int flags)
-{
-	struct pfi_kif	*p;
-
-	p = pfi_lookup_if(name);
-	if (p == NULL)
-		p = pfi_if_create(name, pfi_self, PFI_IFLAG_GROUP);
-	if (p == NULL) {
-		printf("pfi_newgroup: cannot allocate '%s' group", name);
-		return;
-	}
-	p->pfik_flags |= flags;
-}
-
 void
 pfi_fill_oldstatus(struct pf_status *pfs)
 {
-	struct pfi_kif	*p, key;
-	int		 i, j, k, s;
+	struct pfi_kif		*p;
+	struct pfi_kif_cmp 	 key;
+	int			 i, j, k, s;
 
 	strlcpy(key.pfik_name, pfs->ifname, sizeof(key.pfik_name));
 	s = splsoftnet();
-	p = RB_FIND(pfi_ifhead, &pfi_ifs, &key);
+	p = RB_FIND(pfi_ifhead, &pfi_ifs, (struct pfi_kif *)&key);
 	if (p == NULL) {
 		splx(s);
 		return;
@@ -950,92 +761,54 @@
 }
 
 int
-pfi_clr_istats(const char *name, int *nzero, int flags)
+pfi_clr_istats(const char *name)
 {
 	struct pfi_kif	*p;
-	int		 n = 0, s;
-	long		 tzero = time_second;
+	int		 s;
 
-	ACCEPT_FLAGS(PFI_FLAG_GROUP|PFI_FLAG_INSTANCE);
 	s = splsoftnet();
 	RB_FOREACH(p, pfi_ifhead, &pfi_ifs) {
-		if (pfi_skip_if(name, p, flags))
+		if (pfi_skip_if(name, p))
 			continue;
 		bzero(p->pfik_packets, sizeof(p->pfik_packets));
 		bzero(p->pfik_bytes, sizeof(p->pfik_bytes));
-		p->pfik_tzero = tzero;
-		n++;
-	}
-	splx(s);
-	if (nzero != NULL)
-		*nzero = n;
-	return (0);
-}
-
-int
-pfi_set_flags(const char *name, int flags)
-{
-	struct pfi_kif	*p;
-	int		 s;
-
-	if (flags & ~PFI_IFLAG_SETABLE_MASK)
-		return (EINVAL);
-
-	s = splsoftnet();
-	RB_FOREACH(p, pfi_ifhead, &pfi_ifs) {
-		if (pfi_skip_if(name, p, PFI_FLAG_GROUP|PFI_FLAG_INSTANCE))
-			continue;
-		p->pfik_flags |= flags;
+		p->pfik_tzero = time_second;
 	}
 	splx(s);
-	return (0);
-}
-
-int
-pfi_clear_flags(const char *name, int flags)
-{
-	struct pfi_kif	*p;
-	int		 s;
-
-	if (flags & ~PFI_IFLAG_SETABLE_MASK)
-		return (EINVAL);
 
-	s = splsoftnet();
-	RB_FOREACH(p, pfi_ifhead, &pfi_ifs) {
-		if (pfi_skip_if(name, p, PFI_FLAG_GROUP|PFI_FLAG_INSTANCE))
-			continue;
-		p->pfik_flags &= ~flags;
-	}
-	splx(s);
 	return (0);
 }
 
 int
-pfi_get_ifaces(const char *name, struct pfi_if *buf, int *size, int flags)
+pfi_get_ifaces(const char *name, struct pfi_kif *buf, int *size)
 {
-	struct pfi_kif	*p;
+	struct pfi_kif	*p, *nextp;
 	int		 s, n = 0;
 #ifdef __FreeBSD__
-	int		 ec;
+	int		 error;
 #endif
 
-	ACCEPT_FLAGS(PFI_FLAG_GROUP|PFI_FLAG_INSTANCE);
 	s = splsoftnet();
-	RB_FOREACH(p, pfi_ifhead, &pfi_ifs) {
-		if (pfi_skip_if(name, p, flags))
+	for (p = RB_MIN(pfi_ifhead, &pfi_ifs); p; p = nextp) {
+		nextp = RB_NEXT(pfi_ifhead, &pfi_ifs, p);
+		if (pfi_skip_if(name, p))
 			continue;
 		if (*size > n++) {
 			if (!p->pfik_tzero)
 				p->pfik_tzero = time_second;
+			pfi_kif_ref(p, PFI_KIF_REF_RULE);
 #ifdef __FreeBSD__
-			PF_COPYOUT(p, buf++, sizeof(*buf), ec);
-			if (ec) {
+			PF_COPYOUT(p, buf++, sizeof(*buf), error);
+			if (error) {
 #else
 			if (copyout(p, buf++, sizeof(*buf))) {
 #endif
+				pfi_kif_unref(p, PFI_KIF_REF_RULE);
 				splx(s);
 				return (EFAULT);
 			}
+			nextp = RB_NEXT(pfi_ifhead, &pfi_ifs, p);
+			pfi_kif_unref(p, PFI_KIF_REF_RULE);
 		}
 	}
 	splx(s);
@@ -1043,25 +816,11 @@
 	return (0);
 }
 
-struct pfi_kif *
-pfi_lookup_if(const char *name)
-{
-	struct pfi_kif	*p, key;
-
-	strlcpy(key.pfik_name, name, sizeof(key.pfik_name));
-	p = RB_FIND(pfi_ifhead, &pfi_ifs, &key);
-	return (p);
-}
-
 int
-pfi_skip_if(const char *filter, struct pfi_kif *p, int f)
+pfi_skip_if(const char *filter, struct pfi_kif *p)
 {
 	int	n;
 
-	if ((p->pfik_flags & PFI_IFLAG_GROUP) && !(f & PFI_FLAG_GROUP))
-		return (1);
-	if ((p->pfik_flags & PFI_IFLAG_INSTANCE) && !(f & PFI_FLAG_INSTANCE))
-		return (1);
 	if (filter == NULL || !*filter)
 		return (0);
 	if (!strcmp(p->pfik_name, filter))
@@ -1076,6 +835,38 @@
 	return (p->pfik_name[n] < '0' || p->pfik_name[n] > '9');
 }
 
+int
+pfi_set_flags(const char *name, int flags)
+{
+	struct pfi_kif	*p;
+	int		 s;
+
+	s = splsoftnet();
+	RB_FOREACH(p, pfi_ifhead, &pfi_ifs) {
+		if (pfi_skip_if(name, p))
+			continue;
+		p->pfik_flags |= flags;
+	}
+	splx(s);
+	return (0);
+}
+
+int
+pfi_clear_flags(const char *name, int flags)
+{
+	struct pfi_kif	*p;
+	int		 s;
+
+	s = splsoftnet();
+	RB_FOREACH(p, pfi_ifhead, &pfi_ifs) {
+		if (pfi_skip_if(name, p))
+			continue;
+		p->pfik_flags &= ~flags;
+	}
+	splx(s);
+	return (0);
+}
+
 /* from pf_print_state.c */
 int
 pfi_unmask(void *addr)
@@ -1096,44 +887,53 @@
 	return (b);
 }
 
+#ifdef __FreeBSD__
 void
-pfi_dohooks(struct pfi_kif *p)
+pfi_attach_ifnet_event(void *arg __unused, struct ifnet *ifp)
 {
-	for (; p != NULL; p = p->pfik_parent)
-		dohooks(p->pfik_ah_head, 0);
+	PF_LOCK();
+	pfi_attach_ifnet(ifp);
+	PF_UNLOCK();
 }
 
-int
-pfi_match_addr(struct pfi_dynaddr *dyn, struct pf_addr *a, sa_family_t af)
+void
+pfi_detach_ifnet_event(void *arg __unused, struct ifnet *ifp)
 {
-	switch (af) {
-#ifdef INET
-	case AF_INET:
-		switch (dyn->pfid_acnt4) {
-		case 0:
-			return (0);
-		case 1:
-			return (PF_MATCHA(0, &dyn->pfid_addr4,
-			    &dyn->pfid_mask4, a, AF_INET));
-		default:
-			return (pfr_match_addr(dyn->pfid_kt, a, AF_INET));
-		}
-		break;
-#endif /* INET */
-#ifdef INET6
-	case AF_INET6:
-		switch (dyn->pfid_acnt6) {
-		case 0:
-			return (0);
-		case 1:
-			return (PF_MATCHA(0, &dyn->pfid_addr6,
-			    &dyn->pfid_mask6, a, AF_INET6));
-		default:
-			return (pfr_match_addr(dyn->pfid_kt, a, AF_INET6));
-		}
-		break;
-#endif /* INET6 */
-	default:
-		return (0);
-	}
+	PF_LOCK();
+	pfi_detach_ifnet(ifp);
+	PF_UNLOCK();
 }
+
+void
+pfi_attach_group_event(void *arg __unused, struct ifg_group *ifg)
+{
+	PF_LOCK();
+	pfi_attach_ifgroup(ifg);
+	PF_UNLOCK();
+}
+
+void
+pfi_change_group_event(void *arg __unused, char *gname)
+{
+	PF_LOCK();
+	pfi_group_change(gname);
+	PF_UNLOCK();
+}
+
+void
+pfi_detach_group_event(void *arg __unused, struct ifg_group *ifg)
+{
+	PF_LOCK();
+	pfi_detach_ifgroup(ifg);
+	PF_UNLOCK();
+}
+
+void
+pfi_ifaddr_event(void *arg __unused, struct ifnet *ifp)
+{
+	PF_LOCK();
+	if (ifp && ifp->if_pf_kif)
+		pfi_kifaddr_update(ifp->if_pf_kif);
+	PF_UNLOCK();
+}
+#endif /* __FreeBSD__ */
Index: pf.c
===================================================================
RCS file: /home/cvs/src/sys/contrib/pf/net/pf.c,v
retrieving revision 1.1.1.2
retrieving revision 1.2
diff -L sys/contrib/pf/net/pf.c -L sys/contrib/pf/net/pf.c -u -r1.1.1.2 -r1.2
--- sys/contrib/pf/net/pf.c
+++ sys/contrib/pf/net/pf.c
@@ -1,5 +1,4 @@
-/*	$FreeBSD: src/sys/contrib/pf/net/pf.c,v 1.34.2.3 2005/12/30 00:50:18 mlaier Exp $	*/
-/*	$OpenBSD: pf.c,v 1.483 2005/03/15 17:38:43 dhartmei Exp $ */
+/*	$OpenBSD: pf.c,v 1.527 2007/02/22 15:23:23 pyr Exp $ */
 
 /*
  * Copyright (c) 2001 Daniel Hartmeier
@@ -39,15 +38,35 @@
 #ifdef __FreeBSD__
 #include "opt_inet.h"
 #include "opt_inet6.h"
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/sys/contrib/pf/net/pf.c,v 1.46.2.1 2007/11/25 19:26:46 mlaier Exp $");
 #endif
 
 #ifdef __FreeBSD__
+#include "opt_mac.h"
 #include "opt_bpf.h"
 #include "opt_pf.h"
+
+#ifdef DEV_BPF
 #define	NBPFILTER	DEV_BPF
+#else
+#define	NBPFILTER	0
+#endif
+
+#ifdef DEV_PFLOG
 #define	NPFLOG		DEV_PFLOG
+#else
+#define	NPFLOG		0
+#endif
+
+#ifdef DEV_PFSYNC
 #define	NPFSYNC		DEV_PFSYNC
 #else
+#define	NPFSYNC		0
+#endif
+
+#else
 #include "bpfilter.h"
 #include "pflog.h"
 #include "pfsync.h"
@@ -67,11 +86,22 @@
 #else
 #include <sys/pool.h>
 #endif
+#include <sys/proc.h>
+#ifdef __FreeBSD__
+#include <sys/kthread.h>
+#include <sys/lock.h>
+#include <sys/sx.h>
+#else
+#include <sys/rwlock.h>
+#endif
 
 #include <net/if.h>
 #include <net/if_types.h>
 #include <net/bpf.h>
 #include <net/route.h>
+#ifndef __FreeBSD__
+#include <net/radix_mpath.h>
+#endif
 
 #include <netinet/in.h>
 #include <netinet/in_var.h>
@@ -114,8 +144,10 @@
 #include <machine/in_cksum.h>
 #include <sys/limits.h>
 #include <sys/ucred.h>
+#include <security/mac/mac_framework.h>
 
 extern int ip_optcopy(struct ip *, struct ip *);
+extern int debug_pfugidhack;
 #endif
 
 #define DPFPRINTF(n, x)	if (pf_status.debug >= (n)) printf x
@@ -124,8 +156,6 @@
  * Global variables
  */
 
-struct pf_anchor_global	 pf_anchors;
-struct pf_ruleset	 pf_main_ruleset;
 struct pf_altqqueue	 pf_altqs[2];
 struct pf_palist	 pf_pabuf;
 struct pf_altqqueue	*pf_altqs_active;
@@ -137,12 +167,6 @@
 int			 altqs_inactive_open;
 u_int32_t		 ticket_pabuf;
 
-#ifdef __FreeBSD__
-struct callout	 	 pf_expire_to;			/* expire timeout */
-#else
-struct timeout		 pf_expire_to;			/* expire timeout */
-#endif
-
 struct pf_anchor_stackframe {
 	struct pf_ruleset			*rs;
 	struct pf_rule				*r;
@@ -168,6 +192,8 @@
 void			 pf_change_ap(struct pf_addr *, u_int16_t *,
 			    u_int16_t *, u_int16_t *, struct pf_addr *,
 			    u_int16_t, u_int8_t, sa_family_t);
+int			 pf_modulate_sack(struct mbuf *, int, struct pf_pdesc *,
+			    struct tcphdr *, struct pf_state_peer *);
 #ifdef INET6
 void			 pf_change_a6(struct pf_addr *, u_int16_t *,
 			    struct pf_addr *, u_int8_t);
@@ -176,11 +202,16 @@
 			    struct pf_addr *, struct pf_addr *, u_int16_t,
 			    u_int16_t *, u_int16_t *, u_int16_t *,
 			    u_int16_t *, u_int8_t, sa_family_t);
+#ifdef __FreeBSD__
+void			 pf_send_tcp(struct mbuf *,
+			    const struct pf_rule *, sa_family_t,
+#else
 void			 pf_send_tcp(const struct pf_rule *, sa_family_t,
+#endif
 			    const struct pf_addr *, const struct pf_addr *,
 			    u_int16_t, u_int16_t, u_int32_t, u_int32_t,
 			    u_int8_t, u_int16_t, u_int16_t, u_int8_t, int,
-			    struct ether_header *, struct ifnet *);
+			    u_int16_t, struct ether_header *, struct ifnet *);
 void			 pf_send_icmp(struct mbuf *, u_int8_t, u_int8_t,
 			    sa_family_t, struct pf_rule *);
 struct pf_rule		*pf_match_translation(struct pf_pdesc *, struct mbuf *,
@@ -233,9 +264,11 @@
 			    void *, struct pf_pdesc *, u_short *);
 int			 pf_test_state_other(struct pf_state **, int,
 			    struct pfi_kif *, struct pf_pdesc *);
-struct pf_tag		*pf_get_tag(struct mbuf *);
 int			 pf_match_tag(struct mbuf *, struct pf_rule *,
-			     struct pf_tag **, int *);
+			     struct pf_mtag *, int *);
+int			 pf_step_out_of_anchor(int *, struct pf_ruleset **,
+			     int, struct pf_rule **, struct pf_rule **,
+			     int *);
 void			 pf_hash(struct pf_addr *, struct pf_addr *,
 			    struct pf_poolhashkey *, sa_family_t);
 int			 pf_map_addr(u_int8_t, struct pf_rule *,
@@ -246,15 +279,15 @@
 			    struct pf_addr *, u_int16_t*, u_int16_t, u_int16_t,
 			    struct pf_src_node **);
 void			 pf_route(struct mbuf **, struct pf_rule *, int,
-			    struct ifnet *, struct pf_state *);
+			    struct ifnet *, struct pf_state *,
+			    struct pf_pdesc *);
 void			 pf_route6(struct mbuf **, struct pf_rule *, int,
-			    struct ifnet *, struct pf_state *);
+			    struct ifnet *, struct pf_state *,
+			    struct pf_pdesc *);
 #ifdef __FreeBSD__
-int			 pf_socket_lookup(uid_t *, gid_t *,
-			    int, struct pf_pdesc *, struct inpcb *);
+/* XXX: import */
 #else
-int			 pf_socket_lookup(uid_t *, gid_t *,
-			    int, struct pf_pdesc *);
+int			 pf_socket_lookup(int, struct pf_pdesc *);
 #endif
 u_int8_t		 pf_get_wscale(struct mbuf *, int, u_int16_t,
 			    sa_family_t);
@@ -268,22 +301,27 @@
 			    u_int8_t, sa_family_t);
 int			 pf_addr_wrap_neq(struct pf_addr_wrap *,
 			    struct pf_addr_wrap *);
-static int		 pf_add_mbuf_tag(struct mbuf *, u_int);
 struct pf_state		*pf_find_state_recurse(struct pfi_kif *,
-			    struct pf_state *, u_int8_t);
+			    struct pf_state_cmp *, u_int8_t);
 int			 pf_src_connlimit(struct pf_state **);
 int			 pf_check_congestion(struct ifqueue *);
 
 #ifdef __FreeBSD__
 int in4_cksum(struct mbuf *m, u_int8_t nxt, int off, int len);
 
-struct pf_pool_limit pf_pool_limits[PF_LIMIT_MAX];
+extern int pf_end_threads;
 
+struct pf_pool_limit pf_pool_limits[PF_LIMIT_MAX];
 #else
+extern struct pool pfr_ktable_pl;
+extern struct pool pfr_kentry_pl;
+
 struct pf_pool_limit pf_pool_limits[PF_LIMIT_MAX] = {
 	{ &pf_state_pl, PFSTATE_HIWAT },
 	{ &pf_src_tree_pl, PFSNODE_HIWAT },
-	{ &pf_frent_pl, PFFRAG_FRENT_HIWAT }
+	{ &pf_frent_pl, PFFRAG_FRENT_HIWAT },
+	{ &pfr_ktable_pl, PFR_KTABLE_HIWAT },
+	{ &pfr_kentry_pl, PFR_KENTRY_HIWAT }
 };
 #endif
 
@@ -315,9 +353,8 @@
 	(s)->lan.addr.addr32[3] != (s)->gwy.addr.addr32[3])) || \
 	(s)->lan.port != (s)->gwy.port
 
-#define BOUND_IFACE(r, k) (((r)->rule_flag & PFRULE_IFBOUND) ? (k) :   \
-	((r)->rule_flag & PFRULE_GRBOUND) ? (k)->pfik_parent :	       \
-	(k)->pfik_parent->pfik_parent)
+#define BOUND_IFACE(r, k) \
+	((r)->rule_flag & PFRULE_IFBOUND) ? (k) : pfi_all
 
 #define STATE_INC_COUNTERS(s)				\
 	do {						\
@@ -337,30 +374,17 @@
 		s->rule.ptr->states--;			\
 	} while (0)
 
-#ifndef __FreeBSD__
-static __inline int pf_src_compare(struct pf_src_node *, struct pf_src_node *);
-static __inline int pf_state_compare_lan_ext(struct pf_state *,
-	struct pf_state *);
-static __inline int pf_state_compare_ext_gwy(struct pf_state *,
-	struct pf_state *);
-static __inline int pf_state_compare_id(struct pf_state *,
-	struct pf_state *);
-static __inline int pf_anchor_compare(struct pf_anchor *, struct pf_anchor *);
-#else
-static int pf_src_compare(struct pf_src_node *, struct pf_src_node *);
-static int pf_state_compare_lan_ext(struct pf_state *,
-	struct pf_state *);
-static int pf_state_compare_ext_gwy(struct pf_state *,
-	struct pf_state *);
-static int pf_state_compare_id(struct pf_state *,
-	struct pf_state *);
-static int pf_anchor_compare(struct pf_anchor *, struct pf_anchor *);
-#endif
-
 struct pf_src_tree tree_src_tracking;
 
 struct pf_state_tree_id tree_id;
-struct pf_state_queue state_updates;
+struct pf_state_queue state_list;
+
+#ifdef __FreeBSD__
+static int pf_src_compare(struct pf_src_node *, struct pf_src_node *);
+static int pf_state_compare_lan_ext(struct pf_state *, struct pf_state *);
+static int pf_state_compare_ext_gwy(struct pf_state *, struct pf_state *);
+static int pf_state_compare_id(struct pf_state *, struct pf_state *);
+#endif
 
 RB_GENERATE(pf_src_tree, pf_src_node, entry, pf_src_compare);
 RB_GENERATE(pf_state_tree_lan_ext, pf_state,
@@ -369,8 +393,6 @@
     u.s.entry_ext_gwy, pf_state_compare_ext_gwy);
 RB_GENERATE(pf_state_tree_id, pf_state,
     u.s.entry_id, pf_state_compare_id);
-RB_GENERATE(pf_anchor_global, pf_anchor, entry_global, pf_anchor_compare);
-RB_GENERATE(pf_anchor_node, pf_anchor, entry_node, pf_anchor_compare);
 
 #ifdef __FreeBSD__
 static int
@@ -583,18 +605,6 @@
 	return (0);
 }
 
-#ifdef __FreeBSD__
-static int
-#else
-static __inline int
-#endif
-pf_anchor_compare(struct pf_anchor *a, struct pf_anchor *b)
-{
-	int c = strcmp(a->path, b->path);
-
-	return (c ? (c < 0 ? -1 : 1) : 0);
-}
-
 #ifdef INET6
 void
 pf_addrcpy(struct pf_addr *dst, struct pf_addr *src, sa_family_t af)
@@ -616,14 +626,14 @@
 #endif /* INET6 */
 
 struct pf_state *
-pf_find_state_byid(struct pf_state *key)
+pf_find_state_byid(struct pf_state_cmp *key)
 {
 	pf_status.fcounters[FCNT_STATE_SEARCH]++;
-	return (RB_FIND(pf_state_tree_id, &tree_id, key));
+	return (RB_FIND(pf_state_tree_id, &tree_id, (struct pf_state *)key));
 }
 
 struct pf_state *
-pf_find_state_recurse(struct pfi_kif *kif, struct pf_state *key, u_int8_t tree)
+pf_find_state_recurse(struct pfi_kif *kif, struct pf_state_cmp *key, u_int8_t tree)
 {
 	struct pf_state *s;
 
@@ -631,20 +641,20 @@
 
 	switch (tree) {
 	case PF_LAN_EXT:
-		for (; kif != NULL; kif = kif->pfik_parent) {
-			s = RB_FIND(pf_state_tree_lan_ext,
-			    &kif->pfik_lan_ext, key);
-			if (s != NULL)
-				return (s);
-		}
+		if ((s = RB_FIND(pf_state_tree_lan_ext, &kif->pfik_lan_ext,
+		    (struct pf_state *)key)) != NULL)
+			return (s);
+		if ((s = RB_FIND(pf_state_tree_lan_ext, &pfi_all->pfik_lan_ext,
+		    (struct pf_state *)key)) != NULL)
+			return (s);
 		return (NULL);
 	case PF_EXT_GWY:
-		for (; kif != NULL; kif = kif->pfik_parent) {
-			s = RB_FIND(pf_state_tree_ext_gwy,
-			    &kif->pfik_ext_gwy, key);
-			if (s != NULL)
-				return (s);
-		}
+		if ((s = RB_FIND(pf_state_tree_ext_gwy, &kif->pfik_ext_gwy,
+		    (struct pf_state *)key)) != NULL)
+			return (s);
+		if ((s = RB_FIND(pf_state_tree_ext_gwy, &pfi_all->pfik_ext_gwy,
+		    (struct pf_state *)key)) != NULL)
+			return (s);
 		return (NULL);
 	default:
 		panic("pf_find_state_recurse");
@@ -652,7 +662,7 @@
 }
 
 struct pf_state *
-pf_find_state_all(struct pf_state *key, u_int8_t tree, int *more)
+pf_find_state_all(struct pf_state_cmp *key, u_int8_t tree, int *more)
 {
 	struct pf_state *s, *ss = NULL;
 	struct pfi_kif	*kif;
@@ -663,7 +673,7 @@
 	case PF_LAN_EXT:
 		TAILQ_FOREACH(kif, &pfi_statehead, pfik_w_states) {
 			s = RB_FIND(pf_state_tree_lan_ext,
-			    &kif->pfik_lan_ext, key);
+			    &kif->pfik_lan_ext, (struct pf_state *)key);
 			if (s == NULL)
 				continue;
 			if (more == NULL)
@@ -675,7 +685,7 @@
 	case PF_EXT_GWY:
 		TAILQ_FOREACH(kif, &pfi_statehead, pfik_w_states) {
 			s = RB_FIND(pf_state_tree_ext_gwy,
-			    &kif->pfik_ext_gwy, key);
+			    &kif->pfik_ext_gwy, (struct pf_state *)key);
 			if (s == NULL)
 				continue;
 			if (more == NULL)
@@ -726,9 +736,7 @@
 	int bad = 0;
 
 	(*state)->src_node->conn++;
-#ifdef __FreeBSD__
-	(*state)->local_flags |= PFSTATE_SRC_CONN;
-#endif
+	(*state)->src.tcp_est = 1;
 	pf_add_threshold(&(*state)->src_node->conn_rate);
 
 	if ((*state)->rule.ptr->max_src_conn &&
@@ -949,11 +957,10 @@
 		RB_REMOVE(pf_state_tree_ext_gwy, &kif->pfik_ext_gwy, state);
 		return (-1);
 	}
-	TAILQ_INSERT_HEAD(&state_updates, state, u.s.entry_updates);
-
+	TAILQ_INSERT_TAIL(&state_list, state, u.s.entry_list);
 	pf_status.fcounters[FCNT_STATE_INSERT]++;
 	pf_status.states++;
-	pfi_attach_state(kif);
+	pfi_kif_ref(kif, PFI_KIF_REF_STATE);
 #if NPFSYNC
 	pfsync_insert_state(state);
 #endif
@@ -961,33 +968,48 @@
 }
 
 void
-pf_purge_timeout(void *arg)
+pf_purge_thread(void *v)
 {
-#ifdef __FreeBSD__
-	struct callout  *to = arg;
-#else
-	struct timeout	*to = arg;
-#endif
-	int		 s;
+	int nloops = 0, s;
+
+	for (;;) {
+		tsleep(pf_purge_thread, PWAIT, "pftm", 1 * hz);
 
 #ifdef __FreeBSD__
-	PF_LOCK();
-#endif
-	s = splsoftnet();
-	pf_purge_expired_states();
-	pf_purge_expired_fragments();
-	pf_purge_expired_src_nodes();
-	splx(s);
-#ifdef __FreeBSD__
-	PF_UNLOCK();
+		sx_slock(&pf_consistency_lock);
+		PF_LOCK();
+
+		if (pf_end_threads) {
+			pf_purge_expired_states(pf_status.states);
+			pf_purge_expired_fragments();
+			pf_purge_expired_src_nodes(0);
+			pf_end_threads++;
+
+			sx_sunlock(&pf_consistency_lock);
+			PF_UNLOCK();
+			wakeup(pf_purge_thread);
+			kthread_exit(0);
+		}
 #endif
+		s = splsoftnet();
 
+		/* process a fraction of the state table every second */
+		pf_purge_expired_states(1 + (pf_status.states
+		    / pf_default_rule.timeout[PFTM_INTERVAL]));
+
+		/* purge other expired types every PFTM_INTERVAL seconds */
+		if (++nloops >= pf_default_rule.timeout[PFTM_INTERVAL]) {
+			pf_purge_expired_fragments();
+			pf_purge_expired_src_nodes(0);
+			nloops = 0;
+		}
+
+		splx(s);
 #ifdef __FreeBSD__
-	callout_reset(to, pf_default_rule.timeout[PFTM_INTERVAL] * hz,
-	    pf_purge_timeout, to);
-#else
-	timeout_add(to, pf_default_rule.timeout[PFTM_INTERVAL] * hz);
+		PF_UNLOCK();
+		sx_sunlock(&pf_consistency_lock);
 #endif
+	}
 }
 
 u_int32_t
@@ -1004,9 +1026,12 @@
 	if (state->timeout == PFTM_UNTIL_PACKET)
 		return (0);
 #ifdef __FreeBSD__	
+	KASSERT(state->timeout != PFTM_UNLINKED,
+	    ("pf_state_expires: timeout == PFTM_UNLINKED"));
 	KASSERT((state->timeout < PFTM_MAX), 
 	    ("pf_state_expires: timeout > PFTM_MAX"));
 #else
+	KASSERT(state->timeout != PFTM_UNLINKED);
 	KASSERT(state->timeout < PFTM_MAX);
 #endif
 	timeout = state->rule.ptr->timeout[state->timeout];
@@ -1032,14 +1057,30 @@
 }
 
 void
-pf_purge_expired_src_nodes(void)
+pf_purge_expired_src_nodes(int waslocked)
 {
 	 struct pf_src_node		*cur, *next;
+	 int				 locked = waslocked;
 
 	 for (cur = RB_MIN(pf_src_tree, &tree_src_tracking); cur; cur = next) {
 		 next = RB_NEXT(pf_src_tree, &tree_src_tracking, cur);
 
 		 if (cur->states <= 0 && cur->expire <= time_second) {
+			 if (! locked) {
+#ifdef __FreeBSD__
+				 if (!sx_try_upgrade(&pf_consistency_lock)) {
+					 PF_UNLOCK();
+					 sx_sunlock(&pf_consistency_lock);
+					 sx_xlock(&pf_consistency_lock);
+					 PF_LOCK();
+				 }
+#else
+				 rw_enter_write(&pf_consistency_lock);
+#endif
+			 	 next = RB_NEXT(pf_src_tree,
+				     &tree_src_tracking, cur);
+				 locked = 1;
+			 }
 			 if (cur->rule.ptr != NULL) {
 				 cur->rule.ptr->src_nodes--;
 				 if (cur->rule.ptr->states <= 0 &&
@@ -1052,6 +1093,13 @@
 			 pool_put(&pf_src_tree_pl, cur);
 		 }
 	 }
+
+	 if (locked && !waslocked)
+#ifdef __FreeBSD__
+		sx_downgrade(&pf_consistency_lock);
+#else
+		rw_exit_write(&pf_consistency_lock);
+#endif
 }
 
 void
@@ -1061,12 +1109,7 @@
 
 	if (s->src_node != NULL) {
 		if (s->proto == IPPROTO_TCP) {
-#ifdef __FreeBSD__
-			if (s->local_flags & PFSTATE_SRC_CONN)
-#else
-			if (s->src.state == PF_TCPS_PROXY_DST ||
-			    s->timeout >= PFTM_TCP_ESTABLISHED)
-#endif
+			if (s->src.tcp_est)
 				--s->src_node->conn;
 		}
 		if (--s->src_node->states <= 0) {
@@ -1089,29 +1132,56 @@
 	s->src_node = s->nat_src_node = NULL;
 }
 
+/* callers should be at splsoftnet */
 void
-pf_purge_expired_state(struct pf_state *cur)
+pf_unlink_state(struct pf_state *cur)
 {
 #ifdef __FreeBSD__
 	if (cur->local_flags & PFSTATE_EXPIRING)
 		return;
 	cur->local_flags |= PFSTATE_EXPIRING;
 #endif
-	if (cur->src.state == PF_TCPS_PROXY_DST)
+	if (cur->src.state == PF_TCPS_PROXY_DST) {
+#ifdef __FreeBSD__
+		pf_send_tcp(NULL, cur->rule.ptr, cur->af,
+#else
 		pf_send_tcp(cur->rule.ptr, cur->af,
+#endif
 		    &cur->ext.addr, &cur->lan.addr,
 		    cur->ext.port, cur->lan.port,
 		    cur->src.seqhi, cur->src.seqlo + 1,
-		    TH_RST|TH_ACK, 0, 0, 0, 1, NULL, NULL);
+		    TH_RST|TH_ACK, 0, 0, 0, 1, cur->tag, NULL, NULL);
+	}
 	RB_REMOVE(pf_state_tree_ext_gwy,
 	    &cur->u.s.kif->pfik_ext_gwy, cur);
 	RB_REMOVE(pf_state_tree_lan_ext,
 	    &cur->u.s.kif->pfik_lan_ext, cur);
 	RB_REMOVE(pf_state_tree_id, &tree_id, cur);
 #if NPFSYNC
-	pfsync_delete_state(cur);
+	if (cur->creatorid == pf_status.hostid)
+		pfsync_delete_state(cur);
 #endif
+	cur->timeout = PFTM_UNLINKED;
 	pf_src_tree_remove_state(cur);
+}
+
+/* callers should be at splsoftnet and hold the
+ * write_lock on pf_consistency_lock */
+void
+pf_free_state(struct pf_state *cur)
+{
+#if NPFSYNC
+	if (pfsyncif != NULL &&
+	    (pfsyncif->sc_bulk_send_next == cur ||
+	    pfsyncif->sc_bulk_terminator == cur))
+		return;
+#endif
+#ifdef __FreeBSD__
+	KASSERT(cur->timeout == PFTM_UNLINKED,
+	    ("pf_free_state: cur->timeout != PFTM_UNLINKED"));
+#else
+	KASSERT(cur->timeout == PFTM_UNLINKED);
+#endif
 	if (--cur->rule.ptr->states <= 0 &&
 	    cur->rule.ptr->src_nodes <= 0)
 		pf_rm_rule(NULL, cur->rule.ptr);
@@ -1123,8 +1193,8 @@
 		if (--cur->anchor.ptr->states <= 0)
 			pf_rm_rule(NULL, cur->anchor.ptr);
 	pf_normalize_tcp_cleanup(cur);
-	pfi_detach_state(cur->u.s.kif);
-	TAILQ_REMOVE(&state_updates, cur, u.s.entry_updates);
+	pfi_kif_unref(cur->u.s.kif, PFI_KIF_REF_STATE);
+	TAILQ_REMOVE(&state_list, cur, u.s.entry_list);
 	if (cur->tag)
 		pf_tag_unref(cur->tag);
 	pool_put(&pf_state_pl, cur);
@@ -1133,16 +1203,66 @@
 }
 
 void
-pf_purge_expired_states(void)
+pf_purge_expired_states(u_int32_t maxcheck)
 {
-	struct pf_state		*cur, *next;
+	static struct pf_state	*cur = NULL;
+	struct pf_state		*next;
+	int 			 locked = 0;
+
+	while (maxcheck--) {
+		/* wrap to start of list when we hit the end */
+		if (cur == NULL) {
+			cur = TAILQ_FIRST(&state_list);
+			if (cur == NULL)
+				break;	/* list empty */
+		}
+
+		/* get next state, as cur may get deleted */
+		next = TAILQ_NEXT(cur, u.s.entry_list);
 
-	for (cur = RB_MIN(pf_state_tree_id, &tree_id);
-	    cur; cur = next) {
-		next = RB_NEXT(pf_state_tree_id, &tree_id, cur);
-		if (pf_state_expires(cur) <= time_second)
-			pf_purge_expired_state(cur);
+		if (cur->timeout == PFTM_UNLINKED) {
+			/* free unlinked state */
+			if (! locked) {
+#ifdef __FreeBSD__
+				 if (!sx_try_upgrade(&pf_consistency_lock)) {
+					 PF_UNLOCK();
+					 sx_sunlock(&pf_consistency_lock);
+					 sx_xlock(&pf_consistency_lock);
+					 PF_LOCK();
+				 }
+#else
+				rw_enter_write(&pf_consistency_lock);
+#endif
+				locked = 1;
+			}
+			pf_free_state(cur);
+		} else if (pf_state_expires(cur) <= time_second) {
+			/* unlink and free expired state */
+			pf_unlink_state(cur);
+			if (! locked) {
+#ifdef __FreeBSD__
+				 if (!sx_try_upgrade(&pf_consistency_lock)) {
+					 PF_UNLOCK();
+					 sx_sunlock(&pf_consistency_lock);
+					 sx_xlock(&pf_consistency_lock);
+					 PF_LOCK();
+				 }
+#else
+				rw_enter_write(&pf_consistency_lock);
+#endif
+				locked = 1;
+			}
+			pf_free_state(cur);
+		}
+		cur = next;
 	}
+
+	if (locked)
+#ifdef __FreeBSD__
+		sx_downgrade(&pf_consistency_lock);
+#else
+		rw_exit_write(&pf_consistency_lock);
+#endif
 }
 
 int
@@ -1368,9 +1488,12 @@
 	case PF_ADDR_DYNIFTL:
 		return (aw1->p.dyn->pfid_kt != aw2->p.dyn->pfid_kt);
 	case PF_ADDR_NOROUTE:
+	case PF_ADDR_URPFFAILED:
 		return (0);
 	case PF_ADDR_TABLE:
 		return (aw1->p.tbl != aw2->p.tbl);
+	case PF_ADDR_RTLABEL:
+		return (aw1->v.rtlabel != aw2->v.rtlabel);
 	default:
 		printf("invalid address type: %d\n", aw1->type);
 		return (1);
@@ -1557,23 +1680,118 @@
 	}
 }
 
+
+/*
+ * Need to modulate the sequence numbers in the TCP SACK option
+ * (credits to Krzysztof Pfaff for report and patch)
+ */
+int
+pf_modulate_sack(struct mbuf *m, int off, struct pf_pdesc *pd,
+    struct tcphdr *th, struct pf_state_peer *dst)
+{
+	int hlen = (th->th_off << 2) - sizeof(*th), thoptlen = hlen;
+#ifdef __FreeBSD__
+	u_int8_t opts[TCP_MAXOLEN], *opt = opts;
+#else
+	u_int8_t opts[MAX_TCPOPTLEN], *opt = opts;
+#endif
+	int copyback = 0, i, olen;
+	struct sackblk sack;
+
+#define TCPOLEN_SACKLEN	(TCPOLEN_SACK + 2)
+	if (hlen < TCPOLEN_SACKLEN ||
+	    !pf_pull_hdr(m, off + sizeof(*th), opts, hlen, NULL, NULL, pd->af))
+		return 0;
+
+	while (hlen >= TCPOLEN_SACKLEN) {
+		olen = opt[1];
+		switch (*opt) {
+		case TCPOPT_EOL:	/* FALLTHROUGH */
+		case TCPOPT_NOP:
+			opt++;
+			hlen--;
+			break;
+		case TCPOPT_SACK:
+			if (olen > hlen)
+				olen = hlen;
+			if (olen >= TCPOLEN_SACKLEN) {
+				for (i = 2; i + TCPOLEN_SACK <= olen;
+				    i += TCPOLEN_SACK) {
+					memcpy(&sack, &opt[i], sizeof(sack));
+					pf_change_a(&sack.start, &th->th_sum,
+					    htonl(ntohl(sack.start) -
+					    dst->seqdiff), 0);
+					pf_change_a(&sack.end, &th->th_sum,
+					    htonl(ntohl(sack.end) -
+					    dst->seqdiff), 0);
+					memcpy(&opt[i], &sack, sizeof(sack));
+				}
+				copyback = 1;
+			}
+			/* FALLTHROUGH */
+		default:
+			if (olen < 2)
+				olen = 2;
+			hlen -= olen;
+			opt += olen;
+		}
+	}
+
+	if (copyback)
+#ifdef __FreeBSD__
+		m_copyback(m, off + sizeof(*th), thoptlen, (caddr_t)opts);
+#else
+		m_copyback(m, off + sizeof(*th), thoptlen, opts);
+#endif
+	return (copyback);
+}
+
 void
+#ifdef __FreeBSD__
+pf_send_tcp(struct mbuf *replyto, const struct pf_rule *r, sa_family_t af,
+#else
 pf_send_tcp(const struct pf_rule *r, sa_family_t af,
+#endif
     const struct pf_addr *saddr, const struct pf_addr *daddr,
     u_int16_t sport, u_int16_t dport, u_int32_t seq, u_int32_t ack,
     u_int8_t flags, u_int16_t win, u_int16_t mss, u_int8_t ttl, int tag,
-    struct ether_header *eh, struct ifnet *ifp)
+    u_int16_t rtag, struct ether_header *eh, struct ifnet *ifp)
 {
 	struct mbuf	*m;
-	int		 len = 0, tlen;		/* make the compiler happy */
+	int		 len, tlen;
 #ifdef INET
-	struct ip	*h = NULL;		/* make the compiler happy */
+	struct ip	*h;
 #endif /* INET */
 #ifdef INET6
-	struct ip6_hdr	*h6 = NULL;		/* make the compiler happy */
+	struct ip6_hdr	*h6;
 #endif /* INET6 */
-	struct tcphdr	*th = NULL;		/* make the compiler happy */
-	char *opt;
+	struct tcphdr	*th;
+	char		*opt;
+	struct pf_mtag	*pf_mtag;
+
+#ifdef __FreeBSD__
+	KASSERT(
+#ifdef INET
+	    af == AF_INET
+#else
+	    0
+#endif
+	    ||
+#ifdef INET6
+	    af == AF_INET6
+#else
+	    0
+#endif
+	    , ("Unsupported AF %d", af));
+	len = 0;
+	th = NULL;
+#ifdef INET
+	h = NULL;
+#endif
+#ifdef INET6
+	h6 = NULL;
+#endif
+#endif
 
 	/* maximum segment size tcp option */
 	tlen = sizeof(struct tcphdr);
@@ -1597,34 +1815,37 @@
 	m = m_gethdr(M_DONTWAIT, MT_HEADER);
 	if (m == NULL)
 		return;
-	if (tag) {
 #ifdef __FreeBSD__
-		m->m_flags |= M_SKIP_FIREWALL;
+#ifdef MAC
+	if (replyto)
+		mac_create_mbuf_netlayer(replyto, m);
+	else
+		mac_create_mbuf_from_firewall(m);
 #else
-		struct m_tag	*mtag;
-
-		mtag = m_tag_get(PACKET_TAG_PF_GENERATED, 0, M_NOWAIT);
-		if (mtag == NULL) {
-			m_freem(m);
-			return;
-		}
-		m_tag_prepend(m, mtag);
+	(void)replyto;
+#endif
 #endif
+	if ((pf_mtag = pf_get_mtag(m)) == NULL) {
+		m_freem(m);
+		return;
 	}
+	if (tag)
+#ifdef __FreeBSD__
+		m->m_flags |= M_SKIP_FIREWALL;
+#else
+		pf_mtag->flags |= PF_TAG_GENERATED;
+#endif
+
+	pf_mtag->tag = rtag;
+
+	if (r != NULL && r->rtableid >= 0)
+		pf_mtag->rtableid = r->rtableid;
 #ifdef ALTQ
 	if (r != NULL && r->qid) {
-		struct m_tag	*mtag;
-		struct altq_tag *atag;
-
-		mtag = m_tag_get(PACKET_TAG_PF_QID, sizeof(*atag), M_NOWAIT);
-		if (mtag != NULL) {
-			atag = (struct altq_tag *)(mtag + 1);
-			atag->qid = r->qid;
-			/* add hints for ecn */
-			atag->af = af;
-			atag->hdr = mtod(m, struct ip *);
-			m_tag_prepend(m, mtag);
-		}
+		pf_mtag->qid = r->qid;
+		/* add hints for ecn */
+		pf_mtag->af = af;
+		pf_mtag->hdr = mtod(m, struct ip *);
 	}
 #endif /* ALTQ */
 	m->m_data += max_linkhdr;
@@ -1760,9 +1981,7 @@
 pf_send_icmp(struct mbuf *m, u_int8_t type, u_int8_t code, sa_family_t af,
     struct pf_rule *r)
 {
-#ifdef ALTQ
-	struct m_tag	*mtag;
-#endif
+	struct pf_mtag	*pf_mtag;
 	struct mbuf	*m0;
 #ifdef __FreeBSD__
 	struct ip *ip;
@@ -1772,32 +1991,27 @@
 	m0 = m_copypacket(m, M_DONTWAIT);
 	if (m0 == NULL)
 		return;
-	m0->m_flags |= M_SKIP_FIREWALL;
 #else
-	mtag = m_tag_get(PACKET_TAG_PF_GENERATED, 0, M_NOWAIT);
-	if (mtag == NULL)
-		return;
 	m0 = m_copy(m, 0, M_COPYALL);
-	if (m0 == NULL) {
-		m_tag_free(mtag);
+#endif
+	if ((pf_mtag = pf_get_mtag(m0)) == NULL)
 		return;
-	}
-	m_tag_prepend(m0, mtag);
+#ifdef __FreeBSD__
+	/* XXX: revisit */
+	m0->m_flags |= M_SKIP_FIREWALL;
+#else
+	pf_mtag->flags |= PF_TAG_GENERATED;
 #endif
 
+	if (r->rtableid >= 0)
+		pf_mtag->rtableid = r->rtableid;
+
 #ifdef ALTQ
 	if (r->qid) {
-		struct altq_tag *atag;
-
-		mtag = m_tag_get(PACKET_TAG_PF_QID, sizeof(*atag), M_NOWAIT);
-		if (mtag != NULL) {
-			atag = (struct altq_tag *)(mtag + 1);
-			atag->qid = r->qid;
-			/* add hints for ecn */
-			atag->af = af;
-			atag->hdr = mtod(m0, struct ip *);
-			m_tag_prepend(m0, mtag);
-		}
+		pf_mtag->qid = r->qid;
+		/* add hints for ecn */
+		pf_mtag->af = af;
+		pf_mtag->hdr = mtod(m0, struct ip *);
 	}
 #endif /* ALTQ */
 
@@ -1813,7 +2027,7 @@
 		icmp_error(m0, type, code, 0, 0);
 		PF_LOCK();
 #else
-		icmp_error(m0, type, code, 0, (void *)NULL);
+		icmp_error(m0, type, code, 0, 0);
 #endif
 		break;
 #endif /* INET */
@@ -1928,58 +2142,73 @@
 	return (pf_match(op, a1, a2, g));
 }
 
-struct pf_tag *
-pf_get_tag(struct mbuf *m)
+#ifndef __FreeBSD__
+struct pf_mtag *
+pf_find_mtag(struct mbuf *m)
 {
 	struct m_tag	*mtag;
 
-	if ((mtag = m_tag_find(m, PACKET_TAG_PF_TAG, NULL)) != NULL)
-		return ((struct pf_tag *)(mtag + 1));
-	else
+	if ((mtag = m_tag_find(m, PACKET_TAG_PF, NULL)) == NULL)
 		return (NULL);
+
+	return ((struct pf_mtag *)(mtag + 1));
 }
 
-int
-pf_match_tag(struct mbuf *m, struct pf_rule *r, struct pf_tag **pftag, int *tag)
+struct pf_mtag *
+pf_get_mtag(struct mbuf *m)
 {
-	if (*tag == -1) {	/* find mbuf tag */
-		*pftag = pf_get_tag(m);
-		if (*pftag != NULL)
-			*tag = (*pftag)->tag;
-		else
-			*tag = 0;
+	struct m_tag	*mtag;
+
+	if ((mtag = m_tag_find(m, PACKET_TAG_PF, NULL)) == NULL) {
+		mtag = m_tag_get(PACKET_TAG_PF, sizeof(struct pf_mtag),
+		    M_NOWAIT);
+		if (mtag == NULL)
+			return (NULL);
+		bzero(mtag + 1, sizeof(struct pf_mtag));
+		m_tag_prepend(m, mtag);
 	}
 
+	return ((struct pf_mtag *)(mtag + 1));
+}
+#endif
+
+int
+pf_match_tag(struct mbuf *m, struct pf_rule *r, struct pf_mtag *pf_mtag,
+    int *tag)
+{
+	if (*tag == -1)
+		*tag = pf_mtag->tag;
+
 	return ((!r->match_tag_not && r->match_tag == *tag) ||
 	    (r->match_tag_not && r->match_tag != *tag));
 }
 
 int
-pf_tag_packet(struct mbuf *m, struct pf_tag *pftag, int tag)
+pf_tag_packet(struct mbuf *m, struct pf_mtag *pf_mtag, int tag, int rtableid)
 {
-	struct m_tag	*mtag;
-
-	if (tag <= 0)
+	if (tag <= 0 && rtableid < 0)
 		return (0);
 
-	if (pftag == NULL) {
-		mtag = m_tag_get(PACKET_TAG_PF_TAG, sizeof(*pftag), M_NOWAIT);
-		if (mtag == NULL)
+	if (pf_mtag == NULL)
+		if ((pf_mtag = pf_get_mtag(m)) == NULL)
 			return (1);
-		((struct pf_tag *)(mtag + 1))->tag = tag;
-		m_tag_prepend(m, mtag);
-	} else
-		pftag->tag = tag;
+	if (tag > 0)
+		pf_mtag->tag = tag;
+	if (rtableid >= 0)
+		pf_mtag->rtableid = rtableid;
 
 	return (0);
 }
 
 static void
 pf_step_into_anchor(int *depth, struct pf_ruleset **rs, int n,
-    struct pf_rule **r, struct pf_rule **a)
+    struct pf_rule **r, struct pf_rule **a,  int *match)
 {
 	struct pf_anchor_stackframe	*f;
 
+	(*r)->anchor->match = 0;
+	if (match)
+		*match = 0;
 	if (*depth >= sizeof(pf_anchor_stack) /
 	    sizeof(pf_anchor_stack[0])) {
 		printf("pf_step_into_anchor: stack overflow\n");
@@ -2006,17 +2235,23 @@
 	*r = TAILQ_FIRST((*rs)->rules[n].active.ptr);
 }
 
-static void
+int
 pf_step_out_of_anchor(int *depth, struct pf_ruleset **rs, int n,
-    struct pf_rule **r, struct pf_rule **a)
+    struct pf_rule **r, struct pf_rule **a, int *match)
 {
 	struct pf_anchor_stackframe	*f;
+	int quick = 0;
 
 	do {
 		if (*depth <= 0)
 			break;
 		f = pf_anchor_stack + *depth - 1;
 		if (f->parent != NULL && f->child != NULL) {
+			if (f->child->match ||
+			    (match != NULL && *match)) {
+				f->r->anchor->match = 1;
+				*match = 0;
+			}
 			f->child = RB_NEXT(pf_anchor_node, f->parent, f->child);
 			if (f->child != NULL) {
 				*rs = &f->child->ruleset;
@@ -2031,8 +2266,12 @@
 		if (*depth == 0 && a != NULL)
 			*a = NULL;
 		*rs = f->rs;
+		if (f->r->anchor->match || (match  != NULL && *match))
+			quick = f->r->quick;
 		*r = TAILQ_NEXT(f->r, entries);
 	} while (*r == NULL);
+
+	return (quick);
 }
 
 #ifdef INET6
@@ -2336,7 +2575,7 @@
     struct pf_addr *naddr, u_int16_t *nport, u_int16_t low, u_int16_t high,
     struct pf_src_node **sn)
 {
-	struct pf_state		key;
+	struct pf_state_cmp	key;
 	struct pf_addr		init_addr;
 	u_int16_t		cut;
 
@@ -2428,8 +2667,8 @@
 {
 	struct pf_rule		*r, *rm = NULL;
 	struct pf_ruleset	*ruleset = NULL;
-	struct pf_tag		*pftag = NULL;
 	int			 tag = -1;
+	int			 rtableid = -1;
 	int			 asd = 0;
 
 	r = TAILQ_FIRST(pf_main_ruleset.rules[rs_num].active.ptr);
@@ -2447,8 +2686,7 @@
 		}
 
 		r->evaluations++;
-		if (r->kif != NULL &&
-		    (r->kif != kif && r->kif != kif->pfik_parent) == !r->ifnot)
+		if (pfi_kif_match(r->kif, kif) == r->ifnot)
 			r = r->skip[PF_SKIP_IFP].ptr;
 		else if (r->direction && r->direction != direction)
 			r = r->skip[PF_SKIP_DIR].ptr;
@@ -2456,7 +2694,8 @@
 			r = r->skip[PF_SKIP_AF].ptr;
 		else if (r->proto && r->proto != pd->proto)
 			r = r->skip[PF_SKIP_PROTO].ptr;
-		else if (PF_MISMATCHAW(&src->addr, saddr, pd->af, src->neg))
+		else if (PF_MISMATCHAW(&src->addr, saddr, pd->af,
+		    src->neg, kif))
 			r = r->skip[src == &r->src ? PF_SKIP_SRC_ADDR :
 			    PF_SKIP_DST_ADDR].ptr;
 		else if (src->port_op && !pf_match_port(src->port_op,
@@ -2464,15 +2703,16 @@
 			r = r->skip[src == &r->src ? PF_SKIP_SRC_PORT :
 			    PF_SKIP_DST_PORT].ptr;
 		else if (dst != NULL &&
-		    PF_MISMATCHAW(&dst->addr, daddr, pd->af, dst->neg))
+		    PF_MISMATCHAW(&dst->addr, daddr, pd->af, dst->neg, NULL))
 			r = r->skip[PF_SKIP_DST_ADDR].ptr;
-		else if (xdst != NULL && PF_MISMATCHAW(xdst, daddr, pd->af, 0))
+		else if (xdst != NULL && PF_MISMATCHAW(xdst, daddr, pd->af,
+		    0, NULL))
 			r = TAILQ_NEXT(r, entries);
 		else if (dst != NULL && dst->port_op &&
 		    !pf_match_port(dst->port_op, dst->port[0],
 		    dst->port[1], dport))
 			r = r->skip[PF_SKIP_DST_PORT].ptr;
-		else if (r->match_tag && !pf_match_tag(m, r, &pftag, &tag))
+		else if (r->match_tag && !pf_match_tag(m, r, pd->pf_mtag, &tag))
 			r = TAILQ_NEXT(r, entries);
 		else if (r->os_fingerprint != PF_OSFP_ANY && (pd->proto !=
 		    IPPROTO_TCP || !pf_osfp_match(pf_osfp_fingerprint(pd, m,
@@ -2481,15 +2721,19 @@
 		else {
 			if (r->tag)
 				tag = r->tag;
+			if (r->rtableid >= 0)
+				rtableid = r->rtableid;
 			if (r->anchor == NULL) {
 				rm = r;
 			} else
-				pf_step_into_anchor(&asd, &ruleset, rs_num, &r, NULL);
+				pf_step_into_anchor(&asd, &ruleset, rs_num,
+				    &r, NULL, NULL);
 		}
 		if (r == NULL)
-			pf_step_out_of_anchor(&asd, &ruleset, rs_num, &r, NULL);
+			pf_step_out_of_anchor(&asd, &ruleset, rs_num, &r,
+			    NULL, NULL);
 	}
-	if (pf_tag_packet(m, pftag, tag))
+	if (pf_tag_packet(m, pd->pf_mtag, tag, rtableid))
 		return (NULL);
 	if (rm != NULL && (rm->action == PF_NONAT ||
 	    rm->action == PF_NORDR || rm->action == PF_NOBINAT))
@@ -2650,10 +2894,9 @@
 
 int
 #ifdef __FreeBSD__
-pf_socket_lookup(uid_t *uid, gid_t *gid, int direction, struct pf_pdesc *pd,
-    struct inpcb *inp_arg)
+pf_socket_lookup(int direction, struct pf_pdesc *pd, struct inpcb *inp_arg)
 #else
-pf_socket_lookup(uid_t *uid, gid_t *gid, int direction, struct pf_pdesc *pd)
+pf_socket_lookup(int direction, struct pf_pdesc *pd)
 #endif
 {
 	struct pf_addr		*saddr, *daddr;
@@ -2665,21 +2908,27 @@
 #endif
 	struct inpcb		*inp;
 
-	*uid = UID_MAX;
-	*gid = GID_MAX;
+	if (pd == NULL)
+		return (-1);
+	pd->lookup.uid = UID_MAX;
+	pd->lookup.gid = GID_MAX;
+	pd->lookup.pid = NO_PID;		/* XXX: revisit */
 #ifdef __FreeBSD__
 	if (inp_arg != NULL) {
 		INP_LOCK_ASSERT(inp_arg);
 		if (inp_arg->inp_socket) {
-			*uid = inp_arg->inp_socket->so_cred->cr_uid;
-			*gid = inp_arg->inp_socket->so_cred->cr_groups[0];
+			pd->lookup.uid = inp_arg->inp_socket->so_cred->cr_uid;
+			pd->lookup.gid =
+			    inp_arg->inp_socket->so_cred->cr_groups[0];
 			return (1);
 		} else
-			return (0);
+			return (-1);
 	}
 #endif
 	switch (pd->proto) {
 	case IPPROTO_TCP:
+		if (pd->hdr.tcp == NULL)
+			return (-1);
 		sport = pd->hdr.tcp->th_sport;
 		dport = pd->hdr.tcp->th_dport;
 #ifdef __FreeBSD__
@@ -2689,6 +2938,8 @@
 #endif
 		break;
 	case IPPROTO_UDP:
+		if (pd->hdr.udp == NULL)
+			return (-1);
 		sport = pd->hdr.udp->uh_sport;
 		dport = pd->hdr.udp->uh_dport;
 #ifdef __FreeBSD__
@@ -2698,7 +2949,7 @@
 #endif
 		break;
 	default:
-		return (0);
+		return (-1);
 	}
 	if (direction == PF_IN) {
 		saddr = pd->src;
@@ -2724,7 +2975,7 @@
 			   daddr->v4, dport, INPLOOKUP_WILDCARD, NULL);
 			if(inp == NULL) {
 				INP_INFO_RUNLOCK(pi);
-				return (0);
+				return (-1);
 			}
 		}
 #else
@@ -2732,7 +2983,7 @@
 		if (inp == NULL) {
 			inp = in_pcblookup_listen(tb, daddr->v4, dport, 0);
 			if (inp == NULL)
-				return (0);
+				return (-1);
 		}
 #endif
 		break;
@@ -2748,7 +2999,7 @@
 			&daddr->v6, dport, INPLOOKUP_WILDCARD, NULL);
 			if (inp == NULL) {
 				INP_INFO_RUNLOCK(pi);
-				return (0);
+				return (-1);
 			}
 		}
 #else
@@ -2757,29 +3008,30 @@
 		if (inp == NULL) {
 			inp = in6_pcblookup_listen(tb, &daddr->v6, dport, 0);
 			if (inp == NULL)
-				return (0);
+				return (-1);
 		}
 #endif
 		break;
 #endif /* INET6 */
 
 	default:
-		return (0);
+		return (-1);
 	}
 #ifdef __FreeBSD__
 	INP_LOCK(inp);
 	if ((inp->inp_socket == NULL) || (inp->inp_socket->so_cred == NULL)) {
 		INP_UNLOCK(inp);
 		INP_INFO_RUNLOCK(pi);
-		return (0);
+		return (-1);
 	}
-	*uid = inp->inp_socket->so_cred->cr_uid;
-	*gid = inp->inp_socket->so_cred->cr_groups[0];
+	pd->lookup.uid = inp->inp_socket->so_cred->cr_uid;
+	pd->lookup.gid = inp->inp_socket->so_cred->cr_groups[0];
 	INP_UNLOCK(inp);
 	INP_INFO_RUNLOCK(pi);
 #else
-	*uid = inp->inp_socket->so_euid;
-	*gid = inp->inp_socket->so_egid;
+	pd->lookup.uid = inp->inp_socket->so_euid;
+	pd->lookup.gid = inp->inp_socket->so_egid;
+	pd->lookup.pid = inp->inp_socket->so_cpid;
 #endif
 	return (1);
 }
@@ -2973,24 +3225,32 @@
 	struct tcphdr		*th = pd->hdr.tcp;
 	u_int16_t		 bport, nport = 0;
 	sa_family_t		 af = pd->af;
-	int			 lookup = -1;
-	uid_t			 uid;
-	gid_t			 gid;
 	struct pf_rule		*r, *a = NULL;
 	struct pf_ruleset	*ruleset = NULL;
 	struct pf_src_node	*nsn = NULL;
 	u_short			 reason;
 	int			 rewrite = 0;
-	struct pf_tag		*pftag = NULL;
-	int			 tag = -1;
+	int			 tag = -1, rtableid = -1;
 	u_int16_t		 mss = tcp_mssdflt;
 	int			 asd = 0;
+	int			 match = 0;
 
 	if (pf_check_congestion(ifq)) {
 		REASON_SET(&reason, PFRES_CONGEST);
 		return (PF_DROP);
 	}
 
+#ifdef __FreeBSD__
+	if (inp != NULL)
+		pd->lookup.done = pf_socket_lookup(direction, pd, inp);
+	else if (debug_pfugidhack) {
+		PF_UNLOCK();
+		DPFPRINTF(PF_DEBUG_MISC, ("pf: unlocked lookup\n"));
+		pd->lookup.done = pf_socket_lookup(direction, pd, inp);
+		PF_LOCK();
+	}
+#endif
+
 	r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr);
 
 	if (direction == PF_OUT) {
@@ -3025,8 +3285,7 @@
 
 	while (r != NULL) {
 		r->evaluations++;
-		if (r->kif != NULL &&
-		    (r->kif != kif && r->kif != kif->pfik_parent) == !r->ifnot)
+		if (pfi_kif_match(r->kif, kif) == r->ifnot)
 			r = r->skip[PF_SKIP_IFP].ptr;
 		else if (r->direction && r->direction != direction)
 			r = r->skip[PF_SKIP_DIR].ptr;
@@ -3034,43 +3293,45 @@
 			r = r->skip[PF_SKIP_AF].ptr;
 		else if (r->proto && r->proto != IPPROTO_TCP)
 			r = r->skip[PF_SKIP_PROTO].ptr;
-		else if (PF_MISMATCHAW(&r->src.addr, saddr, af, r->src.neg))
+		else if (PF_MISMATCHAW(&r->src.addr, saddr, af,
+		    r->src.neg, kif))
 			r = r->skip[PF_SKIP_SRC_ADDR].ptr;
 		else if (r->src.port_op && !pf_match_port(r->src.port_op,
 		    r->src.port[0], r->src.port[1], th->th_sport))
 			r = r->skip[PF_SKIP_SRC_PORT].ptr;
-		else if (PF_MISMATCHAW(&r->dst.addr, daddr, af, r->dst.neg))
+		else if (PF_MISMATCHAW(&r->dst.addr, daddr, af,
+		    r->dst.neg, NULL))
 			r = r->skip[PF_SKIP_DST_ADDR].ptr;
 		else if (r->dst.port_op && !pf_match_port(r->dst.port_op,
 		    r->dst.port[0], r->dst.port[1], th->th_dport))
 			r = r->skip[PF_SKIP_DST_PORT].ptr;
-		else if (r->tos && !(r->tos & pd->tos))
+		else if (r->tos && !(r->tos == pd->tos))
 			r = TAILQ_NEXT(r, entries);
 		else if (r->rule_flag & PFRULE_FRAGMENT)
 			r = TAILQ_NEXT(r, entries);
 		else if ((r->flagset & th->th_flags) != r->flags)
 			r = TAILQ_NEXT(r, entries);
-		else if (r->uid.op && (lookup != -1 || (lookup =
+		else if (r->uid.op && (pd->lookup.done || (pd->lookup.done =
 #ifdef __FreeBSD__
-		    pf_socket_lookup(&uid, &gid, direction, pd, inp), 1)) &&
+		    pf_socket_lookup(direction, pd, inp), 1)) &&
 #else
-		    pf_socket_lookup(&uid, &gid, direction, pd), 1)) &&
+		    pf_socket_lookup(direction, pd), 1)) &&
 #endif
 		    !pf_match_uid(r->uid.op, r->uid.uid[0], r->uid.uid[1],
-		    uid))
+		    pd->lookup.uid))
 			r = TAILQ_NEXT(r, entries);
-		else if (r->gid.op && (lookup != -1 || (lookup =
+		else if (r->gid.op && (pd->lookup.done || (pd->lookup.done =
 #ifdef __FreeBSD__
-		    pf_socket_lookup(&uid, &gid, direction, pd, inp), 1)) &&
+		    pf_socket_lookup(direction, pd, inp), 1)) &&
 #else
-		    pf_socket_lookup(&uid, &gid, direction, pd), 1)) &&
+		    pf_socket_lookup(direction, pd), 1)) &&
 #endif
 		    !pf_match_gid(r->gid.op, r->gid.gid[0], r->gid.gid[1],
-		    gid))
+		    pd->lookup.gid))
 			r = TAILQ_NEXT(r, entries);
 		else if (r->prob && r->prob <= arc4random())
 			r = TAILQ_NEXT(r, entries);
-		else if (r->match_tag && !pf_match_tag(m, r, &pftag, &tag))
+		else if (r->match_tag && !pf_match_tag(m, r, pd->pf_mtag, &tag))
 			r = TAILQ_NEXT(r, entries);
 		else if (r->os_fingerprint != PF_OSFP_ANY && !pf_osfp_match(
 		    pf_osfp_fingerprint(pd, m, off, th), r->os_fingerprint))
@@ -3078,7 +3339,10 @@
 		else {
 			if (r->tag)
 				tag = r->tag;
+			if (r->rtableid >= 0)
+				rtableid = r->rtableid;
 			if (r->anchor == NULL) {
+				match = 1;
 				*rm = r;
 				*am = a;
 				*rsm = ruleset;
@@ -3087,11 +3351,11 @@
 				r = TAILQ_NEXT(r, entries);
 			} else
 				pf_step_into_anchor(&asd, &ruleset,
-				    PF_RULESET_FILTER, &r, &a);
+				    PF_RULESET_FILTER, &r, &a, &match);
 		}
-		if (r == NULL)
-			pf_step_out_of_anchor(&asd, &ruleset,
-			    PF_RULESET_FILTER, &r, &a);
+		if (r == NULL && pf_step_out_of_anchor(&asd, &ruleset,
+		    PF_RULESET_FILTER, &r, &a, &match))
+			break;
 	}
 	r = *rm;
 	a = *am;
@@ -3099,10 +3363,15 @@
 
 	REASON_SET(&reason, PFRES_MATCH);
 
-	if (r->log) {
+	if (r->log || (nr != NULL && nr->natpass && nr->log)) {
 		if (rewrite)
+#ifdef __FreeBSD__
 			m_copyback(m, off, sizeof(*th), (caddr_t)th);
-		PFLOG_PACKET(kif, h, m, af, direction, reason, r, a, ruleset);
+#else
+			m_copyback(m, off, sizeof(*th), th);
+#endif
+		PFLOG_PACKET(kif, h, m, af, direction, reason, r->log ? r : nr,
+		    a, ruleset, pd);
 	}
 
 	if ((r->action == PF_DROP) &&
@@ -3130,10 +3399,14 @@
 				ack++;
 			if (th->th_flags & TH_FIN)
 				ack++;
+#ifdef __FreeBSD__
+			pf_send_tcp(m, r, af, pd->dst,
+#else
 			pf_send_tcp(r, af, pd->dst,
+#endif
 			    pd->src, th->th_dport, th->th_sport,
 			    ntohl(th->th_ack), ack, TH_RST|TH_ACK, 0, 0,
-			    r->return_ttl, 1, pd->eh, kif->pfik_ifp);
+			    r->return_ttl, 1, 0, pd->eh, kif->pfik_ifp);
 		} else if ((af == AF_INET) && r->return_icmp)
 			pf_send_icmp(m, r->return_icmp >> 8,
 			    r->return_icmp & 255, af, r);
@@ -3145,7 +3418,7 @@
 	if (r->action == PF_DROP)
 		return (PF_DROP);
 
-	if (pf_tag_packet(m, pftag, tag)) {
+	if (pf_tag_packet(m, pd->pf_mtag, tag, rtableid)) {
 		REASON_SET(&reason, PFRES_MEMORY);
 		return (PF_DROP);
 	}
@@ -3165,7 +3438,7 @@
 			REASON_SET(&reason, PFRES_MAXSTATES);
 			goto cleanup;
 		}
-		/* src node for flter rule */
+		/* src node for filter rule */
 		if ((r->rule_flag & PFRULE_SRCTRACK ||
 		    r->rpool.opts & PF_POOL_STICKYADDR) &&
 		    pf_insert_src_node(&sn, r, saddr, af) != 0) {
@@ -3205,7 +3478,9 @@
 		s->anchor.ptr = a;
 		STATE_INC_COUNTERS(s);
 		s->allow_opts = r->allow_opts;
-		s->log = r->log & 2;
+		s->log = r->log & PF_LOG_ALL;
+		if (nr != NULL)
+			s->log |= nr->log & PF_LOG_ALL;
 		s->proto = IPPROTO_TCP;
 		s->direction = direction;
 		s->af = af;
@@ -3240,8 +3515,15 @@
 		if ((th->th_flags & (TH_SYN|TH_ACK)) == TH_SYN &&
 		    r->keep_state == PF_STATE_MODULATE) {
 			/* Generate sequence number modulator */
-			while ((s->src.seqdiff = htonl(arc4random())) == 0)
+#ifdef __FreeBSD__
+			while ((s->src.seqdiff =
+			    pf_new_isn(s) - s->src.seqlo) == 0)
+				;	
+#else
+			while ((s->src.seqdiff =
+			    tcp_rndiss_next() - s->src.seqlo) == 0)
 				;
+#endif
 			pf_change_a(&th->th_seq, &th->th_sum,
 			    htonl(s->src.seqlo + s->src.seqdiff), 0);
 			rewrite = 1;
@@ -3331,9 +3613,13 @@
 			mss = pf_calc_mss(saddr, af, mss);
 			mss = pf_calc_mss(daddr, af, mss);
 			s->src.mss = mss;
+#ifdef __FreeBSD__
+			pf_send_tcp(NULL, r, af, daddr, saddr, th->th_dport,
+#else
 			pf_send_tcp(r, af, daddr, saddr, th->th_dport,
+#endif
 			    th->th_sport, s->src.seqhi, ntohl(th->th_seq) + 1,
-			    TH_SYN|TH_ACK, 0, s->src.mss, 0, 1, NULL, NULL);
+			    TH_SYN|TH_ACK, 0, s->src.mss, 0, 1, 0, NULL, NULL);
 			REASON_SET(&reason, PFRES_SYNPROXY);
 			return (PF_SYNPROXY_DROP);
 		}
@@ -3362,23 +3648,31 @@
 	struct udphdr		*uh = pd->hdr.udp;
 	u_int16_t		 bport, nport = 0;
 	sa_family_t		 af = pd->af;
-	int			 lookup = -1;
-	uid_t			 uid;
-	gid_t			 gid;
 	struct pf_rule		*r, *a = NULL;
 	struct pf_ruleset	*ruleset = NULL;
 	struct pf_src_node	*nsn = NULL;
 	u_short			 reason;
 	int			 rewrite = 0;
-	struct pf_tag		*pftag = NULL;
-	int			 tag = -1;
+	int			 tag = -1, rtableid = -1;
 	int			 asd = 0;
+	int			 match = 0;
 
 	if (pf_check_congestion(ifq)) {
 		REASON_SET(&reason, PFRES_CONGEST);
 		return (PF_DROP);
 	}
 
+#ifdef __FreeBSD__
+	if (inp != NULL)
+		pd->lookup.done = pf_socket_lookup(direction, pd, inp);
+	else if (debug_pfugidhack) {
+		PF_UNLOCK();
+		DPFPRINTF(PF_DEBUG_MISC, ("pf: unlocked lookup\n"));
+		pd->lookup.done = pf_socket_lookup(direction, pd, inp);
+		PF_LOCK();
+	}
+#endif
+
 	r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr);
 
 	if (direction == PF_OUT) {
@@ -3413,8 +3707,7 @@
 
 	while (r != NULL) {
 		r->evaluations++;
-		if (r->kif != NULL &&
-		    (r->kif != kif && r->kif != kif->pfik_parent) == !r->ifnot)
+		if (pfi_kif_match(r->kif, kif) == r->ifnot)
 			r = r->skip[PF_SKIP_IFP].ptr;
 		else if (r->direction && r->direction != direction)
 			r = r->skip[PF_SKIP_DIR].ptr;
@@ -3422,48 +3715,53 @@
 			r = r->skip[PF_SKIP_AF].ptr;
 		else if (r->proto && r->proto != IPPROTO_UDP)
 			r = r->skip[PF_SKIP_PROTO].ptr;
-		else if (PF_MISMATCHAW(&r->src.addr, saddr, af, r->src.neg))
+		else if (PF_MISMATCHAW(&r->src.addr, saddr, af,
+		    r->src.neg, kif))
 			r = r->skip[PF_SKIP_SRC_ADDR].ptr;
 		else if (r->src.port_op && !pf_match_port(r->src.port_op,
 		    r->src.port[0], r->src.port[1], uh->uh_sport))
 			r = r->skip[PF_SKIP_SRC_PORT].ptr;
-		else if (PF_MISMATCHAW(&r->dst.addr, daddr, af, r->dst.neg))
+		else if (PF_MISMATCHAW(&r->dst.addr, daddr, af,
+		    r->dst.neg, NULL))
 			r = r->skip[PF_SKIP_DST_ADDR].ptr;
 		else if (r->dst.port_op && !pf_match_port(r->dst.port_op,
 		    r->dst.port[0], r->dst.port[1], uh->uh_dport))
 			r = r->skip[PF_SKIP_DST_PORT].ptr;
-		else if (r->tos && !(r->tos & pd->tos))
+		else if (r->tos && !(r->tos == pd->tos))
 			r = TAILQ_NEXT(r, entries);
 		else if (r->rule_flag & PFRULE_FRAGMENT)
 			r = TAILQ_NEXT(r, entries);
-		else if (r->uid.op && (lookup != -1 || (lookup =
+		else if (r->uid.op && (pd->lookup.done || (pd->lookup.done =
 #ifdef __FreeBSD__
-		    pf_socket_lookup(&uid, &gid, direction, pd, inp), 1)) &&
+		    pf_socket_lookup(direction, pd, inp), 1)) &&
 #else
-		    pf_socket_lookup(&uid, &gid, direction, pd), 1)) &&
+		    pf_socket_lookup(direction, pd), 1)) &&
 #endif
 		    !pf_match_uid(r->uid.op, r->uid.uid[0], r->uid.uid[1],
-		    uid))
+		    pd->lookup.uid))
 			r = TAILQ_NEXT(r, entries);
-		else if (r->gid.op && (lookup != -1 || (lookup =
+		else if (r->gid.op && (pd->lookup.done || (pd->lookup.done =
 #ifdef __FreeBSD__
-		    pf_socket_lookup(&uid, &gid, direction, pd, inp), 1)) &&
+		    pf_socket_lookup(direction, pd, inp), 1)) &&
 #else
-		    pf_socket_lookup(&uid, &gid, direction, pd), 1)) &&
+		    pf_socket_lookup(direction, pd), 1)) &&
 #endif
 		    !pf_match_gid(r->gid.op, r->gid.gid[0], r->gid.gid[1],
-		    gid))
+		    pd->lookup.gid))
 			r = TAILQ_NEXT(r, entries);
 		else if (r->prob && r->prob <= arc4random())
 			r = TAILQ_NEXT(r, entries);
-		else if (r->match_tag && !pf_match_tag(m, r, &pftag, &tag))
+		else if (r->match_tag && !pf_match_tag(m, r, pd->pf_mtag, &tag))
 			r = TAILQ_NEXT(r, entries);
 		else if (r->os_fingerprint != PF_OSFP_ANY)
 			r = TAILQ_NEXT(r, entries);
 		else {
 			if (r->tag)
 				tag = r->tag;
+			if (r->rtableid >= 0)
+				rtableid = r->rtableid;
 			if (r->anchor == NULL) {
+				match = 1;
 				*rm = r;
 				*am = a;
 				*rsm = ruleset;
@@ -3472,11 +3770,11 @@
 				r = TAILQ_NEXT(r, entries);
 			} else
 				pf_step_into_anchor(&asd, &ruleset,
-				    PF_RULESET_FILTER, &r, &a);
+				    PF_RULESET_FILTER, &r, &a, &match);
 		}
-		if (r == NULL)
-			pf_step_out_of_anchor(&asd, &ruleset,
-			    PF_RULESET_FILTER, &r, &a);
+		if (r == NULL && pf_step_out_of_anchor(&asd, &ruleset,
+		    PF_RULESET_FILTER, &r, &a, &match))
+			break;
 	}
 	r = *rm;
 	a = *am;
@@ -3484,10 +3782,15 @@
 
 	REASON_SET(&reason, PFRES_MATCH);
 
-	if (r->log) {
+	if (r->log || (nr != NULL && nr->natpass && nr->log)) {
 		if (rewrite)
+#ifdef __FreeBSD__
 			m_copyback(m, off, sizeof(*uh), (caddr_t)uh);
-		PFLOG_PACKET(kif, h, m, af, direction, reason, r, a, ruleset);
+#else
+			m_copyback(m, off, sizeof(*uh), uh);
+#endif
+		PFLOG_PACKET(kif, h, m, af, direction, reason, r->log ? r : nr,
+		    a, ruleset, pd);
 	}
 
 	if ((r->action == PF_DROP) &&
@@ -3516,7 +3819,7 @@
 	if (r->action == PF_DROP)
 		return (PF_DROP);
 
-	if (pf_tag_packet(m, pftag, tag)) {
+	if (pf_tag_packet(m, pd->pf_mtag, tag, rtableid)) {
 		REASON_SET(&reason, PFRES_MEMORY);
 		return (PF_DROP);
 	}
@@ -3532,7 +3835,7 @@
 			REASON_SET(&reason, PFRES_MAXSTATES);
 			goto cleanup;
 		}
-		/* src node for flter rule */
+		/* src node for filter rule */
 		if ((r->rule_flag & PFRULE_SRCTRACK ||
 		    r->rpool.opts & PF_POOL_STICKYADDR) &&
 		    pf_insert_src_node(&sn, r, saddr, af) != 0) {
@@ -3572,7 +3875,9 @@
 		s->anchor.ptr = a;
 		STATE_INC_COUNTERS(s);
 		s->allow_opts = r->allow_opts;
-		s->log = r->log & 2;
+		s->log = r->log & PF_LOG_ALL;
+		if (nr != NULL)
+			s->log |= nr->log & PF_LOG_ALL;
 		s->proto = IPPROTO_UDP;
 		s->direction = direction;
 		s->af = af;
@@ -3654,12 +3959,12 @@
 	u_int8_t		 icmptype = 0;	/* make the compiler happy */
 	u_int8_t		 icmpcode = 0;	/* make the compiler happy */
 	int			 state_icmp = 0;
-	struct pf_tag		*pftag = NULL;
-	int			 tag = -1;
+	int			 tag = -1, rtableid = -1;
 #ifdef INET6
 	int			 rewrite = 0;
 #endif /* INET6 */
 	int			 asd = 0;
+	int			 match = 0;
 
 	if (pf_check_congestion(ifq)) {
 		REASON_SET(&reason, PFRES_CONGEST);
@@ -3759,8 +4064,7 @@
 
 	while (r != NULL) {
 		r->evaluations++;
-		if (r->kif != NULL &&
-		    (r->kif != kif && r->kif != kif->pfik_parent) == !r->ifnot)
+		if (pfi_kif_match(r->kif, kif) == r->ifnot)
 			r = r->skip[PF_SKIP_IFP].ptr;
 		else if (r->direction && r->direction != direction)
 			r = r->skip[PF_SKIP_DIR].ptr;
@@ -3768,28 +4072,33 @@
 			r = r->skip[PF_SKIP_AF].ptr;
 		else if (r->proto && r->proto != pd->proto)
 			r = r->skip[PF_SKIP_PROTO].ptr;
-		else if (PF_MISMATCHAW(&r->src.addr, saddr, af, r->src.neg))
+		else if (PF_MISMATCHAW(&r->src.addr, saddr, af,
+		    r->src.neg, kif))
 			r = r->skip[PF_SKIP_SRC_ADDR].ptr;
-		else if (PF_MISMATCHAW(&r->dst.addr, daddr, af, r->dst.neg))
+		else if (PF_MISMATCHAW(&r->dst.addr, daddr, af,
+		    r->dst.neg, NULL))
 			r = r->skip[PF_SKIP_DST_ADDR].ptr;
 		else if (r->type && r->type != icmptype + 1)
 			r = TAILQ_NEXT(r, entries);
 		else if (r->code && r->code != icmpcode + 1)
 			r = TAILQ_NEXT(r, entries);
-		else if (r->tos && !(r->tos & pd->tos))
+		else if (r->tos && !(r->tos == pd->tos))
 			r = TAILQ_NEXT(r, entries);
 		else if (r->rule_flag & PFRULE_FRAGMENT)
 			r = TAILQ_NEXT(r, entries);
 		else if (r->prob && r->prob <= arc4random())
 			r = TAILQ_NEXT(r, entries);
-		else if (r->match_tag && !pf_match_tag(m, r, &pftag, &tag))
+		else if (r->match_tag && !pf_match_tag(m, r, pd->pf_mtag, &tag))
 			r = TAILQ_NEXT(r, entries);
 		else if (r->os_fingerprint != PF_OSFP_ANY)
 			r = TAILQ_NEXT(r, entries);
 		else {
 			if (r->tag)
 				tag = r->tag;
+			if (r->rtableid >= 0)
+				rtableid = r->rtableid;
 			if (r->anchor == NULL) {
+				match = 1;
 				*rm = r;
 				*am = a;
 				*rsm = ruleset;
@@ -3798,11 +4107,11 @@
 				r = TAILQ_NEXT(r, entries);
 			} else
 				pf_step_into_anchor(&asd, &ruleset,
-				    PF_RULESET_FILTER, &r, &a);
+				    PF_RULESET_FILTER, &r, &a, &match);
 		}
-		if (r == NULL)
-			pf_step_out_of_anchor(&asd, &ruleset,
-			    PF_RULESET_FILTER, &r, &a);
+		if (r == NULL && pf_step_out_of_anchor(&asd, &ruleset,
+		    PF_RULESET_FILTER, &r, &a, &match))
+			break;
 	}
 	r = *rm;
 	a = *am;
@@ -3810,19 +4119,20 @@
 
 	REASON_SET(&reason, PFRES_MATCH);
 
-	if (r->log) {
+	if (r->log || (nr != NULL && nr->natpass && nr->log)) {
 #ifdef INET6
 		if (rewrite)
 			m_copyback(m, off, sizeof(struct icmp6_hdr),
 			    (caddr_t)pd->hdr.icmp6);
 #endif /* INET6 */
-		PFLOG_PACKET(kif, h, m, af, direction, reason, r, a, ruleset);
+		PFLOG_PACKET(kif, h, m, af, direction, reason, r->log ? r : nr,
+		    a, ruleset, pd);
 	}
 
 	if (r->action != PF_PASS)
 		return (PF_DROP);
 
-	if (pf_tag_packet(m, pftag, tag)) {
+	if (pf_tag_packet(m, pd->pf_mtag, tag, rtableid)) {
 		REASON_SET(&reason, PFRES_MEMORY);
 		return (PF_DROP);
 	}
@@ -3838,7 +4148,7 @@
 			REASON_SET(&reason, PFRES_MAXSTATES);
 			goto cleanup;
 		}
-		/* src node for flter rule */
+		/* src node for filter rule */
 		if ((r->rule_flag & PFRULE_SRCTRACK ||
 		    r->rpool.opts & PF_POOL_STICKYADDR) &&
 		    pf_insert_src_node(&sn, r, saddr, af) != 0) {
@@ -3878,7 +4188,9 @@
 		s->anchor.ptr = a;
 		STATE_INC_COUNTERS(s);
 		s->allow_opts = r->allow_opts;
-		s->log = r->log & 2;
+		s->log = r->log & PF_LOG_ALL;
+		if (nr != NULL)
+			s->log |= nr->log & PF_LOG_ALL;
 		s->proto = pd->proto;
 		s->direction = direction;
 		s->af = af;
@@ -3956,9 +4268,9 @@
 	struct pf_addr		*saddr = pd->src, *daddr = pd->dst;
 	sa_family_t		 af = pd->af;
 	u_short			 reason;
-	struct pf_tag		*pftag = NULL;
-	int			 tag = -1;
+	int			 tag = -1, rtableid = -1;
 	int			 asd = 0;
+	int			 match = 0;
 
 	if (pf_check_congestion(ifq)) {
 		REASON_SET(&reason, PFRES_CONGEST);
@@ -4015,8 +4327,7 @@
 
 	while (r != NULL) {
 		r->evaluations++;
-		if (r->kif != NULL &&
-		    (r->kif != kif && r->kif != kif->pfik_parent) == !r->ifnot)
+		if (pfi_kif_match(r->kif, kif) == r->ifnot)
 			r = r->skip[PF_SKIP_IFP].ptr;
 		else if (r->direction && r->direction != direction)
 			r = r->skip[PF_SKIP_DIR].ptr;
@@ -4024,24 +4335,29 @@
 			r = r->skip[PF_SKIP_AF].ptr;
 		else if (r->proto && r->proto != pd->proto)
 			r = r->skip[PF_SKIP_PROTO].ptr;
-		else if (PF_MISMATCHAW(&r->src.addr, pd->src, af, r->src.neg))
+		else if (PF_MISMATCHAW(&r->src.addr, pd->src, af,
+		    r->src.neg, kif))
 			r = r->skip[PF_SKIP_SRC_ADDR].ptr;
-		else if (PF_MISMATCHAW(&r->dst.addr, pd->dst, af, r->dst.neg))
+		else if (PF_MISMATCHAW(&r->dst.addr, pd->dst, af,
+		    r->dst.neg, NULL))
 			r = r->skip[PF_SKIP_DST_ADDR].ptr;
-		else if (r->tos && !(r->tos & pd->tos))
+		else if (r->tos && !(r->tos == pd->tos))
 			r = TAILQ_NEXT(r, entries);
 		else if (r->rule_flag & PFRULE_FRAGMENT)
 			r = TAILQ_NEXT(r, entries);
 		else if (r->prob && r->prob <= arc4random())
 			r = TAILQ_NEXT(r, entries);
-		else if (r->match_tag && !pf_match_tag(m, r, &pftag, &tag))
+		else if (r->match_tag && !pf_match_tag(m, r, pd->pf_mtag, &tag))
 			r = TAILQ_NEXT(r, entries);
 		else if (r->os_fingerprint != PF_OSFP_ANY)
 			r = TAILQ_NEXT(r, entries);
 		else {
 			if (r->tag)
 				tag = r->tag;
+			if (r->rtableid >= 0)
+				rtableid = r->rtableid;
 			if (r->anchor == NULL) {
+				match = 1;
 				*rm = r;
 				*am = a;
 				*rsm = ruleset;
@@ -4050,11 +4366,11 @@
 				r = TAILQ_NEXT(r, entries);
 			} else
 				pf_step_into_anchor(&asd, &ruleset,
-				    PF_RULESET_FILTER, &r, &a);
+				    PF_RULESET_FILTER, &r, &a, &match);
 		}
-		if (r == NULL)
-			pf_step_out_of_anchor(&asd, &ruleset,
-			    PF_RULESET_FILTER, &r, &a);
+		if (r == NULL && pf_step_out_of_anchor(&asd, &ruleset,
+		    PF_RULESET_FILTER, &r, &a, &match))
+			break;
 	}
 	r = *rm;
 	a = *am;
@@ -4062,8 +4378,9 @@
 
 	REASON_SET(&reason, PFRES_MATCH);
 
-	if (r->log)
-		PFLOG_PACKET(kif, h, m, af, direction, reason, r, a, ruleset);
+	if (r->log || (nr != NULL && nr->natpass && nr->log))
+		PFLOG_PACKET(kif, h, m, af, direction, reason, r->log ? r : nr,
+		    a, ruleset, pd);
 
 	if ((r->action == PF_DROP) &&
 	    ((r->rule_flag & PFRULE_RETURNICMP) ||
@@ -4102,7 +4419,7 @@
 	if (r->action != PF_PASS)
 		return (PF_DROP);
 
-	if (pf_tag_packet(m, pftag, tag)) {
+	if (pf_tag_packet(m, pd->pf_mtag, tag, rtableid)) {
 		REASON_SET(&reason, PFRES_MEMORY);
 		return (PF_DROP);
 	}
@@ -4118,7 +4435,7 @@
 			REASON_SET(&reason, PFRES_MAXSTATES);
 			goto cleanup;
 		}
-		/* src node for flter rule */
+		/* src node for filter rule */
 		if ((r->rule_flag & PFRULE_SRCTRACK ||
 		    r->rpool.opts & PF_POOL_STICKYADDR) &&
 		    pf_insert_src_node(&sn, r, saddr, af) != 0) {
@@ -4158,7 +4475,9 @@
 		s->anchor.ptr = a;
 		STATE_INC_COUNTERS(s);
 		s->allow_opts = r->allow_opts;
-		s->log = r->log & 2;
+		s->log = r->log & PF_LOG_ALL;
+		if (nr != NULL)
+			s->log |= nr->log & PF_LOG_ALL;
 		s->proto = pd->proto;
 		s->direction = direction;
 		s->af = af;
@@ -4218,15 +4537,14 @@
 	struct pf_ruleset	*ruleset = NULL;
 	sa_family_t		 af = pd->af;
 	u_short			 reason;
-	struct pf_tag		*pftag = NULL;
 	int			 tag = -1;
 	int			 asd = 0;
+	int			 match = 0;
 
 	r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr);
 	while (r != NULL) {
 		r->evaluations++;
-		if (r->kif != NULL &&
-		    (r->kif != kif && r->kif != kif->pfik_parent) == !r->ifnot)
+		if (pfi_kif_match(r->kif, kif) == r->ifnot)
 			r = r->skip[PF_SKIP_IFP].ptr;
 		else if (r->direction && r->direction != direction)
 			r = r->skip[PF_SKIP_DIR].ptr;
@@ -4234,22 +4552,33 @@
 			r = r->skip[PF_SKIP_AF].ptr;
 		else if (r->proto && r->proto != pd->proto)
 			r = r->skip[PF_SKIP_PROTO].ptr;
-		else if (PF_MISMATCHAW(&r->src.addr, pd->src, af, r->src.neg))
+		else if (PF_MISMATCHAW(&r->src.addr, pd->src, af,
+		    r->src.neg, kif))
 			r = r->skip[PF_SKIP_SRC_ADDR].ptr;
-		else if (PF_MISMATCHAW(&r->dst.addr, pd->dst, af, r->dst.neg))
+		else if (PF_MISMATCHAW(&r->dst.addr, pd->dst, af,
+		    r->dst.neg, NULL))
 			r = r->skip[PF_SKIP_DST_ADDR].ptr;
-		else if (r->tos && !(r->tos & pd->tos))
+		else if (r->tos && !(r->tos == pd->tos))
+			r = TAILQ_NEXT(r, entries);
+		else if (r->os_fingerprint != PF_OSFP_ANY)
+			r = TAILQ_NEXT(r, entries);
+		else if (pd->proto == IPPROTO_UDP &&
+		    (r->src.port_op || r->dst.port_op))
 			r = TAILQ_NEXT(r, entries);
-		else if (r->src.port_op || r->dst.port_op ||
-		    r->flagset || r->type || r->code ||
-		    r->os_fingerprint != PF_OSFP_ANY)
+		else if (pd->proto == IPPROTO_TCP &&
+		    (r->src.port_op || r->dst.port_op || r->flagset))
+			r = TAILQ_NEXT(r, entries);
+		else if ((pd->proto == IPPROTO_ICMP ||
+		    pd->proto == IPPROTO_ICMPV6) &&
+		    (r->type || r->code))
 			r = TAILQ_NEXT(r, entries);
 		else if (r->prob && r->prob <= arc4random())
 			r = TAILQ_NEXT(r, entries);
-		else if (r->match_tag && !pf_match_tag(m, r, &pftag, &tag))
+		else if (r->match_tag && !pf_match_tag(m, r, pd->pf_mtag, &tag))
 			r = TAILQ_NEXT(r, entries);
 		else {
 			if (r->anchor == NULL) {
+				match = 1;
 				*rm = r;
 				*am = a;
 				*rsm = ruleset;
@@ -4258,11 +4587,11 @@
 				r = TAILQ_NEXT(r, entries);
 			} else
 				pf_step_into_anchor(&asd, &ruleset,
-				    PF_RULESET_FILTER, &r, &a);
+				    PF_RULESET_FILTER, &r, &a, &match);
 		}
-		if (r == NULL)
-			pf_step_out_of_anchor(&asd, &ruleset,
-			    PF_RULESET_FILTER, &r, &a);
+		if (r == NULL && pf_step_out_of_anchor(&asd, &ruleset,
+		    PF_RULESET_FILTER, &r, &a, &match))
+			break;
 	}
 	r = *rm;
 	a = *am;
@@ -4271,12 +4600,13 @@
 	REASON_SET(&reason, PFRES_MATCH);
 
 	if (r->log)
-		PFLOG_PACKET(kif, h, m, af, direction, reason, r, a, ruleset);
+		PFLOG_PACKET(kif, h, m, af, direction, reason, r, a, ruleset,
+		    pd);
 
 	if (r->action != PF_PASS)
 		return (PF_DROP);
 
-	if (pf_tag_packet(m, pftag, tag)) {
+	if (pf_tag_packet(m, pd->pf_mtag, tag, -1)) {
 		REASON_SET(&reason, PFRES_MEMORY);
 		return (PF_DROP);
 	}
@@ -4289,7 +4619,7 @@
     struct mbuf *m, int off, void *h, struct pf_pdesc *pd,
     u_short *reason)
 {
-	struct pf_state		 key;
+	struct pf_state_cmp	 key;
 	struct tcphdr		*th = pd->hdr.tcp;
 	u_int16_t		 win = ntohs(th->th_win);
 	u_int32_t		 ack, end, seq, orig_seq;
@@ -4332,11 +4662,15 @@
 				REASON_SET(reason, PFRES_SYNPROXY);
 				return (PF_DROP);
 			}
+#ifdef __FreeBSD__
+			pf_send_tcp(NULL, (*state)->rule.ptr, pd->af, pd->dst,
+#else
 			pf_send_tcp((*state)->rule.ptr, pd->af, pd->dst,
+#endif
 			    pd->src, th->th_dport, th->th_sport,
 			    (*state)->src.seqhi, ntohl(th->th_seq) + 1,
 			    TH_SYN|TH_ACK, 0, (*state)->src.mss, 0, 1,
-			    NULL, NULL);
+			    0, NULL, NULL);
 			REASON_SET(reason, PFRES_SYNPROXY);
 			return (PF_SYNPROXY_DROP);
 		} else if (!(th->th_flags & TH_ACK) ||
@@ -4371,10 +4705,15 @@
 			(*state)->src.max_win = MAX(ntohs(th->th_win), 1);
 			if ((*state)->dst.seqhi == 1)
 				(*state)->dst.seqhi = htonl(arc4random());
+#ifdef __FreeBSD__
+			pf_send_tcp(NULL, (*state)->rule.ptr, pd->af,
+			    &src->addr,
+#else
 			pf_send_tcp((*state)->rule.ptr, pd->af, &src->addr,
+#endif
 			    &dst->addr, src->port, dst->port,
 			    (*state)->dst.seqhi, 0, TH_SYN, 0,
-			    (*state)->src.mss, 0, 0, NULL, NULL);
+			    (*state)->src.mss, 0, 0, (*state)->tag, NULL, NULL);
 			REASON_SET(reason, PFRES_SYNPROXY);
 			return (PF_SYNPROXY_DROP);
 		} else if (((th->th_flags & (TH_SYN|TH_ACK)) !=
@@ -4385,16 +4724,25 @@
 		} else {
 			(*state)->dst.max_win = MAX(ntohs(th->th_win), 1);
 			(*state)->dst.seqlo = ntohl(th->th_seq);
+#ifdef __FreeBSD__
+			pf_send_tcp(NULL, (*state)->rule.ptr, pd->af, pd->dst,
+#else
 			pf_send_tcp((*state)->rule.ptr, pd->af, pd->dst,
+#endif
 			    pd->src, th->th_dport, th->th_sport,
 			    ntohl(th->th_ack), ntohl(th->th_seq) + 1,
 			    TH_ACK, (*state)->src.max_win, 0, 0, 0,
-			    NULL, NULL);
+			    (*state)->tag, NULL, NULL);
+#ifdef __FreeBSD__
+			pf_send_tcp(NULL, (*state)->rule.ptr, pd->af,
+			    &src->addr,
+#else
 			pf_send_tcp((*state)->rule.ptr, pd->af, &src->addr,
+#endif
 			    &dst->addr, src->port, dst->port,
 			    (*state)->src.seqhi + 1, (*state)->src.seqlo + 1,
 			    TH_ACK, (*state)->dst.max_win, 0, 0, 1,
-			    NULL, NULL);
+			    0, NULL, NULL);
 			(*state)->src.seqdiff = (*state)->dst.seqhi -
 			    (*state)->src.seqlo;
 			(*state)->dst.seqdiff = (*state)->src.seqhi -
@@ -4437,8 +4785,13 @@
 
 		/* Deferred generation of sequence number modulator */
 		if (dst->seqdiff && !src->seqdiff) {
-			while ((src->seqdiff = htonl(arc4random())) == 0)
+#ifdef __FreeBSD__
+			while ((src->seqdiff = pf_new_isn(*state) - seq) == 0)
 				;
+#else
+			while ((src->seqdiff = tcp_rndiss_next() - seq) == 0)
+				;
+#endif
 			ack = ntohl(th->th_ack) - dst->seqdiff;
 			pf_change_a(&th->th_seq, &th->th_sum, htonl(seq +
 			    src->seqdiff), 0);
@@ -4526,6 +4879,25 @@
 
 	ackskew = dst->seqlo - ack;
 
+
+	/*
+	 * Need to demodulate the sequence numbers in any TCP SACK options
+	 * (Selective ACK). We could optionally validate the SACK values
+	 * against the current ACK window, either forwards or backwards, but
+	 * I'm not confident that SACK has been implemented properly
+	 * everywhere. It wouldn't surprise me if several stacks accidently
+	 * SACK too far backwards of previously ACKed data. There really aren't
+	 * any security implications of bad SACKing unless the target stack
+	 * doesn't validate the option length correctly. Someone trying to
+	 * spoof into a TCP connection won't bother blindly sending SACK
+	 * options anyway.
+	 */
+	if (dst->seqdiff && (th->th_off << 2) > sizeof(struct tcphdr)) {
+		if (pf_modulate_sack(m, off, pd, th, dst))
+			copyback = 1;
+	}
+
+
 #define MAXACKWINDOW (0xffff + 1500)	/* 1500 is an arbitrary fudge factor */
 	if (SEQ_GEQ(src->seqhi, end) &&
 	    /* Last octet inside other's window space */
@@ -4536,8 +4908,8 @@
 	    (ackskew <= (MAXACKWINDOW << sws)) &&
 	    /* Acking not more than one window forward */
 	    ((th->th_flags & TH_RST) == 0 || orig_seq == src->seqlo ||
-	    (pd->flags & PFDESC_IP_REAS) == 0)) {
-	    /* Require an exact sequence match on resets when possible */
+	    (orig_seq == src->seqlo + 1) || (pd->flags & PFDESC_IP_REAS) == 0)) {
+	    /* Require an exact/+1 sequence match on resets when possible */
 
 		if (dst->scrub || src->scrub) {
 			if (pf_normalize_tcp_stateful(m, off, pd, reason, th,
@@ -4583,8 +4955,8 @@
 		if (src->state >= TCPS_FIN_WAIT_2 &&
 		    dst->state >= TCPS_FIN_WAIT_2)
 			(*state)->timeout = PFTM_TCP_CLOSED;
-		else if (src->state >= TCPS_FIN_WAIT_2 ||
-		    dst->state >= TCPS_FIN_WAIT_2)
+		else if (src->state >= TCPS_CLOSING &&
+		    dst->state >= TCPS_CLOSING)
 			(*state)->timeout = PFTM_TCP_FIN_WAIT;
 		else if (src->state < TCPS_ESTABLISHED ||
 		    dst->state < TCPS_ESTABLISHED)
@@ -4630,9 +5002,15 @@
 			printf("pf: loose state match: ");
 			pf_print_state(*state);
 			pf_print_flags(th->th_flags);
-			printf(" seq=%u ack=%u len=%u ackskew=%d pkts=%d:%d\n",
-			    seq, ack, pd->p_len, ackskew,
-			    (*state)->packets[0], (*state)->packets[1]);
+			printf(" seq=%u (%u) ack=%u len=%u ackskew=%d "
+			    "pkts=%llu:%llu\n", seq, orig_seq, ack, pd->p_len,
+#ifdef __FreeBSD__
+			    ackskew, (unsigned long long)(*state)->packets[0],
+			    (unsigned long long)(*state)->packets[1]);
+#else
+			    ackskew, (*state)->packets[0],
+			    (*state)->packets[1]);
+#endif
 		}
 
 		if (dst->scrub || src->scrub) {
@@ -4669,11 +5047,15 @@
 		    (*state)->src.state == TCPS_SYN_SENT) {
 			/* Send RST for state mismatches during handshake */
 			if (!(th->th_flags & TH_RST))
+#ifdef __FreeBSD__
+				pf_send_tcp(m, (*state)->rule.ptr, pd->af,
+#else
 				pf_send_tcp((*state)->rule.ptr, pd->af,
+#endif
 				    pd->dst, pd->src, th->th_dport,
 				    th->th_sport, ntohl(th->th_ack), 0,
 				    TH_RST, 0, 0,
-				    (*state)->rule.ptr->return_ttl, 1,
+				    (*state)->rule.ptr->return_ttl, 1, 0,
 				    pd->eh, kif->pfik_ifp);
 			src->seqlo = 0;
 			src->seqhi = 1;
@@ -4682,9 +5064,15 @@
 			printf("pf: BAD state: ");
 			pf_print_state(*state);
 			pf_print_flags(th->th_flags);
-			printf(" seq=%u ack=%u len=%u ackskew=%d pkts=%d:%d "
-			    "dir=%s,%s\n", seq, ack, pd->p_len, ackskew,
+			printf(" seq=%u (%u) ack=%u len=%u ackskew=%d "
+			    "pkts=%llu:%llu dir=%s,%s\n",
+			    seq, orig_seq, ack, pd->p_len, ackskew,
+#ifdef __FreeBSD__
+			    (unsigned long long)(*state)->packets[0],
+			    (unsigned long long)(*state)->packets[1],
+#else
 			    (*state)->packets[0], (*state)->packets[1],
+#endif
 			    direction == PF_IN ? "in" : "out",
 			    direction == (*state)->direction ? "fwd" : "rev");
 			printf("pf: State failure on: %c %c %c %c | %c %c\n",
@@ -4726,7 +5114,7 @@
     struct mbuf *m, int off, void *h, struct pf_pdesc *pd)
 {
 	struct pf_state_peer	*src, *dst;
-	struct pf_state		 key;
+	struct pf_state_cmp	 key;
 	struct udphdr		*uh = pd->hdr.udp;
 
 	key.af = pd->af;
@@ -4791,6 +5179,7 @@
 	u_int16_t	*icmpsum = NULL;	/* make the compiler happy */
 	u_int8_t	 icmptype = 0;		/* make the compiler happy */
 	int		 state_icmp = 0;
+	struct pf_state_cmp key;
 
 	switch (pd->proto) {
 #ifdef INET
@@ -4828,8 +5217,6 @@
 		 * ICMP query/reply message not related to a TCP/UDP packet.
 		 * Search for an ICMP state.
 		 */
-		struct pf_state		key;
-
 		key.af = pd->af;
 		key.proto = pd->proto;
 		if (direction == PF_IN)	{
@@ -5015,13 +5402,16 @@
 			} while (!terminal);
 			break;
 #endif /* INET6 */
+#ifdef __FreeBSD__
+		default:
+			panic("AF not supported: %d", pd->af);
+#endif
 		}
 
 		switch (pd2.proto) {
 		case IPPROTO_TCP: {
 			struct tcphdr		 th;
 			u_int32_t		 seq;
-			struct pf_state		 key;
 			struct pf_state_peer	*src, *dst;
 			u_int8_t		 dws;
 			int			 copyback = 0;
@@ -5063,8 +5453,7 @@
 				dst = &(*state)->dst;
 			}
 
-			if (src->wscale && dst->wscale &&
-			    !(th.th_flags & TH_SYN))
+			if (src->wscale && dst->wscale)
 				dws = dst->wscale & PF_WSCALE_MASK;
 			else
 				dws = 0;
@@ -5138,7 +5527,6 @@
 		}
 		case IPPROTO_UDP: {
 			struct udphdr		uh;
-			struct pf_state		key;
 
 			if (!pf_pull_hdr(m, off2, &uh, sizeof(uh),
 			    NULL, reason, pd2.af)) {
@@ -5207,7 +5595,6 @@
 #ifdef INET
 		case IPPROTO_ICMP: {
 			struct icmp		iih;
-			struct pf_state		key;
 
 			if (!pf_pull_hdr(m, off2, &iih, ICMP_MINLEN,
 			    NULL, reason, pd2.af)) {
@@ -5262,7 +5649,6 @@
 #ifdef INET6
 		case IPPROTO_ICMPV6: {
 			struct icmp6_hdr	iih;
-			struct pf_state		key;
 
 			if (!pf_pull_hdr(m, off2, &iih,
 			    sizeof(struct icmp6_hdr), NULL, reason, pd2.af)) {
@@ -5315,8 +5701,6 @@
 		}
 #endif /* INET6 */
 		default: {
-			struct pf_state		key;
-
 			key.af = pd2.af;
 			key.proto = pd2.proto;
 			if (direction == PF_IN)	{
@@ -5380,7 +5764,7 @@
     struct pf_pdesc *pd)
 {
 	struct pf_state_peer	*src, *dst;
-	struct pf_state		 key;
+	struct pf_state_cmp	 key;
 
 	key.af = pd->af;
 	key.proto = pd->proto;
@@ -5508,16 +5892,28 @@
 }
 
 int
-pf_routable(struct pf_addr *addr, sa_family_t af)
+pf_routable(struct pf_addr *addr, sa_family_t af, struct pfi_kif *kif)
 {
 	struct sockaddr_in	*dst;
+	int			 ret = 1;
+	int			 check_mpath;
+#ifndef __FreeBSD__
+	extern int		 ipmultipath;
+#endif
 #ifdef INET6
+#ifndef __FreeBSD__
+	extern int		 ip6_multipath;
+#endif
 	struct sockaddr_in6	*dst6;
 	struct route_in6	 ro;
 #else
 	struct route		 ro;
 #endif
+	struct radix_node	*rn;
+	struct rtentry		*rt;
+	struct ifnet		*ifp;
 
+	check_mpath = 0;
 	bzero(&ro, sizeof(ro));
 	switch (af) {
 	case AF_INET:
@@ -5525,6 +5921,10 @@
 		dst->sin_family = AF_INET;
 		dst->sin_len = sizeof(*dst);
 		dst->sin_addr = addr->v4;
+#ifndef __FreeBSD__	/* MULTIPATH_ROUTING */
+		if (ipmultipath)
+			check_mpath = 1;
+#endif
 		break;
 #ifdef INET6
 	case AF_INET6:
@@ -5532,28 +5932,62 @@
 		dst6->sin6_family = AF_INET6;
 		dst6->sin6_len = sizeof(*dst6);
 		dst6->sin6_addr = addr->v6;
+#ifndef __FreeBSD__	/* MULTIPATH_ROUTING */
+		if (ip6_multipath)
+			check_mpath = 1;
+#endif
 		break;
 #endif /* INET6 */
 	default:
 		return (0);
 	}
 
+	/* Skip checks for ipsec interfaces */
+	if (kif != NULL && kif->pfik_ifp->if_type == IFT_ENC)
+		goto out;
+
 #ifdef __FreeBSD__
-#ifdef RTF_PRCLONING
-	rtalloc_ign((struct route *)&ro, (RTF_CLONING | RTF_PRCLONING));
-#else /* !RTF_PRCLONING */
 	rtalloc_ign((struct route *)&ro, RTF_CLONING);
-#endif
 #else /* ! __FreeBSD__ */
 	rtalloc_noclone((struct route *)&ro, NO_CLONING);
 #endif
 
 	if (ro.ro_rt != NULL) {
-		RTFREE(ro.ro_rt);
-		return (1);
-	}
+		/* No interface given, this is a no-route check */
+		if (kif == NULL)
+			goto out;
+
+		if (kif->pfik_ifp == NULL) {
+			ret = 0;
+			goto out;
+		}
+
+		/* Perform uRPF check if passed input interface */
+		ret = 0;
+		rn = (struct radix_node *)ro.ro_rt;
+		do {
+			rt = (struct rtentry *)rn;
+#ifndef __FreeBSD__ /* CARPDEV */
+			if (rt->rt_ifp->if_type == IFT_CARP)
+				ifp = rt->rt_ifp->if_carpdev;
+			else
+#endif
+				ifp = rt->rt_ifp;
 
-	return (0);
+			if (kif->pfik_ifp == ifp)
+				ret = 1;
+#ifdef __FreeBSD__ /* MULTIPATH_ROUTING */
+			rn = NULL;
+#else
+			rn = rn_mpath_next(rn);
+#endif
+		} while (check_mpath == 1 && rn != NULL && ret == 0);
+	} else
+		ret = 0;
+out:
+	if (ro.ro_rt != NULL)
+		RTFREE(ro.ro_rt);
+	return (ret);
 }
 
 int
@@ -5615,12 +6049,11 @@
 
 void
 pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
-    struct pf_state *s)
+    struct pf_state *s, struct pf_pdesc *pd)
 {
 	struct mbuf		*m0, *m1;
-	struct m_tag		*mtag;
 	struct route		 iproute;
-	struct route		*ro = NULL;	/* XXX: was uninitialized */
+	struct route		*ro = NULL;
 	struct sockaddr_in	*dst;
 	struct ip		*ip;
 	struct ifnet		*ifp = NULL;
@@ -5630,27 +6063,18 @@
 #ifdef __FreeBSD__
 	int sw_csum;
 #endif
+#ifdef IPSEC
+	struct m_tag		*mtag;
+#endif /* IPSEC */
 
 	if (m == NULL || *m == NULL || r == NULL ||
 	    (dir != PF_IN && dir != PF_OUT) || oifp == NULL)
 		panic("pf_route: invalid parameters");
 
-	if ((mtag = m_tag_find(*m, PACKET_TAG_PF_ROUTED, NULL)) == NULL) {
-		if ((mtag = m_tag_get(PACKET_TAG_PF_ROUTED, 1, M_NOWAIT)) ==
-		    NULL) {
-			m0 = *m;
-			*m = NULL;
-			goto bad;
-		}
-		*(char *)(mtag + 1) = 1;
-		m_tag_prepend(*m, mtag);
-	} else {
-		if (*(char *)(mtag + 1) > 3) {
-			m0 = *m;
-			*m = NULL;
-			goto bad;
-		}
-		(*(char *)(mtag + 1))++;
+	if (pd->pf_mtag->routed++ > 3) {
+		m0 = *m;
+		*m = NULL;
+		goto bad;
 	}
 
 	if (r->rt == PF_DUPTO) {
@@ -5797,33 +6221,33 @@
 #endif /* IPSEC */
 
 	/* Catch routing changes wrt. hardware checksumming for TCP or UDP. */
-	if (m0->m_pkthdr.csum & M_TCPV4_CSUM_OUT) {
+	if (m0->m_pkthdr.csum_flags & M_TCPV4_CSUM_OUT) {
 		if (!(ifp->if_capabilities & IFCAP_CSUM_TCPv4) ||
 		    ifp->if_bridge != NULL) {
 			in_delayed_cksum(m0);
-			m0->m_pkthdr.csum &= ~M_TCPV4_CSUM_OUT; /* Clear */
+			m0->m_pkthdr.csum_flags &= ~M_TCPV4_CSUM_OUT; /* Clear */
 		}
-	} else if (m0->m_pkthdr.csum & M_UDPV4_CSUM_OUT) {
+	} else if (m0->m_pkthdr.csum_flags & M_UDPV4_CSUM_OUT) {
 		if (!(ifp->if_capabilities & IFCAP_CSUM_UDPv4) ||
 		    ifp->if_bridge != NULL) {
 			in_delayed_cksum(m0);
-			m0->m_pkthdr.csum &= ~M_UDPV4_CSUM_OUT; /* Clear */
+			m0->m_pkthdr.csum_flags &= ~M_UDPV4_CSUM_OUT; /* Clear */
 		}
 	}
 
 	if (ntohs(ip->ip_len) <= ifp->if_mtu) {
 		if ((ifp->if_capabilities & IFCAP_CSUM_IPv4) &&
 		    ifp->if_bridge == NULL) {
-			m0->m_pkthdr.csum |= M_IPV4_CSUM_OUT;
+			m0->m_pkthdr.csum_flags |= M_IPV4_CSUM_OUT;
 			ipstat.ips_outhwcsum++;
 		} else {
 			ip->ip_sum = 0;
 			ip->ip_sum = in_cksum(m0, ip->ip_hl << 2);
 		}
 		/* Update relevant hardware checksum stats for TCP/UDP */
-		if (m0->m_pkthdr.csum & M_TCPV4_CSUM_OUT)
+		if (m0->m_pkthdr.csum_flags & M_TCPV4_CSUM_OUT)
 			tcpstat.tcps_outhwcsum++;
-		else if (m0->m_pkthdr.csum & M_UDPV4_CSUM_OUT)
+		else if (m0->m_pkthdr.csum_flags & M_UDPV4_CSUM_OUT)
 			udpstat.udps_outhwcsum++;
 		error = (*ifp->if_output)(ifp, m0, sintosa(dst), NULL);
 		goto done;
@@ -5846,7 +6270,7 @@
 			PF_LOCK();
 #else
 			icmp_error(m0, ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG, 0,
-			    ifp);
+			    ifp->if_mtu);
 #endif
 			goto done;
 		} else
@@ -5909,10 +6333,9 @@
 #ifdef INET6
 void
 pf_route6(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
-    struct pf_state *s)
+    struct pf_state *s, struct pf_pdesc *pd)
 {
 	struct mbuf		*m0;
-	struct m_tag		*mtag;
 	struct route_in6	 ip6route;
 	struct route_in6	*ro;
 	struct sockaddr_in6	*dst;
@@ -5926,22 +6349,10 @@
 	    (dir != PF_IN && dir != PF_OUT) || oifp == NULL)
 		panic("pf_route6: invalid parameters");
 
-	if ((mtag = m_tag_find(*m, PACKET_TAG_PF_ROUTED, NULL)) == NULL) {
-		if ((mtag = m_tag_get(PACKET_TAG_PF_ROUTED, 1, M_NOWAIT)) ==
-		    NULL) {
-			m0 = *m;
-			*m = NULL;
-			goto bad;
-		}
-		*(char *)(mtag + 1) = 1;
-		m_tag_prepend(*m, mtag);
-	} else {
-		if (*(char *)(mtag + 1) > 3) {
-			m0 = *m;
-			*m = NULL;
-			goto bad;
-		}
-		(*(char *)(mtag + 1))++;
+	if (pd->pf_mtag->routed++ > 3) {
+		m0 = *m;
+		*m = NULL;
+		goto bad;
 	}
 
 	if (r->rt == PF_DUPTO) {
@@ -5971,7 +6382,7 @@
 	dst->sin6_len = sizeof(*dst);
 	dst->sin6_addr = ip6->ip6_dst;
 
-	/* Cheat. */
+	/* Cheat. XXX why only in the v6 case??? */
 	if (r->rt == PF_FASTROUTE) {
 #ifdef __FreeBSD__
 		m0->m_flags |= M_SKIP_FIREWALL;
@@ -5983,6 +6394,7 @@
 		if (mtag == NULL)
 			goto bad;
 		m_tag_prepend(m0, mtag);
+		pd->pf_mtag->flags |= PF_TAG_GENERATED;
 		ip6_output(m0, NULL, NULL, 0, NULL, NULL);
 #endif
 		return;
@@ -6038,7 +6450,7 @@
 	 * If the packet is too large for the outgoing interface,
 	 * send back an icmp6 error.
 	 */
-	if (IN6_IS_ADDR_LINKLOCAL(&dst->sin6_addr))
+	if (IN6_IS_SCOPE_EMBED(&dst->sin6_addr))
 		dst->sin6_addr.s6_addr16[1] = htons(ifp->if_index);
 	if ((u_long)m0->m_pkthdr.len <= ifp->if_mtu) {
 #ifdef __FreeBSD__
@@ -6200,7 +6612,7 @@
 	}
 	return (0);
 }
-#else
+#else /* !__FreeBSD__ */
 /*
  * check protocol (tcp/udp/icmp/icmp6) checksum and set mbuf flag
  *   off is the offset where the protocol header starts
@@ -6232,9 +6644,9 @@
 	default:
 		return (1);
 	}
-	if (m->m_pkthdr.csum & flag_ok)
+	if (m->m_pkthdr.csum_flags & flag_ok)
 		return (0);
-	if (m->m_pkthdr.csum & flag_bad)
+	if (m->m_pkthdr.csum_flags & flag_bad)
 		return (1);
 	if (off < sizeof(struct ip) || len < sizeof(struct udphdr))
 		return (1);
@@ -6269,7 +6681,7 @@
 		return (1);
 	}
 	if (sum) {
-		m->m_pkthdr.csum |= flag_bad;
+		m->m_pkthdr.csum_flags |= flag_bad;
 		switch (p) {
 		case IPPROTO_TCP:
 			tcpstat.tcps_rcvbadsum++;
@@ -6288,24 +6700,10 @@
 		}
 		return (1);
 	}
-	m->m_pkthdr.csum |= flag_ok;
-	return (0);
-}
-#endif
-
-static int
-pf_add_mbuf_tag(struct mbuf *m, u_int tag)
-{
-	struct m_tag *mtag;
-
-	if (m_tag_find(m, tag, NULL) != NULL)
-		return (0);
-	mtag = m_tag_get(tag, 0, M_NOWAIT);
-	if (mtag == NULL)
-		return (1);
-	m_tag_prepend(m, mtag);
+	m->m_pkthdr.csum_flags |= flag_ok;
 	return (0);
 }
+#endif /* __FreeBSD__ */
 
 #ifdef INET
 int
@@ -6330,15 +6728,34 @@
 #ifdef __FreeBSD__
 	PF_LOCK();
 #endif
-	if (!pf_status.running ||
+	if (!pf_status.running)
 #ifdef __FreeBSD__
-	    (m->m_flags & M_SKIP_FIREWALL)) {
+	{
 		PF_UNLOCK();
-#else
-	    (m_tag_find(m, PACKET_TAG_PF_GENERATED, NULL) != NULL)) {
 #endif
-	    	return (PF_PASS);
+		return (PF_PASS);
+#ifdef __FreeBSD__
 	}
+#endif
+
+	memset(&pd, 0, sizeof(pd));
+	if ((pd.pf_mtag = pf_get_mtag(m)) == NULL) {
+#ifdef __FreeBSD__
+		PF_UNLOCK();
+#endif
+		DPFPRINTF(PF_DEBUG_URGENT,
+		    ("pf_test: pf_get_mtag returned NULL\n"));
+		return (PF_DROP);
+	}
+#ifdef __FreeBSD__
+	if (m->m_flags & M_SKIP_FIREWALL) {
+		PF_UNLOCK();
+		return (PF_PASS);
+	}
+#else
+	if (pd.pf_mtag->flags & PF_TAG_GENERATED)
+		return (PF_PASS);
+#endif
 
 #ifdef __FreeBSD__
 	/* XXX_IMPORT: later */
@@ -6347,7 +6764,7 @@
 		ifp = ifp->if_carpdev;
 #endif
 
-	kif = pfi_index2kif[ifp->if_index];
+	kif = (struct pfi_kif *)ifp->if_pf_kif;
 	if (kif == NULL) {
 #ifdef __FreeBSD__
 		PF_UNLOCK();
@@ -6372,7 +6789,6 @@
 #endif /* DIAGNOSTIC */
 #endif /* __FreeBSD__ */
 
-	memset(&pd, 0, sizeof(pd));
 	if (m->m_pkthdr.len < (int)sizeof(*h)) {
 		action = PF_DROP;
 		REASON_SET(&reason, PFRES_SHORT);
@@ -6426,6 +6842,7 @@
 		}
 		if (dir == PF_IN && pf_check_proto_cksum(m, off,
 		    ntohs(h->ip_len) - off, IPPROTO_TCP, AF_INET)) {
+			REASON_SET(&reason, PFRES_PROTCKSUM);
 			action = PF_DROP;
 			goto done;
 		}
@@ -6467,12 +6884,14 @@
 		if (dir == PF_IN && uh.uh_sum && pf_check_proto_cksum(m,
 		    off, ntohs(h->ip_len) - off, IPPROTO_UDP, AF_INET)) {
 			action = PF_DROP;
+			REASON_SET(&reason, PFRES_PROTCKSUM);
 			goto done;
 		}
 		if (uh.uh_dport == 0 ||
 		    ntohs(uh.uh_ulen) > m->m_pkthdr.len - off ||
 		    ntohs(uh.uh_ulen) < sizeof(struct udphdr)) {
 			action = PF_DROP;
+			REASON_SET(&reason, PFRES_SHORT);
 			goto done;
 		}
 		action = pf_test_state_udp(&s, dir, kif, m, off, h, &pd);
@@ -6506,6 +6925,7 @@
 		if (dir == PF_IN && pf_check_proto_cksum(m, off,
 		    ntohs(h->ip_len) - off, IPPROTO_ICMP, AF_INET)) {
 			action = PF_DROP;
+			REASON_SET(&reason, PFRES_PROTCKSUM);
 			goto done;
 		}
 		action = pf_test_state_icmp(&s, dir, kif, m, off, h, &pd,
@@ -6558,26 +6978,18 @@
 		    ("pf: dropping packet with ip options\n"));
 	}
 
-	if (s && s->tag)
-		pf_tag_packet(m, pf_get_tag(m), s->tag);
+	if ((s && s->tag) || r->rtableid)
+		pf_tag_packet(m, pd.pf_mtag, s ? s->tag : 0, r->rtableid);
 
 #ifdef ALTQ
 	if (action == PF_PASS && r->qid) {
-		struct m_tag	*mtag;
-		struct altq_tag	*atag;
-
-		mtag = m_tag_get(PACKET_TAG_PF_QID, sizeof(*atag), M_NOWAIT);
-		if (mtag != NULL) {
-			atag = (struct altq_tag *)(mtag + 1);
-			if (pqid || pd.tos == IPTOS_LOWDELAY)
-				atag->qid = r->pqid;
-			else
-				atag->qid = r->qid;
-			/* add hints for ecn */
-			atag->af = AF_INET;
-			atag->hdr = h;
-			m_tag_prepend(m, mtag);
-		}
+		if (pqid || (pd.tos & IPTOS_LOWDELAY))
+			pd.pf_mtag->qid = r->pqid;
+		else
+			pd.pf_mtag->qid = r->qid;
+		/* add hints for ecn */
+		pd.pf_mtag->af = AF_INET;
+		pd.pf_mtag->hdr = h;
 	}
 #endif /* ALTQ */
 
@@ -6590,41 +7002,48 @@
 	    pd.proto == IPPROTO_UDP) && s != NULL && s->nat_rule.ptr != NULL &&
 	    (s->nat_rule.ptr->action == PF_RDR ||
 	    s->nat_rule.ptr->action == PF_BINAT) &&
-	    (ntohl(pd.dst->v4.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET &&
-	    pf_add_mbuf_tag(m, PACKET_TAG_PF_TRANSLATE_LOCALHOST)) {
-		action = PF_DROP;
-		REASON_SET(&reason, PFRES_MEMORY);
-	}
+	    (ntohl(pd.dst->v4.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET)
+		pd.pf_mtag->flags |= PF_TAG_TRANSLATE_LOCALHOST;
 
-	if (log)
-		PFLOG_PACKET(kif, h, m, AF_INET, dir, reason, r, a, ruleset);
+	if (log) {
+		struct pf_rule *lr;
+
+		if (s != NULL && s->nat_rule.ptr != NULL &&
+		    s->nat_rule.ptr->log & PF_LOG_ALL)
+			lr = s->nat_rule.ptr;
+		else
+			lr = r;
+		PFLOG_PACKET(kif, h, m, AF_INET, dir, reason, lr, a, ruleset,
+		    &pd);
+	}
 
 	kif->pfik_bytes[0][dir == PF_OUT][action != PF_PASS] += pd.tot_len;
 	kif->pfik_packets[0][dir == PF_OUT][action != PF_PASS]++;
 
 	if (action == PF_PASS || r->action == PF_DROP) {
-		r->packets++;
-		r->bytes += pd.tot_len;
+		dirndx = (dir == PF_OUT);
+		r->packets[dirndx]++;
+		r->bytes[dirndx] += pd.tot_len;
 		if (a != NULL) {
-			a->packets++;
-			a->bytes += pd.tot_len;
+			a->packets[dirndx]++;
+			a->bytes[dirndx] += pd.tot_len;
 		}
 		if (s != NULL) {
-			dirndx = (dir == s->direction) ? 0 : 1;
-			s->packets[dirndx]++;
-			s->bytes[dirndx] += pd.tot_len;
 			if (s->nat_rule.ptr != NULL) {
-				s->nat_rule.ptr->packets++;
-				s->nat_rule.ptr->bytes += pd.tot_len;
+				s->nat_rule.ptr->packets[dirndx]++;
+				s->nat_rule.ptr->bytes[dirndx] += pd.tot_len;
 			}
 			if (s->src_node != NULL) {
-				s->src_node->packets++;
-				s->src_node->bytes += pd.tot_len;
+				s->src_node->packets[dirndx]++;
+				s->src_node->bytes[dirndx] += pd.tot_len;
 			}
 			if (s->nat_src_node != NULL) {
-				s->nat_src_node->packets++;
-				s->nat_src_node->bytes += pd.tot_len;
+				s->nat_src_node->packets[dirndx]++;
+				s->nat_src_node->bytes[dirndx] += pd.tot_len;
 			}
+			dirndx = (dir == s->direction) ? 0 : 1;
+			s->packets[dirndx]++;
+			s->bytes[dirndx] += pd.tot_len;
 		}
 		tr = r;
 		nr = (s != NULL) ? s->nat_rule.ptr : pd.nat_rule;
@@ -6669,7 +7088,7 @@
 		action = PF_PASS;
 	} else if (r->rt)
 		/* pf_route can free the mbuf causing *m0 to become NULL */
-		pf_route(m0, r, dir, ifp, s);
+		pf_route(m0, r, dir, ifp, s, &pd);
 
 #ifdef __FreeBSD__
 	PF_UNLOCK();
@@ -6691,27 +7110,39 @@
 {
 	struct pfi_kif		*kif;
 	u_short			 action, reason = 0, log = 0;
-	struct mbuf		*m = *m0;
-	struct ip6_hdr		*h = NULL;	/* make the compiler happy */
+	struct mbuf		*m = *m0, *n = NULL;
+	struct ip6_hdr		*h;
 	struct pf_rule		*a = NULL, *r = &pf_default_rule, *tr, *nr;
 	struct pf_state		*s = NULL;
 	struct pf_ruleset	*ruleset = NULL;
 	struct pf_pdesc		 pd;
-	int			 off, terminal = 0, dirndx;
+	int			 off, terminal = 0, dirndx, rh_cnt = 0;
 
 #ifdef __FreeBSD__
 	PF_LOCK();
 #endif
 
-	if (!pf_status.running ||
+	if (!pf_status.running)
 #ifdef __FreeBSD__
-	    (m->m_flags & M_SKIP_FIREWALL)) {
+	{
 		PF_UNLOCK();
-#else
-	    (m_tag_find(m, PACKET_TAG_PF_GENERATED, NULL) != NULL)) {
 #endif
 		return (PF_PASS);
+#ifdef __FreeBSD__
+	}
+#endif
+
+	memset(&pd, 0, sizeof(pd));
+	if ((pd.pf_mtag = pf_get_mtag(m)) == NULL) {
+#ifdef __FreeBSD__
+		PF_UNLOCK();
+#endif
+		DPFPRINTF(PF_DEBUG_URGENT,
+		    ("pf_test6: pf_get_mtag returned NULL\n"));
+		return (PF_DROP);
 	}
+	if (pd.pf_mtag->flags & PF_TAG_GENERATED)
+		return (PF_PASS);
 
 #ifdef __FreeBSD__
 	/* XXX_IMPORT: later */
@@ -6720,7 +7151,7 @@
 		ifp = ifp->if_carpdev;
 #endif
 
-	kif = pfi_index2kif[ifp->if_index];
+	kif = (struct pfi_kif *)ifp->if_pf_kif;
 	if (kif == NULL) {
 #ifdef __FreeBSD__
 		PF_UNLOCK();
@@ -6745,7 +7176,10 @@
 #endif /* DIAGNOSTIC */
 #endif
 
-	memset(&pd, 0, sizeof(pd));
+#ifdef __FreeBSD__
+	h = NULL;	/* make the compiler happy */
+#endif
+
 	if (m->m_pkthdr.len < (int)sizeof(*h)) {
 		action = PF_DROP;
 		REASON_SET(&reason, PFRES_SHORT);
@@ -6761,6 +7195,18 @@
 	m = *m0;
 	h = mtod(m, struct ip6_hdr *);
 
+#if 1
+	/*
+	 * we do not support jumbogram yet.  if we keep going, zero ip6_plen
+	 * will do something bad, so drop the packet for now.
+	 */
+	if (htons(h->ip6_plen) == 0) {
+		action = PF_DROP;
+		REASON_SET(&reason, PFRES_NORM);	/*XXX*/
+		goto done;
+	}
+#endif
+
 	pd.src = (struct pf_addr *)&h->ip6_src;
 	pd.dst = (struct pf_addr *)&h->ip6_dst;
 	PF_ACPY(&pd.baddr, dir == PF_OUT ? pd.src : pd.dst, AF_INET6);
@@ -6780,9 +7226,38 @@
 			if (action == PF_DROP)
 				REASON_SET(&reason, PFRES_FRAG);
 			goto done;
+		case IPPROTO_ROUTING: {
+			struct ip6_rthdr rthdr;
+
+			if (rh_cnt++) {
+				DPFPRINTF(PF_DEBUG_MISC,
+				    ("pf: IPv6 more than one rthdr\n"));
+				action = PF_DROP;
+				REASON_SET(&reason, PFRES_IPOPTIONS);
+				log = 1;
+				goto done;
+			}
+			if (!pf_pull_hdr(m, off, &rthdr, sizeof(rthdr), NULL,
+			    &reason, pd.af)) {
+				DPFPRINTF(PF_DEBUG_MISC,
+				    ("pf: IPv6 short rthdr\n"));
+				action = PF_DROP;
+				REASON_SET(&reason, PFRES_SHORT);
+				log = 1;
+				goto done;
+			}
+			if (rthdr.ip6r_type == IPV6_RTHDR_TYPE_0) {
+				DPFPRINTF(PF_DEBUG_MISC,
+				    ("pf: IPv6 rthdr0\n"));
+				action = PF_DROP;
+				REASON_SET(&reason, PFRES_IPOPTIONS);
+				log = 1;
+				goto done;
+			}
+			/* fallthrough */
+		}
 		case IPPROTO_AH:
 		case IPPROTO_HOPOPTS:
-		case IPPROTO_ROUTING:
 		case IPPROTO_DSTOPTS: {
 			/* get next header and header length */
 			struct ip6_ext	opt6;
@@ -6809,6 +7284,10 @@
 		}
 	} while (!terminal);
 
+	/* if there's no routing header, use unmodified mbuf for checksumming */
+	if (!n)
+		n = m;
+
 	switch (pd.proto) {
 
 	case IPPROTO_TCP: {
@@ -6820,7 +7299,7 @@
 			log = action != PF_PASS;
 			goto done;
 		}
-		if (dir == PF_IN && pf_check_proto_cksum(m, off,
+		if (dir == PF_IN && pf_check_proto_cksum(n, off,
 		    ntohs(h->ip6_plen) - (off - sizeof(struct ip6_hdr)),
 		    IPPROTO_TCP, AF_INET6)) {
 			action = PF_DROP;
@@ -6860,7 +7339,7 @@
 			log = action != PF_PASS;
 			goto done;
 		}
-		if (dir == PF_IN && uh.uh_sum && pf_check_proto_cksum(m,
+		if (dir == PF_IN && uh.uh_sum && pf_check_proto_cksum(n,
 		    off, ntohs(h->ip6_plen) - (off - sizeof(struct ip6_hdr)),
 		    IPPROTO_UDP, AF_INET6)) {
 			action = PF_DROP;
@@ -6871,6 +7350,7 @@
 		    ntohs(uh.uh_ulen) > m->m_pkthdr.len - off ||
 		    ntohs(uh.uh_ulen) < sizeof(struct udphdr)) {
 			action = PF_DROP;
+			REASON_SET(&reason, PFRES_SHORT);
 			goto done;
 		}
 		action = pf_test_state_udp(&s, dir, kif, m, off, h, &pd);
@@ -6901,7 +7381,7 @@
 			log = action != PF_PASS;
 			goto done;
 		}
-		if (dir == PF_IN && pf_check_proto_cksum(m, off,
+		if (dir == PF_IN && pf_check_proto_cksum(n, off,
 		    ntohs(h->ip6_plen) - (off - sizeof(struct ip6_hdr)),
 		    IPPROTO_ICMPV6, AF_INET6)) {
 			action = PF_DROP;
@@ -6949,28 +7429,28 @@
 	}
 
 done:
-	/* XXX handle IPv6 options, if not allowed. not implemented. */
+	/* handle dangerous IPv6 extension headers. */
+	if (action == PF_PASS && rh_cnt &&
+	    !((s && s->allow_opts) || r->allow_opts)) {
+		action = PF_DROP;
+		REASON_SET(&reason, PFRES_IPOPTIONS);
+		log = 1;
+		DPFPRINTF(PF_DEBUG_MISC,
+		    ("pf: dropping packet with dangerous v6 headers\n"));
+	}
 
-	if (s && s->tag)
-		pf_tag_packet(m, pf_get_tag(m), s->tag);
+	if ((s && s->tag) || r->rtableid)
+		pf_tag_packet(m, pd.pf_mtag, s ? s->tag : 0, r->rtableid);
 
 #ifdef ALTQ
 	if (action == PF_PASS && r->qid) {
-		struct m_tag	*mtag;
-		struct altq_tag	*atag;
-
-		mtag = m_tag_get(PACKET_TAG_PF_QID, sizeof(*atag), M_NOWAIT);
-		if (mtag != NULL) {
-			atag = (struct altq_tag *)(mtag + 1);
-			if (pd.tos == IPTOS_LOWDELAY)
-				atag->qid = r->pqid;
-			else
-				atag->qid = r->qid;
-			/* add hints for ecn */
-			atag->af = AF_INET6;
-			atag->hdr = h;
-			m_tag_prepend(m, mtag);
-		}
+		if (pd.tos & IPTOS_LOWDELAY)
+			pd.pf_mtag->qid = r->pqid;
+		else
+			pd.pf_mtag->qid = r->qid;
+		/* add hints for ecn */
+		pd.pf_mtag->af = AF_INET6;
+		pd.pf_mtag->hdr = h;
 	}
 #endif /* ALTQ */
 
@@ -6978,41 +7458,48 @@
 	    pd.proto == IPPROTO_UDP) && s != NULL && s->nat_rule.ptr != NULL &&
 	    (s->nat_rule.ptr->action == PF_RDR ||
 	    s->nat_rule.ptr->action == PF_BINAT) &&
-	    IN6_IS_ADDR_LOOPBACK(&pd.dst->v6) &&
-	    pf_add_mbuf_tag(m, PACKET_TAG_PF_TRANSLATE_LOCALHOST)) {
-		action = PF_DROP;
-		REASON_SET(&reason, PFRES_MEMORY);
-	}
+	    IN6_IS_ADDR_LOOPBACK(&pd.dst->v6))
+		pd.pf_mtag->flags |= PF_TAG_TRANSLATE_LOCALHOST;
+
+	if (log) {
+		struct pf_rule *lr;
 
-	if (log)
-		PFLOG_PACKET(kif, h, m, AF_INET6, dir, reason, r, a, ruleset);
+		if (s != NULL && s->nat_rule.ptr != NULL &&
+		    s->nat_rule.ptr->log & PF_LOG_ALL)
+			lr = s->nat_rule.ptr;
+		else
+			lr = r;
+		PFLOG_PACKET(kif, h, m, AF_INET6, dir, reason, lr, a, ruleset,
+		    &pd);
+	}
 
 	kif->pfik_bytes[1][dir == PF_OUT][action != PF_PASS] += pd.tot_len;
 	kif->pfik_packets[1][dir == PF_OUT][action != PF_PASS]++;
 
 	if (action == PF_PASS || r->action == PF_DROP) {
-		r->packets++;
-		r->bytes += pd.tot_len;
+		dirndx = (dir == PF_OUT);
+		r->packets[dirndx]++;
+		r->bytes[dirndx] += pd.tot_len;
 		if (a != NULL) {
-			a->packets++;
-			a->bytes += pd.tot_len;
+			a->packets[dirndx]++;
+			a->bytes[dirndx] += pd.tot_len;
 		}
 		if (s != NULL) {
-			dirndx = (dir == s->direction) ? 0 : 1;
-			s->packets[dirndx]++;
-			s->bytes[dirndx] += pd.tot_len;
 			if (s->nat_rule.ptr != NULL) {
-				s->nat_rule.ptr->packets++;
-				s->nat_rule.ptr->bytes += pd.tot_len;
+				s->nat_rule.ptr->packets[dirndx]++;
+				s->nat_rule.ptr->bytes[dirndx] += pd.tot_len;
 			}
 			if (s->src_node != NULL) {
-				s->src_node->packets++;
-				s->src_node->bytes += pd.tot_len;
+				s->src_node->packets[dirndx]++;
+				s->src_node->bytes[dirndx] += pd.tot_len;
 			}
 			if (s->nat_src_node != NULL) {
-				s->nat_src_node->packets++;
-				s->nat_src_node->bytes += pd.tot_len;
+				s->nat_src_node->packets[dirndx]++;
+				s->nat_src_node->bytes[dirndx] += pd.tot_len;
 			}
+			dirndx = (dir == s->direction) ? 0 : 1;
+			s->packets[dirndx]++;
+			s->bytes[dirndx] += pd.tot_len;
 		}
 		tr = r;
 		nr = (s != NULL) ? s->nat_rule.ptr : pd.nat_rule;
@@ -7057,7 +7544,7 @@
 		action = PF_PASS;
 	} else if (r->rt)
 		/* pf_route6 can free the mbuf causing *m0 to become NULL */
-		pf_route6(m0, r, dir, ifp, s);
+		pf_route6(m0, r, dir, ifp, s, &pd);
 
 #ifdef __FreeBSD__
 	PF_UNLOCK();
Index: if_pflog.c
===================================================================
RCS file: /home/cvs/src/sys/contrib/pf/net/if_pflog.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -L sys/contrib/pf/net/if_pflog.c -L sys/contrib/pf/net/if_pflog.c -u -r1.2 -r1.3
--- sys/contrib/pf/net/if_pflog.c
+++ sys/contrib/pf/net/if_pflog.c
@@ -1,6 +1,4 @@
-/*	$FreeBSD: src/sys/contrib/pf/net/if_pflog.c,v 1.13.2.2 2006/03/06 16:10:18 mlaier Exp $	*/
-/*	$OpenBSD: if_pflog.c,v 1.12 2004/05/19 17:50:51 dhartmei Exp $	*/
-
+/*	$OpenBSD: if_pflog.c,v 1.22 2006/12/15 09:31:20 otto Exp $	*/
 /*
  * The authors of this code are John Ioannidis (ji at tla.org),
  * Angelos D. Keromytis (kermit at csd.uch.gr) and 
@@ -38,24 +36,37 @@
 #ifdef __FreeBSD__
 #include "opt_inet.h"
 #include "opt_inet6.h"
-#endif
-
-#ifndef __FreeBSD__
-#include "bpfilter.h"
-#include "pflog.h"
-#elif __FreeBSD__ >= 5
 #include "opt_bpf.h"
 #include "opt_pf.h"
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/sys/contrib/pf/net/if_pflog.c,v 1.21 2007/07/03 12:16:07 mlaier Exp $");
+
+#ifdef DEV_BPF
 #define	NBPFILTER	DEV_BPF
+#else
+#define	NBPFILTER	0
+#endif
+
+#ifdef DEV_PFLOG
 #define	NPFLOG		DEV_PFLOG
+#else
+#define	NPFLOG		0
 #endif
 
+#else /* ! __FreeBSD__ */
+#include "bpfilter.h"
+#include "pflog.h"
+#endif /* __FreeBSD__ */
+
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/mbuf.h>
+#include <sys/proc.h>
 #include <sys/socket.h>
 #ifdef __FreeBSD__
 #include <sys/kernel.h>
+#include <sys/limits.h>
 #include <sys/malloc.h>
 #include <sys/module.h>
 #include <sys/sockio.h>
@@ -64,7 +75,7 @@
 #endif
 
 #include <net/if.h>
-#if defined(__FreeBSD__)
+#ifdef __FreeBSD__
 #include <net/if_clone.h>
 #endif
 #include <net/if_types.h>
@@ -78,10 +89,6 @@
 #include <netinet/ip.h>
 #endif
 
-#ifdef __FreeBSD__
-#include <machine/in_cksum.h>
-#endif
-
 #ifdef INET6
 #ifndef INET
 #include <netinet/in.h>
@@ -93,7 +100,7 @@
 #include <net/if_pflog.h>
 
 #ifdef __FreeBSD__
-#define	PFLOGNAME	"pflog"
+#include <machine/in_cksum.h>
 #endif
 
 #define PFLOGMTU	(32768 + MHLEN + MLEN)
@@ -104,111 +111,148 @@
 #define DPRINTF(x)
 #endif
 
-#ifndef __FreeBSD__
-struct pflog_softc pflogif[NPFLOG];
-#endif
-
-#ifdef __FreeBSD__
-static void	pflog_clone_destroy(struct ifnet *);
-static int	pflog_clone_create(struct if_clone *, int);
-#else
 void	pflogattach(int);
-#endif
 int	pflogoutput(struct ifnet *, struct mbuf *, struct sockaddr *,
 	    	       struct rtentry *);
 int	pflogioctl(struct ifnet *, u_long, caddr_t);
-void	pflogrtrequest(int, struct rtentry *, struct sockaddr *);
 void	pflogstart(struct ifnet *);
-
-#ifndef __FreeBSD__
-extern int ifqmaxlen;
+#ifdef __FreeBSD__
+static int pflog_clone_create(struct if_clone *, int, caddr_t);
+static void pflog_clone_destroy(struct ifnet *);
+#else
+int	pflog_clone_create(struct if_clone *, int);
+int	pflog_clone_destroy(struct ifnet *);
 #endif
 
+LIST_HEAD(, pflog_softc)	pflogif_list;
 #ifdef __FreeBSD__
-static MALLOC_DEFINE(M_PFLOG, PFLOGNAME, "Packet Filter Logging Interface");
-static LIST_HEAD(pflog_list, pflog_softc) pflog_list;
-#define	SCP2IFP(sc)		((sc)->sc_ifp)
-IFC_SIMPLE_DECLARE(pflog, 1);
-
-static void
-pflog_clone_destroy(struct ifnet *ifp)
-{
-	struct pflog_softc *sc;
+IFC_SIMPLE_DECLARE(pflog, 1);    
+#else
+struct if_clone	pflog_cloner =
+    IF_CLONE_INITIALIZER("pflog", pflog_clone_create, pflog_clone_destroy);
+#endif
 
-	sc = ifp->if_softc;
+struct ifnet	*pflogifs[PFLOGIFS_MAX];	/* for fast access */
 
-	/*
-	 * Does we really need this?
-	 */
-	IF_DRAIN(&ifp->if_snd);
+#ifndef __FreeBSD__
+extern int ifqmaxlen;
+#endif
 
-	bpfdetach(ifp);
-	if_detach(ifp);
-	if_free(ifp);
-	LIST_REMOVE(sc, sc_next);
-	free(sc, M_PFLOG);
+void
+pflogattach(int npflog)
+{
+	int	i;
+	LIST_INIT(&pflogif_list);
+	for (i = 0; i < PFLOGIFS_MAX; i++)
+		pflogifs[i] = NULL;
+#ifndef __FreeBSD__
+	(void) pflog_clone_create(&pflog_cloner, 0);
+#endif
+	if_clone_attach(&pflog_cloner);
 }
 
+#ifdef __FreeBSD__
 static int
+pflog_clone_create(struct if_clone *ifc, int unit, caddr_t param)
+#else
+int
 pflog_clone_create(struct if_clone *ifc, int unit)
+#endif
 {
-	struct pflog_softc *sc;
 	struct ifnet *ifp;
+	struct pflog_softc *pflogif;
+	int s;
+
+	if (unit >= PFLOGIFS_MAX)
+		return (EINVAL);
 
-	MALLOC(sc, struct pflog_softc *, sizeof(*sc), M_PFLOG, M_WAITOK|M_ZERO);
-	ifp = sc->sc_ifp = if_alloc(IFT_PFLOG);
+	if ((pflogif = malloc(sizeof(*pflogif), M_DEVBUF, M_NOWAIT)) == NULL)
+		return (ENOMEM);
+	bzero(pflogif, sizeof(*pflogif));
+
+	pflogif->sc_unit = unit;
+#ifdef __FreeBSD__
+	ifp = pflogif->sc_ifp = if_alloc(IFT_PFLOG);
 	if (ifp == NULL) {
-		free(sc, M_PFLOG);
+		free(pflogif, M_DEVBUF);
 		return (ENOSPC);
 	}
-
 	if_initname(ifp, ifc->ifc_name, unit);
+#else
+	ifp = &pflogif->sc_if;
+	snprintf(ifp->if_xname, sizeof ifp->if_xname, "pflog%d", unit);
+#endif
+	ifp->if_softc = pflogif;
 	ifp->if_mtu = PFLOGMTU;
 	ifp->if_ioctl = pflogioctl;
 	ifp->if_output = pflogoutput;
 	ifp->if_start = pflogstart;
+#ifndef __FreeBSD__
+	ifp->if_type = IFT_PFLOG;
+#endif
 	ifp->if_snd.ifq_maxlen = ifqmaxlen;
 	ifp->if_hdrlen = PFLOG_HDRLEN;
-	ifp->if_softc = sc;
 	if_attach(ifp);
+#ifndef __FreeBSD__
+	if_alloc_sadl(ifp);
+#endif
 
-	LIST_INSERT_HEAD(&pflog_list, sc, sc_next);
 #if NBPFILTER > 0
+#ifdef __FreeBSD__
 	bpfattach(ifp, DLT_PFLOG, PFLOG_HDRLEN);
+#else
+	bpfattach(&pflogif->sc_if.if_bpf, ifp, DLT_PFLOG, PFLOG_HDRLEN);
+#endif
+#endif
+
+	s = splnet();
+#ifdef __FreeBSD__
+	PF_LOCK();
+#endif
+	LIST_INSERT_HEAD(&pflogif_list, pflogif, sc_list);
+	pflogifs[unit] = ifp;
+#ifdef __FreeBSD__
+	PF_UNLOCK();
 #endif
+	splx(s);
 
 	return (0);
 }
-#else /* !__FreeBSD__ */
-void
-pflogattach(int npflog)
-{
-	struct ifnet *ifp;
-	int i;
 
-	bzero(pflogif, sizeof(pflogif));
+#ifdef __FreeBSD__
+static void
+pflog_clone_destroy(struct ifnet *ifp)
+#else
+int
+pflog_clone_destroy(struct ifnet *ifp)
+#endif
+{
+	struct pflog_softc	*pflogif = ifp->if_softc;
+	int			 s;
 
-	for (i = 0; i < NPFLOG; i++) {
-		ifp = &pflogif[i].sc_if;
-		snprintf(ifp->if_xname, sizeof ifp->if_xname, "pflog%d", i);
-		ifp->if_softc = &pflogif[i];
-		ifp->if_mtu = PFLOGMTU;
-		ifp->if_ioctl = pflogioctl;
-		ifp->if_output = pflogoutput;
-		ifp->if_start = pflogstart;
-		ifp->if_type = IFT_PFLOG;
-		ifp->if_snd.ifq_maxlen = ifqmaxlen;
-		ifp->if_hdrlen = PFLOG_HDRLEN;
-		if_attach(ifp);
-		if_alloc_sadl(ifp);
+	s = splnet();
+#ifdef __FreeBSD__
+	PF_LOCK();
+#endif
+	pflogifs[pflogif->sc_unit] = NULL;
+	LIST_REMOVE(pflogif, sc_list);
+#ifdef __FreeBSD__
+	PF_UNLOCK();
+#endif
+	splx(s);
 
 #if NBPFILTER > 0
-		bpfattach(&pflogif[i].sc_if.if_bpf, ifp, DLT_PFLOG,
-			  PFLOG_HDRLEN);
+	bpfdetach(ifp);
+#endif
+	if_detach(ifp);
+#ifdef __FreeBSD__
+	if_free(ifp);
+#endif
+	free(pflogif, M_DEVBUF);
+#ifndef __FreeBSD__
+	return (0);
 #endif
-	}
 }
-#endif /* __FreeBSD__ */
 
 /*
  * Start output on the pflog interface.
@@ -226,23 +270,18 @@
 		IF_LOCK(&ifp->if_snd);
 		_IF_DROP(&ifp->if_snd);
 		_IF_DEQUEUE(&ifp->if_snd, m);
-		if (m == NULL) {
-			IF_UNLOCK(&ifp->if_snd);
-			return;
-		}
-		else
-			m_freem(m);
-		IF_UNLOCK(&ifp->if_snd);			
+		IF_UNLOCK(&ifp->if_snd);
 #else
-		s = splimp();
+		s = splnet();
 		IF_DROP(&ifp->if_snd);
 		IF_DEQUEUE(&ifp->if_snd, m);
 		splx(s);
+#endif
+
 		if (m == NULL)
 			return;
 		else
 			m_freem(m);
-#endif
 	}
 }
 
@@ -255,14 +294,6 @@
 }
 
 /* ARGSUSED */
-void
-pflogrtrequest(int cmd, struct rtentry *rt, struct sockaddr *sa)
-{
-	if (rt)
-		rt->rt_rmx.rmx_mtu = PFLOGMTU;
-}
-
-/* ARGSUSED */
 int
 pflogioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
 {
@@ -271,10 +302,17 @@
 	case SIOCAIFADDR:
 	case SIOCSIFDSTADDR:
 	case SIOCSIFFLAGS:
+#ifdef __FreeBSD__
 		if (ifp->if_flags & IFF_UP)
 			ifp->if_drv_flags |= IFF_DRV_RUNNING;
 		else
 			ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
+#else
+		if (ifp->if_flags & IFF_UP)
+			ifp->if_flags |= IFF_RUNNING;
+		else
+			ifp->if_flags &= ~IFF_RUNNING;
+#endif
 		break;
 	default:
 		return (EINVAL);
@@ -286,18 +324,18 @@
 int
 pflog_packet(struct pfi_kif *kif, struct mbuf *m, sa_family_t af, u_int8_t dir,
     u_int8_t reason, struct pf_rule *rm, struct pf_rule *am,
-    struct pf_ruleset *ruleset)
+    struct pf_ruleset *ruleset, struct pf_pdesc *pd)
 {
 #if NBPFILTER > 0
 	struct ifnet *ifn;
 	struct pfloghdr hdr;
-#ifndef __FreeBSD__
-	struct mbuf m1;
-#endif
 
-	if (kif == NULL || m == NULL || rm == NULL)
+	if (kif == NULL || m == NULL || rm == NULL || pd == NULL)
 		return (-1);
 
+	if ((ifn = pflogifs[rm->logif]) == NULL || !ifn->if_bpf)
+		return (0);
+
 	bzero(&hdr, sizeof(hdr));
 	hdr.length = PFLOG_REAL_HDRLEN;
 	hdr.af = af;
@@ -315,6 +353,25 @@
 			strlcpy(hdr.ruleset, ruleset->anchor->name,
 			    sizeof(hdr.ruleset));
 	}
+	if (rm->log & PF_LOG_SOCKET_LOOKUP && !pd->lookup.done)
+#ifdef __FreeBSD__
+		/* 
+		 * XXX: This should not happen as we force an early lookup
+		 * via debug.pfugidhack
+		 */
+		 ; /* empty */
+#else
+		pd->lookup.done = pf_socket_lookup(dir, pd);
+#endif
+	if (pd->lookup.done > 0) {
+		hdr.uid = pd->lookup.uid;
+		hdr.pid = pd->lookup.pid;
+	} else {
+		hdr.uid = UID_MAX;
+		hdr.pid = NO_PID;
+	}
+	hdr.rule_uid = rm->cuid;
+	hdr.rule_pid = rm->cpid;
 	hdr.dir = dir;
 
 #ifdef INET
@@ -327,21 +384,13 @@
 	}
 #endif /* INET */
 
-#ifndef __FreeBSD__
-	m1.m_next = m;
-	m1.m_len = PFLOG_HDRLEN;
-	m1.m_data = (char *) &hdr;
-#endif
-
+	ifn->if_opackets++;
+	ifn->if_obytes += m->m_pkthdr.len;
 #ifdef __FreeBSD__
-	KASSERT((!LIST_EMPTY(&pflog_list)), ("pflog: no interface"));
-	ifn = SCP2IFP(LIST_FIRST(&pflog_list));
-	BPF_MTAP2(ifn, &hdr, sizeof(hdr), m);
+	BPF_MTAP2(ifn, &hdr, PFLOG_HDRLEN, m);
 #else
-	ifn = &(pflogif[0].sc_if);
-
-	if (ifn->if_bpf)
-		bpf_mtap(ifn->if_bpf, &m1);
+	bpf_mtap_hdr(ifn->if_bpf, (char *)&hdr, PFLOG_HDRLEN, m,
+	    BPF_DIRECTION_OUT);
 #endif
 #endif
 
@@ -356,22 +405,17 @@
 
 	switch (type) {
 	case MOD_LOAD:
-		LIST_INIT(&pflog_list);
-		if_clone_attach(&pflog_cloner);
+		pflogattach(1);
 		PF_LOCK();
 		pflog_packet_ptr = pflog_packet;
 		PF_UNLOCK();
 		break;
-
 	case MOD_UNLOAD:
 		PF_LOCK();
 		pflog_packet_ptr = NULL;
 		PF_UNLOCK();
 		if_clone_detach(&pflog_cloner);
-		while (!LIST_EMPTY(&pflog_list))
-			pflog_clone_destroy(SCP2IFP(LIST_FIRST(&pflog_list)));
 		break;
-
 	default:
 		error = EINVAL;
 		break;
@@ -380,11 +424,7 @@
 	return error;
 }
 
-static moduledata_t pflog_mod = {
-	"pflog",
-	pflog_modevent,
-	0
-};
+static moduledata_t pflog_mod = { "pflog", pflog_modevent, 0 };
 
 #define PFLOG_MODVER 1
 
Index: pf_norm.c
===================================================================
RCS file: /home/cvs/src/sys/contrib/pf/net/pf_norm.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -L sys/contrib/pf/net/pf_norm.c -L sys/contrib/pf/net/pf_norm.c -u -r1.2 -r1.3
--- sys/contrib/pf/net/pf_norm.c
+++ sys/contrib/pf/net/pf_norm.c
@@ -1,6 +1,4 @@
-/*	$FreeBSD: src/sys/contrib/pf/net/pf_norm.c,v 1.11.2.4 2006/03/28 15:06:03 mlaier Exp $	*/
-/*	$OpenBSD: pf_norm.c,v 1.97 2004/09/21 16:59:12 aaron Exp $ */
-/*	add: $OpenBSD: pf_norm.c,v 1.106 2006/03/25 20:55:24 dhartmei Exp $ */
+/*	$OpenBSD: pf_norm.c,v 1.107 2006/04/16 00:59:52 pascoe Exp $ */
 
 /*
  * Copyright 2001 Niels Provos <provos at citi.umich.edu>
@@ -31,8 +29,16 @@
 #include "opt_inet.h"
 #include "opt_inet6.h"
 #include "opt_pf.h"
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/sys/contrib/pf/net/pf_norm.c,v 1.19 2007/07/03 12:16:07 mlaier Exp $");
+
+#ifdef DEV_PFLOG
 #define	NPFLOG DEV_PFLOG
 #else
+#define	NPFLOG 0
+#endif
+#else
 #include "pflog.h"
 #endif
 
@@ -72,6 +78,8 @@
 #include <net/pfvar.h>
 
 #ifndef __FreeBSD__
+#include <inttypes.h>
+
 struct pf_frent {
 	LIST_ENTRY(pf_frent) fr_next;
 	struct ip *fr_ip;
@@ -487,7 +495,7 @@
 			break;
 		}
 
-		/* This fragment is completely overlapped, loose it */
+		/* This fragment is completely overlapped, lose it */
 		next = LIST_NEXT(frea, fr_next);
 		m_freem(frea->fr_m);
 		LIST_REMOVE(frea, fr_next);
@@ -560,8 +568,17 @@
 		m2 = frent->fr_m;
 		pool_put(&pf_frent_pl, frent);
 		pf_nfrents--;
+#ifdef __FreeBSD__
+		m->m_pkthdr.csum_flags &= m2->m_pkthdr.csum_flags;
+		m->m_pkthdr.csum_data += m2->m_pkthdr.csum_data;
+#endif
 		m_cat(m, m2);
 	}
+#ifdef __FreeBSD__
+	while (m->m_pkthdr.csum_data & 0xffff0000)
+		m->m_pkthdr.csum_data = (m->m_pkthdr.csum_data & 0xffff) +
+		    (m->m_pkthdr.csum_data >> 16);
+#endif
 
 	ip->ip_src = (*frag)->fr_src;
 	ip->ip_dst = (*frag)->fr_dst;
@@ -951,8 +968,7 @@
 	r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_SCRUB].active.ptr);
 	while (r != NULL) {
 		r->evaluations++;
-		if (r->kif != NULL &&
-		    (r->kif != kif && r->kif != kif->pfik_parent) == !r->ifnot)
+		if (pfi_kif_match(r->kif, kif) == r->ifnot)
 			r = r->skip[PF_SKIP_IFP].ptr;
 		else if (r->direction && r->direction != dir)
 			r = r->skip[PF_SKIP_DIR].ptr;
@@ -961,19 +977,23 @@
 		else if (r->proto && r->proto != h->ip_p)
 			r = r->skip[PF_SKIP_PROTO].ptr;
 		else if (PF_MISMATCHAW(&r->src.addr,
-		    (struct pf_addr *)&h->ip_src.s_addr, AF_INET, r->src.neg))
+		    (struct pf_addr *)&h->ip_src.s_addr, AF_INET,
+		    r->src.neg, kif))
 			r = r->skip[PF_SKIP_SRC_ADDR].ptr;
 		else if (PF_MISMATCHAW(&r->dst.addr,
-		    (struct pf_addr *)&h->ip_dst.s_addr, AF_INET, r->dst.neg))
+		    (struct pf_addr *)&h->ip_dst.s_addr, AF_INET,
+		    r->dst.neg, NULL))
 			r = r->skip[PF_SKIP_DST_ADDR].ptr;
 		else
 			break;
 	}
 
-	if (r == NULL)
+	if (r == NULL || r->action == PF_NOSCRUB)
 		return (PF_PASS);
-	else
-		r->packets++;
+	else {
+		r->packets[dir == PF_OUT]++;
+		r->bytes[dir == PF_OUT] += pd->tot_len;
+	}
 
 	/* Check for illegal packets */
 	if (hlen < (int)sizeof(struct ip))
@@ -1046,6 +1066,18 @@
 		if (m == NULL)
 			return (PF_DROP);
 
+		/* use mtag from concatenated mbuf chain */
+		pd->pf_mtag = pf_find_mtag(m);
+#ifdef DIAGNOSTIC
+		if (pd->pf_mtag == NULL) {
+			printf("%s: pf_find_mtag returned NULL(1)\n", __func__);
+			if ((pd->pf_mtag = pf_get_mtag(m)) == NULL) {
+				m_freem(m);
+				*m0 = NULL;
+				goto no_mem;
+			}
+		}
+#endif
 		if (frag != NULL && (frag->fr_flags & PFFRAG_DROP))
 			goto drop;
 
@@ -1054,15 +1086,13 @@
 		/* non-buffering fragment cache (drops or masks overlaps) */
 		int	nomem = 0;
 
-		if (dir == PF_OUT) {
-			if (m_tag_find(m, PACKET_TAG_PF_FRAGCACHE, NULL) !=
-			    NULL) {
-				/* Already passed the fragment cache in the
-				 * input direction.  If we continued, it would
-				 * appear to be a dup and would be dropped.
-				 */
-				goto fragment_pass;
-			}
+		if (dir == PF_OUT && pd->pf_mtag->flags & PF_TAG_FRAGCACHE) {
+			/*
+			 * Already passed the fragment cache in the
+			 * input direction.  If we continued, it would
+			 * appear to be a dup and would be dropped.
+			 */
+			goto fragment_pass;
 		}
 
 		frag = pf_find_fragment(h, &pf_cache_tree);
@@ -1083,14 +1113,21 @@
 			goto drop;
 		}
 
-		if (dir == PF_IN) {
-			struct m_tag	*mtag;
-
-			mtag = m_tag_get(PACKET_TAG_PF_FRAGCACHE, 0, M_NOWAIT);
-			if (mtag == NULL)
+		/* use mtag from copied and trimmed mbuf chain */
+		pd->pf_mtag = pf_find_mtag(m);
+#ifdef DIAGNOSTIC
+		if (pd->pf_mtag == NULL) {
+			printf("%s: pf_find_mtag returned NULL(2)\n", __func__);
+			if ((pd->pf_mtag = pf_get_mtag(m)) == NULL) {
+				m_freem(m);
+				*m0 = NULL;
 				goto no_mem;
-			m_tag_prepend(m, mtag);
+			}
 		}
+#endif
+		if (dir == PF_IN)
+			pd->pf_mtag->flags |= PF_TAG_FRAGCACHE;
+
 		if (frag != NULL && (frag->fr_flags & PFFRAG_DROP))
 			goto drop;
 		goto fragment_pass;
@@ -1139,13 +1176,13 @@
  no_mem:
 	REASON_SET(reason, PFRES_MEMORY);
 	if (r != NULL && r->log)
-		PFLOG_PACKET(kif, h, m, AF_INET, dir, *reason, r, NULL, NULL);
+		PFLOG_PACKET(kif, h, m, AF_INET, dir, *reason, r, NULL, NULL, pd);
 	return (PF_DROP);
 
  drop:
 	REASON_SET(reason, PFRES_NORM);
 	if (r != NULL && r->log)
-		PFLOG_PACKET(kif, h, m, AF_INET, dir, *reason, r, NULL, NULL);
+		PFLOG_PACKET(kif, h, m, AF_INET, dir, *reason, r, NULL, NULL, pd);
 	return (PF_DROP);
 
  bad:
@@ -1157,7 +1194,7 @@
 
 	REASON_SET(reason, PFRES_FRAG);
 	if (r != NULL && r->log)
-		PFLOG_PACKET(kif, h, m, AF_INET, dir, *reason, r, NULL, NULL);
+		PFLOG_PACKET(kif, h, m, AF_INET, dir, *reason, r, NULL, NULL, pd);
 
 	return (PF_DROP);
 }
@@ -1185,8 +1222,7 @@
 	r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_SCRUB].active.ptr);
 	while (r != NULL) {
 		r->evaluations++;
-		if (r->kif != NULL &&
-		    (r->kif != kif && r->kif != kif->pfik_parent) == !r->ifnot)
+		if (pfi_kif_match(r->kif, kif) == r->ifnot)
 			r = r->skip[PF_SKIP_IFP].ptr;
 		else if (r->direction && r->direction != dir)
 			r = r->skip[PF_SKIP_DIR].ptr;
@@ -1197,19 +1233,23 @@
 			r = r->skip[PF_SKIP_PROTO].ptr;
 #endif
 		else if (PF_MISMATCHAW(&r->src.addr,
-		    (struct pf_addr *)&h->ip6_src, AF_INET6, r->src.neg))
+		    (struct pf_addr *)&h->ip6_src, AF_INET6,
+		    r->src.neg, kif))
 			r = r->skip[PF_SKIP_SRC_ADDR].ptr;
 		else if (PF_MISMATCHAW(&r->dst.addr,
-		    (struct pf_addr *)&h->ip6_dst, AF_INET6, r->dst.neg))
+		    (struct pf_addr *)&h->ip6_dst, AF_INET6,
+		    r->dst.neg, NULL))
 			r = r->skip[PF_SKIP_DST_ADDR].ptr;
 		else
 			break;
 	}
 
-	if (r == NULL)
+	if (r == NULL || r->action == PF_NOSCRUB)
 		return (PF_PASS);
-	else
-		r->packets++;
+	else {
+		r->packets[dir == PF_OUT]++;
+		r->bytes[dir == PF_OUT] += pd->tot_len;
+	}
 
 	/* Check for illegal packets */
 	if (sizeof(struct ip6_hdr) + IPV6_MAXPACKET < m->m_pkthdr.len)
@@ -1321,19 +1361,19 @@
  shortpkt:
 	REASON_SET(reason, PFRES_SHORT);
 	if (r != NULL && r->log)
-		PFLOG_PACKET(kif, h, m, AF_INET6, dir, *reason, r, NULL, NULL);
+		PFLOG_PACKET(kif, h, m, AF_INET6, dir, *reason, r, NULL, NULL, pd);
 	return (PF_DROP);
 
  drop:
 	REASON_SET(reason, PFRES_NORM);
 	if (r != NULL && r->log)
-		PFLOG_PACKET(kif, h, m, AF_INET6, dir, *reason, r, NULL, NULL);
+		PFLOG_PACKET(kif, h, m, AF_INET6, dir, *reason, r, NULL, NULL, pd);
 	return (PF_DROP);
 
  badfrag:
 	REASON_SET(reason, PFRES_FRAG);
 	if (r != NULL && r->log)
-		PFLOG_PACKET(kif, h, m, AF_INET6, dir, *reason, r, NULL, NULL);
+		PFLOG_PACKET(kif, h, m, AF_INET6, dir, *reason, r, NULL, NULL, pd);
 	return (PF_DROP);
 }
 #endif /* INET6 */
@@ -1352,8 +1392,7 @@
 	r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_SCRUB].active.ptr);
 	while (r != NULL) {
 		r->evaluations++;
-		if (r->kif != NULL &&
-		    (r->kif != kif && r->kif != kif->pfik_parent) == !r->ifnot)
+		if (pfi_kif_match(r->kif, kif) == r->ifnot)
 			r = r->skip[PF_SKIP_IFP].ptr;
 		else if (r->direction && r->direction != dir)
 			r = r->skip[PF_SKIP_DIR].ptr;
@@ -1361,12 +1400,14 @@
 			r = r->skip[PF_SKIP_AF].ptr;
 		else if (r->proto && r->proto != pd->proto)
 			r = r->skip[PF_SKIP_PROTO].ptr;
-		else if (PF_MISMATCHAW(&r->src.addr, pd->src, af, r->src.neg))
+		else if (PF_MISMATCHAW(&r->src.addr, pd->src, af,
+		    r->src.neg, kif))
 			r = r->skip[PF_SKIP_SRC_ADDR].ptr;
 		else if (r->src.port_op && !pf_match_port(r->src.port_op,
 			    r->src.port[0], r->src.port[1], th->th_sport))
 			r = r->skip[PF_SKIP_SRC_PORT].ptr;
-		else if (PF_MISMATCHAW(&r->dst.addr, pd->dst, af, r->dst.neg))
+		else if (PF_MISMATCHAW(&r->dst.addr, pd->dst, af,
+		    r->dst.neg, NULL))
 			r = r->skip[PF_SKIP_DST_ADDR].ptr;
 		else if (r->dst.port_op && !pf_match_port(r->dst.port_op,
 			    r->dst.port[0], r->dst.port[1], th->th_dport))
@@ -1383,8 +1424,10 @@
 
 	if (rm == NULL || rm->action == PF_NOSCRUB)
 		return (PF_PASS);
-	else
-		r->packets++;
+	else {
+		r->packets[dir == PF_OUT]++;
+		r->bytes[dir == PF_OUT] += pd->tot_len;
+	}
 
 	if (rm->rule_flag & PFRULE_REASSEMBLE_TCP)
 		pd->flags |= PFDESC_TCP_NORM;
@@ -1446,7 +1489,7 @@
  tcp_drop:
 	REASON_SET(&reason, PFRES_NORM);
 	if (rm != NULL && r->log)
-		PFLOG_PACKET(kif, h, m, AF_INET, dir, reason, r, NULL, NULL);
+		PFLOG_PACKET(kif, h, m, AF_INET, dir, reason, r, NULL, NULL, pd);
 	return (PF_DROP);
 }
 
@@ -1830,8 +1873,9 @@
 			    SEQ_LT(tsecr, dst->scrub->pfss_tsval0)? '3' : ' '));
 #ifdef __FreeBSD__
 			DPFPRINTF((" tsval: %u  tsecr: %u  +ticks: %u  "
-			    "idle: %lus %lums\n",
-			    tsval, tsecr, tsval_from_last, delta_ts.tv_sec,
+			    "idle: %jus %lums\n",
+			    tsval, tsecr, tsval_from_last,
+			    (uintmax_t)delta_ts.tv_sec,
 			    delta_ts.tv_usec / 1000));
 			DPFPRINTF((" src->tsval: %u  tsecr: %u\n",
 			    src->scrub->pfss_tsval, src->scrub->pfss_tsecr));
@@ -1915,7 +1959,7 @@
 	 * timestamps.  And require all data packets to contain a timestamp
 	 * if the first does.  PAWS implicitly requires that all data packets be
 	 * timestamped.  But I think there are middle-man devices that hijack
-	 * TCP streams immedietly after the 3whs and don't timestamp their
+	 * TCP streams immediately after the 3whs and don't timestamp their
 	 * packets (seen in a WWW accelerator or cache).
 	 */
 	if (pd->p_len > 0 && src->scrub && (src->scrub->pfss_flags &
Index: pf_osfp.c
===================================================================
RCS file: /home/cvs/src/sys/contrib/pf/net/pf_osfp.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/contrib/pf/net/pf_osfp.c -L sys/contrib/pf/net/pf_osfp.c -u -r1.1.1.1 -r1.2
--- sys/contrib/pf/net/pf_osfp.c
+++ sys/contrib/pf/net/pf_osfp.c
@@ -1,5 +1,4 @@
-/*	$FreeBSD: src/sys/contrib/pf/net/pf_osfp.c,v 1.5 2005/05/03 16:43:32 mlaier Exp $	*/
-/*	$OpenBSD: pf_osfp.c,v 1.10 2004/04/09 19:30:41 frantzen Exp $ */
+/*	$OpenBSD: pf_osfp.c,v 1.12 2006/12/13 18:14:10 itojun Exp $ */
 
 /*
  * Copyright (c) 2003 Mike Frantzen <frantzen at w4g.org>
@@ -18,6 +17,11 @@
  *
  */
 
+#ifdef __FreeBSD__
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/sys/contrib/pf/net/pf_osfp.c,v 1.6 2007/07/03 12:16:07 mlaier Exp $");
+#endif
+
 #include <sys/param.h>
 #include <sys/socket.h>
 #ifdef _KERNEL
@@ -33,9 +37,10 @@
 #include <net/if.h>
 #include <net/pfvar.h>
 
-#ifdef INET6
 #include <netinet/ip6.h>
-#endif /* INET6 */
+#ifdef _KERNEL
+#include <netinet6/in6_var.h>
+#endif
 
 #ifdef _KERNEL
 # define DPFPRINTF(format, x...)		\
@@ -55,6 +60,7 @@
 # include <stdio.h>
 # include <stdlib.h>
 # include <string.h>
+# include <netdb.h>
 # define pool_t			int
 # define pool_get(pool, flags)	malloc(*(pool))
 # define pool_put(pool, item)	free(item)
@@ -95,38 +101,96 @@
     const struct tcphdr *tcp)
 {
 	struct ip *ip;
+	struct ip6_hdr *ip6;
 	char hdr[60];
 
-	/* XXX don't have a fingerprint database for IPv6 :-( */
-	if (pd->af != PF_INET || pd->proto != IPPROTO_TCP || (tcp->th_off << 2)
-	    < sizeof(*tcp))
+	if ((pd->af != PF_INET && pd->af != PF_INET6) ||
+	    pd->proto != IPPROTO_TCP || (tcp->th_off << 2) < sizeof(*tcp))
 		return (NULL);
 
-	ip = mtod(m, struct ip *);
-	if (!pf_pull_hdr(m, off, hdr, tcp->th_off << 2, NULL, NULL, pd->af))
-		return (NULL);
+	if (pd->af == PF_INET) {
+		ip = mtod(m, struct ip *);
+		ip6 = (struct ip6_hdr *)NULL;
+	} else {
+		ip = (struct ip *)NULL;
+		ip6 = mtod(m, struct ip6_hdr *);
+	}
+	if (!pf_pull_hdr(m, off, hdr, tcp->th_off << 2, NULL, NULL,
+	    pd->af)) return (NULL);
 
-	return (pf_osfp_fingerprint_hdr(ip, (struct tcphdr *)hdr));
+	return (pf_osfp_fingerprint_hdr(ip, ip6, (struct tcphdr *)hdr));
 }
 #endif /* _KERNEL */
 
 struct pf_osfp_enlist *
-pf_osfp_fingerprint_hdr(const struct ip *ip, const struct tcphdr *tcp)
+pf_osfp_fingerprint_hdr(const struct ip *ip, const struct ip6_hdr *ip6, const struct tcphdr *tcp)
 {
 	struct pf_os_fingerprint fp, *fpresult;
 	int cnt, optlen = 0;
 	const u_int8_t *optp;
+#ifdef _KERNEL
+	char srcname[128];
+#else
+	char srcname[NI_MAXHOST];
+#endif
 
-	if ((tcp->th_flags & (TH_SYN|TH_ACK)) != TH_SYN || (ip->ip_off &
-	    htons(IP_OFFMASK)))
+	if ((tcp->th_flags & (TH_SYN|TH_ACK)) != TH_SYN)
 		return (NULL);
+	if (ip) {
+		if ((ip->ip_off & htons(IP_OFFMASK)) != 0)
+			return (NULL);
+	}
 
 	memset(&fp, 0, sizeof(fp));
 
-	fp.fp_psize = ntohs(ip->ip_len);
-	fp.fp_ttl = ip->ip_ttl;
-	if (ip->ip_off & htons(IP_DF))
+	if (ip) {
+#ifndef _KERNEL
+		struct sockaddr_in sin;
+#endif
+
+		fp.fp_psize = ntohs(ip->ip_len);
+		fp.fp_ttl = ip->ip_ttl;
+		if (ip->ip_off & htons(IP_DF))
+			fp.fp_flags |= PF_OSFP_DF;
+#ifdef _KERNEL
+		strlcpy(srcname, inet_ntoa(ip->ip_src), sizeof(srcname));
+#else
+		memset(&sin, 0, sizeof(sin));
+		sin.sin_family = AF_INET;
+		sin.sin_len = sizeof(struct sockaddr_in);
+		sin.sin_addr = ip->ip_src;
+		(void)getnameinfo((struct sockaddr *)&sin,
+		    sizeof(struct sockaddr_in), srcname, sizeof(srcname),
+		    NULL, 0, NI_NUMERICHOST);
+#endif
+	}
+#ifdef INET6
+	else if (ip6) {
+#ifndef _KERNEL
+		struct sockaddr_in6 sin6;
+#endif
+
+		/* jumbo payload? */
+		fp.fp_psize = sizeof(struct ip6_hdr) + ntohs(ip6->ip6_plen);
+		fp.fp_ttl = ip6->ip6_hlim;
 		fp.fp_flags |= PF_OSFP_DF;
+		fp.fp_flags |= PF_OSFP_INET6;
+#ifdef _KERNEL
+		strlcpy(srcname, ip6_sprintf((struct in6_addr *)&ip6->ip6_src),
+		    sizeof(srcname));
+#else
+		memset(&sin6, 0, sizeof(sin6));
+		sin6.sin6_family = AF_INET6;
+		sin6.sin6_len = sizeof(struct sockaddr_in6);
+		sin6.sin6_addr = ip6->ip6_src;
+		(void)getnameinfo((struct sockaddr *)&sin6,
+		    sizeof(struct sockaddr_in6), srcname, sizeof(srcname),
+		    NULL, 0, NI_NUMERICHOST);
+#endif
+	}
+#endif
+	else
+		return (NULL);
 	fp.fp_wsize = ntohs(tcp->th_win);
 
 
@@ -189,7 +253,7 @@
 
 	DPFPRINTF("fingerprinted %s:%d  %d:%d:%d:%d:%llx (%d) "
 	    "(TS=%s,M=%s%d,W=%s%d)\n",
-	    inet_ntoa(ip->ip_src), ntohs(tcp->th_sport),
+	    srcname, ntohs(tcp->th_sport),
 	    fp.fp_wsize, fp.fp_ttl, (fp.fp_flags & PF_OSFP_DF) != 0,
 	    fp.fp_psize, (long long int)fp.fp_tcpopts, fp.fp_optcnt,
 	    (fp.fp_flags & PF_OSFP_TS0) ? "0" : "",
Index: pf_subr.c
===================================================================
RCS file: /home/cvs/src/sys/contrib/pf/net/pf_subr.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/contrib/pf/net/pf_subr.c -L sys/contrib/pf/net/pf_subr.c -u -r1.1.1.1 -r1.2
--- sys/contrib/pf/net/pf_subr.c
+++ sys/contrib/pf/net/pf_subr.c
@@ -1,15 +1,6 @@
-/*	$FreeBSD: src/sys/contrib/pf/net/pf_subr.c,v 1.2 2005/05/03 16:43:32 mlaier Exp $ */
-/*	from $OpenBSD: kern_subr.c,v 1.26 2003/10/31 11:10:41 markus Exp $	*/
-/*	$NetBSD: kern_subr.c,v 1.15 1996/04/09 17:21:56 ragge Exp $	*/
-
-/*
- * Copyright (c) 1982, 1986, 1991, 1993
+/*-
+ * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1995
  *	The Regents of the University of California.  All rights reserved.
- * (c) UNIX System Laboratories, Inc.
- * All or some portions of this file are derived from material licensed
- * to the University of California by American Telephone and Telegraph
- * Co. or Unix System Laboratories, Inc. and are reproduced herein with
- * the permission of UNIX System Laboratories, Inc.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -19,7 +10,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
+ * 4. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
@@ -35,93 +26,143 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- *	@(#)kern_subr.c	8.3 (Berkeley) 1/21/94
  */
 
+#include "opt_inet.h"
+#include "opt_inet6.h"
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/sys/contrib/pf/net/pf_subr.c,v 1.4 2007/07/05 15:28:59 mlaier Exp $");
+
 #include <sys/param.h>
-#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/libkern.h>
+#include <sys/mbuf.h>
+#include <sys/md5.h>
+#include <sys/time.h>
+#include <sys/random.h>
 #include <sys/socket.h>
 #include <sys/socketvar.h>
-#include <sys/proc.h>
-#include <sys/malloc.h>
-#include <sys/queue.h>
-#include <sys/kernel.h>
-#include <sys/resourcevar.h>
+#include <sys/systm.h>
+#include <sys/time.h>
 
 #include <net/if.h>
+#include <net/if_types.h>
+#include <net/bpf.h>
+#include <net/route.h>
 
 #include <netinet/in.h>
 #include <netinet/in_var.h>
-
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+#include <netinet/tcp.h>
+#include <netinet/tcp_seq.h>
+#include <netinet/udp.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/in_pcb.h>
+#include <netinet/tcp_timer.h>
+#include <netinet/tcp_var.h>
+#include <netinet/if_ether.h>
 #include <net/pfvar.h>
 
 /*
- * This implements additional functions used by pf which can not be ported
- * easyly. At this point it boils down to mostly the Net/OpenBSD hook
- * implementation.
+ * Following is where TCP initial sequence number generation occurs.
+ *
+ * There are two places where we must use initial sequence numbers:
+ * 1.  In SYN-ACK packets.
+ * 2.  In SYN packets.
+ *
+ * All ISNs for SYN-ACK packets are generated by the syncache.  See
+ * tcp_syncache.c for details.
+ *
+ * The ISNs in SYN packets must be monotonic; TIME_WAIT recycling
+ * depends on this property.  In addition, these ISNs should be
+ * unguessable so as to prevent connection hijacking.  To satisfy
+ * the requirements of this situation, the algorithm outlined in
+ * RFC 1948 is used, with only small modifications.
+ *
+ * Implementation details:
+ *
+ * Time is based off the system timer, and is corrected so that it
+ * increases by one megabyte per second.  This allows for proper
+ * recycling on high speed LANs while still leaving over an hour
+ * before rollover.
+ *
+ * As reading the *exact* system time is too expensive to be done
+ * whenever setting up a TCP connection, we increment the time
+ * offset in two ways.  First, a small random positive increment
+ * is added to isn_offset for each connection that is set up.
+ * Second, the function tcp_isn_tick fires once per clock tick
+ * and increments isn_offset as necessary so that sequence numbers
+ * are incremented at approximately ISN_BYTES_PER_SECOND.  The
+ * random positive increments serve only to ensure that the same
+ * exact sequence number is never sent out twice (as could otherwise
+ * happen when a port is recycled in less than the system tick
+ * interval.)
+ *
+ * net.inet.tcp.isn_reseed_interval controls the number of seconds
+ * between seeding of isn_secret.  This is normally set to zero,
+ * as reseeding should not be necessary.
  *
- * BEWARE: this is not locked! Required locking is done by the caller.
+ * Locking of the global variables isn_secret, isn_last_reseed, isn_offset,
+ * isn_offset_old, and isn_ctx is performed using the TCP pcbinfo lock.  In
+ * general, this means holding an exclusive (write) lock.
  */
 
-void *
-hook_establish(struct hook_desc_head *head, int tail, void (*fn)(void *),
-    void *arg)
-{
-	struct hook_desc *hdp;
-
-	hdp = (struct hook_desc *)malloc(sizeof (*hdp), M_DEVBUF, M_NOWAIT);
-	if (hdp == NULL)
-		return (NULL);
-
-	hdp->hd_fn = fn;
-	hdp->hd_arg = arg;
-	if (tail)
-		TAILQ_INSERT_TAIL(head, hdp, hd_list);
-	else
-		TAILQ_INSERT_HEAD(head, hdp, hd_list);
-
-	return (hdp);
-}
+#define ISN_BYTES_PER_SECOND 1048576
+#define ISN_STATIC_INCREMENT 4096
+#define ISN_RANDOM_INCREMENT (4096 - 1)
+
+static u_char isn_secret[32];
+static int isn_last_reseed;
+static u_int32_t isn_offset;
+static MD5_CTX isn_ctx;
 
-void
-hook_disestablish(struct hook_desc_head *head, void *vhook)
+u_int32_t
+pf_new_isn(struct pf_state *s)
 {
-	struct hook_desc *hdp;
-
-#ifdef DIAGNOSTIC
-	for (hdp = TAILQ_FIRST(head); hdp != NULL;
-	    hdp = TAILQ_NEXT(hdp, hd_list))
-                if (hdp == vhook)
-			break;
-	if (hdp == NULL)
-		panic("hook_disestablish: hook not established");
-#endif
-	hdp = vhook;
-	TAILQ_REMOVE(head, hdp, hd_list);
-	free(hdp, M_DEVBUF);
-}
-
-/*
- * Run hooks.  Startup hooks are invoked right after scheduler_start but
- * before root is mounted.  Shutdown hooks are invoked immediately before the
- * system is halted or rebooted, i.e. after file systems unmounted,
- * after crash dump done, etc.
- */
-void
-dohooks(struct hook_desc_head *head, int flags)
-{
-	struct hook_desc *hdp;
+	u_int32_t md5_buffer[4];
+	u_int32_t new_isn;
+	struct pf_state_host *src, *dst;
+
+	/* Seed if this is the first use, reseed if requested. */
+	if (isn_last_reseed == 0) {
+		read_random(&isn_secret, sizeof(isn_secret));
+		isn_last_reseed = ticks;
+	}
 
-	if ((flags & HOOK_REMOVE) == 0) {
-		TAILQ_FOREACH(hdp, head, hd_list) {
-			(*hdp->hd_fn)(hdp->hd_arg);
-		}
+	if (s->direction == PF_IN) {
+		src = &s->ext;
+		dst = &s->gwy;
 	} else {
-		while ((hdp = TAILQ_FIRST(head)) != NULL) {
-			TAILQ_REMOVE(head, hdp, hd_list);
-			(*hdp->hd_fn)(hdp->hd_arg);
-			if ((flags & HOOK_FREE) != 0)
-				free(hdp, M_DEVBUF);
-		}
+		src = &s->lan;
+		dst = &s->ext;
+	}
+
+	/* Compute the md5 hash and return the ISN. */
+	MD5Init(&isn_ctx);
+	MD5Update(&isn_ctx, (u_char *) &dst->port, sizeof(u_short));
+	MD5Update(&isn_ctx, (u_char *) &src->port, sizeof(u_short));
+#ifdef INET6
+	if (s->af == AF_INET6) {
+		MD5Update(&isn_ctx, (u_char *) &dst->addr,
+			  sizeof(struct in6_addr));
+		MD5Update(&isn_ctx, (u_char *) &src->addr,
+			  sizeof(struct in6_addr));
+	} else
+#endif
+	{
+		MD5Update(&isn_ctx, (u_char *) &dst->addr,
+			  sizeof(struct in_addr));
+		MD5Update(&isn_ctx, (u_char *) &src->addr,
+			  sizeof(struct in_addr));
 	}
+	MD5Update(&isn_ctx, (u_char *) &isn_secret, sizeof(isn_secret));
+	MD5Final((u_char *) &md5_buffer, &isn_ctx);
+	new_isn = (tcp_seq) md5_buffer[0];
+	isn_offset += ISN_STATIC_INCREMENT +
+		(arc4random() & ISN_RANDOM_INCREMENT);
+	new_isn += isn_offset;
+	return (new_isn);
 }
--- /dev/null
+++ sys/contrib/pf/net/pf_ruleset.c
@@ -0,0 +1,431 @@
+/*	$OpenBSD: pf_ruleset.c,v 1.1 2006/10/27 13:56:51 mcbride Exp $ */
+
+/*
+ * Copyright (c) 2001 Daniel Hartmeier
+ * Copyright (c) 2002,2003 Henning Brauer
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *    - Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *    - 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 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 HOLDERS 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.
+ *
+ * Effort sponsored in part by the Defense Advanced Research Projects
+ * Agency (DARPA) and Air Force Research Laboratory, Air Force
+ * Materiel Command, USAF, under agreement number F30602-01-2-0537.
+ *
+ */
+
+#ifdef __FreeBSD__
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/sys/contrib/pf/net/pf_ruleset.c,v 1.2 2007/07/03 12:16:07 mlaier Exp $");
+#endif
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#ifdef _KERNEL
+# include <sys/systm.h>
+#endif /* _KERNEL */
+#include <sys/mbuf.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/tcp.h>
+
+#include <net/if.h>
+#include <net/pfvar.h>
+
+#ifdef INET6
+#include <netinet/ip6.h>
+#endif /* INET6 */
+
+
+#ifdef _KERNEL
+# define DPFPRINTF(format, x...)		\
+	if (pf_status.debug >= PF_DEBUG_NOISY)	\
+		printf(format , ##x)
+#ifdef __FreeBSD__
+#define rs_malloc(x)		malloc(x, M_TEMP, M_NOWAIT)
+#else
+#define rs_malloc(x)		malloc(x, M_TEMP, M_WAITOK)
+#endif
+#define rs_free(x)		free(x, M_TEMP)
+
+#else
+/* Userland equivalents so we can lend code to pfctl et al. */
+
+# include <arpa/inet.h>
+# include <errno.h>
+# include <stdio.h>
+# include <stdlib.h>
+# include <string.h>
+# define rs_malloc(x)		 malloc(x)
+# define rs_free(x)		 free(x)
+
+# ifdef PFDEBUG
+#  include <sys/stdarg.h>
+#  define DPFPRINTF(format, x...)	fprintf(stderr, format , ##x)
+# else
+#  define DPFPRINTF(format, x...)	((void)0)
+# endif /* PFDEBUG */
+#endif /* _KERNEL */
+
+
+struct pf_anchor_global	 pf_anchors;
+struct pf_anchor	 pf_main_anchor;
+
+#ifndef __FreeBSD__
+/* XXX: hum? */
+int			 pf_get_ruleset_number(u_int8_t);
+void			 pf_init_ruleset(struct pf_ruleset *);
+int			 pf_anchor_setup(struct pf_rule *,
+			    const struct pf_ruleset *, const char *);
+int			 pf_anchor_copyout(const struct pf_ruleset *,
+			    const struct pf_rule *, struct pfioc_rule *);
+void			 pf_anchor_remove(struct pf_rule *);
+#endif
+
+static __inline int pf_anchor_compare(struct pf_anchor *, struct pf_anchor *);
+
+RB_GENERATE(pf_anchor_global, pf_anchor, entry_global, pf_anchor_compare);
+RB_GENERATE(pf_anchor_node, pf_anchor, entry_node, pf_anchor_compare);
+
+static __inline int
+pf_anchor_compare(struct pf_anchor *a, struct pf_anchor *b)
+{
+	int c = strcmp(a->path, b->path);
+
+	return (c ? (c < 0 ? -1 : 1) : 0);
+}
+
+int
+pf_get_ruleset_number(u_int8_t action)
+{
+	switch (action) {
+	case PF_SCRUB:
+	case PF_NOSCRUB:
+		return (PF_RULESET_SCRUB);
+		break;
+	case PF_PASS:
+	case PF_DROP:
+		return (PF_RULESET_FILTER);
+		break;
+	case PF_NAT:
+	case PF_NONAT:
+		return (PF_RULESET_NAT);
+		break;
+	case PF_BINAT:
+	case PF_NOBINAT:
+		return (PF_RULESET_BINAT);
+		break;
+	case PF_RDR:
+	case PF_NORDR:
+		return (PF_RULESET_RDR);
+		break;
+	default:
+		return (PF_RULESET_MAX);
+		break;
+	}
+}
+
+void
+pf_init_ruleset(struct pf_ruleset *ruleset)
+{
+	int	i;
+
+	memset(ruleset, 0, sizeof(struct pf_ruleset));
+	for (i = 0; i < PF_RULESET_MAX; i++) {
+		TAILQ_INIT(&ruleset->rules[i].queues[0]);
+		TAILQ_INIT(&ruleset->rules[i].queues[1]);
+		ruleset->rules[i].active.ptr = &ruleset->rules[i].queues[0];
+		ruleset->rules[i].inactive.ptr = &ruleset->rules[i].queues[1];
+	}
+}
+
+struct pf_anchor *
+pf_find_anchor(const char *path)
+{
+	struct pf_anchor	*key, *found;
+
+	key = (struct pf_anchor *)rs_malloc(sizeof(*key));
+	memset(key, 0, sizeof(*key));
+	strlcpy(key->path, path, sizeof(key->path));
+	found = RB_FIND(pf_anchor_global, &pf_anchors, key);
+	rs_free(key);
+	return (found);
+}
+
+struct pf_ruleset *
+pf_find_ruleset(const char *path)
+{
+	struct pf_anchor	*anchor;
+
+	while (*path == '/')
+		path++;
+	if (!*path)
+		return (&pf_main_ruleset);
+	anchor = pf_find_anchor(path);
+	if (anchor == NULL)
+		return (NULL);
+	else
+		return (&anchor->ruleset);
+}
+
+struct pf_ruleset *
+pf_find_or_create_ruleset(const char *path)
+{
+	char			*p, *q, *r;
+	struct pf_ruleset	*ruleset;
+#ifdef __FreeBSD__
+	struct pf_anchor	*anchor = NULL, *dup, *parent = NULL;
+#else
+	struct pf_anchor	*anchor, *dup, *parent = NULL;
+#endif
+
+	if (path[0] == 0)
+		return (&pf_main_ruleset);
+	while (*path == '/')
+		path++;
+	ruleset = pf_find_ruleset(path);
+	if (ruleset != NULL)
+		return (ruleset);
+	p = (char *)rs_malloc(MAXPATHLEN);
+	bzero(p, MAXPATHLEN);
+	strlcpy(p, path, MAXPATHLEN);
+	while (parent == NULL && (q = strrchr(p, '/')) != NULL) {
+		*q = 0;
+		if ((ruleset = pf_find_ruleset(p)) != NULL) {
+			parent = ruleset->anchor;
+			break;
+		}
+	}
+	if (q == NULL)
+		q = p;
+	else
+		q++;
+	strlcpy(p, path, MAXPATHLEN);
+	if (!*q) {
+		rs_free(p);
+		return (NULL);
+	}
+	while ((r = strchr(q, '/')) != NULL || *q) {
+		if (r != NULL)
+			*r = 0;
+		if (!*q || strlen(q) >= PF_ANCHOR_NAME_SIZE ||
+		    (parent != NULL && strlen(parent->path) >=
+		    MAXPATHLEN - PF_ANCHOR_NAME_SIZE - 1)) {
+			rs_free(p);
+			return (NULL);
+		}
+		anchor = (struct pf_anchor *)rs_malloc(sizeof(*anchor));
+		if (anchor == NULL) {
+			rs_free(p);
+			return (NULL);
+		}
+		memset(anchor, 0, sizeof(*anchor));
+		RB_INIT(&anchor->children);
+		strlcpy(anchor->name, q, sizeof(anchor->name));
+		if (parent != NULL) {
+			strlcpy(anchor->path, parent->path,
+			    sizeof(anchor->path));
+			strlcat(anchor->path, "/", sizeof(anchor->path));
+		}
+		strlcat(anchor->path, anchor->name, sizeof(anchor->path));
+		if ((dup = RB_INSERT(pf_anchor_global, &pf_anchors, anchor)) !=
+		    NULL) {
+			printf("pf_find_or_create_ruleset: RB_INSERT1 "
+			    "'%s' '%s' collides with '%s' '%s'\n",
+			    anchor->path, anchor->name, dup->path, dup->name);
+			rs_free(anchor);
+			rs_free(p);
+			return (NULL);
+		}
+		if (parent != NULL) {
+			anchor->parent = parent;
+			if ((dup = RB_INSERT(pf_anchor_node, &parent->children,
+			    anchor)) != NULL) {
+				printf("pf_find_or_create_ruleset: "
+				    "RB_INSERT2 '%s' '%s' collides with "
+				    "'%s' '%s'\n", anchor->path, anchor->name,
+				    dup->path, dup->name);
+				RB_REMOVE(pf_anchor_global, &pf_anchors,
+				    anchor);
+				rs_free(anchor);
+				rs_free(p);
+				return (NULL);
+			}
+		}
+		pf_init_ruleset(&anchor->ruleset);
+		anchor->ruleset.anchor = anchor;
+		parent = anchor;
+		if (r != NULL)
+			q = r + 1;
+		else
+			*q = 0;
+	}
+	rs_free(p);
+	return (&anchor->ruleset);
+}
+
+void
+pf_remove_if_empty_ruleset(struct pf_ruleset *ruleset)
+{
+	struct pf_anchor	*parent;
+	int			 i;
+
+	while (ruleset != NULL) {
+		if (ruleset == &pf_main_ruleset || ruleset->anchor == NULL ||
+		    !RB_EMPTY(&ruleset->anchor->children) ||
+		    ruleset->anchor->refcnt > 0 || ruleset->tables > 0 ||
+		    ruleset->topen)
+			return;
+		for (i = 0; i < PF_RULESET_MAX; ++i)
+			if (!TAILQ_EMPTY(ruleset->rules[i].active.ptr) ||
+			    !TAILQ_EMPTY(ruleset->rules[i].inactive.ptr) ||
+			    ruleset->rules[i].inactive.open)
+				return;
+		RB_REMOVE(pf_anchor_global, &pf_anchors, ruleset->anchor);
+		if ((parent = ruleset->anchor->parent) != NULL)
+			RB_REMOVE(pf_anchor_node, &parent->children,
+			    ruleset->anchor);
+		rs_free(ruleset->anchor);
+		if (parent == NULL)
+			return;
+		ruleset = &parent->ruleset;
+	}
+}
+
+int
+pf_anchor_setup(struct pf_rule *r, const struct pf_ruleset *s,
+    const char *name)
+{
+	char			*p, *path;
+	struct pf_ruleset	*ruleset;
+
+	r->anchor = NULL;
+	r->anchor_relative = 0;
+	r->anchor_wildcard = 0;
+	if (!name[0])
+		return (0);
+	path = (char *)rs_malloc(MAXPATHLEN);
+	bzero(path, MAXPATHLEN);
+	if (name[0] == '/')
+		strlcpy(path, name + 1, MAXPATHLEN);
+	else {
+		/* relative path */
+		r->anchor_relative = 1;
+		if (s->anchor == NULL || !s->anchor->path[0])
+			path[0] = 0;
+		else
+			strlcpy(path, s->anchor->path, MAXPATHLEN);
+		while (name[0] == '.' && name[1] == '.' && name[2] == '/') {
+			if (!path[0]) {
+				printf("pf_anchor_setup: .. beyond root\n");
+				rs_free(path);
+				return (1);
+			}
+			if ((p = strrchr(path, '/')) != NULL)
+				*p = 0;
+			else
+				path[0] = 0;
+			r->anchor_relative++;
+			name += 3;
+		}
+		if (path[0])
+			strlcat(path, "/", MAXPATHLEN);
+		strlcat(path, name, MAXPATHLEN);
+	}
+	if ((p = strrchr(path, '/')) != NULL && !strcmp(p, "/*")) {
+		r->anchor_wildcard = 1;
+		*p = 0;
+	}
+	ruleset = pf_find_or_create_ruleset(path);
+	rs_free(path);
+	if (ruleset == NULL || ruleset->anchor == NULL) {
+		printf("pf_anchor_setup: ruleset\n");
+		return (1);
+	}
+	r->anchor = ruleset->anchor;
+	r->anchor->refcnt++;
+	return (0);
+}
+
+int
+pf_anchor_copyout(const struct pf_ruleset *rs, const struct pf_rule *r,
+    struct pfioc_rule *pr)
+{
+	pr->anchor_call[0] = 0;
+	if (r->anchor == NULL)
+		return (0);
+	if (!r->anchor_relative) {
+		strlcpy(pr->anchor_call, "/", sizeof(pr->anchor_call));
+		strlcat(pr->anchor_call, r->anchor->path,
+		    sizeof(pr->anchor_call));
+	} else {
+		char	*a, *p;
+		int	 i;
+
+		a = (char *)rs_malloc(MAXPATHLEN);
+		bzero(a, MAXPATHLEN);
+		if (rs->anchor == NULL)
+			a[0] = 0;
+		else
+			strlcpy(a, rs->anchor->path, MAXPATHLEN);
+		for (i = 1; i < r->anchor_relative; ++i) {
+			if ((p = strrchr(a, '/')) == NULL)
+				p = a;
+			*p = 0;
+			strlcat(pr->anchor_call, "../",
+			    sizeof(pr->anchor_call));
+		}
+		if (strncmp(a, r->anchor->path, strlen(a))) {
+			printf("pf_anchor_copyout: '%s' '%s'\n", a,
+			    r->anchor->path);
+			rs_free(a);
+			return (1);
+		}
+		if (strlen(r->anchor->path) > strlen(a))
+			strlcat(pr->anchor_call, r->anchor->path + (a[0] ?
+			    strlen(a) + 1 : 0), sizeof(pr->anchor_call));
+		rs_free(a);
+	}
+	if (r->anchor_wildcard)
+		strlcat(pr->anchor_call, pr->anchor_call[0] ? "/*" : "*",
+		    sizeof(pr->anchor_call));
+	return (0);
+}
+
+void
+pf_anchor_remove(struct pf_rule *r)
+{
+	if (r->anchor == NULL)
+		return;
+	if (r->anchor->refcnt <= 0) {
+		printf("pf_anchor_remove: broken refcount\n");
+		r->anchor = NULL;
+		return;
+	}
+	if (!--r->anchor->refcnt)
+		pf_remove_if_empty_ruleset(&r->anchor->ruleset);
+	r->anchor = NULL;
+}
Index: if_pfsync.c
===================================================================
RCS file: /home/cvs/src/sys/contrib/pf/net/if_pfsync.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/contrib/pf/net/if_pfsync.c -L sys/contrib/pf/net/if_pfsync.c -u -r1.1.1.1 -r1.2
--- sys/contrib/pf/net/if_pfsync.c
+++ sys/contrib/pf/net/if_pfsync.c
@@ -1,5 +1,4 @@
-/*	$FreeBSD: src/sys/contrib/pf/net/if_pfsync.c,v 1.19.2.3 2005/09/17 15:19:38 mlaier Exp $	*/
-/*	$OpenBSD: if_pfsync.c,v 1.46 2005/02/20 15:58:38 mcbride Exp $	*/
+/*	$OpenBSD: if_pfsync.c,v 1.73 2006/11/16 13:13:38 henning Exp $	*/
 
 /*
  * Copyright (c) 2002 Michael Shalayeff
@@ -30,30 +29,47 @@
 #ifdef __FreeBSD__
 #include "opt_inet.h"
 #include "opt_inet6.h"
-#endif
-
-#ifndef __FreeBSD__
-#include "bpfilter.h"
-#include "pfsync.h"
-#elif __FreeBSD__ >= 5
+#include "opt_carp.h"
 #include "opt_bpf.h"
 #include "opt_pf.h"
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/sys/contrib/pf/net/if_pfsync.c,v 1.36 2007/07/28 07:31:29 rwatson Exp $");
+
+#ifdef DEV_BPF
 #define	NBPFILTER	DEV_BPF
+#else
+#define	NBPFILTER	0
+#endif
+
+#ifdef DEV_PFSYNC
 #define	NPFSYNC		DEV_PFSYNC
+#else
+#define	NPFSYNC		0
+#endif
+
+#ifdef DEV_CARP
+#define	NCARP		DEV_CARP
+#else
+#define	NCARP		0
 #endif
+#endif /* __FreeBSD__ */
 
 #include <sys/param.h>
+#ifdef __FreeBSD__
+#include <sys/priv.h>
+#endif
 #include <sys/proc.h>
 #include <sys/systm.h>
 #include <sys/time.h>
 #include <sys/mbuf.h>
 #include <sys/socket.h>
-#include <sys/kernel.h>
 #ifdef __FreeBSD__
 #include <sys/endian.h>
 #include <sys/malloc.h>
 #include <sys/module.h>
 #include <sys/sockio.h>
+#include <sys/taskqueue.h>
 #include <sys/lock.h>
 #include <sys/mutex.h>
 #include <sys/sysctl.h>
@@ -61,19 +77,21 @@
 #include <sys/ioctl.h>
 #include <sys/timeout.h>
 #endif
+#include <sys/kernel.h>
 
 #include <net/if.h>
-#if defined(__FreeBSD__)
+#ifdef __FreeBSD__
 #include <net/if_clone.h>
 #endif
 #include <net/if_types.h>
 #include <net/route.h>
 #include <net/bpf.h>
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
 #include <netinet/tcp.h>
 #include <netinet/tcp_seq.h>
 
 #ifdef	INET
-#include <netinet/in.h>
 #include <netinet/in_systm.h>
 #include <netinet/in_var.h>
 #include <netinet/ip.h>
@@ -81,29 +99,22 @@
 #endif
 
 #ifdef INET6
-#ifndef INET
-#include <netinet/in.h>
-#endif
 #include <netinet6/nd6.h>
 #endif /* INET6 */
 
-#ifdef __FreeBSD__
-#include "opt_carp.h"
-#ifdef DEV_CARP
-#define	NCARP	1
-#endif
-#else
+#ifndef __FreeBSD__
 #include "carp.h"
 #endif
 #if NCARP > 0
-extern int carp_suppress_preempt;
+#include <netinet/ip_carp.h>
 #endif
 
 #include <net/pfvar.h>
 #include <net/if_pfsync.h>
 
-#ifdef __FreeBSD__
-#define	PFSYNCNAME	"pfsync"
+#ifndef __FreeBSD__
+#include "bpfilter.h"
+#include "pfsync.h"
 #endif
 
 #define PFSYNC_MINMTU	\
@@ -116,32 +127,30 @@
 #define DPRINTF(x)
 #endif
 
-#ifndef __FreeBSD__
-struct pfsync_softc	pfsyncif;
-#endif
-struct pfsyncstats	pfsyncstats;
+struct pfsync_softc	*pfsyncif = NULL;
+struct pfsyncstats	 pfsyncstats;
 #ifdef __FreeBSD__
 SYSCTL_DECL(_net_inet_pfsync);
 SYSCTL_STRUCT(_net_inet_pfsync, 0, stats, CTLFLAG_RW,
     &pfsyncstats, pfsyncstats,
     "PFSYNC statistics (struct pfsyncstats, net/if_pfsync.h)");
+#endif
 
-/*
- * Locking notes:
- * Whenever we really touch/look at the state table we have to hold the
- * PF_LOCK. Functions that do just the interface handling, grab the per
- * softc lock instead.
- *
- */
-
-static void	pfsync_clone_destroy(struct ifnet *);
-static int	pfsync_clone_create(struct if_clone *, int);
-static void	pfsync_senddef(void *);
-#else
 void	pfsyncattach(int);
+#ifdef __FreeBSD__
+int	pfsync_clone_create(struct if_clone *, int, caddr_t);
+void	pfsync_clone_destroy(struct ifnet *);
+#else
+int	pfsync_clone_create(struct if_clone *, int);
+int	pfsync_clone_destroy(struct ifnet *);
 #endif
 void	pfsync_setmtu(struct pfsync_softc *, int);
-int	pfsync_insert_net_state(struct pfsync_state *);
+int	pfsync_alloc_scrub_memory(struct pfsync_state_peer *,
+	    struct pf_state_peer *);
+int	pfsync_insert_net_state(struct pfsync_state *, u_int8_t);
+#ifdef PFSYNC_TDB
+void	pfsync_update_net_tdb(struct pfsync_tdb *);
+#endif
 int	pfsyncoutput(struct ifnet *, struct mbuf *, struct sockaddr *,
 	    struct rtentry *);
 int	pfsyncioctl(struct ifnet *, u_long, caddr_t);
@@ -150,134 +159,193 @@
 struct mbuf *pfsync_get_mbuf(struct pfsync_softc *, u_int8_t, void **);
 int	pfsync_request_update(struct pfsync_state_upd *, struct in_addr *);
 int	pfsync_sendout(struct pfsync_softc *);
+#ifdef PFSYNC_TDB
+int	pfsync_tdb_sendout(struct pfsync_softc *);
+#endif
+int	pfsync_sendout_mbuf(struct pfsync_softc *, struct mbuf *);
 void	pfsync_timeout(void *);
+#ifdef PFSYNC_TDB
+void	pfsync_tdb_timeout(void *);
+#endif
 void	pfsync_send_bus(struct pfsync_softc *, u_int8_t);
 void	pfsync_bulk_update(void *);
 void	pfsync_bulkfail(void *);
 
+#ifdef __FreeBSD__
+void	pfsync_ifdetach(void *, struct ifnet *);
+void	pfsync_senddef(void *, int);
+
+/* XXX: ugly */
+#define	betoh64		(unsigned long long)be64toh
+#define	timeout_del	callout_stop
+#endif
+
 int	pfsync_sync_ok;
 #ifndef __FreeBSD__
 extern int ifqmaxlen;
-extern struct timeval time;
-extern struct timeval mono_time;
-extern int hz;
 #endif
 
 #ifdef __FreeBSD__
-static MALLOC_DEFINE(M_PFSYNC, PFSYNCNAME, "Packet Filter State Sync. Interface");
-static LIST_HEAD(pfsync_list, pfsync_softc) pfsync_list;
-#define	SCP2IFP(sc)		((sc)->sc_ifp)
 IFC_SIMPLE_DECLARE(pfsync, 1);
+#else
+struct if_clone	pfsync_cloner =
+    IF_CLONE_INITIALIZER("pfsync", pfsync_clone_create, pfsync_clone_destroy);
+#endif
 
-static void
-pfsync_clone_destroy(struct ifnet *ifp)
+void
+pfsyncattach(int npfsync)
 {
-        struct pfsync_softc *sc;
-
-	sc = ifp->if_softc;
-	callout_stop(&sc->sc_tmo);
-	callout_stop(&sc->sc_bulk_tmo);
-	callout_stop(&sc->sc_bulkfail_tmo);
-
-	callout_stop(&sc->sc_send_tmo);
-
-#if NBPFILTER > 0
-        bpfdetach(ifp);
-#endif
-        if_detach(ifp);
-	if_free(ifp);
-        LIST_REMOVE(sc, sc_next);
-        free(sc, M_PFSYNC);
+	if_clone_attach(&pfsync_cloner);
 }
 
-static int
+int
+#ifdef __FreeBSD__
+pfsync_clone_create(struct if_clone *ifc, int unit, caddr_t param)
+#else
 pfsync_clone_create(struct if_clone *ifc, int unit)
+#endif
 {
-	struct pfsync_softc *sc;
 	struct ifnet *ifp;
 
-	MALLOC(sc, struct pfsync_softc *, sizeof(*sc), M_PFSYNC,
-	    M_WAITOK|M_ZERO);
-	ifp = sc->sc_ifp = if_alloc(IFT_PFSYNC);
+	if (unit != 0)
+		return (EINVAL);
+
+	pfsync_sync_ok = 1;
+	if ((pfsyncif = malloc(sizeof(*pfsyncif), M_DEVBUF, M_NOWAIT)) == NULL)
+		return (ENOMEM);
+	bzero(pfsyncif, sizeof(*pfsyncif));
+#ifdef __FreeBSD__
+	if ((pfsyncif->sc_imo.imo_membership = (struct in_multi **)malloc(
+	    (sizeof(struct in_multi *) * IP_MIN_MEMBERSHIPS), M_DEVBUF,
+	    M_NOWAIT)) == NULL) {
+		free(pfsyncif, M_DEVBUF);
+		return (ENOSPC);
+	}
+	pfsyncif->sc_imo.imo_mfilters = NULL;
+	pfsyncif->sc_imo.imo_max_memberships = IP_MIN_MEMBERSHIPS;
+	pfsyncif->sc_imo.imo_multicast_vif = -1;
+
+	ifp = pfsyncif->sc_ifp = if_alloc(IFT_PFSYNC);
 	if (ifp == NULL) {
-		free(sc, M_PFSYNC);
+		free(pfsyncif->sc_imo.imo_membership, M_DEVBUF);
+		free(pfsyncif, M_DEVBUF);
 		return (ENOSPC);
 	}
+	if_initname(ifp, ifc->ifc_name, unit);
 
-	pfsync_sync_ok = 1;
-	sc->sc_mbuf = NULL;
-	sc->sc_mbuf_net = NULL;
-	sc->sc_statep.s = NULL;
-	sc->sc_statep_net.s = NULL;
-	sc->sc_maxupdates = 128;
-	sc->sc_sendaddr.s_addr = htonl(INADDR_PFSYNC_GROUP);
-	sc->sc_ureq_received = 0;
-	sc->sc_ureq_sent = 0;
+	pfsyncif->sc_detachtag = EVENTHANDLER_REGISTER(ifnet_departure_event,
+	    pfsync_ifdetach, pfsyncif, EVENTHANDLER_PRI_ANY);
+	if (pfsyncif->sc_detachtag == NULL) {
+		if_free(ifp);
+		free(pfsyncif->sc_imo.imo_membership, M_DEVBUF);
+		free(pfsyncif, M_DEVBUF);
+		return (ENOSPC);
+	}
 
-	ifp = SCP2IFP(sc);
-	if_initname(ifp, ifc->ifc_name, unit);
+	pfsyncif->sc_ifq.ifq_maxlen = ifqmaxlen;
+	mtx_init(&pfsyncif->sc_ifq.ifq_mtx, ifp->if_xname,
+	    "pfsync send queue", MTX_DEF);
+	TASK_INIT(&pfsyncif->sc_send_task, 0, pfsync_senddef, pfsyncif);
+#endif
+	pfsyncif->sc_mbuf = NULL;
+	pfsyncif->sc_mbuf_net = NULL;
+#ifdef PFSYNC_TDB
+	pfsyncif->sc_mbuf_tdb = NULL;
+#endif
+	pfsyncif->sc_statep.s = NULL;
+	pfsyncif->sc_statep_net.s = NULL;
+#ifdef PFSYNC_TDB
+	pfsyncif->sc_statep_tdb.t = NULL;
+#endif
+	pfsyncif->sc_maxupdates = 128;
+#ifdef __FreeBSD__
+	pfsyncif->sc_sync_peer.s_addr = htonl(INADDR_PFSYNC_GROUP);
+	pfsyncif->sc_sendaddr.s_addr = htonl(INADDR_PFSYNC_GROUP);
+#else
+	pfsyncif->sc_sync_peer.s_addr = INADDR_PFSYNC_GROUP;
+	pfsyncif->sc_sendaddr.s_addr = INADDR_PFSYNC_GROUP;
+#endif
+	pfsyncif->sc_ureq_received = 0;
+	pfsyncif->sc_ureq_sent = 0;
+	pfsyncif->sc_bulk_send_next = NULL;
+	pfsyncif->sc_bulk_terminator = NULL;
+#ifndef __FreeBSD__
+	ifp = &pfsyncif->sc_if;
+	snprintf(ifp->if_xname, sizeof ifp->if_xname, "pfsync%d", unit);
+#endif
+	ifp->if_softc = pfsyncif;
 	ifp->if_ioctl = pfsyncioctl;
 	ifp->if_output = pfsyncoutput;
 	ifp->if_start = pfsyncstart;
+	ifp->if_type = IFT_PFSYNC;
 	ifp->if_snd.ifq_maxlen = ifqmaxlen;
 	ifp->if_hdrlen = PFSYNC_HDRLEN;
-	ifp->if_baudrate = IF_Mbps(100);
-	ifp->if_softc = sc;
-	pfsync_setmtu(sc, MCLBYTES);
-	callout_init(&sc->sc_tmo, NET_CALLOUT_MPSAFE);
-	callout_init(&sc->sc_bulk_tmo, NET_CALLOUT_MPSAFE);
-	callout_init(&sc->sc_bulkfail_tmo, NET_CALLOUT_MPSAFE);
-	callout_init(&sc->sc_send_tmo, NET_CALLOUT_MPSAFE);
-	sc->sc_ifq.ifq_maxlen = ifqmaxlen;
-	mtx_init(&sc->sc_ifq.ifq_mtx, ifp->if_xname, "pfsync send queue",
-	    MTX_DEF);
+	pfsync_setmtu(pfsyncif, ETHERMTU);
+#ifdef __FreeBSD__
+	callout_init(&pfsyncif->sc_tmo, CALLOUT_MPSAFE);
+#ifdef PFSYNC_TDB
+	callout_init(&pfsyncif->sc_tdb_tmo, CALLOUT_MPSAFE);
+#endif
+	callout_init(&pfsyncif->sc_bulk_tmo, CALLOUT_MPSAFE);
+	callout_init(&pfsyncif->sc_bulkfail_tmo, CALLOUT_MPSAFE);
+#else
+	timeout_set(&pfsyncif->sc_tmo, pfsync_timeout, pfsyncif);
+	timeout_set(&pfsyncif->sc_tdb_tmo, pfsync_tdb_timeout, pfsyncif);
+	timeout_set(&pfsyncif->sc_bulk_tmo, pfsync_bulk_update, pfsyncif);
+	timeout_set(&pfsyncif->sc_bulkfail_tmo, pfsync_bulkfail, pfsyncif);
+#endif
 	if_attach(ifp);
+#ifndef __FreeBSD__
+	if_alloc_sadl(ifp);
+#endif
+
+#if NCARP > 0
+	if_addgroup(ifp, "carp");
+#endif
 
-	LIST_INSERT_HEAD(&pfsync_list, sc, sc_next);
 #if NBPFILTER > 0
+#ifdef __FreeBSD__
 	bpfattach(ifp, DLT_PFSYNC, PFSYNC_HDRLEN);
+#else
+	bpfattach(&pfsyncif->sc_if.if_bpf, ifp, DLT_PFSYNC, PFSYNC_HDRLEN);
+#endif
 #endif
 
 	return (0);
 }
-#else /* !__FreeBSD__ */
+
+#ifdef __FreeBSD__
 void
-pfsyncattach(int npfsync)
+#else
+int
+#endif
+pfsync_clone_destroy(struct ifnet *ifp)
 {
-	struct ifnet *ifp;
-
-	pfsync_sync_ok = 1;
-	bzero(&pfsyncif, sizeof(pfsyncif));
-	pfsyncif.sc_mbuf = NULL;
-	pfsyncif.sc_mbuf_net = NULL;
-	pfsyncif.sc_statep.s = NULL;
-	pfsyncif.sc_statep_net.s = NULL;
-	pfsyncif.sc_maxupdates = 128;
-	pfsyncif.sc_sync_peer.s_addr = INADDR_PFSYNC_GROUP;
-	pfsyncif.sc_sendaddr.s_addr = INADDR_PFSYNC_GROUP;
-	pfsyncif.sc_ureq_received = 0;
-	pfsyncif.sc_ureq_sent = 0;
-	ifp = &pfsyncif.sc_if;
-	strlcpy(ifp->if_xname, "pfsync0", sizeof ifp->if_xname);
-	ifp->if_softc = &pfsyncif;
-	ifp->if_ioctl = pfsyncioctl;
-	ifp->if_output = pfsyncoutput;
-	ifp->if_start = pfsyncstart;
-	ifp->if_type = IFT_PFSYNC;
-	ifp->if_snd.ifq_maxlen = ifqmaxlen;
-	ifp->if_hdrlen = PFSYNC_HDRLEN;
-	pfsync_setmtu(&pfsyncif, MCLBYTES);
-	timeout_set(&pfsyncif.sc_tmo, pfsync_timeout, &pfsyncif);
-	timeout_set(&pfsyncif.sc_bulk_tmo, pfsync_bulk_update, &pfsyncif);
-	timeout_set(&pfsyncif.sc_bulkfail_tmo, pfsync_bulkfail, &pfsyncif);
-	if_attach(ifp);
-	if_alloc_sadl(ifp);
+#ifdef __FreeBSD__
+	EVENTHANDLER_DEREGISTER(ifnet_departure_event, pfsyncif->sc_detachtag);
+	callout_stop(&pfsyncif->sc_tmo);
+#ifdef PFSYNC_TDB
+	callout_stop(&pfsyncif->sc_tdb_tmo);
+#endif
+	callout_stop(&pfsyncif->sc_bulk_tmo);
+	callout_stop(&pfsyncif->sc_bulkfail_tmo);
+	/* XXX: more? */
+#endif
 
 #if NBPFILTER > 0
-	bpfattach(&pfsyncif.sc_if.if_bpf, ifp, DLT_PFSYNC, PFSYNC_HDRLEN);
+	bpfdetach(ifp);
 #endif
-}
+	if_detach(ifp);
+#ifdef __FreeBSD__
+	if_free(ifp);
+	free(pfsyncif->sc_imo.imo_membership, M_DEVBUF);
+#endif
+	free(pfsyncif, M_DEVBUF);
+	pfsyncif = NULL;
+#ifndef __FreeBSD__
+	return (0);
 #endif
+}
 
 /*
  * Start output on the pfsync interface.
@@ -285,46 +353,59 @@
 void
 pfsyncstart(struct ifnet *ifp)
 {
-#ifdef __FreeBSD__
-	IF_LOCK(&ifp->if_snd);
-	_IF_DROP(&ifp->if_snd);
-	_IF_DRAIN(&ifp->if_snd);
-	IF_UNLOCK(&ifp->if_snd);
-#else
 	struct mbuf *m;
+#ifndef __FreeBSD__
 	int s;
+#endif
 
 	for (;;) {
-		s = splimp();
+#ifdef __FreeBSD__
+		IF_LOCK(&ifp->if_snd);
+		_IF_DROP(&ifp->if_snd);
+		_IF_DEQUEUE(&ifp->if_snd, m);
+		IF_UNLOCK(&ifp->if_snd);
+#else
+		s = splnet();
 		IF_DROP(&ifp->if_snd);
 		IF_DEQUEUE(&ifp->if_snd, m);
 		splx(s);
+#endif
 
 		if (m == NULL)
 			return;
 		else
 			m_freem(m);
 	}
-#endif
 }
 
 int
-pfsync_insert_net_state(struct pfsync_state *sp)
+pfsync_alloc_scrub_memory(struct pfsync_state_peer *s,
+    struct pf_state_peer *d)
+{
+	if (s->scrub.scrub_flag && d->scrub == NULL) {
+		d->scrub = pool_get(&pf_state_scrub_pl, PR_NOWAIT);
+		if (d->scrub == NULL)
+			return (ENOMEM);
+		bzero(d->scrub, sizeof(*d->scrub));
+	}
+
+	return (0);
+}
+
+int
+pfsync_insert_net_state(struct pfsync_state *sp, u_int8_t chksum_flag)
 {
 	struct pf_state	*st = NULL;
 	struct pf_rule *r = NULL;
 	struct pfi_kif	*kif;
 
-#ifdef __FreeBSD__
-	PF_ASSERT(MA_OWNED);
-#endif
 	if (sp->creatorid == 0 && pf_status.debug >= PF_DEBUG_MISC) {
 		printf("pfsync_insert_net_state: invalid creator id:"
 		    " %08x\n", ntohl(sp->creatorid));
 		return (EINVAL);
 	}
 
-	kif = pfi_lookup_create(sp->ifname);
+	kif = pfi_kif_get(sp->ifname);
 	if (kif == NULL) {
 		if (pf_status.debug >= PF_DEBUG_MISC)
 			printf("pfsync_insert_net_state: "
@@ -334,19 +415,33 @@
 	}
 
 	/*
-	 * Just use the default rule until we have infrastructure to find the
-	 * best matching rule.
+	 * If the ruleset checksums match, it's safe to associate the state
+	 * with the rule of that number.
 	 */
-	r = &pf_default_rule;
+	if (sp->rule != htonl(-1) && sp->anchor == htonl(-1) && chksum_flag)
+		r = pf_main_ruleset.rules[
+		    PF_RULESET_FILTER].active.ptr_array[ntohl(sp->rule)];
+	else
+		r = &pf_default_rule;
 
 	if (!r->max_states || r->states < r->max_states)
 		st = pool_get(&pf_state_pl, PR_NOWAIT);
 	if (st == NULL) {
-		pfi_maybe_destroy(kif);
+		pfi_kif_unref(kif, PFI_KIF_REF_NONE);
 		return (ENOMEM);
 	}
 	bzero(st, sizeof(*st));
 
+	/* allocate memory for scrub info */
+	if (pfsync_alloc_scrub_memory(&sp->src, &st->src) ||
+	    pfsync_alloc_scrub_memory(&sp->dst, &st->dst)) {
+		pfi_kif_unref(kif, PFI_KIF_REF_NONE);
+		if (st->src.scrub)
+			pool_put(&pf_state_scrub_pl, st->src.scrub);
+		pool_put(&pf_state_pl, st);
+		return (ENOMEM);
+	}
+
 	st->rule.ptr = r;
 	/* XXX get pointers to nat_rule and anchor */
 
@@ -376,11 +471,14 @@
 	st->creatorid = sp->creatorid;
 	st->sync_flags = PFSTATE_FROMSYNC;
 
-
 	if (pf_insert_state(kif, st)) {
-		pfi_maybe_destroy(kif);
+		pfi_kif_unref(kif, PFI_KIF_REF_NONE);
 		/* XXX when we have nat_rule/anchors, use STATE_DEC_COUNTERS */
 		r->states--;
+		if (st->dst.scrub)
+			pool_put(&pf_state_scrub_pl, st->dst.scrub);
+		if (st->src.scrub)
+			pool_put(&pf_state_scrub_pl, st->src.scrub);
 		pool_put(&pf_state_pl, st);
 		return (EINVAL);
 	}
@@ -397,26 +495,27 @@
 {
 	struct ip *ip = mtod(m, struct ip *);
 	struct pfsync_header *ph;
-#ifdef __FreeBSD__
-	struct pfsync_softc *sc = LIST_FIRST(&pfsync_list);
-#else
-	struct pfsync_softc *sc = &pfsyncif;
-#endif
-	struct pf_state *st, key;
+	struct pfsync_softc *sc = pfsyncif;
+	struct pf_state *st;
+	struct pf_state_cmp key;
 	struct pfsync_state *sp;
 	struct pfsync_state_upd *up;
 	struct pfsync_state_del *dp;
 	struct pfsync_state_clr *cp;
 	struct pfsync_state_upd_req *rup;
 	struct pfsync_state_bus *bus;
+#ifdef PFSYNC_TDB
+	struct pfsync_tdb *pt;
+#endif
 	struct in_addr src;
 	struct mbuf *mp;
 	int iplen, action, error, i, s, count, offp, sfail, stale = 0;
+	u_int8_t chksum_flag = 0;
 
 	pfsyncstats.pfsyncs_ipackets++;
 
 	/* verify that we have a sync interface configured */
-	if (!sc->sc_sync_ifp || !pf_status.running) /* XXX PF_LOCK? */
+	if (!sc || !sc->sc_sync_ifp || !pf_status.running)
 		goto done;
 
 	/* verify that the packet came in on the right interface */
@@ -465,6 +564,9 @@
 	/* Cheaper to grab this now than having to mess with mbufs later */
 	src = ip->ip_src;
 
+	if (!bcmp(&ph->pf_chksum, &pf_status.pf_chksum, PF_MD5_DIGEST_LENGTH))
+		chksum_flag++;
+
 	switch (action) {
 	case PFSYNC_ACT_CLR: {
 		struct pf_state *nexts;
@@ -485,31 +587,27 @@
 		if (cp->ifname[0] == '\0') {
 			for (st = RB_MIN(pf_state_tree_id, &tree_id);
 			    st; st = nexts) {
-                		nexts = RB_NEXT(pf_state_tree_id, &tree_id, st);
+				nexts = RB_NEXT(pf_state_tree_id, &tree_id, st);
 				if (st->creatorid == creatorid) {
-					st->timeout = PFTM_PURGE;
-					pf_purge_expired_state(st);
+					st->sync_flags |= PFSTATE_FROMSYNC;
+					pf_unlink_state(st);
 				}
 			}
 		} else {
-			kif = pfi_lookup_if(cp->ifname);
-			if (kif == NULL) {
-				if (pf_status.debug >= PF_DEBUG_MISC)
-					printf("pfsync_input: PFSYNC_ACT_CLR "
-					    "bad interface: %s\n", cp->ifname);
-				splx(s);
+			if ((kif = pfi_kif_get(cp->ifname)) == NULL) {
 #ifdef __FreeBSD__
 				PF_UNLOCK();
 #endif
-				goto done;
+				splx(s);
+				return;
 			}
 			for (st = RB_MIN(pf_state_tree_lan_ext,
 			    &kif->pfik_lan_ext); st; st = nexts) {
 				nexts = RB_NEXT(pf_state_tree_lan_ext,
 				    &kif->pfik_lan_ext, st);
 				if (st->creatorid == creatorid) {
-					st->timeout = PFTM_PURGE;
-					pf_purge_expired_state(st);
+					st->sync_flags |= PFSTATE_FROMSYNC;
+					pf_unlink_state(st);
 				}
 			}
 		}
@@ -546,12 +644,13 @@
 				continue;
 			}
 
-			if ((error = pfsync_insert_net_state(sp))) {
+			if ((error = pfsync_insert_net_state(sp,
+			    chksum_flag))) {
 				if (error == ENOMEM) {
-					splx(s);
 #ifdef __FreeBSD__
 					PF_UNLOCK();
 #endif
+					splx(s);
 					goto done;
 				}
 				continue;
@@ -594,7 +693,7 @@
 			st = pf_find_state_byid(&key);
 			if (st == NULL) {
 				/* insert the update */
-				if (pfsync_insert_net_state(sp))
+				if (pfsync_insert_net_state(sp, chksum_flag))
 					pfsyncstats.pfsyncs_badstate++;
 				continue;
 			}
@@ -633,7 +732,7 @@
 				 */
 				if (st->src.state > sp->src.state)
 					sfail = 5;
-				else if ( st->dst.state > sp->dst.state)
+				else if (st->dst.state > sp->dst.state)
 					sfail = 6;
 			}
 			if (sfail) {
@@ -643,11 +742,7 @@
 					    "creatorid: %08x\n",
 					    (sfail < 7 ?  "ignoring"
 					     : "partial"), sfail,
-#ifdef __FreeBSD__
-					    (unsigned long long)be64toh(st->id),
-#else
 					    betoh64(st->id),
-#endif
 					    ntohl(st->creatorid));
 				pfsyncstats.pfsyncs_badstate++;
 
@@ -662,6 +757,7 @@
 				}
 				continue;
 			}
+	    		pfsync_alloc_scrub_memory(&sp->dst, &st->dst);
 			pf_state_peer_ntoh(&sp->src, &st->src);
 			pf_state_peer_ntoh(&sp->dst, &st->dst);
 			st->expire = ntohl(sp->expire) + time_second;
@@ -699,9 +795,8 @@
 				pfsyncstats.pfsyncs_badstate++;
 				continue;
 			}
-			st->timeout = PFTM_PURGE;
 			st->sync_flags |= PFSTATE_FROMSYNC;
-			pf_purge_expired_state(st);
+			pf_unlink_state(st);
 		}
 #ifdef __FreeBSD__
 		PF_UNLOCK();
@@ -743,6 +838,9 @@
 				/* We don't have this state. Ask for it. */
 				error = pfsync_request_update(up, &src);
 				if (error == ENOMEM) {
+#ifdef __FreeBSD__
+					PF_UNLOCK();
+#endif
 					splx(s);
 					goto done;
 				}
@@ -784,11 +882,7 @@
 					printf("pfsync: ignoring stale update "
 					    "(%d) id: %016llx "
 					    "creatorid: %08x\n", sfail,
-#ifdef __FreeBSD__
-					    (unsigned long long)be64toh(st->id),
-#else
 					    betoh64(st->id),
-#endif
 					    ntohl(st->creatorid));
 				pfsyncstats.pfsyncs_badstate++;
 
@@ -804,6 +898,7 @@
 					    PFSYNC_FLAG_STALE);
 				continue;
 			}
+	    		pfsync_alloc_scrub_memory(&up->dst, &st->dst);
 			pf_state_peer_ntoh(&up->src, &st->src);
 			pf_state_peer_ntoh(&up->dst, &st->dst);
 			st->expire = ntohl(up->expire) + time_second;
@@ -838,9 +933,8 @@
 				pfsyncstats.pfsyncs_badstate++;
 				continue;
 			}
-			st->timeout = PFTM_PURGE;
 			st->sync_flags |= PFSTATE_FROMSYNC;
-			pf_purge_expired_state(st);
+			pf_unlink_state(st);
 		}
 #ifdef __FreeBSD__
 		PF_UNLOCK();
@@ -872,14 +966,17 @@
 
 			if (key.id == 0 && key.creatorid == 0) {
 				sc->sc_ureq_received = time_uptime;
+				if (sc->sc_bulk_send_next == NULL)
+					sc->sc_bulk_send_next =
+					    TAILQ_FIRST(&state_list);
+				sc->sc_bulk_terminator = sc->sc_bulk_send_next;
 				if (pf_status.debug >= PF_DEBUG_MISC)
 					printf("pfsync: received "
 					    "bulk update request\n");
 				pfsync_send_bus(sc, PFSYNC_BUS_START);
 #ifdef __FreeBSD__
 				callout_reset(&sc->sc_bulk_tmo, 1 * hz,
-				    pfsync_bulk_update,
-				    LIST_FIRST(&pfsync_list));
+				    pfsync_bulk_update, pfsyncif);
 #else
 				timeout_add(&sc->sc_bulk_tmo, 1 * hz);
 #endif
@@ -917,8 +1014,8 @@
 #ifdef __FreeBSD__
 			callout_reset(&sc->sc_bulkfail_tmo,
 			    pf_pool_limits[PF_LIMIT_STATES].limit /
-			    (PFSYNC_BULKPACKETS * sc->sc_maxcount), 
-			    pfsync_bulkfail, LIST_FIRST(&pfsync_list));
+			    (PFSYNC_BULKPACKETS * sc->sc_maxcount),
+			    pfsync_bulkfail, pfsyncif);
 #else
 			timeout_add(&sc->sc_bulkfail_tmo,
 			    pf_pool_limits[PF_LIMIT_STATES].limit /
@@ -934,14 +1031,16 @@
 				/* that's it, we're happy */
 				sc->sc_ureq_sent = 0;
 				sc->sc_bulk_tries = 0;
+				timeout_del(&sc->sc_bulkfail_tmo);
+#if NCARP > 0
+				if (!pfsync_sync_ok)
 #ifdef __FreeBSD__
-				callout_stop(&sc->sc_bulkfail_tmo);
+#ifdef CARP_ADVANCED
+					carp_group_demote_adj(sc->sc_ifp, -1);
+#endif
 #else
-				timeout_del(&sc->sc_bulkfail_tmo);
+					carp_group_demote_adj(&sc->sc_if, -1);
 #endif
-#if NCARP > 0	/* XXX_IMPORT */
-				if (!pfsync_sync_ok)
-					carp_suppress_preempt--;
 #endif
 				pfsync_sync_ok = 1;
 				if (pf_status.debug >= PF_DEBUG_MISC)
@@ -955,6 +1054,26 @@
 			break;
 		}
 		break;
+#ifdef PFSYNC_TDB
+	case PFSYNC_ACT_TDB_UPD:
+		if ((mp = m_pulldown(m, iplen + sizeof(*ph),
+		    count * sizeof(*pt), &offp)) == NULL) {
+			pfsyncstats.pfsyncs_badlen++;
+			return;
+		}
+		s = splsoftnet();
+#ifdef __FreeBSD__
+		PF_LOCK();
+#endif
+		for (i = 0, pt = (struct pfsync_tdb *)(mp->m_data + offp);
+		    i < count; i++, pt++)
+			pfsync_update_net_tdb(pt);
+#ifdef __FreeBSD__
+		PF_UNLOCK();
+#endif
+		splx(s);
+		break;
+#endif
 	}
 
 done:
@@ -989,10 +1108,17 @@
 	case SIOCAIFADDR:
 	case SIOCSIFDSTADDR:
 	case SIOCSIFFLAGS:
+#ifdef __FreeBSD__
 		if (ifp->if_flags & IFF_UP)
 			ifp->if_drv_flags |= IFF_DRV_RUNNING;
 		else
 			ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
+#else
+		if (ifp->if_flags & IFF_UP)
+			ifp->if_flags |= IFF_RUNNING;
+		else
+			ifp->if_flags &= ~IFF_RUNNING;
+#endif
 		break;
 	case SIOCSIFMTU:
 		if (ifr->ifr_mtu < PFSYNC_MINMTU)
@@ -1003,9 +1129,8 @@
 #ifdef __FreeBSD__
 		PF_LOCK();
 #endif
-		if (ifr->ifr_mtu < ifp->if_mtu) {
+		if (ifr->ifr_mtu < ifp->if_mtu)
 			pfsync_sendout(sc);
-		}
 		pfsync_setmtu(sc, ifr->ifr_mtu);
 #ifdef __FreeBSD__
 		PF_UNLOCK();
@@ -1013,9 +1138,6 @@
 		splx(s);
 		break;
 	case SIOCGETPFSYNC:
-#ifdef __FreeBSD__
-		/* XXX: read unlocked */
-#endif
 		bzero(&pfsyncr, sizeof(pfsyncr));
 		if (sc->sc_sync_ifp)
 			strlcpy(pfsyncr.pfsyncr_syncdev,
@@ -1027,7 +1149,7 @@
 		break;
 	case SIOCSETPFSYNC:
 #ifdef __FreeBSD__
-		if ((error = suser(curthread)) != 0)
+		if ((error = priv_check(curthread, PRIV_NETINET_PF)) != 0)
 #else
 		if ((error = suser(p, p->p_acflag)) != 0)
 #endif
@@ -1035,17 +1157,27 @@
 		if ((error = copyin(ifr->ifr_data, &pfsyncr, sizeof(pfsyncr))))
 			return (error);
 
+#ifdef __FreeBSD__
+		PF_LOCK();
+#endif
 		if (pfsyncr.pfsyncr_syncpeer.s_addr == 0)
+#ifdef __FreeBSD__
+			sc->sc_sync_peer.s_addr = htonl(INADDR_PFSYNC_GROUP);
+#else
 			sc->sc_sync_peer.s_addr = INADDR_PFSYNC_GROUP;
+#endif
 		else
 			sc->sc_sync_peer.s_addr =
 			    pfsyncr.pfsyncr_syncpeer.s_addr;
 
 		if (pfsyncr.pfsyncr_maxupdates > 255)
+#ifdef __FreeBSD__
+		{
+			PF_UNLOCK();
+#endif
 			return (EINVAL);
 #ifdef __FreeBSD__
-		callout_drain(&sc->sc_send_tmo);
-		PF_LOCK();
+		}
 #endif
 		sc->sc_maxupdates = pfsyncr.pfsyncr_maxupdates;
 
@@ -1059,26 +1191,28 @@
 				sc->sc_statep_net.s = NULL;
 				splx(s);
 			}
+#ifdef __FreeBSD__
+			PF_UNLOCK();
+#endif
 			if (imo->imo_num_memberships > 0) {
 				in_delmulti(imo->imo_membership[--imo->imo_num_memberships]);
 				imo->imo_multicast_ifp = NULL;
 			}
-#ifdef __FreeBSD__
-			PF_UNLOCK();
-#endif
 			break;
 		}
 
-		if ((sifp = ifunit(pfsyncr.pfsyncr_syncdev)) == NULL) {
 #ifdef __FreeBSD__
-			PF_UNLOCK();
+		PF_UNLOCK();
 #endif
+		if ((sifp = ifunit(pfsyncr.pfsyncr_syncdev)) == NULL)
 			return (EINVAL);
-		}
+#ifdef __FreeBSD__
+		PF_LOCK();
+#endif
 
 		s = splnet();
 #ifdef __FreeBSD__
-		if (sifp->if_mtu < SCP2IFP(sc)->if_mtu ||
+		if (sifp->if_mtu < sc->sc_ifp->if_mtu ||
 #else
 		if (sifp->if_mtu < sc->sc_if.if_mtu ||
 #endif
@@ -1089,18 +1223,28 @@
 		sc->sc_sync_ifp = sifp;
 
 #ifdef __FreeBSD__
-		pfsync_setmtu(sc, SCP2IFP(sc)->if_mtu);
+		pfsync_setmtu(sc, sc->sc_ifp->if_mtu);
 #else
 		pfsync_setmtu(sc, sc->sc_if.if_mtu);
 #endif
 
 		if (imo->imo_num_memberships > 0) {
+#ifdef __FreeBSD__
+			PF_UNLOCK();
+#endif
 			in_delmulti(imo->imo_membership[--imo->imo_num_memberships]);
+#ifdef __FreeBSD__
+			PF_LOCK();
+#endif
 			imo->imo_multicast_ifp = NULL;
 		}
 
 		if (sc->sc_sync_ifp &&
+#ifdef __FreeBSD__
+		    sc->sc_sync_peer.s_addr == htonl(INADDR_PFSYNC_GROUP)) {
+#else
 		    sc->sc_sync_peer.s_addr == INADDR_PFSYNC_GROUP) {
+#endif
 			struct in_addr addr;
 
 			if (!(sc->sc_sync_ifp->if_flags & IFF_MULTICAST)) {
@@ -1111,42 +1255,55 @@
 				splx(s);
 				return (EADDRNOTAVAIL);
 			}
+
 #ifdef __FreeBSD__
-			PF_UNLOCK();		/* addmulti mallocs w/ WAITOK */
 			addr.s_addr = htonl(INADDR_PFSYNC_GROUP);
 #else
 			addr.s_addr = INADDR_PFSYNC_GROUP;
 #endif
 
+#ifdef __FreeBSD__
+			PF_UNLOCK();
+#endif
 			if ((imo->imo_membership[0] =
 			    in_addmulti(&addr, sc->sc_sync_ifp)) == NULL) {
 				sc->sc_sync_ifp = NULL;
 				splx(s);
 				return (ENOBUFS);
 			}
+#ifdef __FreeBSD__
+			PF_LOCK();
+#endif
 			imo->imo_num_memberships++;
 			imo->imo_multicast_ifp = sc->sc_sync_ifp;
 			imo->imo_multicast_ttl = PFSYNC_DFLTTL;
 			imo->imo_multicast_loop = 0;
-#ifdef __FreeBSD__
-			PF_LOCK();
-#endif
 		}
 
 		if (sc->sc_sync_ifp ||
+#ifdef __FreeBSD__
+		    sc->sc_sendaddr.s_addr != htonl(INADDR_PFSYNC_GROUP)) {
+#else
 		    sc->sc_sendaddr.s_addr != INADDR_PFSYNC_GROUP) {
+#endif
 			/* Request a full state table update. */
 			sc->sc_ureq_sent = time_uptime;
 #if NCARP > 0
 			if (pfsync_sync_ok)
-				carp_suppress_preempt++;
+#ifdef __FreeBSD__
+#ifdef CARP_ADVANCED
+				carp_group_demote_adj(sc->sc_ifp, 1);
+#endif
+#else
+				carp_group_demote_adj(&sc->sc_if, 1);
+#endif
 #endif
 			pfsync_sync_ok = 0;
 			if (pf_status.debug >= PF_DEBUG_MISC)
 				printf("pfsync: requesting bulk update\n");
 #ifdef __FreeBSD__
 			callout_reset(&sc->sc_bulkfail_tmo, 5 * hz,
-			    pfsync_bulkfail, LIST_FIRST(&pfsync_list));
+			    pfsync_bulkfail, pfsyncif);
 #else
 			timeout_add(&sc->sc_bulkfail_tmo, 5 * hz);
 #endif
@@ -1189,12 +1346,11 @@
 	if (sc->sc_maxcount > 254)
 	    sc->sc_maxcount = 254;
 #ifdef __FreeBSD__
-	SCP2IFP(sc)->if_mtu = sizeof(struct pfsync_header) +
-	    sc->sc_maxcount * sizeof(struct pfsync_state);
+	sc->sc_ifp->if_mtu = sizeof(struct pfsync_header) +
 #else
 	sc->sc_if.if_mtu = sizeof(struct pfsync_header) +
-	    sc->sc_maxcount * sizeof(struct pfsync_state);
 #endif
+	    sc->sc_maxcount * sizeof(struct pfsync_state);
 }
 
 struct mbuf *
@@ -1204,13 +1360,10 @@
 	struct mbuf *m;
 	int len;
 
-#ifdef __FreeBSD__
-	PF_ASSERT(MA_OWNED);
-#endif
 	MGETHDR(m, M_DONTWAIT, MT_DATA);
 	if (m == NULL) {
 #ifdef __FreeBSD__
-		SCP2IFP(sc)->if_oerrors++;
+		sc->sc_ifp->if_oerrors++;
 #else
 		sc->sc_if.if_oerrors++;
 #endif
@@ -1238,6 +1391,12 @@
 		len = sizeof(struct pfsync_header) +
 		    sizeof(struct pfsync_state_bus);
 		break;
+#ifdef PFSYNC_TDB
+	case PFSYNC_ACT_TDB_UPD:
+		len = (sc->sc_maxcount * sizeof(struct pfsync_tdb)) +
+		    sizeof(struct pfsync_header);
+		break;
+#endif
 	default:
 		len = (sc->sc_maxcount * sizeof(struct pfsync_state)) +
 		    sizeof(struct pfsync_header);
@@ -1249,7 +1408,7 @@
 		if ((m->m_flags & M_EXT) == 0) {
 			m_free(m);
 #ifdef __FreeBSD__
-			SCP2IFP(sc)->if_oerrors++;
+			sc->sc_ifp->if_oerrors++;
 #else
 			sc->sc_if.if_oerrors++;
 #endif
@@ -1266,13 +1425,27 @@
 	h->af = 0;
 	h->count = 0;
 	h->action = action;
+#ifndef PFSYNC_TDB
+	if (action != PFSYNC_ACT_TDB_UPD)
+#endif
+		bcopy(&pf_status.pf_chksum, &h->pf_chksum,
+		    PF_MD5_DIGEST_LENGTH);
 
 	*sp = (void *)((char *)h + PFSYNC_HDRLEN);
+#ifdef PFSYNC_TDB
+	if (action == PFSYNC_ACT_TDB_UPD)
 #ifdef __FreeBSD__
-	callout_reset(&sc->sc_tmo, hz, pfsync_timeout,
-	    LIST_FIRST(&pfsync_list));
+		callout_reset(&sc->sc_tdb_tmo, hz, pfsync_tdb_timeout,
+		    pfsyncif);
 #else
-	timeout_add(&sc->sc_tmo, hz);
+		timeout_add(&sc->sc_tdb_tmo, hz);
+#endif
+	else
+#endif
+#ifdef __FreeBSD__
+		callout_reset(&sc->sc_tmo, hz, pfsync_timeout, pfsyncif);
+#else
+		timeout_add(&sc->sc_tmo, hz);
 #endif
 	return (m);
 }
@@ -1280,12 +1453,8 @@
 int
 pfsync_pack_state(u_int8_t action, struct pf_state *st, int flags)
 {
-#ifdef __FreeBSD__
-	struct ifnet *ifp = SCP2IFP(LIST_FIRST(&pfsync_list));
-#else
-	struct ifnet *ifp = &pfsyncif.sc_if;
-#endif
-	struct pfsync_softc *sc = ifp->if_softc;
+	struct ifnet *ifp = NULL;
+	struct pfsync_softc *sc = pfsyncif;
 	struct pfsync_header *h, *h_net;
 	struct pfsync_state *sp = NULL;
 	struct pfsync_state_upd *up = NULL;
@@ -1295,15 +1464,24 @@
 	int s, ret = 0;
 	u_int8_t i = 255, newaction = 0;
 
+	if (sc == NULL)
+		return (0);
 #ifdef __FreeBSD__
-	PF_ASSERT(MA_OWNED);
+	ifp = sc->sc_ifp;
+#else
+	ifp = &sc->sc_if;
 #endif
+
 	/*
 	 * If a packet falls in the forest and there's nobody around to
 	 * hear, does it make a sound?
 	 */
 	if (ifp->if_bpf == NULL && sc->sc_sync_ifp == NULL &&
+#ifdef __FreeBSD__
+	    sc->sc_sync_peer.s_addr == htonl(INADDR_PFSYNC_GROUP)) {
+#else
 	    sc->sc_sync_peer.s_addr == INADDR_PFSYNC_GROUP) {
+#endif
 		/* Don't leave any stale pfsync packets hanging around. */
 		if (sc->sc_mbuf != NULL) {
 			m_freem(sc->sc_mbuf);
@@ -1317,6 +1495,9 @@
 		return (EINVAL);
 
 	s = splnet();
+#ifdef __FreeBSD__
+	PF_ASSERT(MA_OWNED);
+#endif
 	if (sc->sc_mbuf == NULL) {
 		if ((sc->sc_mbuf = pfsync_get_mbuf(sc, action,
 		    (void *)&sc->sc_statep.s)) == NULL) {
@@ -1360,8 +1541,6 @@
 	secs = time_second;
 
 	st->pfsync_time = time_uptime;
-	TAILQ_REMOVE(&state_updates, st, u.s.entry_updates);
-	TAILQ_INSERT_TAIL(&state_updates, st, u.s.entry_updates);
 
 	if (sp == NULL) {
 		/* not a "duplicate" update */
@@ -1383,10 +1562,10 @@
 		bcopy(&st->rt_addr, &sp->rt_addr, sizeof(sp->rt_addr));
 
 		sp->creation = htonl(secs - st->creation);
-		sp->packets[0] = htonl(st->packets[0]);
-		sp->packets[1] = htonl(st->packets[1]);
-		sp->bytes[0] = htonl(st->bytes[0]);
-		sp->bytes[1] = htonl(st->bytes[1]);
+		pf_state_counter_hton(st->packets[0], sp->packets[0]);
+		pf_state_counter_hton(st->packets[1], sp->packets[1]);
+		pf_state_counter_hton(st->bytes[0], sp->bytes[0]);
+		pf_state_counter_hton(st->bytes[1], sp->bytes[1]);
 		if ((r = st->rule.ptr) == NULL)
 			sp->rule = htonl(-1);
 		else
@@ -1485,18 +1664,19 @@
 int
 pfsync_request_update(struct pfsync_state_upd *up, struct in_addr *src)
 {
-#ifdef __FreeBSD__
-	struct ifnet *ifp = SCP2IFP(LIST_FIRST(&pfsync_list));
-#else
-	struct ifnet *ifp = &pfsyncif.sc_if;
-#endif
+	struct ifnet *ifp = NULL;
 	struct pfsync_header *h;
-	struct pfsync_softc *sc = ifp->if_softc;
+	struct pfsync_softc *sc = pfsyncif;
 	struct pfsync_state_upd_req *rup;
 	int ret = 0;
 
+	if (sc == NULL)
+		return (0);
+
 #ifdef __FreeBSD__
-	PF_ASSERT(MA_OWNED);
+	ifp = sc->sc_ifp;
+#else
+	ifp = &sc->sc_if;
 #endif
 	if (sc->sc_mbuf == NULL) {
 		if ((sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_UREQ,
@@ -1534,19 +1714,23 @@
 int
 pfsync_clear_states(u_int32_t creatorid, char *ifname)
 {
-#ifdef __FreeBSD__
-	struct ifnet *ifp = SCP2IFP(LIST_FIRST(&pfsync_list));
-#else
-	struct ifnet *ifp = &pfsyncif.sc_if;
-#endif
-	struct pfsync_softc *sc = ifp->if_softc;
+	struct ifnet *ifp = NULL;
+	struct pfsync_softc *sc = pfsyncif;
 	struct pfsync_state_clr *cp;
 	int s, ret;
 
-	s = splnet();
+	if (sc == NULL)
+		return (0);
+
+#ifdef __FreeBSD__
+	ifp = sc->sc_ifp;
+#else
+	ifp = &sc->sc_if;
+#endif
 #ifdef __FreeBSD__
 	PF_ASSERT(MA_OWNED);
 #endif
+	s = splnet();
 	if (sc->sc_mbuf != NULL)
 		pfsync_sendout(sc);
 	if ((sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_CLR,
@@ -1582,6 +1766,25 @@
 	splx(s);
 }
 
+#ifdef PFSYNC_TDB
+void
+pfsync_tdb_timeout(void *v)
+{
+	struct pfsync_softc *sc = v;
+	int s;
+
+	s = splnet();
+#ifdef __FreeBSD__
+	PF_LOCK();
+#endif
+	pfsync_tdb_sendout(sc);
+#ifdef __FreeBSD__
+	PF_UNLOCK();
+#endif
+	splx(s);
+}
+#endif
+
 /* This must be called in splnet() */
 void
 pfsync_send_bus(struct pfsync_softc *sc, u_int8_t status)
@@ -1613,10 +1816,10 @@
 	int s, i = 0;
 	struct pf_state *state;
 
+	s = splnet();
 #ifdef __FreeBSD__
 	PF_LOCK();
 #endif
-	s = splnet();
 	if (sc->sc_mbuf != NULL)
 		pfsync_sendout(sc);
 
@@ -1624,37 +1827,44 @@
 	 * Grab at most PFSYNC_BULKPACKETS worth of states which have not
 	 * been sent since the latest request was made.
 	 */
-	while ((state = TAILQ_FIRST(&state_updates)) != NULL &&
-	    ++i < (sc->sc_maxcount * PFSYNC_BULKPACKETS)) {
-		if (state->pfsync_time > sc->sc_ureq_received) {
-			/* we're done */
-			pfsync_send_bus(sc, PFSYNC_BUS_END);
-			sc->sc_ureq_received = 0;
-#ifdef __FreeBSD__
-			callout_stop(&sc->sc_bulk_tmo);
-#else
-			timeout_del(&sc->sc_bulk_tmo);
-#endif
-			if (pf_status.debug >= PF_DEBUG_MISC)
-				printf("pfsync: bulk update complete\n");
-			break;
-		} else {
-			/* send an update and move to end of list */
-			if (!state->sync_flags)
+	state = sc->sc_bulk_send_next;
+	if (state)
+		do {
+			/* send state update if syncable and not already sent */
+			if (!state->sync_flags
+			    && state->timeout < PFTM_MAX
+			    && state->pfsync_time <= sc->sc_ureq_received) {
 				pfsync_pack_state(PFSYNC_ACT_UPD, state, 0);
-			state->pfsync_time = time_uptime;
-			TAILQ_REMOVE(&state_updates, state, u.s.entry_updates);
-			TAILQ_INSERT_TAIL(&state_updates, state,
-			    u.s.entry_updates);
+				i++;
+			}
 
-			/* look again for more in a bit */
+			/* figure next state to send */
+			state = TAILQ_NEXT(state, u.s.entry_list);
+
+			/* wrap to start of list if we hit the end */
+			if (!state)
+				state = TAILQ_FIRST(&state_list);
+		} while (i < sc->sc_maxcount * PFSYNC_BULKPACKETS &&
+		    state != sc->sc_bulk_terminator);
+
+	if (!state || state == sc->sc_bulk_terminator) {
+		/* we're done */
+		pfsync_send_bus(sc, PFSYNC_BUS_END);
+		sc->sc_ureq_received = 0;
+		sc->sc_bulk_send_next = NULL;
+		sc->sc_bulk_terminator = NULL;
+		timeout_del(&sc->sc_bulk_tmo);
+		if (pf_status.debug >= PF_DEBUG_MISC)
+			printf("pfsync: bulk update complete\n");
+	} else {
+		/* look again for more in a bit */
 #ifdef __FreeBSD__
-			callout_reset(&sc->sc_bulk_tmo, 1, pfsync_timeout,
-			    LIST_FIRST(&pfsync_list));
+		callout_reset(&sc->sc_bulk_tmo, 1, pfsync_bulk_update,
+		    pfsyncif);
 #else
-			timeout_add(&sc->sc_bulk_tmo, 1);
+		timeout_add(&sc->sc_bulk_tmo, 1);
 #endif
-		}
+		sc->sc_bulk_send_next = state;
 	}
 	if (sc->sc_mbuf != NULL)
 		pfsync_sendout(sc);
@@ -1677,7 +1887,7 @@
 		/* Try again in a bit */
 #ifdef __FreeBSD__
 		callout_reset(&sc->sc_bulkfail_tmo, 5 * hz, pfsync_bulkfail,
-		    LIST_FIRST(&pfsync_list));
+		    pfsyncif);
 #else
 		timeout_add(&sc->sc_bulkfail_tmo, 5 * hz);
 #endif
@@ -1696,17 +1906,19 @@
 		sc->sc_bulk_tries = 0;
 #if NCARP > 0
 		if (!pfsync_sync_ok)
-			carp_suppress_preempt--;
+#ifdef __FreeBSD__
+#ifdef CARP_ADVANCED
+			carp_group_demote_adj(sc->sc_ifp, -1);
+#endif
+#else
+			carp_group_demote_adj(&sc->sc_if, -1);
+#endif
 #endif
 		pfsync_sync_ok = 1;
 		if (pf_status.debug >= PF_DEBUG_MISC)
 			printf("pfsync: failed to receive "
 			    "bulk update status\n");
-#ifdef __FreeBSD__
-		callout_stop(&sc->sc_bulkfail_tmo);
-#else
 		timeout_del(&sc->sc_bulkfail_tmo);
-#endif
 	}
 #ifdef __FreeBSD__
 	PF_UNLOCK();
@@ -1715,24 +1927,21 @@
 
 /* This must be called in splnet() */
 int
-pfsync_sendout(sc)
-	struct pfsync_softc *sc;
+pfsync_sendout(struct pfsync_softc *sc)
 {
 #if NBPFILTER > 0
-# ifdef __FreeBSD__
-	struct ifnet *ifp = SCP2IFP(sc);
-# else
-	struct ifnet *ifp = &sc->if_sc;
-# endif
+#ifdef __FreeBSD__
+	struct ifnet *ifp = sc->sc_ifp;
+#else
+	struct ifnet *ifp = &sc->sc_if;
+#endif
 #endif
 	struct mbuf *m;
 
 #ifdef __FreeBSD__
 	PF_ASSERT(MA_OWNED);
-	callout_stop(&sc->sc_tmo);
-#else
-	timeout_del(&sc->sc_tmo);
 #endif
+	timeout_del(&sc->sc_tmo);
 
 	if (sc->sc_mbuf == NULL)
 		return (0);
@@ -1740,12 +1949,13 @@
 	sc->sc_mbuf = NULL;
 	sc->sc_statep.s = NULL;
 
-#ifdef __FreeBSD__
-	KASSERT(m != NULL, ("pfsync_sendout: null mbuf"));
-#endif
 #if NBPFILTER > 0
 	if (ifp->if_bpf)
-		bpf_mtap(ifp->if_bpf, m);
+#ifdef __FreeBSD__
+		BPF_MTAP(ifp, m);
+#else
+		bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
+#endif
 #endif
 
 	if (sc->sc_mbuf_net) {
@@ -1755,10 +1965,61 @@
 		sc->sc_statep_net.s = NULL;
 	}
 
-	if (sc->sc_sync_ifp || sc->sc_sync_peer.s_addr != INADDR_PFSYNC_GROUP) {
-		struct ip *ip;
-		struct sockaddr sa;
+	return pfsync_sendout_mbuf(sc, m);
+}
+
+#ifdef PFSYNC_TDB
+int
+pfsync_tdb_sendout(struct pfsync_softc *sc)
+{
+#if NBPFILTER > 0
+#ifdef __FreeBSD__
+	struct ifnet *ifp = sc->sc_ifp;
+#else
+	struct ifnet *ifp = &sc->sc_if;
+#endif
+#endif
+	struct mbuf *m;
 
+#ifdef __FreeBSD__
+	PF_ASSERT(MA_OWNED);
+#endif
+	timeout_del(&sc->sc_tdb_tmo);
+
+	if (sc->sc_mbuf_tdb == NULL)
+		return (0);
+	m = sc->sc_mbuf_tdb;
+	sc->sc_mbuf_tdb = NULL;
+	sc->sc_statep_tdb.t = NULL;
+
+#if NBPFILTER > 0
+	if (ifp->if_bpf)
+#ifdef __FreeBSD__
+		BPF_MTAP(ifp, m);
+#else
+		bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
+#endif
+#endif
+
+	return pfsync_sendout_mbuf(sc, m);
+}
+#endif
+
+int
+pfsync_sendout_mbuf(struct pfsync_softc *sc, struct mbuf *m)
+{
+	struct sockaddr sa;
+	struct ip *ip;
+
+#ifdef __FreeBSD__
+	PF_ASSERT(MA_OWNED);
+#endif
+	if (sc->sc_sync_ifp ||
+#ifdef __FreeBSD__
+	    sc->sc_sync_peer.s_addr != htonl(INADDR_PFSYNC_GROUP)) {
+#else
+	    sc->sc_sync_peer.s_addr != INADDR_PFSYNC_GROUP) {
+#endif
 		M_PREPEND(m, sizeof(struct ip), M_DONTWAIT);
 		if (m == NULL) {
 			pfsyncstats.pfsyncs_onomem++;
@@ -1793,18 +2054,14 @@
 #endif
 			m->m_flags |= M_MCAST;
 		ip->ip_dst = sc->sc_sendaddr;
-#ifdef __FreeBSD__
-		/* XXX_IMPORT */
-		sc->sc_sendaddr.s_addr = htonl(sc->sc_sync_peer.s_addr);
-#else
 		sc->sc_sendaddr.s_addr = sc->sc_sync_peer.s_addr;
-#endif
 
 		pfsyncstats.pfsyncs_opackets++;
+
 #ifdef __FreeBSD__
 		if (!IF_HANDOFF(&sc->sc_ifq, m, NULL))
 			pfsyncstats.pfsyncs_oerrors++;
-		callout_reset(&sc->sc_send_tmo, 1, pfsync_senddef, sc);
+		taskqueue_enqueue(taskqueue_thread, &pfsyncif->sc_send_task);
 #else
 		if (ip_output(m, NULL, NULL, IP_RAWOUTPUT, &sc->sc_imo, NULL))
 			pfsyncstats.pfsyncs_oerrors++;
@@ -1815,9 +2072,210 @@
 	return (0);
 }
 
+#ifdef PFSYNC_TDB
+/* Update an in-kernel tdb. Silently fail if no tdb is found. */
+void
+pfsync_update_net_tdb(struct pfsync_tdb *pt)
+{
+	struct tdb		*tdb;
+	int			 s;
+
+	/* check for invalid values */
+	if (ntohl(pt->spi) <= SPI_RESERVED_MAX ||
+	    (pt->dst.sa.sa_family != AF_INET &&
+	     pt->dst.sa.sa_family != AF_INET6))
+		goto bad;
+
+	s = spltdb();
+	tdb = gettdb(pt->spi, &pt->dst, pt->sproto);
+	if (tdb) {
+		pt->rpl = ntohl(pt->rpl);
+		pt->cur_bytes = betoh64(pt->cur_bytes);
+
+		/* Neither replay nor byte counter should ever decrease. */
+		if (pt->rpl < tdb->tdb_rpl ||
+		    pt->cur_bytes < tdb->tdb_cur_bytes) {
+			splx(s);
+			goto bad;
+		}
+
+		tdb->tdb_rpl = pt->rpl;
+		tdb->tdb_cur_bytes = pt->cur_bytes;
+	}
+	splx(s);
+	return;
+
+ bad:
+	if (pf_status.debug >= PF_DEBUG_MISC)
+		printf("pfsync_insert: PFSYNC_ACT_TDB_UPD: "
+		    "invalid value\n");
+	pfsyncstats.pfsyncs_badstate++;
+	return;
+}
+
+/* One of our local tdbs have been updated, need to sync rpl with others */
+int
+pfsync_update_tdb(struct tdb *tdb, int output)
+{
+	struct ifnet *ifp = NULL;
+	struct pfsync_softc *sc = pfsyncif;
+	struct pfsync_header *h;
+	struct pfsync_tdb *pt = NULL;
+	int s, i, ret;
+
+	if (sc == NULL)
+		return (0);
+
 #ifdef __FreeBSD__
-static void
-pfsync_senddef(void *arg)
+	ifp = sc->sc_ifp;
+#else
+	ifp = &sc->sc_if;
+#endif
+	if (ifp->if_bpf == NULL && sc->sc_sync_ifp == NULL &&
+#ifdef __FreeBSD__
+	    sc->sc_sync_peer.s_addr == htonl(INADDR_PFSYNC_GROUP)) {
+#else
+	    sc->sc_sync_peer.s_addr == INADDR_PFSYNC_GROUP) {
+#endif
+		/* Don't leave any stale pfsync packets hanging around. */
+		if (sc->sc_mbuf_tdb != NULL) {
+			m_freem(sc->sc_mbuf_tdb);
+			sc->sc_mbuf_tdb = NULL;
+			sc->sc_statep_tdb.t = NULL;
+		}
+		return (0);
+	}
+
+#ifdef __FreeBSD__
+	PF_ASSERT(MA_OWNED);
+#endif
+	s = splnet();
+	if (sc->sc_mbuf_tdb == NULL) {
+		if ((sc->sc_mbuf_tdb = pfsync_get_mbuf(sc, PFSYNC_ACT_TDB_UPD,
+		    (void *)&sc->sc_statep_tdb.t)) == NULL) {
+			splx(s);
+			return (ENOMEM);
+		}
+		h = mtod(sc->sc_mbuf_tdb, struct pfsync_header *);
+	} else {
+		h = mtod(sc->sc_mbuf_tdb, struct pfsync_header *);
+		if (h->action != PFSYNC_ACT_TDB_UPD) {
+			/*
+			 * XXX will never happen as long as there's
+			 * only one "TDB action".
+			 */
+			pfsync_tdb_sendout(sc);
+			sc->sc_mbuf_tdb = pfsync_get_mbuf(sc,
+			    PFSYNC_ACT_TDB_UPD, (void *)&sc->sc_statep_tdb.t);
+			if (sc->sc_mbuf_tdb == NULL) {
+				splx(s);
+				return (ENOMEM);
+			}
+			h = mtod(sc->sc_mbuf_tdb, struct pfsync_header *);
+		} else if (sc->sc_maxupdates) {
+			/*
+			 * If it's an update, look in the packet to see if
+			 * we already have an update for the state.
+			 */
+			struct pfsync_tdb *u =
+			    (void *)((char *)h + PFSYNC_HDRLEN);
+
+			for (i = 0; !pt && i < h->count; i++) {
+				if (tdb->tdb_spi == u->spi &&
+				    tdb->tdb_sproto == u->sproto &&
+			            !bcmp(&tdb->tdb_dst, &u->dst,
+				    SA_LEN(&u->dst.sa))) {
+					pt = u;
+					pt->updates++;
+				}
+				u++;
+			}
+		}
+	}
+
+	if (pt == NULL) {
+		/* not a "duplicate" update */
+		pt = sc->sc_statep_tdb.t++;
+		sc->sc_mbuf_tdb->m_pkthdr.len =
+		    sc->sc_mbuf_tdb->m_len += sizeof(struct pfsync_tdb);
+		h->count++;
+		bzero(pt, sizeof(*pt));
+
+		pt->spi = tdb->tdb_spi;
+		memcpy(&pt->dst, &tdb->tdb_dst, sizeof pt->dst);
+		pt->sproto = tdb->tdb_sproto;
+	}
+
+	/*
+	 * When a failover happens, the master's rpl is probably above
+	 * what we see here (we may be up to a second late), so
+	 * increase it a bit for outbound tdbs to manage most such
+	 * situations.
+	 *
+	 * For now, just add an offset that is likely to be larger
+	 * than the number of packets we can see in one second. The RFC
+	 * just says the next packet must have a higher seq value.
+	 *
+	 * XXX What is a good algorithm for this? We could use
+	 * a rate-determined increase, but to know it, we would have
+	 * to extend struct tdb.
+	 * XXX pt->rpl can wrap over MAXINT, but if so the real tdb
+	 * will soon be replaced anyway. For now, just don't handle
+	 * this edge case.
+	 */
+#define RPL_INCR 16384
+	pt->rpl = htonl(tdb->tdb_rpl + (output ? RPL_INCR : 0));
+	pt->cur_bytes = htobe64(tdb->tdb_cur_bytes);
+
+	if (h->count == sc->sc_maxcount ||
+	    (sc->sc_maxupdates && (pt->updates >= sc->sc_maxupdates)))
+		ret = pfsync_tdb_sendout(sc);
+
+	splx(s);
+	return (ret);
+}
+#endif /* PFSYNC_TDB */
+
+#ifdef __FreeBSD__
+void
+pfsync_ifdetach(void *arg, struct ifnet *ifp)
+{
+	struct pfsync_softc *sc = (struct pfsync_softc *)arg;
+	struct ip_moptions *imo;
+
+	if (sc == NULL || sc->sc_sync_ifp != ifp)
+		return;         /* not for us; unlocked read */
+
+	PF_LOCK();
+
+	/* Deal with a member interface going away from under us. */
+	sc->sc_sync_ifp = NULL;
+	if (sc->sc_mbuf_net != NULL) {
+		m_freem(sc->sc_mbuf_net);
+		sc->sc_mbuf_net = NULL;
+		sc->sc_statep_net.s = NULL;
+	}
+	imo = &sc->sc_imo;
+	if (imo->imo_num_memberships > 0) {
+		KASSERT(imo->imo_num_memberships == 1,
+		    ("%s: imo_num_memberships != 1", __func__));
+		/*
+		 * Our event handler is always called after protocol
+		 * domains have been detached from the underlying ifnet.
+		 * Do not call in_delmulti(); we held a single reference
+		 * which the protocol domain has purged in in_purgemaddrs().
+		 */
+		PF_UNLOCK();
+		imo->imo_membership[--imo->imo_num_memberships] = NULL;
+		PF_LOCK();
+		imo->imo_multicast_ifp = NULL;
+	}
+
+	PF_UNLOCK();
+}
+
+void
+pfsync_senddef(void *arg, __unused int pending)
 {
 	struct pfsync_softc *sc = (struct pfsync_softc *)arg;
 	struct mbuf *m;
@@ -1826,6 +2284,12 @@
 		IF_DEQUEUE(&sc->sc_ifq, m);
 		if (m == NULL)
 			break;
+		/* Deal with a member interface going away from under us. */
+		if (sc->sc_sync_ifp == NULL) {
+			pfsyncstats.pfsyncs_oerrors++;
+			m_freem(m);
+			continue;
+		}
 		if (ip_output(m, NULL, NULL, IP_RAWOUTPUT, &sc->sc_imo, NULL))
 			pfsyncstats.pfsyncs_oerrors++;
 	}
@@ -1838,17 +2302,11 @@
 
 	switch (type) {
 	case MOD_LOAD:
-		LIST_INIT(&pfsync_list);
-		if_clone_attach(&pfsync_cloner);
+		pfsyncattach(0);
 		break;
-
 	case MOD_UNLOAD:
 		if_clone_detach(&pfsync_cloner);
-		while (!LIST_EMPTY(&pfsync_list))
-			pfsync_clone_destroy(
-			    SCP2IFP(LIST_FIRST(&pfsync_list)));
 		break;
-
 	default:
 		error = EINVAL;
 		break;
@@ -1867,4 +2325,5 @@
 
 DECLARE_MODULE(pfsync, pfsync_mod, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY);
 MODULE_VERSION(pfsync, PFSYNC_MODVER);
+MODULE_DEPEND(pflog, pf, PF_MODVER, PF_MODVER, PF_MODVER);
 #endif /* __FreeBSD__ */
--- /dev/null
+++ sys/contrib/pf/net/pf_mtag.h
@@ -0,0 +1,82 @@
+/*	$FreeBSD: src/sys/contrib/pf/net/pf_mtag.h,v 1.1 2007/07/03 12:46:06 mlaier Exp $	*/
+/*
+ * Copyright (c) 2001 Daniel Hartmeier
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *    - Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *    - 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 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 HOLDERS 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 _NET_PF_MTAG_H_
+#define _NET_PF_MTAG_H_
+
+#ifdef _KERNEL
+
+#define	PF_TAG_GENERATED		0x01
+#define	PF_TAG_FRAGCACHE		0x02
+#define	PF_TAG_TRANSLATE_LOCALHOST	0x04
+
+struct pf_mtag {
+	void		*hdr;		/* saved hdr pos in mbuf, for ECN */
+	u_int		 rtableid;	/* alternate routing table id */
+	u_int32_t	 qid;		/* queue id */
+	u_int16_t	 tag;		/* tag id */
+	u_int8_t	 flags;
+	u_int8_t	 routed;
+	sa_family_t	 af;		/* for ECN */
+};
+
+static __inline struct pf_mtag *pf_find_mtag(struct mbuf *);
+static __inline struct pf_mtag *pf_get_mtag(struct mbuf *);
+
+static __inline struct pf_mtag *
+pf_find_mtag(struct mbuf *m)
+{
+	struct m_tag	*mtag;
+
+	if ((mtag = m_tag_find(m, PACKET_TAG_PF, NULL)) == NULL)
+		return (NULL);
+
+	return ((struct pf_mtag *)(mtag + 1));
+}
+
+static __inline struct pf_mtag *
+pf_get_mtag(struct mbuf *m)
+{
+	struct m_tag	*mtag;
+
+	if ((mtag = m_tag_find(m, PACKET_TAG_PF, NULL)) == NULL) {
+		mtag = m_tag_get(PACKET_TAG_PF, sizeof(struct pf_mtag),
+		    M_NOWAIT);
+		if (mtag == NULL)
+			return (NULL);
+		bzero(mtag + 1, sizeof(struct pf_mtag));
+		m_tag_prepend(m, mtag);
+	}
+
+	return ((struct pf_mtag *)(mtag + 1));
+}
+#endif /* _KERNEL */
+#endif /* _NET_PF_MTAG_H_ */


More information about the Midnightbsd-cvs mailing list