pf: Update to OpenBSD 4.2
authorJan Lentfer <Jan.Lentfer@web.de>
Fri, 27 Aug 2010 20:01:56 +0000 (22:01 +0200)
committerJan Lentfer <Jan.Lentfer@web.de>
Thu, 9 Sep 2010 18:40:09 +0000 (20:40 +0200)
All sorts of informations is now stored directly in
the mbuf header instead of a seperate mbuf tag. This
brings in a 100% performance increase in comparison
to OpenBSD 4.1. For DragonFly this basically means
this is the same performance as in 2.6, but we are
equal again with OpenBSD's pf data structures.

Necesary additions:

sys/net: add more interface groups related functions

if_creategroup()
if_addgroup()
if_delgroup()
if_getgroup()
if_getgroupmembers()

Imported from OpenBSD

carp: add carp_group_demote_adj()

altq: re-add check of packet tagging

fairq & red support, UDP nat'ing, reassembly fixed by Matthew Dillon

36 files changed:
sys/net/altq/altq_cbq.c
sys/net/altq/altq_fairq.c
sys/net/altq/altq_hfsc.c
sys/net/altq/altq_priq.c
sys/net/altq/altq_red.c
sys/net/altq/altq_subr.c
sys/net/altq/altq_var.h
sys/net/if.c
sys/net/if_var.h
sys/net/pf/if_pflog.c
sys/net/pf/if_pflog.h
sys/net/pf/if_pfsync.c
sys/net/pf/if_pfsync.h
sys/net/pf/pf.c
sys/net/pf/pf_if.c
sys/net/pf/pf_ioctl.c
sys/net/pf/pf_norm.c
sys/net/pf/pf_subr.c
sys/net/pf/pf_table.c
sys/net/pf/pfvar.h
sys/netinet/ip_carp.c
sys/netinet/ip_carp.h
sys/sys/mbuf.h
sys/sys/sockio.h
usr.sbin/ftp-proxy/filter.c
usr.sbin/ftp-proxy/filter.h
usr.sbin/ftp-proxy/ftp-proxy.8
usr.sbin/ftp-proxy/ftp-proxy.c
usr.sbin/pfctl/parse.y
usr.sbin/pfctl/pf_print_state.c
usr.sbin/pfctl/pfctl.8
usr.sbin/pfctl/pfctl.c
usr.sbin/pfctl/pfctl.h
usr.sbin/pfctl/pfctl_altq.c
usr.sbin/pflogd/pflogd.8
usr.sbin/pflogd/pflogd.c

index bbe5e75..41c958e 100644 (file)
@@ -485,7 +485,6 @@ cbq_enqueue(struct ifaltq *ifq, struct mbuf *m, struct altq_pktattr *pktattr)
 {
        cbq_state_t     *cbqp = (cbq_state_t *)ifq->altq_disc;
        struct rm_class *cl;
-       struct pf_mtag *pf;
        int len;
 
        /* grab class set by classifier */
@@ -495,9 +494,8 @@ cbq_enqueue(struct ifaltq *ifq, struct mbuf *m, struct altq_pktattr *pktattr)
                m_freem(m);
                return (ENOBUFS);
        }
-
-       if ((pf = altq_find_pftag(m)) != NULL)
-               cl = clh_to_clp(cbqp, pf->qid);
+       if (m->m_pkthdr.fw_flags & PF_MBUF_STRUCTURE)
+               cl = clh_to_clp(cbqp, m->m_pkthdr.pf.qid);
        else
                cl = NULL;
        if (cl == NULL) {
index 4c79581..79283ad 100644 (file)
@@ -123,7 +123,7 @@ static int  fairq_class_destroy(struct fairq_class *);
 static int     fairq_enqueue(struct ifaltq *, struct mbuf *, struct altq_pktattr *);
 static struct mbuf *fairq_dequeue(struct ifaltq *, struct mbuf *, int);
 
-static int     fairq_addq(struct fairq_class *, struct mbuf *, struct pf_mtag *);
+static int     fairq_addq(struct fairq_class *, struct mbuf *, int hash);
 static struct mbuf *fairq_getq(struct fairq_class *, uint64_t);
 static struct mbuf *fairq_pollq(struct fairq_class *, uint64_t, int *);
 static fairq_bucket_t *fairq_selectq(struct fairq_class *, int);
@@ -498,9 +498,9 @@ fairq_enqueue(struct ifaltq *ifq, struct mbuf *m, struct altq_pktattr *pktattr)
 {
        struct fairq_if *pif = (struct fairq_if *)ifq->altq_disc;
        struct fairq_class *cl;
-       struct pf_mtag *pf;
        int error;
        int len;
+       int hash;
 
        crit_enter();
 
@@ -513,10 +513,16 @@ fairq_enqueue(struct ifaltq *ifq, struct mbuf *m, struct altq_pktattr *pktattr)
                goto done;
        }
 
-       if ((pf = altq_find_pftag(m)) != NULL)
-               cl = clh_to_clp(pif, pf->qid);
-       else
+       if (m->m_pkthdr.fw_flags & PF_MBUF_STRUCTURE) {
+               cl = clh_to_clp(pif, m->m_pkthdr.pf.qid);
+               if (m->m_pkthdr.pf.flags & PF_TAG_STATE_HASHED)
+                       hash = (int)m->m_pkthdr.pf.state_hash;
+               else
+                       hash = 0;
+       } else {
                cl = NULL;
+               hash = 0;
+       }
        if (cl == NULL) {
                cl = pif->pif_default;
                if (cl == NULL) {
@@ -528,7 +534,7 @@ fairq_enqueue(struct ifaltq *ifq, struct mbuf *m, struct altq_pktattr *pktattr)
        cl->cl_flags |= FARF_HAS_PACKETS;
        cl->cl_pktattr = NULL;
        len = m_pktlen(m);
-       if (fairq_addq(cl, m, pf) != 0) {
+       if (fairq_addq(cl, m, hash) != 0) {
                /* drop occurred.  mbuf was freed in fairq_addq. */
                PKTCNTR_ADD(&cl->cl_dropcnt, len);
                error = ENOBUFS;
@@ -627,7 +633,7 @@ fairq_dequeue(struct ifaltq *ifq, struct mbuf *mpolled, int op)
 }
 
 static int
-fairq_addq(struct fairq_class *cl, struct mbuf *m, struct pf_mtag *pf)
+fairq_addq(struct fairq_class *cl, struct mbuf *m, int hash)
 {
        fairq_bucket_t *b;
        u_int hindex;
@@ -637,13 +643,13 @@ fairq_addq(struct fairq_class *cl, struct mbuf *m, struct pf_mtag *pf)
         * If the packet doesn't have any keep state put it on the end of
         * our queue.  XXX this can result in out of order delivery.
         */
-       if (pf == NULL || (pf->flags & PF_TAG_STATE_HASHED) == 0) {
+       if (hash == 0) {
                if (cl->cl_head)
                        b = cl->cl_head->prev;
                else
                        b = &cl->cl_buckets[0];
        } else {
-               hindex = pf->state_hash & cl->cl_nbucket_mask;
+               hindex = hash & cl->cl_nbucket_mask;
                b = &cl->cl_buckets[hindex];
        }
 
index 43609de..303e539 100644 (file)
@@ -645,7 +645,6 @@ hfsc_enqueue(struct ifaltq *ifq, struct mbuf *m, struct altq_pktattr *pktattr)
 {
        struct hfsc_if  *hif = (struct hfsc_if *)ifq->altq_disc;
        struct hfsc_class *cl;
-       struct pf_mtag *pf;
        int len;
 
        /* grab class set by classifier */
@@ -656,8 +655,8 @@ hfsc_enqueue(struct ifaltq *ifq, struct mbuf *m, struct altq_pktattr *pktattr)
                return (ENOBUFS);
        }
        crit_enter();
-       if ((pf = altq_find_pftag(m)) != NULL)
-               cl = clh_to_clp(hif, pf->qid);
+       if (m->m_pkthdr.fw_flags & PF_MBUF_STRUCTURE)
+               cl = clh_to_clp(hif, m->m_pkthdr.pf.qid);
        else
                cl = NULL;
        if (cl == NULL || is_a_parent_class(cl)) {
index 00dd4e1..84eae1b 100644 (file)
@@ -415,7 +415,6 @@ priq_enqueue(struct ifaltq *ifq, struct mbuf *m, struct altq_pktattr *pktattr)
 {
        struct priq_if *pif = (struct priq_if *)ifq->altq_disc;
        struct priq_class *cl;
-       struct pf_mtag *pf;
        int error;
        int len;
 
@@ -430,8 +429,8 @@ priq_enqueue(struct ifaltq *ifq, struct mbuf *m, struct altq_pktattr *pktattr)
                goto done;
        }
 
-       if ((pf = altq_find_pftag(m)) != NULL)
-               cl = clh_to_clp(pif, pf->qid);
+       if (m->m_pkthdr.fw_flags & PF_MBUF_STRUCTURE)
+               cl = clh_to_clp(pif, m->m_pkthdr.pf.qid);
        else
                cl = NULL;
        if (cl == NULL) {
index 1a4dade..d9f750a 100644 (file)
@@ -419,16 +419,13 @@ drop_early(int fp_len, int fp_probd, int count)
 int
 mark_ecn(struct mbuf *m, struct altq_pktattr *pktattr, int flags)
 {
-       struct pf_mtag *pf;
        struct mbuf *m0;
        void *hdr;
        int  af;
 
-       pf = altq_find_pftag(m);
-       if (pf == NULL)
-               return (0);
-       af = pf->af;
-       hdr = pf->hdr;
+       KKASSERT(m->m_pkthdr.fw_flags & PF_MBUF_STRUCTURE);
+       af = m->m_pkthdr.pf.ecn_af;
+       hdr = m->m_pkthdr.pf.hdr;
 
        if (af != AF_INET && af != AF_INET6)
                return (0);
@@ -451,9 +448,6 @@ mark_ecn(struct mbuf *m, struct altq_pktattr *pktattr, int flags)
                        uint8_t otos;
                        int sum;
 
-                       if (ip->ip_v != 4)
-                               return (0);     /* version mismatch! */
-
                        if ((ip->ip_tos & IPTOS_ECN_MASK) == IPTOS_ECN_NOTECT)
                                return (0);     /* not-ECT */
                        if ((ip->ip_tos & IPTOS_ECN_MASK) == IPTOS_ECN_CE)
index 9b39768..1ca6f68 100644 (file)
@@ -878,14 +878,3 @@ read_machclk(void)
        return (val);
 }
 
-struct pf_mtag *
-altq_find_pftag(struct mbuf *m)
-{
-       struct m_tag *mtag;
-
-       mtag = m_tag_find(m, PF_MBUF_TAGGED, NULL);
-       if (mtag)
-               return((struct pf_mtag *)(mtag + 1));
-       return(NULL);
-}
-
index c5db2cc..47d4712 100644 (file)
@@ -67,7 +67,6 @@ struct pf_altq;
 struct pf_mtag;
 
 void   *altq_lookup(const char *, int);
-struct pf_mtag *altq_find_pftag(struct mbuf *m);
 uint8_t        read_dsfield(struct mbuf *, struct altq_pktattr *);
 void   write_dsfield(struct mbuf *, struct altq_pktattr *, uint8_t);
 int    tbr_set(struct ifaltq *, struct tb_profile *);
index 8fd4813..c1a3988 100644 (file)
@@ -203,6 +203,8 @@ KTR_INFO(KTR_IF_START, if_start, chase_sched, 4,
 #endif
 #define logifstart(name, arg)  KTR_LOG(if_start_ ## name, arg)
 
+TAILQ_HEAD(, ifg_group) ifg_head;
+
 /*
  * Network interface utility routines.
  *
@@ -811,6 +813,201 @@ if_detach(struct ifnet *ifp)
 }
 
 /*
+ * Create interface group without members
+ */
+struct ifg_group *
+if_creategroup(const char *groupname)
+{
+        struct ifg_group        *ifg = NULL;
+
+        if ((ifg = (struct ifg_group *)kmalloc(sizeof(struct ifg_group),
+            M_TEMP, M_NOWAIT)) == NULL)
+                return (NULL);
+
+        strlcpy(ifg->ifg_group, groupname, sizeof(ifg->ifg_group));
+        ifg->ifg_refcnt = 0;
+        ifg->ifg_carp_demoted = 0;
+        TAILQ_INIT(&ifg->ifg_members);
+#if NPF > 0
+        pfi_attach_ifgroup(ifg);
+#endif
+        TAILQ_INSERT_TAIL(&ifg_head, ifg, ifg_next);
+
+        return (ifg);
+}
+
+/*
+ * Add a group to an interface
+ */
+int
+if_addgroup(struct ifnet *ifp, const char *groupname)
+{
+       struct ifg_list         *ifgl;
+       struct ifg_group        *ifg = NULL;
+       struct ifg_member       *ifgm;
+
+       if (groupname[0] && groupname[strlen(groupname) - 1] >= '0' &&
+           groupname[strlen(groupname) - 1] <= '9')
+               return (EINVAL);
+
+       TAILQ_FOREACH(ifgl, &ifp->if_groups, ifgl_next)
+               if (!strcmp(ifgl->ifgl_group->ifg_group, groupname))
+                       return (EEXIST);
+
+       if ((ifgl = kmalloc(sizeof(*ifgl), M_TEMP, M_NOWAIT)) == NULL)
+               return (ENOMEM);
+
+       if ((ifgm = kmalloc(sizeof(*ifgm), M_TEMP, M_NOWAIT)) == NULL) {
+               kfree(ifgl, M_TEMP);
+               return (ENOMEM);
+       }
+
+       TAILQ_FOREACH(ifg, &ifg_head, ifg_next)
+               if (!strcmp(ifg->ifg_group, groupname))
+                       break;
+
+       if (ifg == NULL && (ifg = if_creategroup(groupname)) == NULL) {
+               kfree(ifgl, M_TEMP);
+               kfree(ifgm, M_TEMP);
+               return (ENOMEM);
+       }
+
+       ifg->ifg_refcnt++;
+       ifgl->ifgl_group = ifg;
+       ifgm->ifgm_ifp = ifp;
+
+       TAILQ_INSERT_TAIL(&ifg->ifg_members, ifgm, ifgm_next);
+       TAILQ_INSERT_TAIL(&ifp->if_groups, ifgl, ifgl_next);
+
+#if NPF > 0
+       pfi_group_change(groupname);
+#endif
+
+       return (0);
+}
+
+/*
+ * Remove a group from an interface
+ */
+int
+if_delgroup(struct ifnet *ifp, const char *groupname)
+{
+       struct ifg_list         *ifgl;
+       struct ifg_member       *ifgm;
+
+       TAILQ_FOREACH(ifgl, &ifp->if_groups, ifgl_next)
+               if (!strcmp(ifgl->ifgl_group->ifg_group, groupname))
+                       break;
+       if (ifgl == NULL)
+               return (ENOENT);
+
+       TAILQ_REMOVE(&ifp->if_groups, ifgl, ifgl_next);
+
+       TAILQ_FOREACH(ifgm, &ifgl->ifgl_group->ifg_members, ifgm_next)
+               if (ifgm->ifgm_ifp == ifp)
+                       break;
+
+       if (ifgm != NULL) {
+               TAILQ_REMOVE(&ifgl->ifgl_group->ifg_members, ifgm, ifgm_next);
+               kfree(ifgm, M_TEMP);
+       }
+
+       if (--ifgl->ifgl_group->ifg_refcnt == 0) {
+               TAILQ_REMOVE(&ifg_head, ifgl->ifgl_group, ifg_next);
+#if NPF > 0
+               pfi_detach_ifgroup(ifgl->ifgl_group);
+#endif
+               kfree(ifgl->ifgl_group, M_TEMP);
+       }
+
+       kfree(ifgl, M_TEMP);
+
+#if NPF > 0
+       pfi_group_change(groupname);
+#endif
+
+       return (0);
+}
+
+/*
+ * Stores all groups from an interface in memory pointed
+ * to by data
+ */
+int
+if_getgroup(caddr_t data, struct ifnet *ifp)
+{
+       int                      len, error;
+       struct ifg_list         *ifgl;
+       struct ifg_req           ifgrq, *ifgp;
+       struct ifgroupreq       *ifgr = (struct ifgroupreq *)data;
+
+       if (ifgr->ifgr_len == 0) {
+               TAILQ_FOREACH(ifgl, &ifp->if_groups, ifgl_next)
+                       ifgr->ifgr_len += sizeof(struct ifg_req);
+               return (0);
+       }
+
+       len = ifgr->ifgr_len;
+       ifgp = ifgr->ifgr_groups;
+       TAILQ_FOREACH(ifgl, &ifp->if_groups, ifgl_next) {
+               if (len < sizeof(ifgrq))
+                       return (EINVAL);
+               bzero(&ifgrq, sizeof ifgrq);
+               strlcpy(ifgrq.ifgrq_group, ifgl->ifgl_group->ifg_group,
+                   sizeof(ifgrq.ifgrq_group));
+               if ((error = copyout((caddr_t)&ifgrq, (caddr_t)ifgp,
+                   sizeof(struct ifg_req))))
+                       return (error);
+               len -= sizeof(ifgrq);
+               ifgp++;
+       }
+
+       return (0);
+}
+
+/*
+ * Stores all members of a group in memory pointed to by data
+ */
+int
+if_getgroupmembers(caddr_t data)
+{
+       struct ifgroupreq       *ifgr = (struct ifgroupreq *)data;
+       struct ifg_group        *ifg;
+       struct ifg_member       *ifgm;
+       struct ifg_req           ifgrq, *ifgp;
+       int                      len, error;
+
+       TAILQ_FOREACH(ifg, &ifg_head, ifg_next)
+               if (!strcmp(ifg->ifg_group, ifgr->ifgr_name))
+                       break;
+       if (ifg == NULL)
+               return (ENOENT);
+
+       if (ifgr->ifgr_len == 0) {
+               TAILQ_FOREACH(ifgm, &ifg->ifg_members, ifgm_next)
+                       ifgr->ifgr_len += sizeof(ifgrq);
+               return (0);
+       }
+
+       len = ifgr->ifgr_len;
+       ifgp = ifgr->ifgr_groups;
+       TAILQ_FOREACH(ifgm, &ifg->ifg_members, ifgm_next) {
+               if (len < sizeof(ifgrq))
+                       return (EINVAL);
+               bzero(&ifgrq, sizeof ifgrq);
+               strlcpy(ifgrq.ifgrq_member, ifgm->ifgm_ifp->if_xname,
+                   sizeof(ifgrq.ifgrq_member));
+               if ((error = copyout((caddr_t)&ifgrq, (caddr_t)ifgp,
+                   sizeof(struct ifg_req))))
+                       return (error);
+               len -= sizeof(ifgrq);
+               ifgp++;
+       }
+
+       return (0);
+}
+
+/*
  * Delete Routes for a Network Interface
  *
  * Called for each routing entry via the rnh->rnh_walktree() call above
@@ -1309,6 +1506,12 @@ ifioctl(struct socket *so, u_long cmd, caddr_t data, struct ucred *cred)
                ifr->ifr_mtu = ifp->if_mtu;
                break;
 
+       case SIOCGIFDATA:
+               error = copyout((caddr_t)&ifp->if_data, ifr->ifr_data,
+                   sizeof(ifp->if_data));
+               break;
+
+
        case SIOCGIFPHYS:
                ifr->ifr_phys = ifp->if_physical;
                break;
index c016aa8..784cf5a 100644 (file)
@@ -275,6 +275,12 @@ struct ifnet {
        int     if_cpuid;
        struct netmsg *if_start_nmsg; /* percpu messages to schedule if_start */
        void    *if_pf_kif; /* pf interface abstraction */
+       union {
+               void *carp_s;           /* carp structure (used by !carp ifs) */
+               struct ifnet *carp_d;   /* ptr to carpdev (used by carp ifs) */
+       } if_carp_ptr;
+       #define if_carp         if_carp_ptr.carp_s
+       #define if_carpdev      if_carp_ptr.carp_d
 };
 typedef void if_init_f_t (void *);
 
@@ -609,6 +615,7 @@ struct ifg_group {
        char                             ifg_group[IFNAMSIZ];
        u_int                            ifg_refcnt;
        void                            *ifg_pf_kif;
+       int                              ifg_carp_demoted;
        TAILQ_HEAD(, ifg_member)         ifg_members;
        TAILQ_ENTRY(ifg_group)           ifg_next;
 };
@@ -756,6 +763,12 @@ int        ifpromisc(struct ifnet *, int);
 struct ifnet *ifunit(const char *);
 struct ifnet *if_withname(struct sockaddr *);
 
+struct ifg_group *if_creategroup(const char *);
+int     if_addgroup(struct ifnet *, const char *);
+int     if_delgroup(struct ifnet *, const char *);
+int     if_getgroup(caddr_t, struct ifnet *);
+int     if_getgroupmembers(caddr_t);
+
 struct ifaddr *ifa_ifwithaddr(struct sockaddr *);
 struct ifaddr *ifa_ifwithdstaddr(struct sockaddr *);
 struct ifaddr *ifa_ifwithnet(struct sockaddr *);
index 7b6da40..98344f3 100644 (file)
@@ -1,7 +1,4 @@
-/*     $FreeBSD: src/sys/contrib/pf/net/if_pflog.c,v 1.9 2004/06/22 20:13:24 brooks Exp $      */
-/*     $OpenBSD: if_pflog.c,v 1.11 2003/12/31 11:18:25 cedric Exp $    */
-/*     $DragonFly: src/sys/net/pf/if_pflog.c,v 1.6 2006/12/22 23:44:57 swildner Exp $ */
-/*     $OpenBSD: if_pflog.c,v 1.22 2006/12/15 09:31:20 otto Exp $      */
+/*     $OpenBSD: if_pflog.c,v 1.24 2007/05/26 17:13:30 jason Exp $     */
 /*
  * The authors of this code are John Ioannidis (ji@tla.org),
  * Angelos D. Keromytis (kermit@csd.uch.gr) and 
@@ -92,7 +89,6 @@ int   pflogoutput(struct ifnet *, struct mbuf *, struct sockaddr *,
 int    pflogioctl(struct ifnet *, u_long, caddr_t, struct ucred *);
 void   pflogrtrequest(int, struct rtentry *, struct sockaddr *);
 void   pflogstart(struct ifnet *);
-
 int    pflog_clone_create(struct if_clone *, int, caddr_t);
 void pflog_clone_destroy(struct ifnet *);
 
@@ -109,7 +105,6 @@ pflogattach(int npflog)
        LIST_INIT(&pflogif_list);
        for (i = 0; i < PFLOGIFS_MAX; i++)
                pflogifs[i] = NULL;
-       (void) pflog_clone_create(&pflog_cloner, 0, NULL);
        if_clone_attach(&pflog_cloner);
 }
 
@@ -251,13 +246,12 @@ pflog_packet(struct pfi_kif *kif, struct mbuf *m, sa_family_t af, u_int8_t dir,
        } else {
                hdr.rulenr = htonl(am->nr);
                hdr.subrulenr = htonl(rm->nr);
-               if (ruleset != NULL && ruleset->anchor != NULL) {
+               if (ruleset != NULL && ruleset->anchor != NULL)
                        strlcpy(hdr.ruleset, ruleset->anchor->name,
                            sizeof(hdr.ruleset));
-               }
        }
        if (rm->log & PF_LOG_SOCKET_LOOKUP && !pd->lookup.done)
-               pd->lookup.done = pf_socket_lookup(dir, pd, NULL);
+               pd->lookup.done = pf_socket_lookup(dir, pd);
        if (pd->lookup.done > 0) {
                hdr.uid = pd->lookup.uid;
                hdr.pid = pd->lookup.pid;
index 7b3a8ed..c6557dd 100644 (file)
@@ -1,6 +1,3 @@
-/* $FreeBSD: src/sys/contrib/pf/net/if_pflog.h,v 1.4 2004/06/16 23:24:00 mlaier Exp $ */
-/* $OpenBSD: if_pflog.h,v 1.10 2004/03/19 04:52:04 frantzen Exp $ */
-/* $DragonFly: src/sys/net/pf/if_pflog.h,v 1.1 2004/09/19 22:32:47 joerg Exp $ */
 /* $OpenBSD: if_pflog.h,v 1.14 2006/10/25 11:27:01 henning Exp $ */
 /*
  * Copyright (c) 2004 The DragonFly Project.  All rights reserved.
index ba2d6d6..3c05de9 100644 (file)
@@ -28,6 +28,7 @@
 
 #include "opt_inet.h"
 #include "opt_inet6.h"
+#include "use_carp.h"
 
 #include <sys/param.h>
 #include <sys/endian.h>
@@ -52,6 +53,7 @@
 #include <net/bpf.h>
 #include <netinet/in.h>
 #include <netinet/if_ether.h>
+#include <netinet/ip_carp.h>
 #include <netinet/tcp.h>
 #include <netinet/tcp_seq.h>
 
@@ -211,6 +213,7 @@ int
 pfsync_insert_net_state(struct pfsync_state *sp, u_int8_t chksum_flag)
 {
        struct pf_state *st = NULL;
+       struct pf_state_key *sk = NULL;
        struct pf_rule *r = NULL;
        struct pfi_kif  *kif;
 
@@ -233,7 +236,9 @@ pfsync_insert_net_state(struct pfsync_state *sp, u_int8_t chksum_flag)
         * If the ruleset checksums match, it's safe to associate the state
         * with the rule of that number.
         */
-       if (sp->rule != htonl(-1) && sp->anchor == htonl(-1) && chksum_flag)
+       if (sp->rule != htonl(-1) && sp->anchor == htonl(-1) && chksum_flag &&
+           ntohl(sp->rule) <
+           pf_main_ruleset.rules[PF_RULESET_FILTER].active.rcount)
                r = pf_main_ruleset.rules[
                    PF_RULESET_FILTER].active.ptr_array[ntohl(sp->rule)];
        else
@@ -247,6 +252,12 @@ pfsync_insert_net_state(struct pfsync_state *sp, u_int8_t chksum_flag)
        }
        bzero(st, sizeof(*st));
 
+       if ((sk = pf_alloc_state_key(st)) == NULL) {
+               pool_put(&pf_state_pl, st);
+               pfi_kif_unref(kif, PFI_KIF_REF_NONE);
+               return (ENOMEM);
+       }
+
        /* allocate memory for scrub info */
        if (pfsync_alloc_scrub_memory(&sp->src, &st->src) ||
            pfsync_alloc_scrub_memory(&sp->dst, &st->dst)) {
@@ -254,6 +265,7 @@ pfsync_insert_net_state(struct pfsync_state *sp, u_int8_t chksum_flag)
                if (st->src.scrub)
                        pool_put(&pf_state_scrub_pl, st->src.scrub);
                pool_put(&pf_state_pl, st);
+               pool_put(&pf_state_key_pl, sk);
                return (ENOMEM);
        }
 
@@ -264,9 +276,9 @@ pfsync_insert_net_state(struct pfsync_state *sp, u_int8_t chksum_flag)
        r->states++;
 
        /* fill in the rest of the state entry */
-       pf_state_host_ntoh(&sp->lan, &st->lan);
-       pf_state_host_ntoh(&sp->gwy, &st->gwy);
-       pf_state_host_ntoh(&sp->ext, &st->ext);
+       pf_state_host_ntoh(&sp->lan, &sk->lan);
+       pf_state_host_ntoh(&sp->gwy, &sk->gwy);
+       pf_state_host_ntoh(&sp->ext, &sk->ext);
 
        pf_state_peer_ntoh(&sp->src, &st->src);
        pf_state_peer_ntoh(&sp->dst, &st->dst);
@@ -275,9 +287,9 @@ pfsync_insert_net_state(struct pfsync_state *sp, u_int8_t chksum_flag)
        st->creation = time_second - ntohl(sp->creation);
        st->expire = ntohl(sp->expire) + time_second;
 
-       st->af = sp->af;
-       st->proto = sp->proto;
-       st->direction = sp->direction;
+       sk->af = sp->af;
+       sk->proto = sp->proto;
+       sk->direction = sp->direction;
        st->log = sp->log;
        st->timeout = sp->timeout;
        st->allow_opts = sp->allow_opts;
@@ -308,13 +320,17 @@ pfsync_input(struct mbuf *m, ...)
        struct pfsync_header *ph;
        struct pfsync_softc *sc = pfsyncif;
        struct pf_state *st;
-       struct pf_state_cmp key;
+       struct pf_state_key *sk;
+       struct pf_state_cmp id_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 IPSEC
+       struct pfsync_tdb *pt;
+#endif
        struct in_addr src;
        struct mbuf *mp;
        int iplen, action, error, i, count, offp, sfail, stale = 0;
@@ -378,7 +394,8 @@ pfsync_input(struct mbuf *m, ...)
        switch (action) {
        case PFSYNC_ACT_CLR: {
                struct pf_state *nexts;
-               struct pfi_kif  *kif;
+               struct pf_state_key *nextsk;
+               struct pfi_kif *kif;
                u_int32_t creatorid;
                if ((mp = m_pulldown(m, iplen + sizeof(*ph),
                    sizeof(*cp), &offp)) == NULL) {
@@ -403,13 +420,16 @@ pfsync_input(struct mbuf *m, ...)
                                crit_exit();
                                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->sync_flags |= PFSTATE_FROMSYNC;
-                                       pf_unlink_state(st);
+                       for (sk = RB_MIN(pf_state_tree_lan_ext,
+                           &pf_statetbl_lan_ext); sk; sk = nextsk) {
+                               nextsk = RB_NEXT(pf_state_tree_lan_ext,
+                                   &pf_statetbl_lan_ext, sk);
+                               TAILQ_FOREACH(st, &sk->states, next) {
+                                       if (st->creatorid == creatorid) {
+                                               st->sync_flags |=
+                                                   PFSTATE_FROMSYNC;
+                                               pf_unlink_state(st);
+                                       }
                                }
                        }
                }
@@ -474,18 +494,19 @@ pfsync_input(struct mbuf *m, ...)
                                continue;
                        }
 
-                       bcopy(sp->id, &key.id, sizeof(key.id));
-                       key.creatorid = sp->creatorid;
+                       bcopy(sp->id, &id_key.id, sizeof(id_key.id));
+                       id_key.creatorid = sp->creatorid;
 
-                       st = pf_find_state_byid(&key);
+                       st = pf_find_state_byid(&id_key);
                        if (st == NULL) {
                                /* insert the update */
                                if (pfsync_insert_net_state(sp, chksum_flag))
                                        pfsyncstats.pfsyncs_badstate++;
                                continue;
                        }
+                       sk = st->state_key;
                        sfail = 0;
-                       if (st->proto == IPPROTO_TCP) {
+                       if (sk->proto == IPPROTO_TCP) {
                                /*
                                 * The state should never go backwards except
                                 * for syn-proxy states.  Neither should the
@@ -568,10 +589,10 @@ pfsync_input(struct mbuf *m, ...)
                crit_enter();
                for (i = 0, sp = (struct pfsync_state *)(mp->m_data + offp);
                    i < count; i++, sp++) {
-                       bcopy(sp->id, &key.id, sizeof(key.id));
-                       key.creatorid = sp->creatorid;
+                       bcopy(sp->id, &id_key.id, sizeof(id_key.id));
+                       id_key.creatorid = sp->creatorid;
 
-                       st = pf_find_state_byid(&key);
+                       st = pf_find_state_byid(&id_key);
                        if (st == NULL) {
                                pfsyncstats.pfsyncs_badstate++;
                                continue;
@@ -605,10 +626,10 @@ pfsync_input(struct mbuf *m, ...)
                                continue;
                        }
 
-                       bcopy(up->id, &key.id, sizeof(key.id));
-                       key.creatorid = up->creatorid;
+                       bcopy(up->id, &id_key.id, sizeof(id_key.id));
+                       id_key.creatorid = up->creatorid;
 
-                       st = pf_find_state_byid(&key);
+                       st = pf_find_state_byid(&id_key);
                        if (st == NULL) {
                                /* We don't have this state. Ask for it. */
                                error = pfsync_request_update(up, &src);
@@ -620,8 +641,9 @@ pfsync_input(struct mbuf *m, ...)
                                pfsyncstats.pfsyncs_badstate++;
                                continue;
                        }
+                       sk = st->state_key;
                        sfail = 0;
-                       if (st->proto == IPPROTO_TCP) {
+                       if (sk->proto == IPPROTO_TCP) {
                                /*
                                 * The state should never go backwards except
                                 * for syn-proxy states.  Neither should the
@@ -691,10 +713,10 @@ pfsync_input(struct mbuf *m, ...)
                crit_enter();
                for (i = 0, dp = (struct pfsync_state_del *)(mp->m_data + offp);
                    i < count; i++, dp++) {
-                       bcopy(dp->id, &key.id, sizeof(key.id));
-                       key.creatorid = dp->creatorid;
+                       bcopy(dp->id, &id_key.id, sizeof(id_key.id));
+                       id_key.creatorid = dp->creatorid;
 
-                       st = pf_find_state_byid(&key);
+                       st = pf_find_state_byid(&id_key);
                        if (st == NULL) {
                                pfsyncstats.pfsyncs_badstate++;
                                continue;
@@ -721,10 +743,10 @@ pfsync_input(struct mbuf *m, ...)
                for (i = 0,
                    rup = (struct pfsync_state_upd_req *)(mp->m_data + offp);
                    i < count; i++, rup++) {
-                       bcopy(rup->id, &key.id, sizeof(key.id));
-                       key.creatorid = rup->creatorid;
+                       bcopy(rup->id, &id_key.id, sizeof(id_key.id));
+                       id_key.creatorid = rup->creatorid;
 
-                       if (key.id == 0 && key.creatorid == 0) {
+                       if (id_key.id == 0 && id_key.creatorid == 0) {
                                sc->sc_ureq_received = mycpu->gd_time_seconds;
                                if (sc->sc_bulk_send_next == NULL)
                                        sc->sc_bulk_send_next =
@@ -738,7 +760,7 @@ pfsync_input(struct mbuf *m, ...)
                                    pfsync_bulk_update,
                                    LIST_FIRST(&pfsync_list));
                        } else {
-                               st = pf_find_state_byid(&key);
+                               st = pf_find_state_byid(&id_key);
                                if (st == NULL) {
                                        pfsyncstats.pfsyncs_badstate++;
                                        continue;
@@ -796,6 +818,20 @@ pfsync_input(struct mbuf *m, ...)
                        break;
                }
                break;
+#ifdef IPSEC
+       case PFSYNC_ACT_TDB_UPD:
+               if ((mp = m_pulldown(m, iplen + sizeof(*ph),
+                   count * sizeof(*pt), &offp)) == NULL) {
+                       pfsyncstats.pfsyncs_badlen++;
+                       return;
+               }
+               s = splsoftnet();
+               for (i = 0, pt = (struct pfsync_tdb *)(mp->m_data + offp);
+                   i < count; i++, pt++)
+                       pfsync_update_net_tdb(pt);
+               splx(s);
+               break;
+#endif
        }
 
 done:
@@ -1011,6 +1047,10 @@ pfsync_get_mbuf(struct pfsync_softc *sc, u_int8_t action, void **sp)
                len = sizeof(struct pfsync_header) +
                    sizeof(struct pfsync_state_bus);
                break;
+       case PFSYNC_ACT_TDB_UPD:
+               len = (sc->sc_maxcount * sizeof(struct pfsync_tdb)) +
+                   sizeof(struct pfsync_header);
+               break;
        default:
                len = (sc->sc_maxcount * sizeof(struct pfsync_state)) +
                    sizeof(struct pfsync_header);
@@ -1051,6 +1091,7 @@ pfsync_pack_state(u_int8_t action, struct pf_state *st, int flags)
        struct pfsync_state *sp = NULL;
        struct pfsync_state_upd *up = NULL;
        struct pfsync_state_del *dp = NULL;
+       struct pf_state_key *sk = st->state_key;
        struct pf_rule *r;
        u_long secs;
        int ret = 0;
@@ -1135,10 +1176,10 @@ pfsync_pack_state(u_int8_t action, struct pf_state *st, int flags)
                bcopy(&st->id, sp->id, sizeof(sp->id));
                sp->creatorid = st->creatorid;
 
-               strlcpy(sp->ifname, st->u.s.kif->pfik_name, sizeof(sp->ifname));
-               pf_state_host_hton(&st->lan, &sp->lan);
-               pf_state_host_hton(&st->gwy, &sp->gwy);
-               pf_state_host_hton(&st->ext, &sp->ext);
+               strlcpy(sp->ifname, st->kif->pfik_name, sizeof(sp->ifname));
+               pf_state_host_hton(&sk->lan, &sp->lan);
+               pf_state_host_hton(&sk->gwy, &sp->gwy);
+               pf_state_host_hton(&sk->ext, &sp->ext);
 
                bcopy(&st->rt_addr, &sp->rt_addr, sizeof(sp->rt_addr));
 
@@ -1155,9 +1196,9 @@ pfsync_pack_state(u_int8_t action, struct pf_state *st, int flags)
                        sp->anchor = htonl(-1);
                else
                        sp->anchor = htonl(r->nr);
-               sp->af = st->af;
-               sp->proto = st->proto;
-               sp->direction = st->direction;
+               sp->af = sk->af;
+               sp->proto = sk->proto;
+               sp->direction = sk->direction;
                sp->log = st->log;
                sp->allow_opts = st->allow_opts;
                sp->timeout = st->timeout;
@@ -1376,7 +1417,7 @@ pfsync_bulk_update(void *v)
                        }
 
                        /* figure next state to send */
-                       state = TAILQ_NEXT(state, u.s.entry_list);
+                       state = TAILQ_NEXT(state, entry_list);
 
                        /* wrap to start of list if we hit the end */
                        if (!state)
index 5060141..eac35a5 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: if_pfsync.h,v 1.30 2006/10/31 14:49:01 henning Exp $  */
+/*     $OpenBSD: if_pfsync.h,v 1.31 2007/05/31 04:11:42 mcbride Exp $  */
 
 /*
  * Copyright (c) 2001 Michael Shalayeff
 
 #define PFSYNC_ID_LEN  sizeof(u_int64_t)
 
-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;
-
-struct pfsync_state_host {
-       struct pf_addr  addr;
-       u_int16_t       port;
-       u_int16_t       pad[3];
-} __packed;
-
-struct pfsync_state_peer {
-       struct pfsync_state_scrub scrub;        /* state is scrubbed    */
-       u_int32_t       seqlo;          /* Max sequence number sent     */
-       u_int32_t       seqhi;          /* Max the other end ACKd + win */
-       u_int32_t       seqdiff;        /* Sequence number modulator    */
-       u_int16_t       max_win;        /* largest window (pre scaling) */
-       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        pad[6];
-} __packed;
-
-struct pfsync_state {
-       u_int32_t        id[2];
-       char             ifname[IFNAMSIZ];
-       struct pfsync_state_host lan;
-       struct pfsync_state_host gwy;
-       struct pfsync_state_host ext;
-       struct pfsync_state_peer src;
-       struct pfsync_state_peer dst;
-       struct pf_addr   rt_addr;
-       u_int32_t        rule;
-       u_int32_t        anchor;
-       u_int32_t        nat_rule;
-       u_int32_t        creation;
-       u_int32_t        expire;
-       u_int32_t        packets[2][2];
-       u_int32_t        bytes[2][2];
-       u_int32_t        creatorid;
-       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;
-       u_int8_t         updates;
-} __packed;
-
 #define PFSYNC_FLAG_COMPRESS   0x01
 #define PFSYNC_FLAG_STALE      0x02
 
+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;
+
 struct pfsync_state_upd {
        u_int32_t               id[2];
        struct pfsync_state_peer        src;
@@ -259,7 +216,7 @@ struct pfsyncreq {
 #define SIOCSETPFSYNC  _IOW('i', 247, struct ifreq)
 #define SIOCGETPFSYNC  _IOWR('i', 248, struct ifreq)
 
-
+/* for copies to/from network */
 #define pf_state_peer_hton(s,d) do {           \
        (d)->seqlo = htonl((s)->seqlo);         \
        (d)->seqhi = htonl((s)->seqhi);         \
@@ -321,7 +278,7 @@ int pfsync_clear_states(u_int32_t, char *);
 int pfsync_pack_state(u_int8_t, struct pf_state *, int);
 #define pfsync_insert_state(st)        do {                            \
        if ((st->rule.ptr->rule_flag & PFRULE_NOSYNC) ||        \
-           (st->proto == IPPROTO_PFSYNC))                      \
+           (st->state_key->proto == IPPROTO_PFSYNC))                   \
                st->sync_flags |= PFSTATE_NOSYNC;               \
        else if (!st->sync_flags)                               \
                pfsync_pack_state(PFSYNC_ACT_INS, (st),         \
index 4c78941..7c0bc59 100644 (file)
@@ -1,8 +1,4 @@
-/*     $FreeBSD: src/sys/contrib/pf/net/pf.c,v 1.19 2004/09/11 11:18:25 mlaier Exp $   */
-/*     $OpenBSD: pf.c,v 1.433.2.2 2004/07/17 03:22:34 brad Exp $ */
-/* add $OpenBSD: pf.c,v 1.448 2004/05/11 07:34:11 dhartmei Exp $ */
-/*     $DragonFly: src/sys/net/pf/pf.c,v 1.20 2008/06/05 18:06:32 swildner Exp $ */
-/*     $OpenBSD: pf.c,v 1.527 2007/02/22 15:23:23 pyr Exp $ */
+/*     $OpenBSD: pf.c,v 1.552 2007/08/21 15:57:27 dhartmei Exp $ */
 
 /*
  * Copyright (c) 2004 The DragonFly Project.  All rights reserved.
@@ -117,6 +113,10 @@ extern int debug_pfugidhack;
  * Global variables
  */
 
+/* state tables */
+struct pf_state_tree_lan_ext    pf_statetbl_lan_ext;
+struct pf_state_tree_ext_gwy    pf_statetbl_ext_gwy;
+
 struct pf_altqqueue     pf_altqs[2];
 struct pf_palist        pf_pabuf;
 struct pf_altqqueue    *pf_altqs_active;
@@ -135,8 +135,9 @@ struct pf_anchor_stackframe {
        struct pf_anchor                        *child;
 } pf_anchor_stack[64];
 
-vm_zone_t               pf_src_tree_pl, pf_rule_pl;
-vm_zone_t               pf_state_pl, pf_altq_pl, pf_pooladdr_pl;
+vm_zone_t               pf_src_tree_pl, pf_rule_pl, pf_pooladdr_pl;
+vm_zone_t               pf_state_pl, pf_state_key_pl;
+vm_zone_t               pf_altq_pl;
 
 void                    pf_print_host(struct pf_addr *, u_int16_t, u_int8_t);
 
@@ -174,22 +175,13 @@ struct pf_rule            *pf_get_translation(struct pf_pdesc *, struct mbuf *,
                            struct pf_addr *, u_int16_t,
                            struct pf_addr *, u_int16_t,
                            struct pf_addr *, u_int16_t *);
-int                     pf_test_tcp(struct pf_rule **, struct pf_state **,
-                           int, struct pfi_kif *, struct mbuf *, int,
-                           void *, struct pf_pdesc *, struct pf_rule **,
-                           struct pf_ruleset **, struct ifqueue *, struct inpcb *);
-int                     pf_test_udp(struct pf_rule **, struct pf_state **,
+void                    pf_attach_state(struct pf_state_key *,
+                           struct pf_state *, int);
+void                    pf_detach_state(struct pf_state *, int);
+int                     pf_test_rule(struct pf_rule **, struct pf_state **,
                            int, struct pfi_kif *, struct mbuf *, int,
                            void *, struct pf_pdesc *, struct pf_rule **,
                            struct pf_ruleset **, struct ifqueue *, struct inpcb *);
-int                     pf_test_icmp(struct pf_rule **, struct pf_state **,
-                           int, struct pfi_kif *, struct mbuf *, int,
-                           void *, struct pf_pdesc *, struct pf_rule **,
-                           struct pf_ruleset **, struct ifqueue *);
-int                     pf_test_other(struct pf_rule **, struct pf_state **,
-                           int, struct pfi_kif *, struct mbuf *, int, void *,
-                           struct pf_pdesc *, struct pf_rule **,
-                           struct pf_ruleset **, struct ifqueue *);
 int                     pf_test_fragment(struct pf_rule **, int,
                            struct pfi_kif *, struct mbuf *, void *,
                            struct pf_pdesc *, struct pf_rule **,
@@ -205,8 +197,9 @@ int                  pf_test_state_icmp(struct pf_state **, int,
                            void *, struct pf_pdesc *, u_short *);
 int                     pf_test_state_other(struct pf_state **, int,
                            struct pfi_kif *, struct pf_pdesc *);
-int                     pf_match_tag(struct mbuf *, struct pf_rule *,
-                            struct pf_mtag *, int *);
+int                     pf_match_tag(struct mbuf *, struct pf_rule *, int *);
+void                    pf_step_into_anchor(int *, struct pf_ruleset **, int,
+                           struct pf_rule **, struct pf_rule **,  int *);
 int                     pf_step_out_of_anchor(int *, struct pf_ruleset **,
                             int, struct pf_rule **, struct pf_rule **,
                             int *);
@@ -237,9 +230,11 @@ int                         pf_check_proto_cksum(struct mbuf *, int, int,
                            u_int8_t, sa_family_t);
 int                     pf_addr_wrap_neq(struct pf_addr_wrap *,
                            struct pf_addr_wrap *);
-struct pf_state                *pf_find_state_recurse(struct pfi_kif *,
-                           struct pf_state_cmp *, u_int8_t);
+struct pf_state                *pf_find_state(struct pfi_kif *,
+                           struct pf_state_key_cmp *, u_int8_t);
 int                     pf_src_connlimit(struct pf_state **);
+void                    pf_stateins_err(const char *, struct pf_state *,
+                           struct pfi_kif *);
 int                     pf_check_congestion(struct ifqueue *);
 
 extern int pf_end_threads;
@@ -255,11 +250,9 @@ struct pf_pool_limit pf_pool_limits[PF_LIMIT_MAX] = {
 #define STATE_LOOKUP()                                                 \
        do {                                                            \
                if (direction == PF_IN)                                 \
-                       *state = pf_find_state_recurse(                 \
-                           kif, &key, PF_EXT_GWY);                     \
+                       *state = pf_find_state(kif, &key, PF_EXT_GWY);  \
                else                                                    \
-                       *state = pf_find_state_recurse(         \
-                           kif, &key, PF_LAN_EXT);                     \
+                       *state = pf_find_state(kif, &key, PF_LAN_EXT);  \
                if (*state == NULL || (*state)->timeout == PFTM_PURGE)  \
                        return (PF_DROP);                               \
                if (direction == PF_OUT &&                              \
@@ -272,13 +265,13 @@ struct pf_pool_limit pf_pool_limits[PF_LIMIT_MAX] = {
                        return (PF_PASS);                               \
        } while (0)
 
-#define        STATE_TRANSLATE(s) \
-       (s)->lan.addr.addr32[0] != (s)->gwy.addr.addr32[0] || \
-       ((s)->af == AF_INET6 && \
-       ((s)->lan.addr.addr32[1] != (s)->gwy.addr.addr32[1] || \
-       (s)->lan.addr.addr32[2] != (s)->gwy.addr.addr32[2] || \
-       (s)->lan.addr.addr32[3] != (s)->gwy.addr.addr32[3])) || \
-       (s)->lan.port != (s)->gwy.port
+#define        STATE_TRANSLATE(sk) \
+       (sk)->lan.addr.addr32[0] != (sk)->gwy.addr.addr32[0] || \
+       ((sk)->af == AF_INET6 && \
+       ((sk)->lan.addr.addr32[1] != (sk)->gwy.addr.addr32[1] || \
+       (sk)->lan.addr.addr32[2] != (sk)->gwy.addr.addr32[2] || \
+       (sk)->lan.addr.addr32[3] != (sk)->gwy.addr.addr32[3])) || \
+       (sk)->lan.port != (sk)->gwy.port
 
 #define BOUND_IFACE(r, k) \
        ((r)->rule_flag & PFRULE_IFBOUND) ? (k) : pfi_all
@@ -302,10 +295,10 @@ struct pf_pool_limit pf_pool_limits[PF_LIMIT_MAX] = {
        } while (0)
 
 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_lan_ext(struct pf_state_key *,
+       struct pf_state_key *);
+static __inline int pf_state_compare_ext_gwy(struct pf_state_key *,
+       struct pf_state_key *);
 static __inline int pf_state_compare_id(struct pf_state *,
        struct pf_state *);
 
@@ -315,12 +308,15 @@ struct pf_state_tree_id tree_id;
 struct pf_state_queue state_list;
 
 RB_GENERATE(pf_src_tree, pf_src_node, entry, pf_src_compare);
-RB_GENERATE(pf_state_tree_lan_ext, pf_state,
-    u.s.entry_lan_ext, pf_state_compare_lan_ext);
-RB_GENERATE(pf_state_tree_ext_gwy, pf_state,
-    u.s.entry_ext_gwy, pf_state_compare_ext_gwy);
+RB_GENERATE(pf_state_tree_lan_ext, pf_state_key,
+    entry_lan_ext, pf_state_compare_lan_ext);
+RB_GENERATE(pf_state_tree_ext_gwy, pf_state_key,
+    entry_ext_gwy, pf_state_compare_ext_gwy);
 RB_GENERATE(pf_state_tree_id, pf_state,
-    u.s.entry_id, pf_state_compare_id);
+    entry_id, pf_state_compare_id);
+
+#define        PF_DT_SKIP_LANEXT       0x01
+#define        PF_DT_SKIP_EXTGWY       0x02
 
 static __inline int
 pf_src_compare(struct pf_src_node *a, struct pf_src_node *b)
@@ -367,20 +363,20 @@ pf_src_compare(struct pf_src_node *a, struct pf_src_node *b)
 }
 
 u_int32_t
-pf_state_hash(struct pf_state *s)
+pf_state_hash(struct pf_state_key *sk)
 {
-       u_int32_t hv = (intptr_t)s / sizeof(*s);
+       u_int32_t hv = (intptr_t)sk / sizeof(*sk);
 
-       hv ^= crc32(&s->lan, sizeof(s->lan));
-       hv ^= crc32(&s->gwy, sizeof(s->gwy));
-       hv ^= crc32(&s->ext, sizeof(s->ext));
+       hv ^= crc32(&sk->lan, sizeof(sk->lan));
+       hv ^= crc32(&sk->gwy, sizeof(sk->gwy));
+       hv ^= crc32(&sk->ext, sizeof(sk->ext));
        if (hv == 0)    /* disallow 0 */
                hv = 1;
        return(hv);
 }
 
 static __inline int
-pf_state_compare_lan_ext(struct pf_state *a, struct pf_state *b)
+pf_state_compare_lan_ext(struct pf_state_key *a, struct pf_state_key *b)
 {
        int     diff;
 
@@ -448,7 +444,7 @@ pf_state_compare_lan_ext(struct pf_state *a, struct pf_state *b)
 }
 
 static __inline int
-pf_state_compare_ext_gwy(struct pf_state *a, struct pf_state *b)
+pf_state_compare_ext_gwy(struct pf_state_key *a, struct pf_state_key *b)
 {
        int     diff;
 
@@ -554,74 +550,71 @@ struct pf_state *
 pf_find_state_byid(struct pf_state_cmp *key)
 {
        pf_status.fcounters[FCNT_STATE_SEARCH]++;
+       
        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_cmp *key, u_int8_t tree)
+pf_find_state(struct pfi_kif *kif, struct pf_state_key_cmp *key, u_int8_t tree)
 {
-       struct pf_state *s;
+       struct pf_state_key     *sk;
+       struct pf_state         *s;
 
        pf_status.fcounters[FCNT_STATE_SEARCH]++;
 
        switch (tree) {
        case PF_LAN_EXT:
-               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);
+               sk = RB_FIND(pf_state_tree_lan_ext, &pf_statetbl_lan_ext,
+                   (struct pf_state_key *)key);
+               break;
        case PF_EXT_GWY:
-               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);
+               sk = RB_FIND(pf_state_tree_ext_gwy, &pf_statetbl_ext_gwy,
+                   (struct pf_state_key *)key);
+               break;
        default:
-               panic("pf_find_state_recurse");
+               panic("pf_find_state");
        }
+
+       /* list is sorted, if-bound states before floating ones */
+       if (sk != NULL)
+               TAILQ_FOREACH(s, &sk->states, next)
+                       if (s->kif == pfi_all || s->kif == kif)
+                               return (s);
+
+       return (NULL);
 }
 
 struct pf_state *
-pf_find_state_all(struct pf_state_cmp *key, u_int8_t tree, int *more)
+pf_find_state_all(struct pf_state_key_cmp *key, u_int8_t tree, int *more)
 {
-       struct pf_state *s, *ss = NULL;
-       struct pfi_kif  *kif;
+       struct pf_state_key     *sk;
+       struct pf_state         *s, *ret = NULL;
 
        pf_status.fcounters[FCNT_STATE_SEARCH]++;
 
        switch (tree) {
        case PF_LAN_EXT:
-               TAILQ_FOREACH(kif, &pfi_statehead, pfik_w_states) {
-                       s = RB_FIND(pf_state_tree_lan_ext,
-                           &kif->pfik_lan_ext, (struct pf_state *)key);
-                       if (s == NULL)
-                               continue;
-                       if (more == NULL)
-                               return (s);
-                       ss = s;
-                       (*more)++;
-               }
-               return (ss);
+               sk = RB_FIND(pf_state_tree_lan_ext,
+                   &pf_statetbl_lan_ext, (struct pf_state_key *)key);
+               break;
        case PF_EXT_GWY:
-               TAILQ_FOREACH(kif, &pfi_statehead, pfik_w_states) {
-                       s = RB_FIND(pf_state_tree_ext_gwy,
-                           &kif->pfik_ext_gwy, (struct pf_state *)key);
-                       if (s == NULL)
-                               continue;
-                       if (more == NULL)
-                               return (s);
-                       ss = s;
-                       (*more)++;
-               }
-               return (ss);
+               sk = RB_FIND(pf_state_tree_ext_gwy,
+                   &pf_statetbl_ext_gwy, (struct pf_state_key *)key);
+               break;
        default:
                panic("pf_find_state_all");
        }
+
+       if (sk != NULL) {
+               ret = TAILQ_FIRST(&sk->states);
+               if (more == NULL)
+                       return (ret);
+
+               TAILQ_FOREACH(s, &sk->states, next)
+                       (*more)++;
+       }
+
+       return (ret);
 }
 
 void
@@ -657,7 +650,6 @@ pf_check_threshold(struct pf_threshold *threshold)
 int
 pf_src_connlimit(struct pf_state **state)
 {
-       struct pf_state *s;
        int bad = 0;
 
        (*state)->src_node->conn++;
@@ -688,12 +680,12 @@ pf_src_connlimit(struct pf_state **state)
                if (pf_status.debug >= PF_DEBUG_MISC) {
                        kprintf("pf_src_connlimit: blocking address ");
                        pf_print_host(&(*state)->src_node->addr, 0,
-                           (*state)->af);
+                           (*state)->state_key->af);
                }
 
                bzero(&p, sizeof(p));
-               p.pfra_af = (*state)->af;
-               switch ((*state)->af) {
+               p.pfra_af = (*state)->state_key->af;
+               switch ((*state)->state_key->af) {
 #ifdef INET
                case AF_INET:
                        p.pfra_net = 32;
@@ -713,26 +705,31 @@ pf_src_connlimit(struct pf_state **state)
 
                /* kill existing states if that's required. */
                if ((*state)->rule.ptr->flush) {
-                       pf_status.lcounters[LCNT_OVERLOAD_FLUSH]++;
+                       struct pf_state_key *sk;
+                       struct pf_state *st;
 
-                       RB_FOREACH(s, pf_state_tree_id, &tree_id) {
+                       pf_status.lcounters[LCNT_OVERLOAD_FLUSH]++;
+                       RB_FOREACH(st, pf_state_tree_id, &tree_id) {
+                               sk = st->state_key;
                                /*
                                 * Kill states from this source.  (Only those
                                 * from the same rule if PF_FLUSH_GLOBAL is not
                                 * set)
                                 */
-                               if (s->af == (*state)->af &&
-                                   (((*state)->direction == PF_OUT &&
+                               if (sk->af ==
+                                   (*state)->state_key->af &&
+                                   (((*state)->state_key->direction ==
+                                       PF_OUT &&
                                    PF_AEQ(&(*state)->src_node->addr,
-                                   &s->lan.addr, s->af)) ||
-                                   ((*state)->direction == PF_IN &&
+                                       &sk->lan.addr, sk->af)) ||
+                                   ((*state)->state_key->direction == PF_IN &&
                                    PF_AEQ(&(*state)->src_node->addr,
-                                   &s->ext.addr, s->af))) &&
+                                       &sk->ext.addr, sk->af))) &&
                                    ((*state)->rule.ptr->flush &
                                    PF_FLUSH_GLOBAL ||
-                                   (*state)->rule.ptr == s->rule.ptr)) {
-                                       s->timeout = PFTM_PURGE;
-                                       s->src.state = s->dst.state =
+                                   (*state)->rule.ptr == st->rule.ptr)) {
+                                       st->timeout = PFTM_PURGE;
+                                       st->src.state = st->dst.state =
                                            TCPS_CLOSED;
                                        killed++;
                                }
@@ -814,73 +811,80 @@ pf_insert_src_node(struct pf_src_node **sn, struct pf_rule *rule,
        return (0);
 }
 
+void
+pf_stateins_err(const char *tree, struct pf_state *s, struct pfi_kif *kif)
+{
+       struct pf_state_key     *sk = s->state_key;
+
+       if (pf_status.debug >= PF_DEBUG_MISC) {
+               kprintf("pf: state insert failed: %s %s", tree, kif->pfik_name);
+               kprintf(" lan: ");
+               pf_print_host(&sk->lan.addr, sk->lan.port,
+                   sk->af);
+               kprintf(" gwy: ");
+               pf_print_host(&sk->gwy.addr, sk->gwy.port,
+                   sk->af);
+               kprintf(" ext: ");
+               pf_print_host(&sk->ext.addr, sk->ext.port,
+                   sk->af);
+               if (s->sync_flags & PFSTATE_FROMSYNC)
+                       kprintf(" (from sync)");
+               kprintf("\n");
+       }
+}
+
 int
-pf_insert_state(struct pfi_kif *kif, struct pf_state *state)
+pf_insert_state(struct pfi_kif *kif, struct pf_state *s)
 {
-       /* Thou MUST NOT insert multiple duplicate keys */
-       state->u.s.kif = kif;
-       if (RB_INSERT(pf_state_tree_lan_ext, &kif->pfik_lan_ext, state)) {
-               if (pf_status.debug >= PF_DEBUG_MISC) {
-                       kprintf("pf: state insert failed: tree_lan_ext");
-                       kprintf(" lan: ");
-                       pf_print_host(&state->lan.addr, state->lan.port,
-                           state->af);
-                       kprintf(" gwy: ");
-                       pf_print_host(&state->gwy.addr, state->gwy.port,
-                           state->af);
-                       kprintf(" ext: ");
-                       pf_print_host(&state->ext.addr, state->ext.port,
-                           state->af);
-                       if (state->sync_flags & PFSTATE_FROMSYNC)
-                               kprintf(" (from sync)");
-                       kprintf("\n");
-               }
-               return (-1);
+       struct pf_state_key     *cur;
+       struct pf_state         *sp;
+
+       KKASSERT(s->state_key != NULL);
+       s->kif = kif;
+
+       if ((cur = RB_INSERT(pf_state_tree_lan_ext, &pf_statetbl_lan_ext,
+           s->state_key)) != NULL) {
+               /* key exists. check for same kif, if none, add to key */
+               TAILQ_FOREACH(sp, &cur->states, next)
+                       if (sp->kif == kif) {   /* collision! */
+                               pf_stateins_err("tree_lan_ext", s, kif);
+                               return (-1);
+                       }
+               pf_detach_state(s, PF_DT_SKIP_LANEXT|PF_DT_SKIP_EXTGWY);
+               pf_attach_state(cur, s, kif == pfi_all ? 1 : 0);
        }
 
-       if (RB_INSERT(pf_state_tree_ext_gwy, &kif->pfik_ext_gwy, state)) {
-               if (pf_status.debug >= PF_DEBUG_MISC) {
-                       kprintf("pf: state insert failed: tree_ext_gwy");
-                       kprintf(" lan: ");
-                       pf_print_host(&state->lan.addr, state->lan.port,
-                           state->af);
-                       kprintf(" gwy: ");
-                       pf_print_host(&state->gwy.addr, state->gwy.port,
-                           state->af);
-                       kprintf(" ext: ");
-                       pf_print_host(&state->ext.addr, state->ext.port,
-                           state->af);
-                       if (state->sync_flags & PFSTATE_FROMSYNC)
-                               kprintf(" (from sync)");
-                       kprintf("\n");
-               }
-               RB_REMOVE(pf_state_tree_lan_ext, &kif->pfik_lan_ext, state);
+       /* if cur != NULL, we already found a state key and attached to it */
+       if (cur == NULL && (cur = RB_INSERT(pf_state_tree_ext_gwy,
+           &pf_statetbl_ext_gwy, s->state_key)) != NULL) {
+               /* must not happen. we must have found the sk above! */
+               pf_stateins_err("tree_ext_gwy", s, kif);
+               pf_detach_state(s, PF_DT_SKIP_EXTGWY);
                return (-1);
        }
 
-       if (state->id == 0 && state->creatorid == 0) {
-               state->id = htobe64(pf_status.stateid++);
-               state->creatorid = pf_status.hostid;
+       if (s->id == 0 && s->creatorid == 0) {
+               s->id = htobe64(pf_status.stateid++);
+               s->creatorid = pf_status.hostid;
        }
-       if (RB_INSERT(pf_state_tree_id, &tree_id, state) != NULL) {
+       if (RB_INSERT(pf_state_tree_id, &tree_id, s) != NULL) {
                if (pf_status.debug >= PF_DEBUG_MISC) {
                        kprintf("pf: state insert failed: "
-                           "id: %016" PRIx64 " creatorid: %08" PRIx32,
-                           be64toh(state->id), ntohl(state->creatorid));
-                       if (state->sync_flags & PFSTATE_FROMSYNC)
+                           "id: %016llx creatorid: %08x",
+                           be64toh(s->id), ntohl(s->creatorid));
+                       if (s->sync_flags & PFSTATE_FROMSYNC)
                                kprintf(" (from sync)");
                        kprintf("\n");
                }
-               RB_REMOVE(pf_state_tree_lan_ext, &kif->pfik_lan_ext, state);
-               RB_REMOVE(pf_state_tree_ext_gwy, &kif->pfik_ext_gwy, state);
+               pf_detach_state(s, 0);
                return (-1);
        }
-       TAILQ_INSERT_TAIL(&state_list, state, u.s.entry_list);
+       TAILQ_INSERT_TAIL(&state_list, sentry_list);
        pf_status.fcounters[FCNT_STATE_INSERT]++;
        pf_status.states++;
        pfi_kif_ref(kif, PFI_KIF_REF_STATE);
 #if NPFSYNC
-       pfsync_insert_state(state);
+       pfsync_insert_state(s);
 #endif
        return (0);
 }
@@ -1009,7 +1013,7 @@ pf_src_tree_remove_state(struct pf_state *s)
        u_int32_t timeout;
 
        if (s->src_node != NULL) {
-               if (s->proto == IPPROTO_TCP) {
+               if (s->state_key->proto == IPPROTO_TCP) {
                        if (s->src.tcp_est)
                                --s->src_node->conn;
                }
@@ -1038,16 +1042,12 @@ void
 pf_unlink_state(struct pf_state *cur)
 {
        if (cur->src.state == PF_TCPS_PROXY_DST) {
-               pf_send_tcp(cur->rule.ptr, cur->af,
-                   &cur->ext.addr, &cur->lan.addr,
-                   cur->ext.port, cur->lan.port,
+               pf_send_tcp(cur->rule.ptr, cur->state_key->af,
+                   &cur->state_key->ext.addr, &cur->state_key->lan.addr,
+                   cur->state_key->ext.port, cur->state_key->lan.port,
                    cur->src.seqhi, cur->src.seqlo + 1,
                    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
        if (cur->creatorid == pf_status.hostid)
@@ -1055,6 +1055,7 @@ pf_unlink_state(struct pf_state *cur)
 #endif
        cur->timeout = PFTM_UNLINKED;
        pf_src_tree_remove_state(cur);
+       pf_detach_state(cur, 0);
 }
 
 /* callers should be at crit_enter() and hold the
@@ -1080,8 +1081,8 @@ pf_free_state(struct pf_state *cur)
                if (--cur->anchor.ptr->states <= 0)
                        pf_rm_rule(NULL, cur->anchor.ptr);
        pf_normalize_tcp_cleanup(cur);
-       pfi_kif_unref(cur->u.s.kif, PFI_KIF_REF_STATE);
-       TAILQ_REMOVE(&state_list, cur, u.s.entry_list);
+       pfi_kif_unref(cur->kif, PFI_KIF_REF_STATE);
+       TAILQ_REMOVE(&state_list, cur, entry_list);
        if (cur->tag)
                pf_tag_unref(cur->tag);
        pool_put(&pf_state_pl, cur);
@@ -1105,7 +1106,7 @@ pf_purge_expired_states(u_int32_t maxcheck, int waslocked)
                }
 
                /* get next state, as cur may get deleted */
-               next = TAILQ_NEXT(cur, u.s.entry_list);
+               next = TAILQ_NEXT(cur, entry_list);
 
                if (cur->timeout == PFTM_UNLINKED) {
                        /* free unlinked state */
@@ -1232,7 +1233,8 @@ pf_print_host(struct pf_addr *addr, u_int16_t p, sa_family_t af)
 void
 pf_print_state(struct pf_state *s)
 {
-       switch (s->proto) {
+       struct pf_state_key *sk = s->state_key;
+       switch (sk->proto) {
        case IPPROTO_TCP:
                kprintf("TCP ");
                break;
@@ -1246,14 +1248,14 @@ pf_print_state(struct pf_state *s)
                kprintf("ICMPV6 ");
                break;
        default:
-               kprintf("%u ", s->proto);
+               kprintf("%u ", sk->proto);
                break;
        }
-       pf_print_host(&s->lan.addr, s->lan.port, s->af);
+       pf_print_host(&sk->lan.addr, sk->lan.port, sk->af);
        kprintf(" ");
-       pf_print_host(&s->gwy.addr, s->gwy.port, s->af);
+       pf_print_host(&sk->gwy.addr, sk->gwy.port, sk->af);
        kprintf(" ");
-       pf_print_host(&s->ext.addr, s->ext.port, s->af);
+       pf_print_host(&sk->ext.addr, sk->ext.port, sk->af);
        kprintf(" [lo=%u high=%u win=%u modulator=%u", s->src.seqlo,
            s->src.seqhi, s->src.max_win, s->src.seqdiff);
        if (s->src.wscale && s->dst.wscale)
@@ -1622,7 +1624,6 @@ pf_send_tcp(const struct pf_rule *r, sa_family_t af,
 #endif /* INET6 */
        struct tcphdr   *th = NULL;
        char            *opt;
-       struct pf_mtag  *pf_mtag;
 
        /* maximum segment size tcp option */
        tlen = sizeof(struct tcphdr);
@@ -1646,24 +1647,19 @@ pf_send_tcp(const struct pf_rule *r, sa_family_t af,
        m = m_gethdr(MB_DONTWAIT, MT_HEADER);
        if (m == NULL)
                return;
-       if ((pf_mtag = pf_get_mtag(m)) == NULL) {
-               m_freem(m);
-               return;
-       }
        if (tag)
-               pf_mtag->flags |= PF_TAG_GENERATED;
-
-       pf_mtag->tag = rtag;
+               m->m_pkthdr.pf.flags |= PF_TAG_GENERATED;
+       m->m_pkthdr.pf.tag = rtag;
 
        if (r != NULL && r->rtableid >= 0)
-               pf_mtag->rtableid = r->rtableid;
+               m->m_pkthdr.pf.rtableid = m->m_pkthdr.pf.rtableid;
 
 #ifdef ALTQ
        if (r != NULL && r->qid) {
-               pf_mtag->qid = r->qid;
-               /* add hints for ecn */
-               pf_mtag->af = af;
-               pf_mtag->hdr = mtod(m, struct ip *);
+               m->m_pkthdr.fw_flags |= PF_MBUF_STRUCTURE;
+               m->m_pkthdr.pf.qid = r->qid;
+               m->m_pkthdr.pf.ecn_af = af;
+               m->m_pkthdr.pf.hdr = mtod(m, struct ip *);
        }
 #endif /* ALTQ */
        m->m_data += max_linkhdr;
@@ -1773,24 +1769,20 @@ void
 pf_send_icmp(struct mbuf *m, u_int8_t type, u_int8_t code, sa_family_t af,
     struct pf_rule *r)
 {
-       struct pf_mtag  *pf_mtag;
        struct mbuf     *m0;
 
        m0 = m_copy(m, 0, M_COPYALL);
-
-       if ((pf_mtag = pf_get_mtag(m0)) == NULL)
-               return;
-       pf_mtag->flags |= PF_TAG_GENERATED;
+       m0->m_pkthdr.pf.flags |= PF_TAG_GENERATED;
 
        if (r->rtableid >= 0)
-               pf_mtag->rtableid = r->rtableid;
+               m0->m_pkthdr.pf.rtableid = r->rtableid;
 
 #ifdef ALTQ
        if (r->qid) {
-               pf_mtag->qid = r->qid;
-               /* add hints for ecn */
-               pf_mtag->af = af;
-               pf_mtag->hdr = mtod(m0, struct ip *);
+               m->m_pkthdr.fw_flags |= PF_MBUF_STRUCTURE;
+               m0->m_pkthdr.pf.qid = r->qid;
+               m0->m_pkthdr.pf.ecn_af = af;
+               m0->m_pkthdr.pf.hdr = mtod(m0, struct ip *);
        }
 #endif /* ALTQ */
 
@@ -1905,63 +1897,31 @@ pf_match_gid(u_int8_t op, gid_t a1, gid_t a2, gid_t g)
        return (pf_match(op, a1, a2, g));
 }
 
-struct pf_mtag *
-pf_find_mtag(struct mbuf *m)
-{
-       struct m_tag    *mtag;
-
-       if ((mtag = m_tag_find(m, PF_MBUF_TAGGED, NULL)) == NULL)
-               return (NULL);
-
-       return ((struct pf_mtag *)(mtag + 1));
-}
-
-struct pf_mtag *
-pf_get_mtag(struct mbuf *m)
-{
-       struct m_tag    *mtag;
-
-       if ((mtag = m_tag_find(m, PF_MBUF_TAGGED, NULL)) == NULL) {
-               mtag = m_tag_get(PF_MBUF_TAGGED, 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));
-}
-
 int
-pf_match_tag(struct mbuf *m, struct pf_rule *r, struct pf_mtag *pf_mtag,
-    int *tag)
+pf_match_tag(struct mbuf *m, struct pf_rule *r, int *tag)
 {
        if (*tag == -1)
-               *tag = pf_mtag->tag;
+               *tag = m->m_pkthdr.pf.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_mtag *pf_mtag, int tag, int rtableid)
+pf_tag_packet(struct mbuf *m, int tag, int rtableid)
 {
        if (tag <= 0 && rtableid < 0)
                return (0);
 
-       if (pf_mtag == NULL)
-               if ((pf_mtag = pf_get_mtag(m)) == NULL)
-                       return (1);
        if (tag > 0)
-               pf_mtag->tag = tag;
+               m->m_pkthdr.pf.tag = tag;
        if (rtableid >= 0)
-               pf_mtag->rtableid = rtableid;
+               m->m_pkthdr.pf.rtableid = rtableid;
 
        return (0);
 }
 
-static void
+void
 pf_step_into_anchor(int *depth, struct pf_ruleset **rs, int n,
     struct pf_rule **r, struct pf_rule **a,  int *match)
 {
@@ -2336,7 +2296,7 @@ pf_get_sport(sa_family_t af, u_int8_t proto, struct pf_rule *r,
     struct pf_addr *naddr, u_int16_t *nport, u_int16_t low, u_int16_t high,
     struct pf_src_node **sn)
 {
-       struct pf_state_cmp     key;
+       struct pf_state_key_cmp key;
        struct pf_addr          init_addr;
        u_int16_t               cut;
 
@@ -2473,7 +2433,7 @@ pf_match_translation(struct pf_pdesc *pd, struct mbuf *m, int off,
                    !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, pd->pf_mtag, &tag))
+               else if (r->match_tag && !pf_match_tag(m, r, &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,
@@ -2494,7 +2454,7 @@ pf_match_translation(struct pf_pdesc *pd, struct mbuf *m, int off,
                        pf_step_out_of_anchor(&asd, &ruleset, rs_num, &r,
                            NULL, NULL);
        }
-       if (pf_tag_packet(m, pd->pf_mtag, tag, rtableid))
+       if (pf_tag_packet(m, tag, rtableid))
                return (NULL);
        if (rm != NULL && (rm->action == PF_NONAT ||
            rm->action == PF_NORDR || rm->action == PF_NOBINAT))
@@ -2627,6 +2587,7 @@ pf_get_translation(struct pf_pdesc *pd, struct mbuf *m, int off, int direction,
                                PF_POOLMASK(naddr, naddr,
                                    &r->rpool.cur->addr.v.a.mask, daddr,
                                    pd->af);
+
                        if (r->rpool.proxy_port[1]) {
                                u_int32_t       tmp_nport;
 
@@ -2684,7 +2645,7 @@ in_pcblookup_hash_handler(struct netmsg *msg0)
 #endif /* SMP */
 
 int
-pf_socket_lookup(int direction, struct pf_pdesc *pd, struct inpcb *inp_arg)
+pf_socket_lookup(int direction, struct pf_pdesc *pd)
 {
        struct pf_addr          *saddr, *daddr;
        u_int16_t                sport, dport;
@@ -2709,6 +2670,8 @@ pf_socket_lookup(int direction, struct pf_pdesc *pd, struct inpcb *inp_arg)
        }
        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;
 
@@ -2740,12 +2703,14 @@ pf_socket_lookup(int direction, struct pf_pdesc *pd, struct inpcb *inp_arg)
 #endif /* SMP */
                break;
        case IPPROTO_UDP:
+               if (pd->hdr.udp == NULL)
+                       return (-1);
                sport = pd->hdr.udp->uh_sport;
                dport = pd->hdr.udp->uh_dport;
                pi = &udbinfo;
                break;
        default:
-               return (0);
+               return (-1);
        }
        if (direction != PF_IN) {
                u_int16_t       p;
@@ -2791,7 +2756,7 @@ pf_socket_lookup(int direction, struct pf_pdesc *pd, struct inpcb *inp_arg)
                            dport, INPLOOKUP_WILDCARD, NULL);
                }
                if (inp == NULL)
-                       return (0);
+                       return (-1);
                break;
 
        default:
@@ -2866,7 +2831,6 @@ pf_get_mss(struct mbuf *m, int off, u_int16_t th_off, sa_family_t af)
                        break;
                case TCPOPT_MAXSEG:
                        bcopy((caddr_t)(opt + 2), (caddr_t)&mss, 2);
-                       NTOHS(mss);
                        /* FALLTHROUGH */
                default:
                        optlen = opt[1];
@@ -2940,7 +2904,7 @@ pf_set_rt_ifp(struct pf_state *s, struct pf_addr *saddr)
        s->rt_kif = NULL;
        if (!r->rt || r->rt == PF_FASTROUTE)
                return;
-       switch (s->af) {
+       switch (s->state_key->af) {
 #ifdef INET
        case AF_INET:
                pf_map_addr(AF_INET, r, saddr, &s->rt_addr, NULL,
@@ -2958,68 +2922,249 @@ pf_set_rt_ifp(struct pf_state *s, struct pf_addr *saddr)
        }
 }
 
+void
+pf_attach_state(struct pf_state_key *sk, struct pf_state *s, int tail)
+{
+       s->state_key = sk;
+       sk->refcnt++;
+
+       /* list is sorted, if-bound states before floating */
+       if (tail)
+               TAILQ_INSERT_TAIL(&sk->states, s, next);
+       else
+               TAILQ_INSERT_HEAD(&sk->states, s, next);
+}
+
+void
+pf_detach_state(struct pf_state *s, int flags)
+{
+       struct pf_state_key     *sk = s->state_key;
+
+       if (sk == NULL)
+               return;
+
+       s->state_key = NULL;
+       TAILQ_REMOVE(&sk->states, s, next);
+       if (--sk->refcnt == 0) {
+               if (!(flags & PF_DT_SKIP_EXTGWY))
+                       RB_REMOVE(pf_state_tree_ext_gwy,
+                           &pf_statetbl_ext_gwy, sk);
+               if (!(flags & PF_DT_SKIP_LANEXT))
+                       RB_REMOVE(pf_state_tree_lan_ext,
+                           &pf_statetbl_lan_ext, sk);
+               pool_put(&pf_state_key_pl, sk);
+       }
+}
+
+struct pf_state_key *
+pf_alloc_state_key(struct pf_state *s)
+{
+       struct pf_state_key     *sk;
+
+       if ((sk = pool_get(&pf_state_key_pl, PR_NOWAIT)) == NULL)
+               return (NULL);
+       bzero(sk, sizeof(*sk));
+       TAILQ_INIT(&sk->states);
+       pf_attach_state(sk, s, 0);
+
+       return (sk);
+}
+
 int
-pf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction,
+pf_test_rule(struct pf_rule **rm, struct pf_state **sm, int direction,
     struct pfi_kif *kif, struct mbuf *m, int off, void *h,
     struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm,
     struct ifqueue *ifq, struct inpcb *inp)
 {
        struct pf_rule          *nr = NULL;
        struct pf_addr          *saddr = pd->src, *daddr = pd->dst;
-       struct tcphdr           *th = pd->hdr.tcp;
        u_int16_t                bport, nport = 0;
        sa_family_t              af = pd->af;
        struct pf_rule          *r, *a = NULL;
        struct pf_ruleset       *ruleset = NULL;
        struct pf_src_node      *nsn = NULL;
+       struct tcphdr           *th = pd->hdr.tcp;
        u_short                  reason;
-       int                      rewrite = 0;
+       int                      rewrite = 0, hdrlen = 0;
        int                      tag = -1, rtableid = -1;
-       u_int16_t                mss = tcp_mssdflt;
        int                      asd = 0;
        int                      match = 0;
+       int                      state_icmp = 0;
+       u_int16_t                mss = tcp_mssdflt;
+       u_int16_t                sport, dport;
+       u_int8_t                 icmptype = 0, icmpcode = 0;
 
-       if (pf_check_congestion(ifq)) {
+       if (direction == PF_IN && pf_check_congestion(ifq)) {
                REASON_SET(&reason, PFRES_CONGEST);
                return (PF_DROP);
        }
 
        if (inp != NULL)
-               pd->lookup.done = pf_socket_lookup(direction, pd, inp);
-       else if (debug_pfugidhack) {
+               pd->lookup.done = pf_socket_lookup(direction, pd);
+       else if (debug_pfugidhack) { 
                crit_exit();
                DPFPRINTF(PF_DEBUG_MISC, ("pf: unlocked lookup\n"));
-               pd->lookup.done = pf_socket_lookup(direction, pd, inp);
+               pd->lookup.done = pf_socket_lookup(direction, pd);
                crit_enter();
        }
-       
+
+       sport = dport = hdrlen = 0;
+
+       switch (pd->proto) {
+       case IPPROTO_TCP:
+               sport = th->th_sport;
+               dport = th->th_dport;
+               hdrlen = sizeof(*th);
+               break;
+       case IPPROTO_UDP:
+               sport = pd->hdr.udp->uh_sport;
+               dport = pd->hdr.udp->uh_dport;
+               hdrlen = sizeof(*pd->hdr.udp);
+               break;
+#ifdef INET
+       case IPPROTO_ICMP:
+               if (pd->af != AF_INET)
+                       break;
+               sport = dport = pd->hdr.icmp->icmp_id;
+               icmptype = pd->hdr.icmp->icmp_type;
+               icmpcode = pd->hdr.icmp->icmp_code;
+
+               if (icmptype == ICMP_UNREACH ||
+                   icmptype == ICMP_SOURCEQUENCH ||
+                   icmptype == ICMP_REDIRECT ||
+                   icmptype == ICMP_TIMXCEED ||
+                   icmptype == ICMP_PARAMPROB)
+                       state_icmp++;
+               break;
+#endif /* INET */
+#ifdef INET6
+       case IPPROTO_ICMPV6:
+               if (pd->af != AF_INET6)
+                       break;
+               sport = dport = pd->hdr.icmp6->icmp6_id;
+               hdrlen = sizeof(*pd->hdr.icmp6);
+               icmptype = pd->hdr.icmp6->icmp6_type;
+               icmpcode = pd->hdr.icmp6->icmp6_code;
+
+               if (icmptype == ICMP6_DST_UNREACH ||
+                   icmptype == ICMP6_PACKET_TOO_BIG ||
+                   icmptype == ICMP6_TIME_EXCEEDED ||
+                   icmptype == ICMP6_PARAM_PROB)
+                       state_icmp++;
+               break;
+#endif /* INET6 */
+       }
 
        r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr);
 
        if (direction == PF_OUT) {
-               bport = nport = th->th_sport;
+               bport = nport = sport;
                /* check outgoing packet for BINAT/NAT */
                if ((nr = pf_get_translation(pd, m, off, PF_OUT, kif, &nsn,
-                   saddr, th->th_sport, daddr, th->th_dport,
-                   &pd->naddr, &nport)) != NULL) {
+                   saddr, sport, daddr, dport, &pd->naddr, &nport)) != NULL) {
                        PF_ACPY(&pd->baddr, saddr, af);
-                       pf_change_ap(saddr, &th->th_sport, pd->ip_sum,
-                           &th->th_sum, &pd->naddr, nport, 0, af);
-                       rewrite++;
+                       switch (pd->proto) {
+                       case IPPROTO_TCP:
+                               pf_change_ap(saddr, &th->th_sport, pd->ip_sum,
+                                   &th->th_sum, &pd->naddr, nport, 0, af);
+                               sport = th->th_sport;
+                               rewrite++;
+                               break;
+                       case IPPROTO_UDP:
+                               pf_change_ap(saddr, &pd->hdr.udp->uh_sport,
+                                   pd->ip_sum, &pd->hdr.udp->uh_sum,
+                                   &pd->naddr, nport, 1, af);
+                               sport = pd->hdr.udp->uh_sport;
+                               rewrite++;
+                               break;
+#ifdef INET
+                       case IPPROTO_ICMP:
+                               pf_change_a(&saddr->v4.s_addr, pd->ip_sum,
+                                   pd->naddr.v4.s_addr, 0);
+                               pd->hdr.icmp->icmp_cksum = pf_cksum_fixup(
+                                   pd->hdr.icmp->icmp_cksum, sport, nport, 0);
+                               pd->hdr.icmp->icmp_id = nport;
+                               m_copyback(m, off, ICMP_MINLEN, (caddr_t)pd->hdr.icmp);
+                               break;
+#endif /* INET */
+#ifdef INET6
+                       case IPPROTO_ICMPV6:
+                               pf_change_a6(saddr, &pd->hdr.icmp6->icmp6_cksum,
+                                   &pd->naddr, 0);
+                               rewrite++;
+                               break;
+#endif /* INET */
+                       default:
+                               switch (af) {
+#ifdef INET
+                               case AF_INET:
+                                       pf_change_a(&saddr->v4.s_addr,
+                                           pd->ip_sum, pd->naddr.v4.s_addr, 0);
+                                       break;
+#endif /* INET */
+#ifdef INET6
+                               case AF_INET6:
+                                       PF_ACPY(saddr, &pd->naddr, af);
+                                       break;
+#endif /* INET */
+                               }
+                               break;
+                       }
+
                        if (nr->natpass)
                                r = NULL;
                        pd->nat_rule = nr;
                }
        } else {
-               bport = nport = th->th_dport;
+               bport = nport = dport;
                /* check incoming packet for BINAT/RDR */
                if ((nr = pf_get_translation(pd, m, off, PF_IN, kif, &nsn,
-                   saddr, th->th_sport, daddr, th->th_dport,
-                   &pd->naddr, &nport)) != NULL) {
+                   saddr, sport, daddr, dport, &pd->naddr, &nport)) != NULL) {
                        PF_ACPY(&pd->baddr, daddr, af);
-                       pf_change_ap(daddr, &th->th_dport, pd->ip_sum,
-                           &th->th_sum, &pd->naddr, nport, 0, af);
-                       rewrite++;
+                       switch (pd->proto) {
+                       case IPPROTO_TCP:
+                               pf_change_ap(daddr, &th->th_dport, pd->ip_sum,
+                                   &th->th_sum, &pd->naddr, nport, 0, af);
+                               dport = th->th_dport;
+                               rewrite++;
+                               break;
+                       case IPPROTO_UDP:
+                               pf_change_ap(daddr, &pd->hdr.udp->uh_dport,
+                                   pd->ip_sum, &pd->hdr.udp->uh_sum,
+                                   &pd->naddr, nport, 1, af);
+                               dport = pd->hdr.udp->uh_dport;
+                               rewrite++;
+                               break;
+#ifdef INET
+                       case IPPROTO_ICMP:
+                               pf_change_a(&daddr->v4.s_addr, pd->ip_sum,
+                                   pd->naddr.v4.s_addr, 0);
+                               break;
+#endif /* INET */
+#ifdef INET6
+                       case IPPROTO_ICMPV6:
+                               pf_change_a6(daddr, &pd->hdr.icmp6->icmp6_cksum,
+                                   &pd->naddr, 0);
+                               rewrite++;
+                               break;
+#endif /* INET6 */
+                       default:
+                               switch (af) {
+#ifdef INET
+                               case AF_INET:
+                                       pf_change_a(&daddr->v4.s_addr,
+                                           pd->ip_sum, pd->naddr.v4.s_addr, 0);
+                                       break;
+#endif /* INET */
+#ifdef INET6
+                               case AF_INET6:
+                                       PF_ACPY(daddr, &pd->naddr, af);
+                                       break;
+#endif /* INET */
+                               }
+                               break;
+                       }
+
                        if (nr->natpass)
                                r = NULL;
                        pd->nat_rule = nr;
@@ -3034,42 +3179,55 @@ pf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction,
                        r = r->skip[PF_SKIP_DIR].ptr;
                else if (r->af && r->af != af)
                        r = r->skip[PF_SKIP_AF].ptr;
-               else if (r->proto && r->proto != IPPROTO_TCP)
+               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, kif))
                        r = r->skip[PF_SKIP_SRC_ADDR].ptr;
+               /* tcp/udp only. port_op always 0 in other cases */
                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->src.port[0], r->src.port[1], sport))
                        r = r->skip[PF_SKIP_SRC_PORT].ptr;
                else if (PF_MISMATCHAW(&r->dst.addr, daddr, af,
                    r->dst.neg, NULL))
                        r = r->skip[PF_SKIP_DST_ADDR].ptr;
+               /* tcp/udp only. port_op always 0 in other cases */
                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->dst.port[0], r->dst.port[1], dport))
                        r = r->skip[PF_SKIP_DST_PORT].ptr;
+               /* icmp only. type always 0 in other cases */
+               else if (r->type && r->type != icmptype + 1)
+                       r = TAILQ_NEXT(r, entries);
+               /* icmp only. type always 0 in other cases */
+               else if (r->code && r->code != icmpcode + 1)
+                       r = TAILQ_NEXT(r, entries);
                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)
+               else if (pd->proto == IPPROTO_TCP &&
+                   (r->flagset & th->th_flags) != r->flags)
                        r = TAILQ_NEXT(r, entries);
+               /* tcp/udp only. uid.op always 0 in other cases */
                else if (r->uid.op && (pd->lookup.done || (pd->lookup.done =
-                   pf_socket_lookup(direction, pd, inp), 1)) &&
+                   pf_socket_lookup(direction, pd), 1)) &&
                    !pf_match_uid(r->uid.op, r->uid.uid[0], r->uid.uid[1],
                    pd->lookup.uid))
                        r = TAILQ_NEXT(r, entries);
+               /* tcp/udp only. gid.op always 0 in other cases */
                else if (r->gid.op && (pd->lookup.done || (pd->lookup.done =
-                   pf_socket_lookup(direction, pd, inp), 1)) &&
+                   pf_socket_lookup(direction, pd), 1)) &&
                    !pf_match_gid(r->gid.op, r->gid.gid[0], r->gid.gid[1],
                    pd->lookup.gid))
                        r = TAILQ_NEXT(r, entries);
                else if (r->prob && r->prob <= karc4random())
                        r = TAILQ_NEXT(r, entries);
-               else if (r->match_tag && !pf_match_tag(m, r, pd->pf_mtag, &tag))
+               else if (r->match_tag && !pf_match_tag(m, r, &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))
+               else if (r->os_fingerprint != PF_OSFP_ANY &&
+                   (pd->proto != IPPROTO_TCP || !pf_osfp_match(
+                   pf_osfp_fingerprint(pd, m, off, th),
+                   r->os_fingerprint)))
                        r = TAILQ_NEXT(r, entries);
                else {
                        if (r->tag)
@@ -3098,9 +3256,9 @@ pf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction,
 
        REASON_SET(&reason, PFRES_MATCH);
 
-       if (r->log || (nr != NULL && nr->natpass && nr->log)) {
+       if (r->log || (nr != NULL && nr->log)) {
                if (rewrite)
-                       m_copyback(m, off, sizeof(*th), (caddr_t)th);
+                       m_copyback(m, off, hdrlen, pd->hdr.any);
                PFLOG_PACKET(kif, h, m, af, direction, reason, r->log ? r : nr,
                    a, ruleset, pd);
        }
@@ -3112,28 +3270,97 @@ pf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction,
                /* undo NAT changes, if they have taken place */
                if (nr != NULL) {
                        if (direction == PF_OUT) {
-                               pf_change_ap(saddr, &th->th_sport, pd->ip_sum,
-                                   &th->th_sum, &pd->baddr, bport, 0, af);
-                               rewrite++;
+                               switch (pd->proto) {
+                               case IPPROTO_TCP:
+                                       pf_change_ap(saddr, &th->th_sport,
+                                           pd->ip_sum, &th->th_sum,
+                                           &pd->baddr, bport, 0, af);
+                                       sport = th->th_sport;
+                                       rewrite++;
+                                       break;
+                               case IPPROTO_UDP:
+                                       pf_change_ap(saddr,
+                                           &pd->hdr.udp->uh_sport, pd->ip_sum,
+                                           &pd->hdr.udp->uh_sum, &pd->baddr,
+                                           bport, 1, af);
+                                       sport = pd->hdr.udp->uh_sport;
+                                       rewrite++;
+                                       break;
+                               case IPPROTO_ICMP:
+#ifdef INET6
+                               case IPPROTO_ICMPV6:
+#endif
+                                       /* nothing! */
+                                       break;
+                               default:
+                                       switch (af) {
+                                       case AF_INET:
+                                               pf_change_a(&saddr->v4.s_addr,
+                                                   pd->ip_sum,
+                                                   pd->baddr.v4.s_addr, 0);
+                                               break;
+                                       case AF_INET6:
+                                               PF_ACPY(saddr, &pd->baddr, af);
+                                               break;
+                                       }
+                               }
                        } else {
-                               pf_change_ap(daddr, &th->th_dport, pd->ip_sum,
-                                   &th->th_sum, &pd->baddr, bport, 0, af);
-                               rewrite++;
+                               switch (pd->proto) {
+                               case IPPROTO_TCP:
+                                       pf_change_ap(daddr, &th->th_dport,
+                                           pd->ip_sum, &th->th_sum,
+                                           &pd->baddr, bport, 0, af);
+                                       dport = th->th_dport;
+                                       rewrite++;
+                                       break;
+                               case IPPROTO_UDP:
+                                       pf_change_ap(daddr,
+                                           &pd->hdr.udp->uh_dport, pd->ip_sum,
+                                           &pd->hdr.udp->uh_sum, &pd->baddr,
+                                           bport, 1, af);
+                                       dport = pd->hdr.udp->uh_dport;
+                                       rewrite++;
+                                       break;
+                               case IPPROTO_ICMP:
+#ifdef INET6
+                               case IPPROTO_ICMPV6:
+#endif
+                                       /* nothing! */
+                                       break;
+                               default:
+                                       switch (af) {
+                                       case AF_INET:
+                                               pf_change_a(&daddr->v4.s_addr,
+                                                   pd->ip_sum,
+                                                   pd->baddr.v4.s_addr, 0);
+                                               break;
+                                       case AF_INET6:
+                                               PF_ACPY(daddr, &pd->baddr, af);
+                                               break;
+                                       }
+                               }
                        }
                }
-               if (((r->rule_flag & PFRULE_RETURNRST) ||
+               if (pd->proto == IPPROTO_TCP &&
+                   ((r->rule_flag & PFRULE_RETURNRST) ||
                    (r->rule_flag & PFRULE_RETURN)) &&
                    !(th->th_flags & TH_RST)) {
-                       u_int32_t ack = ntohl(th->th_seq) + pd->p_len;
+                       u_int32_t        ack = ntohl(th->th_seq) + pd->p_len;
+                       struct ip       *h = mtod(m, struct ip *);
 
-                       if (th->th_flags & TH_SYN)
-                               ack++;
-                       if (th->th_flags & TH_FIN)
-                               ack++;
-                       pf_send_tcp(r, af, pd->dst,
-                           pd->src, th->th_dport, th->th_sport,
-                           ntohl(th->th_ack), ack, TH_RST|TH_ACK, 0, 0,
-                           r->return_ttl, 1, 0, pd->eh, kif->pfik_ifp);
+                       if (pf_check_proto_cksum(m, off,
+                           h->ip_len - off, IPPROTO_TCP, AF_INET))
+                               REASON_SET(&reason, PFRES_PROTCKSUM);
+                       else {
+                               if (th->th_flags & TH_SYN)
+                                       ack++;
+                               if (th->th_flags & TH_FIN)
+                                       ack++;
+                               pf_send_tcp(r, af, pd->dst,
+                                   pd->src, th->th_dport, th->th_sport,
+                                   ntohl(th->th_ack), ack, TH_RST|TH_ACK, 0, 0,
+                                   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);
@@ -3142,24 +3369,22 @@ pf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction,
                            r->return_icmp6 & 255, af, r);
        }
 
-       if (r->action == PF_DROP) {
+       if (r->action == PF_DROP)
                return (PF_DROP);
-       }
 
-       if (pf_tag_packet(m, pd->pf_mtag, tag, rtableid)) {
+       if (pf_tag_packet(m, tag, rtableid)) {
                REASON_SET(&reason, PFRES_MEMORY);
                return (PF_DROP);
        }
 
-       if (r->keep_state || nr != NULL ||
-           (pd->flags & PFDESC_TCP_NORM)) {
+       if (!state_icmp && (r->keep_state || nr != NULL ||
+           (pd->flags & PFDESC_TCP_NORM))) {
                /* create new state */
-               u_int16_t        len;
+               u_int16_t        len = 0;
                struct pf_state *s = NULL;
+               struct pf_state_key *sk = NULL;
                struct pf_src_node *sn = NULL;
 
-               len = pd->tot_len - off - (th->th_off << 2);
-
                /* check maximums */
                if (r->max_states && (r->states >= r->max_states)) {
                        pf_status.lcounters[LCNT_STATES]++;
@@ -3198,6 +3423,9 @@ cleanup:
                                pf_status.src_nodes--;
                                pool_put(&pf_src_tree_pl, nsn);
                        }
+                       if (sk != NULL) {
+                               pool_put(&pf_state_key_pl, sk);
+                       }
                        return (PF_DROP);
                }
                bzero(s, sizeof(*s));
@@ -3209,994 +3437,63 @@ cleanup:
                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;
-               if (direction == PF_OUT) {
-                       PF_ACPY(&s->gwy.addr, saddr, af);
-                       s->gwy.port = th->th_sport;             /* sport */
-                       PF_ACPY(&s->ext.addr, daddr, af);
-                       s->ext.port = th->th_dport;
-                       if (nr != NULL) {
-                               PF_ACPY(&s->lan.addr, &pd->baddr, af);
-                               s->lan.port = bport;
-                       } else {
-                               PF_ACPY(&s->lan.addr, &s->gwy.addr, af);
-                               s->lan.port = s->gwy.port;
+               switch (pd->proto) {
+               case IPPROTO_TCP:
+                       len = pd->tot_len - off - (th->th_off << 2);
+                       s->src.seqlo = ntohl(th->th_seq);
+                       s->src.seqhi = s->src.seqlo + len + 1;
+                       if ((th->th_flags & (TH_SYN|TH_ACK)) ==
+                       TH_SYN && r->keep_state == PF_STATE_MODULATE) {
+                               /* Generate sequence number modulator */
+                               while ((s->src.seqdiff =
+                                   pf_new_isn(sk) - s->src.seqlo) == 0)
+                                       ;
+                               pf_change_a(&th->th_seq, &th->th_sum,
+                                   htonl(s->src.seqlo + s->src.seqdiff), 0);
+                               rewrite = 1;
+                       } else
+                               s->src.seqdiff = 0;
+                       if (th->th_flags & TH_SYN) {
+                               s->src.seqhi++;
+                               s->src.wscale = pf_get_wscale(m, off,
+                                   th->th_off, af);
                        }
-               } else {
-                       PF_ACPY(&s->lan.addr, daddr, af);
-                       s->lan.port = th->th_dport;
-                       PF_ACPY(&s->ext.addr, saddr, af);
-                       s->ext.port = th->th_sport;
-                       if (nr != NULL) {
-                               PF_ACPY(&s->gwy.addr, &pd->baddr, af);
-                               s->gwy.port = bport;
-                       } else {
-                               PF_ACPY(&s->gwy.addr, &s->lan.addr, af);
-                               s->gwy.port = s->lan.port;
+                       s->src.max_win = MAX(ntohs(th->th_win), 1);
+                       if (s->src.wscale & PF_WSCALE_MASK) {
+                               /* Remove scale factor from initial window */
+                               int win = s->src.max_win;
+                               win += 1 << (s->src.wscale & PF_WSCALE_MASK);
+                               s->src.max_win = (win - 1) >>
+                                   (s->src.wscale & PF_WSCALE_MASK);
                        }
-               }
-
-               s->hash = pf_state_hash(s);
-               s->src.seqlo = ntohl(th->th_seq);
-               s->src.seqhi = s->src.seqlo + len + 1;
-               s->pickup_mode = r->pickup_mode;
-
-               if ((th->th_flags & (TH_SYN|TH_ACK)) == TH_SYN &&
-                   r->keep_state == PF_STATE_MODULATE) {
-                       /* Generate sequence number modulator */
-                       while ((s->src.seqdiff =
-                           pf_new_isn(s) - s->src.seqlo) == 0)
-                               ;
-                       pf_change_a(&th->th_seq, &th->th_sum,
-                           htonl(s->src.seqlo + s->src.seqdiff), 0);
-                       rewrite = 1;
-               } else
-                       s->src.seqdiff = 0;
-               if (th->th_flags & TH_SYN) {
-                       s->src.seqhi++;
-                       s->src.wscale = pf_get_wscale(m, off, th->th_off, af);
-                       s->sync_flags |= PFSTATE_GOT_SYN1;
-               }
-               s->src.max_win = MAX(ntohs(th->th_win), 1);
-               if (s->src.wscale & PF_WSCALE_MASK) {
-                       /* Remove scale factor from initial window */
-                       u_int win = s->src.max_win;
-                       win += 1 << (s->src.wscale & PF_WSCALE_MASK);
-                       s->src.max_win = (win - 1) >>
-                           (s->src.wscale & PF_WSCALE_MASK);
-               }
-               if (th->th_flags & TH_FIN)
-                       s->src.seqhi++;
-               s->dst.seqhi = 1;
-               s->dst.max_win = 1;
-               s->src.state = TCPS_SYN_SENT;
-               s->dst.state = TCPS_CLOSED;
-               s->creation = time_second;
-               s->expire = time_second;
-               s->timeout = PFTM_TCP_FIRST_PACKET;
-               pf_set_rt_ifp(s, saddr);
-               if (sn != NULL) {
-                       s->src_node = sn;
-                       s->src_node->states++;
-               }
-               if (nsn != NULL) {
-                       PF_ACPY(&nsn->raddr, &pd->naddr, af);
-                       s->nat_src_node = nsn;
-                       s->nat_src_node->states++;
-               }
-               if ((pd->flags & PFDESC_TCP_NORM) && pf_normalize_tcp_init(m,
-                   off, pd, th, &s->src, &s->dst)) {
-                       REASON_SET(&reason, PFRES_MEMORY);
-                       pf_src_tree_remove_state(s);
-                       STATE_DEC_COUNTERS(s);
-                       pool_put(&pf_state_pl, s);
-                       return (PF_DROP);
-               }
-               if ((pd->flags & PFDESC_TCP_NORM) && s->src.scrub &&
-                   pf_normalize_tcp_stateful(m, off, pd, &reason, th, s,
-                   &s->src, &s->dst, &rewrite)) {
-                       /* This really shouldn't happen!!! */
-                       DPFPRINTF(PF_DEBUG_URGENT,
-                           ("pf_normalize_tcp_stateful failed on first pkt"));
-                       pf_normalize_tcp_cleanup(s);
-                       pf_src_tree_remove_state(s);
-                       STATE_DEC_COUNTERS(s);
-                       pool_put(&pf_state_pl, s);
-                       return (PF_DROP);
-               }
-               if (pf_insert_state(BOUND_IFACE(r, kif), s)) {
-                       pf_normalize_tcp_cleanup(s);
-                       REASON_SET(&reason, PFRES_STATEINS);
-                       pf_src_tree_remove_state(s);
-                       STATE_DEC_COUNTERS(s);
-                       pool_put(&pf_state_pl, s);
-                       return (PF_DROP);
-               } else
-                       *sm = s;
-               if (tag > 0) {
-                       pf_tag_ref(tag);
-                       s->tag = tag;
-               }
-               if ((th->th_flags & (TH_SYN|TH_ACK)) == TH_SYN &&
-                   r->keep_state == PF_STATE_SYNPROXY) {
-                       s->src.state = PF_TCPS_PROXY_SRC;
-                       if (nr != NULL) {
-                               if (direction == PF_OUT) {
-                                       pf_change_ap(saddr, &th->th_sport,
-                                           pd->ip_sum, &th->th_sum, &pd->baddr,
-                                           bport, 0, af);
-                               } else {
-                                       pf_change_ap(daddr, &th->th_dport,
-                                           pd->ip_sum, &th->th_sum, &pd->baddr,
-                                           bport, 0, af);
-                               }
-                       }
-                       s->src.seqhi = htonl(karc4random());
-                       /* Find mss option */
-                       mss = pf_get_mss(m, off, th->th_off, af);
-                       mss = pf_calc_mss(saddr, af, mss);
-                       mss = pf_calc_mss(daddr, af, mss);
-                       s->src.mss = mss;
-                       pf_send_tcp(r, af, daddr, saddr, th->th_dport,
-                           th->th_sport, s->src.seqhi, ntohl(th->th_seq) + 1,
-                           TH_SYN|TH_ACK, 0, s->src.mss, 0, 1, 0, NULL, NULL);
-                       REASON_SET(&reason, PFRES_SYNPROXY);
-                       return (PF_SYNPROXY_DROP);
-               }
-       }
-
-       /* copy back packet headers if we performed NAT operations */
-       if (rewrite)
-               m_copyback(m, off, sizeof(*th), (caddr_t)th);
-
-       return (PF_PASS);
-}
-
-int
-pf_test_udp(struct pf_rule **rm, struct pf_state **sm, int direction,
-    struct pfi_kif *kif, struct mbuf *m, int off, void *h,
-    struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm,
-    struct ifqueue *ifq, struct inpcb *inp)
-{
-       struct pf_rule          *nr = NULL;
-       struct pf_addr          *saddr = pd->src, *daddr = pd->dst;
-       struct udphdr           *uh = pd->hdr.udp;
-       u_int16_t                bport, nport = 0;
-       sa_family_t              af = pd->af;
-       struct pf_rule          *r, *a = NULL;
-       struct pf_ruleset       *ruleset = NULL;
-       struct pf_src_node      *nsn = NULL;
-       u_short                  reason;
-       int                      rewrite = 0;
-       int                      tag = -1, rtableid = -1;
-       int                      asd = 0;
-       int                      match = 0;
-
-       if (pf_check_congestion(ifq)) {
-               REASON_SET(&reason, PFRES_CONGEST);
-               return (PF_DROP);
-       }
-
-       r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr);
-
-       if (direction == PF_OUT) {
-               bport = nport = uh->uh_sport;
-               /* check outgoing packet for BINAT/NAT */
-               if ((nr = pf_get_translation(pd, m, off, PF_OUT, kif, &nsn,
-                   saddr, uh->uh_sport, daddr, uh->uh_dport,
-                   &pd->naddr, &nport)) != NULL) {
-                       PF_ACPY(&pd->baddr, saddr, af);
-                       pf_change_ap(saddr, &uh->uh_sport, pd->ip_sum,
-                           &uh->uh_sum, &pd->naddr, nport, 1, af);
-                       rewrite++;
-                       if (nr->natpass)
-                               r = NULL;
-                       pd->nat_rule = nr;
-               }
-       } else {
-               bport = nport = uh->uh_dport;
-               /* check incoming packet for BINAT/RDR */
-               if ((nr = pf_get_translation(pd, m, off, PF_IN, kif, &nsn,
-                   saddr, uh->uh_sport, daddr, uh->uh_dport, &pd->naddr,
-                   &nport)) != NULL) {
-                       PF_ACPY(&pd->baddr, daddr, af);
-                       pf_change_ap(daddr, &uh->uh_dport, pd->ip_sum,
-                           &uh->uh_sum, &pd->naddr, nport, 1, af);
-                       rewrite++;
-                       if (nr->natpass)
-                               r = NULL;
-                       pd->nat_rule = nr;
-               }
-       }
-
-       while (r != NULL) {
-               r->evaluations++;
-               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;
-               else if (r->af && r->af != af)
-                       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, 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, 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))
-                       r = TAILQ_NEXT(r, entries);
-               else if (r->rule_flag & PFRULE_FRAGMENT)
-                       r = TAILQ_NEXT(r, entries);
-               else if (r->uid.op && (pd->lookup.done || (pd->lookup.done =
-                   pf_socket_lookup(direction, pd, inp), 1)) &&
-                   !pf_match_uid(r->uid.op, r->uid.uid[0], r->uid.uid[1],
-                   pd->lookup.uid))
-                       r = TAILQ_NEXT(r, entries);
-               else if (r->gid.op && (pd->lookup.done || (pd->lookup.done =
-                   pf_socket_lookup(direction, pd, inp), 1)) &&
-                   !pf_match_gid(r->gid.op, r->gid.gid[0], r->gid.gid[1],
-                   pd->lookup.gid))
-                       r = TAILQ_NEXT(r, entries);
-               else if (r->prob && r->prob <= karc4random())
-                       r = TAILQ_NEXT(r, entries);
-               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;
-                               if ((*rm)->quick)
-                                       break;
-                               r = TAILQ_NEXT(r, entries);
-                       } else
-                               pf_step_into_anchor(&asd, &ruleset,
-                                   PF_RULESET_FILTER, &r, &a, &match);
-               }
-               if (r == NULL && pf_step_out_of_anchor(&asd, &ruleset,
-                   PF_RULESET_FILTER, &r, &a, &match))
-                       break;
-       }
-       r = *rm;
-       a = *am;
-       ruleset = *rsm;
-
-       REASON_SET(&reason, PFRES_MATCH);
-
-       if (r->log || (nr != NULL && nr->natpass && nr->log)) {
-               if (rewrite)
-                       m_copyback(m, off, sizeof(*uh), (caddr_t)uh);
-               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) ||
-           (r->rule_flag & PFRULE_RETURN))) {
-               /* undo NAT changes, if they have taken place */
-               if (nr != NULL) {
-                       if (direction == PF_OUT) {
-                               pf_change_ap(saddr, &uh->uh_sport, pd->ip_sum,
-                                   &uh->uh_sum, &pd->baddr, bport, 1, af);
-                               rewrite++;
-                       } else {
-                               pf_change_ap(daddr, &uh->uh_dport, pd->ip_sum,
-                                   &uh->uh_sum, &pd->baddr, bport, 1, af);
-                               rewrite++;
-                       }
-               }
-               if ((af == AF_INET) && r->return_icmp)
-                       pf_send_icmp(m, r->return_icmp >> 8,
-                           r->return_icmp & 255, af, r);
-               else if ((af == AF_INET6) && r->return_icmp6)
-                       pf_send_icmp(m, r->return_icmp6 >> 8,
-                           r->return_icmp6 & 255, af, r);
-       }
-
-       if (r->action == PF_DROP)
-               return (PF_DROP);
-
-       if (pf_tag_packet(m, pd->pf_mtag, tag, rtableid)) {
-               REASON_SET(&reason, PFRES_MEMORY);
-               return (PF_DROP);
-       }
-
-       if (r->keep_state || nr != NULL) {
-               /* create new state */
-               struct pf_state *s = NULL;
-               struct pf_src_node *sn = NULL;
-
-               /* check maximums */
-               if (r->max_states && (r->states >= r->max_states)) {
-                       pf_status.lcounters[LCNT_STATES]++;
-                       REASON_SET(&reason, PFRES_MAXSTATES);
-                       goto cleanup;
-               }
-               /* 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) {
-                       REASON_SET(&reason, PFRES_SRCLIMIT);
-                       goto cleanup;
-               }
-               /* src node for translation rule */
-               if (nr != NULL && (nr->rpool.opts & PF_POOL_STICKYADDR) &&
-                   ((direction == PF_OUT &&
-                   pf_insert_src_node(&nsn, nr, &pd->baddr, af) != 0) ||
-                   (pf_insert_src_node(&nsn, nr, saddr, af) != 0))) {
-                       REASON_SET(&reason, PFRES_SRCLIMIT);
-                       goto cleanup;
-               }
-               s = pool_get(&pf_state_pl, PR_NOWAIT);
-               if (s == NULL) {
-                       REASON_SET(&reason, PFRES_MEMORY);
-cleanup:
-                       if (sn != NULL && sn->states == 0 && sn->expire == 0) {
-                               RB_REMOVE(pf_src_tree, &tree_src_tracking, sn);
-                               pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
-                               pf_status.src_nodes--;
-                               pool_put(&pf_src_tree_pl, sn);
-                       }
-                       if (nsn != sn && nsn != NULL && nsn->states == 0 &&
-                           nsn->expire == 0) {
-                               RB_REMOVE(pf_src_tree, &tree_src_tracking, nsn);
-                               pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
-                               pf_status.src_nodes--;
-                               pool_put(&pf_src_tree_pl, nsn);
-                       }
-                       return (PF_DROP);
-               }
-               bzero(s, sizeof(*s));
-               s->rule.ptr = r;
-               s->nat_rule.ptr = nr;
-               s->anchor.ptr = a;
-               STATE_INC_COUNTERS(s);
-               s->allow_opts = r->allow_opts;
-               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;
-               if (direction == PF_OUT) {
-                       PF_ACPY(&s->gwy.addr, saddr, af);
-                       s->gwy.port = uh->uh_sport;
-                       PF_ACPY(&s->ext.addr, daddr, af);
-                       s->ext.port = uh->uh_dport;
-                       if (nr != NULL) {
-                               PF_ACPY(&s->lan.addr, &pd->baddr, af);
-                               s->lan.port = bport;
-                       } else {
-                               PF_ACPY(&s->lan.addr, &s->gwy.addr, af);
-                               s->lan.port = s->gwy.port;
-                       }
-               } else {
-                       PF_ACPY(&s->lan.addr, daddr, af);
-                       s->lan.port = uh->uh_dport;
-                       PF_ACPY(&s->ext.addr, saddr, af);
-                       s->ext.port = uh->uh_sport;
-                       if (nr != NULL) {
-                               PF_ACPY(&s->gwy.addr, &pd->baddr, af);
-                               s->gwy.port = bport;
-                       } else {
-                               PF_ACPY(&s->gwy.addr, &s->lan.addr, af);
-                               s->gwy.port = s->lan.port;
-                       }
-               }
-               s->hash = pf_state_hash(s);
-               s->src.state = PFUDPS_SINGLE;
-               s->dst.state = PFUDPS_NO_TRAFFIC;
-               s->creation = time_second;
-               s->expire = time_second;
-               s->timeout = PFTM_UDP_FIRST_PACKET;
-               pf_set_rt_ifp(s, saddr);
-               if (sn != NULL) {
-                       s->src_node = sn;
-                       s->src_node->states++;
-               }
-               if (nsn != NULL) {
-                       PF_ACPY(&nsn->raddr, &pd->naddr, af);
-                       s->nat_src_node = nsn;
-                       s->nat_src_node->states++;
-               }
-               if (pf_insert_state(BOUND_IFACE(r, kif), s)) {
-                       REASON_SET(&reason, PFRES_STATEINS);
-                       pf_src_tree_remove_state(s);
-                       STATE_DEC_COUNTERS(s);
-                       pool_put(&pf_state_pl, s);
-                       return (PF_DROP);
-               } else
-                       *sm = s;
-               if (tag > 0) {
-                       pf_tag_ref(tag);
-                       s->tag = tag;
-               }
-       }
-
-       /* copy back packet headers if we performed NAT operations */
-       if (rewrite)
-               m_copyback(m, off, sizeof(*uh), (caddr_t)uh);
-
-       return (PF_PASS);
-}
-
-int
-pf_test_icmp(struct pf_rule **rm, struct pf_state **sm, int direction,
-    struct pfi_kif *kif, struct mbuf *m, int off, void *h,
-    struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm,
-    struct ifqueue *ifq)
-{
-       struct pf_rule          *nr = NULL;
-       struct pf_addr          *saddr = pd->src, *daddr = pd->dst;
-       struct pf_rule          *r, *a = NULL;
-       struct pf_ruleset       *ruleset = NULL;
-       struct pf_src_node      *nsn = NULL;
-       u_short                  reason;
-       u_int16_t                icmpid = 0, bport, nport = 0;
-       sa_family_t              af = pd->af;
-       u_int8_t                 icmptype = 0, icmpcode = 0;
-       int                      state_icmp = 0;
-       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);
-               return (PF_DROP);
-       }
-
-       switch (pd->proto) {
-#ifdef INET
-       case IPPROTO_ICMP:
-               icmptype = pd->hdr.icmp->icmp_type;
-               icmpcode = pd->hdr.icmp->icmp_code;
-               icmpid = pd->hdr.icmp->icmp_id;
-
-               if (icmptype == ICMP_UNREACH ||
-                   icmptype == ICMP_SOURCEQUENCH ||
-                   icmptype == ICMP_REDIRECT ||
-                   icmptype == ICMP_TIMXCEED ||
-                   icmptype == ICMP_PARAMPROB)
-                       state_icmp++;
-               break;
-#endif /* INET */
-#ifdef INET6
-       case IPPROTO_ICMPV6:
-               icmptype = pd->hdr.icmp6->icmp6_type;
-               icmpcode = pd->hdr.icmp6->icmp6_code;
-               icmpid = pd->hdr.icmp6->icmp6_id;
-
-               if (icmptype == ICMP6_DST_UNREACH ||
-                   icmptype == ICMP6_PACKET_TOO_BIG ||
-                   icmptype == ICMP6_TIME_EXCEEDED ||
-                   icmptype == ICMP6_PARAM_PROB)
-                       state_icmp++;
-               break;
-#endif /* INET6 */
-       }
-
-       r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr);
-
-       if (direction == PF_OUT) {
-               bport = nport = icmpid;
-               /* check outgoing packet for BINAT/NAT */
-               if ((nr = pf_get_translation(pd, m, off, PF_OUT, kif, &nsn,
-                   saddr, icmpid, daddr, icmpid, &pd->naddr, &nport)) !=
-                   NULL) {
-                       PF_ACPY(&pd->baddr, saddr, af);
-                       switch (af) {
-#ifdef INET
-                       case AF_INET:
-                               pf_change_a(&saddr->v4.s_addr, pd->ip_sum,
-                                   pd->naddr.v4.s_addr, 0);
-                               pd->hdr.icmp->icmp_cksum = pf_cksum_fixup(
-                                   pd->hdr.icmp->icmp_cksum, icmpid, nport, 0);
-                               pd->hdr.icmp->icmp_id = nport;
-                               m_copyback(m, off, ICMP_MINLEN, (caddr_t)pd->hdr.icmp);
-                               break;
-#endif /* INET */
-#ifdef INET6
-                       case AF_INET6:
-                               pf_change_a6(saddr, &pd->hdr.icmp6->icmp6_cksum,
-                                   &pd->naddr, 0);
-                               rewrite++;
-                               break;
-#endif /* INET6 */
-                       }
-                       if (nr->natpass)
-                               r = NULL;
-                       pd->nat_rule = nr;
-               }
-       } else {
-               bport = nport = icmpid;
-               /* check incoming packet for BINAT/RDR */
-               if ((nr = pf_get_translation(pd, m, off, PF_IN, kif, &nsn,
-                   saddr, icmpid, daddr, icmpid, &pd->naddr, &nport)) !=
-                   NULL) {
-                       PF_ACPY(&pd->baddr, daddr, af);
-                       switch (af) {
-#ifdef INET
-                       case AF_INET:
-                               pf_change_a(&daddr->v4.s_addr,
-                                   pd->ip_sum, pd->naddr.v4.s_addr, 0);
-                               break;
-#endif /* INET */
-#ifdef INET6
-                       case AF_INET6:
-                               pf_change_a6(daddr, &pd->hdr.icmp6->icmp6_cksum,
-                                   &pd->naddr, 0);
-                               rewrite++;
-                               break;
-#endif /* INET6 */
-                       }
-                       if (nr->natpass)
-                               r = NULL;
-                       pd->nat_rule = nr;
-               }
-       }
-
-       while (r != NULL) {
-               r->evaluations++;
-               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;
-               else if (r->af && r->af != af)
-                       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, kif))
-                       r = r->skip[PF_SKIP_SRC_ADDR].ptr;
-               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))
-                       r = TAILQ_NEXT(r, entries);
-               else if (r->rule_flag & PFRULE_FRAGMENT)
-                       r = TAILQ_NEXT(r, entries);
-               else if (r->prob && r->prob <= karc4random())
-                       r = TAILQ_NEXT(r, entries);
-               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;
-                               if ((*rm)->quick)
-                                       break;
-                               r = TAILQ_NEXT(r, entries);
-                       } else
-                               pf_step_into_anchor(&asd, &ruleset,
-                                   PF_RULESET_FILTER, &r, &a, &match);
-               }
-               if (r == NULL && pf_step_out_of_anchor(&asd, &ruleset,
-                   PF_RULESET_FILTER, &r, &a, &match))
-                       break;
-       }
-       r = *rm;
-       a = *am;
-       ruleset = *rsm;
-
-       REASON_SET(&reason, PFRES_MATCH);
-
-       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->log ? r : nr,
-                   a, ruleset, pd);
-       }
-
-       if (r->action != PF_PASS)
-               return (PF_DROP);
-
-       if (pf_tag_packet(m, pd->pf_mtag, tag, rtableid)) {
-               REASON_SET(&reason, PFRES_MEMORY);
-               return (PF_DROP);
-       }
-
-       if (!state_icmp && (r->keep_state || nr != NULL)) {
-               /* create new state */
-               struct pf_state *s = NULL;
-               struct pf_src_node *sn = NULL;
-
-               /* check maximums */
-               if (r->max_states && (r->states >= r->max_states)) {
-                       pf_status.lcounters[LCNT_STATES]++;
-                       REASON_SET(&reason, PFRES_MAXSTATES);
-                       goto cleanup;
-               }
-               /* 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) {
-                       REASON_SET(&reason, PFRES_SRCLIMIT);
-                       goto cleanup;
-               }
-               /* src node for translation rule */
-               if (nr != NULL && (nr->rpool.opts & PF_POOL_STICKYADDR) &&
-                   ((direction == PF_OUT &&
-                   pf_insert_src_node(&nsn, nr, &pd->baddr, af) != 0) ||
-                   (pf_insert_src_node(&nsn, nr, saddr, af) != 0))) {
-                       REASON_SET(&reason, PFRES_SRCLIMIT);
-                       goto cleanup;
-               }
-               s = pool_get(&pf_state_pl, PR_NOWAIT);
-               if (s == NULL) {
-                       REASON_SET(&reason, PFRES_MEMORY);
-cleanup:
-                       if (sn != NULL && sn->states == 0 && sn->expire == 0) {
-                               RB_REMOVE(pf_src_tree, &tree_src_tracking, sn);
-                               pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
-                               pf_status.src_nodes--;
-                               pool_put(&pf_src_tree_pl, sn);
-                       }
-                       if (nsn != sn && nsn != NULL && nsn->states == 0 &&
-                           nsn->expire == 0) {
-                               RB_REMOVE(pf_src_tree, &tree_src_tracking, nsn);
-                               pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
-                               pf_status.src_nodes--;
-                               pool_put(&pf_src_tree_pl, nsn);
-                       }
-                       return (PF_DROP);
-               }
-               bzero(s, sizeof(*s));
-               s->rule.ptr = r;
-               s->nat_rule.ptr = nr;
-               s->anchor.ptr = a;
-               STATE_INC_COUNTERS(s);
-               s->allow_opts = r->allow_opts;
-               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;
-               if (direction == PF_OUT) {
-                       PF_ACPY(&s->gwy.addr, saddr, af);
-                       s->gwy.port = nport;
-                       PF_ACPY(&s->ext.addr, daddr, af);
-                       s->ext.port = 0;
-                       if (nr != NULL) {
-                               PF_ACPY(&s->lan.addr, &pd->baddr, af);
-                               s->lan.port = bport;
-                       } else {
-                               PF_ACPY(&s->lan.addr, &s->gwy.addr, af);
-                               s->lan.port = s->gwy.port;
-                       }
-               } else {
-                       PF_ACPY(&s->lan.addr, daddr, af);
-                       s->lan.port = nport;
-                       PF_ACPY(&s->ext.addr, saddr, af);
-                       s->ext.port = 0; 
-                       if (nr != NULL) {
-                               PF_ACPY(&s->gwy.addr, &pd->baddr, af);
-                               s->gwy.port = bport;
-                       } else {
-                               PF_ACPY(&s->gwy.addr, &s->lan.addr, af);
-                               s->gwy.port = s->lan.port;
-                       }
-               }
-               s->hash = pf_state_hash(s);
-               s->creation = time_second;
-               s->expire = time_second;
-               s->timeout = PFTM_ICMP_FIRST_PACKET;
-               pf_set_rt_ifp(s, saddr);
-               if (sn != NULL) {
-                       s->src_node = sn;
-                       s->src_node->states++;
-               }
-               if (nsn != NULL) {
-                       PF_ACPY(&nsn->raddr, &pd->naddr, af);
-                       s->nat_src_node = nsn;
-                       s->nat_src_node->states++;
-               }
-               if (pf_insert_state(BOUND_IFACE(r, kif), s)) {
-                       REASON_SET(&reason, PFRES_STATEINS);
-                       pf_src_tree_remove_state(s);
-                       STATE_DEC_COUNTERS(s);
-                       pool_put(&pf_state_pl, s);
-                       return (PF_DROP);
-               } else
-                       *sm = s;
-               if (tag > 0) {
-                       pf_tag_ref(tag);
-                       s->tag = tag;
-               }
-       }
-
-#ifdef INET6
-       /* copy back packet headers if we performed IPv6 NAT operations */
-       if (rewrite)
-               m_copyback(m, off, sizeof(struct icmp6_hdr),
-                   (caddr_t)pd->hdr.icmp6);
-#endif /* INET6 */
-
-       return (PF_PASS);
-}
-
-int
-pf_test_other(struct pf_rule **rm, struct pf_state **sm, int direction,
-    struct pfi_kif *kif, struct mbuf *m, int off, void *h, struct pf_pdesc *pd,
-    struct pf_rule **am, struct pf_ruleset **rsm, struct ifqueue *ifq)
-{
-       struct pf_rule          *nr = NULL;
-       struct pf_rule          *r, *a = NULL;
-       struct pf_ruleset       *ruleset = NULL;
-       struct pf_src_node      *nsn = NULL;
-       struct pf_addr          *saddr = pd->src, *daddr = pd->dst;
-       sa_family_t              af = pd->af;
-       u_short                  reason;
-       int                      tag = -1, rtableid = -1;
-       int                      asd = 0;
-       int                      match = 0;
-
-       if (pf_check_congestion(ifq)) {
-               REASON_SET(&reason, PFRES_CONGEST);
-               return (PF_DROP);
-       }
-
-       r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr);
-
-       if (direction == PF_OUT) {
-               /* check outgoing packet for BINAT/NAT */
-               if ((nr = pf_get_translation(pd, m, off, PF_OUT, kif, &nsn,
-                   saddr, 0, daddr, 0, &pd->naddr, NULL)) != NULL) {
-                       PF_ACPY(&pd->baddr, saddr, af);
-                       switch (af) {
-#ifdef INET
-                       case AF_INET:
-                               pf_change_a(&saddr->v4.s_addr, pd->ip_sum,
-                                   pd->naddr.v4.s_addr, 0);
-                               break;
-#endif /* INET */
-#ifdef INET6
-                       case AF_INET6:
-                               PF_ACPY(saddr, &pd->naddr, af);
-                               break;
-#endif /* INET6 */
-                       }
-                       if (nr->natpass)
-                               r = NULL;
-                       pd->nat_rule = nr;
-               }
-       } else {
-               /* check incoming packet for BINAT/RDR */
-               if ((nr = pf_get_translation(pd, m, off, PF_IN, kif, &nsn,
-                   saddr, 0, daddr, 0, &pd->naddr, NULL)) != NULL) {
-                       PF_ACPY(&pd->baddr, daddr, af);
-                       switch (af) {
-#ifdef INET
-                       case AF_INET:
-                               pf_change_a(&daddr->v4.s_addr,
-                                   pd->ip_sum, pd->naddr.v4.s_addr, 0);
-                               break;
-#endif /* INET */
-#ifdef INET6
-                       case AF_INET6:
-                               PF_ACPY(daddr, &pd->naddr, af);
-                               break;
-#endif /* INET6 */
-                       }
-                       if (nr->natpass)
-                               r = NULL;
-                       pd->nat_rule = nr;
-               }
-       }
-
-       while (r != NULL) {
-               r->evaluations++;
-               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;
-               else if (r->af && r->af != af)
-                       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, kif))
-                       r = r->skip[PF_SKIP_SRC_ADDR].ptr;
-               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))
-                       r = TAILQ_NEXT(r, entries);
-               else if (r->rule_flag & PFRULE_FRAGMENT)
-                       r = TAILQ_NEXT(r, entries);
-               else if (r->prob && r->prob <= karc4random())
-                       r = TAILQ_NEXT(r, entries);
-               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;
-                               if ((*rm)->quick)
-                                       break;
-                               r = TAILQ_NEXT(r, entries);
-                       } else
-                               pf_step_into_anchor(&asd, &ruleset,
-                                   PF_RULESET_FILTER, &r, &a, &match);
-               }
-               if (r == NULL && pf_step_out_of_anchor(&asd, &ruleset,
-                   PF_RULESET_FILTER, &r, &a, &match))
+                       if (th->th_flags & TH_FIN)
+                               s->src.seqhi++;
+                       s->dst.seqhi = 1;
+                       s->dst.max_win = 1;
+                       s->src.state = TCPS_SYN_SENT;
+                       s->dst.state = TCPS_CLOSED;
+                       s->timeout = PFTM_TCP_FIRST_PACKET;
                        break;
-       }
-       r = *rm;
-       a = *am;
-       ruleset = *rsm;
-
-       REASON_SET(&reason, PFRES_MATCH);
-
-       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) ||
-           (r->rule_flag & PFRULE_RETURN))) {
-               struct pf_addr *a = NULL;
-
-               if (nr != NULL) {
-                       if (direction == PF_OUT)
-                               a = saddr;
-                       else
-                               a = daddr;
-               }
-               if (a != NULL) {
-                       switch (af) {
-#ifdef INET
-                       case AF_INET:
-                               pf_change_a(&a->v4.s_addr, pd->ip_sum,
-                                   pd->baddr.v4.s_addr, 0);
-                               break;
-#endif /* INET */
+               case IPPROTO_UDP:
+                       s->src.state = PFUDPS_SINGLE;
+                       s->dst.state = PFUDPS_NO_TRAFFIC;
+                       s->timeout = PFTM_UDP_FIRST_PACKET;
+                       break;
+               case IPPROTO_ICMP:
 #ifdef INET6
-                       case AF_INET6:
-                               PF_ACPY(a, &pd->baddr, af);
-                               break;
-#endif /* INET6 */
-                       }
+               case IPPROTO_ICMPV6:
+#endif
+                       s->timeout = PFTM_ICMP_FIRST_PACKET;
+                       break;
+               default:
+                       s->src.state = PFOTHERS_SINGLE;
+                       s->dst.state = PFOTHERS_NO_TRAFFIC;
+                       s->timeout = PFTM_OTHER_FIRST_PACKET;
                }
-               if ((af == AF_INET) && r->return_icmp)
-                       pf_send_icmp(m, r->return_icmp >> 8,
-                           r->return_icmp & 255, af, r);
-               else if ((af == AF_INET6) && r->return_icmp6)
-                       pf_send_icmp(m, r->return_icmp6 >> 8,
-                           r->return_icmp6 & 255, af, r);
-       }
-
-       if (r->action != PF_PASS)
-               return (PF_DROP);
-
-       if (pf_tag_packet(m, pd->pf_mtag, tag, rtableid)) {
-               REASON_SET(&reason, PFRES_MEMORY);
-               return (PF_DROP);
-       }
-
-       if (r->keep_state || nr != NULL) {
-               /* create new state */
-               struct pf_state *s = NULL;
-               struct pf_src_node *sn = NULL;
 
-               /* check maximums */
-               if (r->max_states && (r->states >= r->max_states)) {
-                       pf_status.lcounters[LCNT_STATES]++;
-                       REASON_SET(&reason, PFRES_MAXSTATES);
-                       goto cleanup;
-               }
-               /* 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) {
-                       REASON_SET(&reason, PFRES_SRCLIMIT);
-                       goto cleanup;
-               }
-               /* src node for translation rule */
-               if (nr != NULL && (nr->rpool.opts & PF_POOL_STICKYADDR) &&
-                   ((direction == PF_OUT &&
-                   pf_insert_src_node(&nsn, nr, &pd->baddr, af) != 0) ||
-                   (pf_insert_src_node(&nsn, nr, saddr, af) != 0))) {
-                       REASON_SET(&reason, PFRES_SRCLIMIT);
-                       goto cleanup;
-               }
-               s = pool_get(&pf_state_pl, PR_NOWAIT);
-               if (s == NULL) {
-                       REASON_SET(&reason, PFRES_MEMORY);
-cleanup:
-                       if (sn != NULL && sn->states == 0 && sn->expire == 0) {
-                               RB_REMOVE(pf_src_tree, &tree_src_tracking, sn);
-                               pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
-                               pf_status.src_nodes--;
-                               pool_put(&pf_src_tree_pl, sn);
-                       }
-                       if (nsn != sn && nsn != NULL && nsn->states == 0 &&
-                           nsn->expire == 0) {
-                               RB_REMOVE(pf_src_tree, &tree_src_tracking, nsn);
-                               pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
-                               pf_status.src_nodes--;
-                               pool_put(&pf_src_tree_pl, nsn);
-                       }
-                       return (PF_DROP);
-               }
-               bzero(s, sizeof(*s));
-               s->rule.ptr = r;
-               s->nat_rule.ptr = nr;
-               s->anchor.ptr = a;
-               STATE_INC_COUNTERS(s);
-               s->allow_opts = r->allow_opts;
-               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;
-               if (direction == PF_OUT) {
-                       PF_ACPY(&s->gwy.addr, saddr, af);
-                       PF_ACPY(&s->ext.addr, daddr, af);
-                       if (nr != NULL)
-                               PF_ACPY(&s->lan.addr, &pd->baddr, af);
-                       else
-                               PF_ACPY(&s->lan.addr, &s->gwy.addr, af);
-               } else {
-                       PF_ACPY(&s->lan.addr, daddr, af);
-                       PF_ACPY(&s->ext.addr, saddr, af);
-                       if (nr != NULL)
-                               PF_ACPY(&s->gwy.addr, &pd->baddr, af);
-                       else
-                               PF_ACPY(&s->gwy.addr, &s->lan.addr, af);
-               }
-               s->hash = pf_state_hash(s);
-               s->src.state = PFOTHERS_SINGLE;
-               s->dst.state = PFOTHERS_NO_TRAFFIC;
                s->creation = time_second;
                s->expire = time_second;
-               s->timeout = PFTM_OTHER_FIRST_PACKET;
-               pf_set_rt_ifp(s, saddr);
+
                if (sn != NULL) {
                        s->src_node = sn;
                        s->src_node->states++;
@@ -4206,7 +3503,93 @@ cleanup:
                        s->nat_src_node = nsn;
                        s->nat_src_node->states++;
                }
+               if (pd->proto == IPPROTO_TCP) {
+                       if ((pd->flags & PFDESC_TCP_NORM) &&
+                           pf_normalize_tcp_init(m, off, pd, th, &s->src,
+                           &s->dst)) {
+                               REASON_SET(&reason, PFRES_MEMORY);
+                               pf_src_tree_remove_state(s);
+                               STATE_DEC_COUNTERS(s);
+                               pool_put(&pf_state_pl, s);
+                               return (PF_DROP);
+                       }
+                       if ((pd->flags & PFDESC_TCP_NORM) && s->src.scrub &&
+                           pf_normalize_tcp_stateful(m, off, pd, &reason,
+                           th, s, &s->src, &s->dst, &rewrite)) {
+                               /* This really shouldn't happen!!! */
+                               DPFPRINTF(PF_DEBUG_URGENT,
+                                   ("pf_normalize_tcp_stateful failed on "
+                                   "first pkt"));
+                               pf_normalize_tcp_cleanup(s);
+                               pf_src_tree_remove_state(s);
+                               STATE_DEC_COUNTERS(s);
+                               pool_put(&pf_state_pl, s);
+                               return (PF_DROP);
+                       }
+               }
+
+               if ((sk = pf_alloc_state_key(s)) == NULL) {
+                       REASON_SET(&reason, PFRES_MEMORY);
+                       goto cleanup;
+               }
+
+               sk->proto = pd->proto;
+               sk->direction = direction;
+               sk->af = af;
+               if (direction == PF_OUT) {
+                       PF_ACPY(&sk->gwy.addr, saddr, af);
+                       PF_ACPY(&sk->ext.addr, daddr, af);
+                       switch (pd->proto) {
+                       case IPPROTO_ICMP:
+#ifdef INET6
+                       case IPPROTO_ICMPV6:
+#endif
+                               sk->gwy.port = nport;
+                               sk->ext.port = 0;
+                               break;
+                       default:
+                               sk->gwy.port = sport;
+                               sk->ext.port = dport;
+                       }
+                       if (nr != NULL) {
+                               PF_ACPY(&sk->lan.addr, &pd->baddr, af);
+                               sk->lan.port = bport;
+                       } else {
+                               PF_ACPY(&sk->lan.addr, &sk->gwy.addr, af);
+                               sk->lan.port = sk->gwy.port;
+                       }
+               } else {
+                       PF_ACPY(&sk->lan.addr, daddr, af);
+                       PF_ACPY(&sk->ext.addr, saddr, af);
+                       switch (pd->proto) {
+                       case IPPROTO_ICMP:
+#ifdef INET6
+                       case IPPROTO_ICMPV6:
+#endif
+                               sk->lan.port = nport;
+                               sk->ext.port = 0;
+                               break;
+                       default:
+                               sk->lan.port = dport;
+                               sk->ext.port = sport;
+                       }
+                       if (nr != NULL) {
+                               PF_ACPY(&sk->gwy.addr, &pd->baddr, af);
+                               sk->gwy.port = bport;
+                       } else {
+                               PF_ACPY(&sk->gwy.addr, &sk->lan.addr, af);
+                               sk->gwy.port = sk->lan.port;
+                       }
+               }
+
+               s->hash = pf_state_hash(sk);
+               s->pickup_mode = r->pickup_mode;
+
+               pf_set_rt_ifp(s, saddr);        /* needs s->state_key set */
+
                if (pf_insert_state(BOUND_IFACE(r, kif), s)) {
+                       if (pd->proto == IPPROTO_TCP)
+                               pf_normalize_tcp_cleanup(s);
                        REASON_SET(&reason, PFRES_STATEINS);
                        pf_src_tree_remove_state(s);
                        STATE_DEC_COUNTERS(s);
@@ -4218,8 +3601,41 @@ cleanup:
                        pf_tag_ref(tag);
                        s->tag = tag;
                }
+               if (pd->proto == IPPROTO_TCP &&
+                   (th->th_flags & (TH_SYN|TH_ACK)) == TH_SYN &&
+                   r->keep_state == PF_STATE_SYNPROXY) {
+                       s->src.state = PF_TCPS_PROXY_SRC;
+                       if (nr != NULL) {
+                               if (direction == PF_OUT) {
+                                       pf_change_ap(saddr, &th->th_sport,
+                                           pd->ip_sum, &th->th_sum, &pd->baddr,
+                                           bport, 0, af);
+                                       sport = th->th_sport;
+                               } else {
+                                       pf_change_ap(daddr, &th->th_dport,
+                                           pd->ip_sum, &th->th_sum, &pd->baddr,
+                                           bport, 0, af);
+                                       sport = th->th_dport;
+                               }
+                       }
+                       s->src.seqhi = htonl(karc4random());
+                       /* Find mss option */
+                       mss = pf_get_mss(m, off, th->th_off, af);
+                       mss = pf_calc_mss(saddr, af, mss);
+                       mss = pf_calc_mss(daddr, af, mss);
+                       s->src.mss = mss;
+                       pf_send_tcp(r, af, daddr, saddr, th->th_dport,
+                           th->th_sport, s->src.seqhi, ntohl(th->th_seq) + 1,
+                           TH_SYN|TH_ACK, 0, s->src.mss, 0, 1, 0, NULL, NULL);
+                       REASON_SET(&reason, PFRES_SYNPROXY);
+                       return (PF_SYNPROXY_DROP);
+               }
        }
 
+       /* copy back packet headers if we performed NAT operations */
+       if (rewrite)
+               m_copyback(m, off, hdrlen, pd->hdr.any);
+
        return (PF_PASS);
 }
 
@@ -4269,7 +3685,7 @@ pf_test_fragment(struct pf_rule **rm, int direction, struct pfi_kif *kif,
                        r = TAILQ_NEXT(r, entries);
                else if (r->prob && r->prob <= karc4random())
                        r = TAILQ_NEXT(r, entries);
-               else if (r->match_tag && !pf_match_tag(m, r, NULL, &tag))
+               else if (r->match_tag && !pf_match_tag(m, r, &tag))
                        r = TAILQ_NEXT(r, entries);
                else {
                        if (r->anchor == NULL) {
@@ -4301,7 +3717,7 @@ pf_test_fragment(struct pf_rule **rm, int direction, struct pfi_kif *kif,
        if (r->action != PF_PASS)
                return (PF_DROP);
 
-       if (pf_tag_packet(m, pd->pf_mtag, tag, -1)) {
+       if (pf_tag_packet(m, tag, -1)) {
                REASON_SET(&reason, PFRES_MEMORY);
                return (PF_DROP);
        }
@@ -4314,7 +3730,7 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif,
     struct mbuf *m, int off, void *h, struct pf_pdesc *pd,
     u_short *reason)
 {
-       struct pf_state_cmp      key;
+       struct pf_state_key_cmp  key;
        struct tcphdr           *th = pd->hdr.tcp;
        u_int16_t                win = ntohs(th->th_win);
        u_int32_t                ack, end, seq, orig_seq;
@@ -4339,7 +3755,7 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif,
 
        STATE_LOOKUP();
 
-       if (direction == (*state)->direction) {
+       if (direction == (*state)->state_key->direction) {
                src = &(*state)->src;
                dst = &(*state)->dst;
        } else {
@@ -4348,7 +3764,7 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif,
        }
 
        if ((*state)->src.state == PF_TCPS_PROXY_SRC) {
-               if (direction != (*state)->direction) {
+               if (direction != (*state)->state_key->direction) {
                        REASON_SET(reason, PFRES_SYNPROXY);
                        return (PF_SYNPROXY_DROP);
                }
@@ -4380,13 +3796,13 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif,
                struct pf_state_host *src, *dst;
 
                if (direction == PF_OUT) {
-                       src = &(*state)->gwy;
-                       dst = &(*state)->ext;
+                       src = &(*state)->state_key->gwy;
+                       dst = &(*state)->state_key->ext;
                } else {
-                       src = &(*state)->ext;
-                       dst = &(*state)->lan;
+                       src = &(*state)->state_key->ext;
+                       dst = &(*state)->state_key->lan;
                }
-               if (direction == (*state)->direction) {
+               if (direction == (*state)->state_key->direction) {
                        if (((th->th_flags & (TH_SYN|TH_ACK)) != TH_ACK) ||
                            (ntohl(th->th_ack) != (*state)->src.seqhi + 1) ||
                            (ntohl(th->th_seq) != (*state)->src.seqlo + 1)) {
@@ -4462,7 +3878,8 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif,
 
                /* Deferred generation of sequence number modulator */
                if (dst->seqdiff && !src->seqdiff) {
-                       while ((src->seqdiff = pf_new_isn(*state) - seq) == 0)
+                       
+                       while ((src->seqdiff = pf_new_isn((struct pf_state_key *)&key) - seq) == 0)
                                ;
                        ack = ntohl(th->th_ack) - dst->seqdiff;
                        pf_change_a(&th->th_seq, &th->th_sum, htonl(seq +
@@ -4752,7 +4169,8 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif,
                            (unsigned long long)(*state)->packets[0],
                                (unsigned long long)(*state)->packets[1],
                            direction == PF_IN ? "in" : "out",
-                           direction == (*state)->direction ? "fwd" : "rev");
+                           direction == (*state)->state_key->direction ?
+                               "fwd" : "rev");
                        kprintf("pf: State failure on: %c %c %c %c | %c %c\n",
                            SEQ_GEQ(src->seqhi, end) ? ' ' : '1',
                            SEQ_GEQ(seq, src->seqlo - (dst->max_win << dws)) ?
@@ -4769,11 +4187,11 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif,
        /* Any packets which have gotten here are to be passed */
 
        /* translate source/destination address, if necessary */
-       if (STATE_TRANSLATE(*state)) {
+       if (STATE_TRANSLATE((*state)->state_key)) {
                if (direction == PF_OUT) {
                        pf_change_ap(pd->src, &th->th_sport, pd->ip_sum,
-                           &th->th_sum, &(*state)->gwy.addr,
-                           (*state)->gwy.port, 0, pd->af);
+                           &th->th_sum, &(*state)->state_key->gwy.addr,
+                           (*state)->state_key->gwy.port, 0, pd->af);
                } else {
                        /*
                         * If we don't redispatch the packet will go into
@@ -4782,8 +4200,8 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif,
                         */
                        m->m_pkthdr.fw_flags |= FW_MBUF_REDISPATCH;
                        pf_change_ap(pd->dst, &th->th_dport, pd->ip_sum,
-                           &th->th_sum, &(*state)->lan.addr,
-                           (*state)->lan.port, 0, pd->af);
+                           &th->th_sum, &(*state)->state_key->lan.addr,
+                           (*state)->state_key->lan.port, 0, pd->af);
                }
                m_copyback(m, off, sizeof(*th), (caddr_t)th);
        } else if (copyback) {
@@ -4799,7 +4217,7 @@ pf_test_state_udp(struct pf_state **state, int direction, struct pfi_kif *kif,
     struct mbuf *m, int off, void *h, struct pf_pdesc *pd)
 {
        struct pf_state_peer    *src, *dst;
-       struct pf_state_cmp      key;
+       struct pf_state_key_cmp  key;
        struct udphdr           *uh = pd->hdr.udp;
 
        key.af = pd->af;
@@ -4818,7 +4236,7 @@ pf_test_state_udp(struct pf_state **state, int direction, struct pfi_kif *kif,
 
        STATE_LOOKUP();
 
-       if (direction == (*state)->direction) {
+       if (direction == (*state)->state_key->direction) {
                src = &(*state)->src;
                dst = &(*state)->dst;
        } else {
@@ -4840,11 +4258,11 @@ pf_test_state_udp(struct pf_state **state, int direction, struct pfi_kif *kif,
                (*state)->timeout = PFTM_UDP_SINGLE;
 
        /* translate source/destination address, if necessary */
-       if (STATE_TRANSLATE(*state)) {
+       if (STATE_TRANSLATE((*state)->state_key)) {
                if (direction == PF_OUT) {
                        pf_change_ap(pd->src, &uh->uh_sport, pd->ip_sum,
-                           &uh->uh_sum, &(*state)->gwy.addr,
-                           (*state)->gwy.port, 1, pd->af);
+                           &uh->uh_sum, &(*state)->state_key->gwy.addr,
+                           (*state)->state_key->gwy.port, 1, pd->af);
                } else {
                        /*
                         * If we don't redispatch the packet will go into
@@ -4853,8 +4271,8 @@ pf_test_state_udp(struct pf_state **state, int direction, struct pfi_kif *kif,
                         */
                        m->m_pkthdr.fw_flags |= FW_MBUF_REDISPATCH;
                        pf_change_ap(pd->dst, &uh->uh_dport, pd->ip_sum,
-                           &uh->uh_sum, &(*state)->lan.addr,
-                           (*state)->lan.port, 1, pd->af);
+                           &uh->uh_sum, &(*state)->state_key->lan.addr,
+                           (*state)->state_key->lan.port, 1, pd->af);
                }
                m_copyback(m, off, sizeof(*uh), (caddr_t)uh);
        }
@@ -4870,7 +4288,7 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
        u_int16_t        icmpid = 0, *icmpsum;
        u_int8_t         icmptype;
        int              state_icmp = 0;
-       struct pf_state_cmp key;
+       struct pf_state_key_cmp key;
 
        switch (pd->proto) {
 #ifdef INET
@@ -4928,20 +4346,20 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
                (*state)->timeout = PFTM_ICMP_ERROR_REPLY;
 
                /* translate source/destination address, if necessary */
-               if (STATE_TRANSLATE(*state)) {
+               if (STATE_TRANSLATE((*state)->state_key)) {
                        if (direction == PF_OUT) {
                                switch (pd->af) {
 #ifdef INET
                                case AF_INET:
                                        pf_change_a(&saddr->v4.s_addr,
                                            pd->ip_sum,
-                                           (*state)->gwy.addr.v4.s_addr, 0);
+                                           (*state)->state_key->gwy.addr.v4.s_addr, 0);
                                        pd->hdr.icmp->icmp_cksum =
                                            pf_cksum_fixup(
                                            pd->hdr.icmp->icmp_cksum, icmpid,
-                                           (*state)->gwy.port, 0);
+                                           (*state)->state_key->gwy.port, 0);
                                        pd->hdr.icmp->icmp_id =
-                                           (*state)->gwy.port;
+                                           (*state)->state_key->gwy.port;
                                        m_copyback(m, off, ICMP_MINLEN,
                                            (caddr_t)pd->hdr.icmp);
                                        break;
@@ -4950,7 +4368,7 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
                                case AF_INET6:
                                        pf_change_a6(saddr,
                                            &pd->hdr.icmp6->icmp6_cksum,
-                                           &(*state)->gwy.addr, 0);
+                                           &(*state)->state_key->gwy.addr, 0);
                                        m_copyback(m, off,
                                            sizeof(struct icmp6_hdr),
                                            (caddr_t)pd->hdr.icmp6);
@@ -4963,13 +4381,13 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
                                case AF_INET:
                                        pf_change_a(&daddr->v4.s_addr,
                                            pd->ip_sum,
-                                           (*state)->lan.addr.v4.s_addr, 0);
+                                           (*state)->state_key->lan.addr.v4.s_addr, 0);
                                        pd->hdr.icmp->icmp_cksum =
                                            pf_cksum_fixup(
                                            pd->hdr.icmp->icmp_cksum, icmpid,
-                                           (*state)->lan.port, 0);
+                                           (*state)->state_key->lan.port, 0);
                                        pd->hdr.icmp->icmp_id =
-                                           (*state)->lan.port;
+                                           (*state)->state_key->lan.port;
                                        m_copyback(m, off, ICMP_MINLEN,
                                            (caddr_t)pd->hdr.icmp);
                                        break;
@@ -4978,7 +4396,7 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
                                case AF_INET6:
                                        pf_change_a6(daddr,
                                            &pd->hdr.icmp6->icmp6_cksum,
-                                           &(*state)->lan.addr, 0);
+                                           &(*state)->state_key->lan.addr, 0);
                                        m_copyback(m, off,
                                            sizeof(struct icmp6_hdr),
                                            (caddr_t)pd->hdr.icmp6);
@@ -5104,7 +4522,6 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
                case IPPROTO_TCP: {
                        struct tcphdr            th;
                        u_int32_t                seq;
-                       struct pf_state_cmp              key;
                        struct pf_state_peer    *src, *dst;
                        u_int8_t                 dws;
                        int                      copyback = 0;
@@ -5138,7 +4555,7 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
 
                        STATE_LOOKUP();
 
-                       if (direction == (*state)->direction) {
+                       if (direction == (*state)->state_key->direction) {
                                src = &(*state)->dst;
                                dst = &(*state)->src;
                        } else {
@@ -5146,8 +4563,7 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
                                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;
@@ -5176,17 +4592,17 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
                                return (PF_DROP);
                        }
 
-                       if (STATE_TRANSLATE(*state)) {
+                       if (STATE_TRANSLATE((*state)->state_key)) {
                                if (direction == PF_IN) {
                                        pf_change_icmp(pd2.src, &th.th_sport,
-                                           daddr, &(*state)->lan.addr,
-                                           (*state)->lan.port, NULL,
+                                           daddr, &(*state)->state_key->lan.addr,
+                                           (*state)->state_key->lan.port, NULL,
                                            pd2.ip_sum, icmpsum,
                                            pd->ip_sum, 0, pd2.af);
                                } else {
                                        pf_change_icmp(pd2.dst, &th.th_dport,
-                                           saddr, &(*state)->gwy.addr,
-                                           (*state)->gwy.port, NULL,
+                                           saddr, &(*state)->state_key->gwy.addr,
+                                           (*state)->state_key->gwy.port, NULL,
                                            pd2.ip_sum, icmpsum,
                                            pd->ip_sum, 0, pd2.af);
                                }
@@ -5246,17 +4662,20 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
 
                        STATE_LOOKUP();
 
-                       if (STATE_TRANSLATE(*state)) {
+                       if (STATE_TRANSLATE((*state)->state_key)) {
                                if (direction == PF_IN) {
                                        pf_change_icmp(pd2.src, &uh.uh_sport,
-                                           daddr, &(*state)->lan.addr,
-                                           (*state)->lan.port, &uh.uh_sum,
+                                           daddr,
+                                           &(*state)->state_key->lan.addr,
+                                           (*state)->state_key->lan.port,
+                                           &uh.uh_sum,
                                            pd2.ip_sum, icmpsum,
                                            pd->ip_sum, 1, pd2.af);
                                } else {
                                        pf_change_icmp(pd2.dst, &uh.uh_dport,
-                                           saddr, &(*state)->gwy.addr,
-                                           (*state)->gwy.port, &uh.uh_sum,
+                                           saddr,
+                                           &(*state)->state_key->gwy.addr,
+                                           (*state)->state_key->gwy.port, &uh.uh_sum,
                                            pd2.ip_sum, icmpsum,
                                            pd->ip_sum, 1, pd2.af);
                                }
@@ -5312,17 +4731,19 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
 
                        STATE_LOOKUP();
 
-                       if (STATE_TRANSLATE(*state)) {
+                       if (STATE_TRANSLATE((*state)->state_key)) {
                                if (direction == PF_IN) {
                                        pf_change_icmp(pd2.src, &iih.icmp_id,
-                                           daddr, &(*state)->lan.addr,
-                                           (*state)->lan.port, NULL,
+                                           daddr,
+                                           &(*state)->state_key->lan.addr,
+                                           (*state)->state_key->lan.port, NULL,
                                            pd2.ip_sum, icmpsum,
                                            pd->ip_sum, 0, AF_INET);
                                } else {
                                        pf_change_icmp(pd2.dst, &iih.icmp_id,
-                                           saddr, &(*state)->gwy.addr,
-                                           (*state)->gwy.port, NULL,
+                                           saddr,
+                                           &(*state)->state_key->gwy.addr,
+                                           (*state)->state_key->gwy.port, NULL,
                                            pd2.ip_sum, icmpsum,
                                            pd->ip_sum, 0, AF_INET);
                                }
@@ -5363,17 +4784,18 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
 
                        STATE_LOOKUP();
 
-                       if (STATE_TRANSLATE(*state)) {
+                       if (STATE_TRANSLATE((*state)->state_key)) {
                                if (direction == PF_IN) {
                                        pf_change_icmp(pd2.src, &iih.icmp6_id,
-                                           daddr, &(*state)->lan.addr,
-                                           (*state)->lan.port, NULL,
+                                           daddr,
+                                           &(*state)->state_key->lan.addr,
+                                           (*state)->state_key->lan.port, NULL,
                                            pd2.ip_sum, icmpsum,
                                            pd->ip_sum, 0, AF_INET6);
                                } else {
                                        pf_change_icmp(pd2.dst, &iih.icmp6_id,
-                                           saddr, &(*state)->gwy.addr,
-                                           (*state)->gwy.port, NULL,
+                                           saddr, &(*state)->state_key->gwy.addr,
+                                           (*state)->state_key->gwy.port, NULL,
                                            pd2.ip_sum, icmpsum,
                                            pd->ip_sum, 0, AF_INET6);
                                }
@@ -5405,16 +4827,18 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
 
                        STATE_LOOKUP();
 
-                       if (STATE_TRANSLATE(*state)) {
+                       if (STATE_TRANSLATE((*state)->state_key)) {
                                if (direction == PF_IN) {
                                        pf_change_icmp(pd2.src, NULL,
-                                           daddr, &(*state)->lan.addr,
+                                           daddr,
+                                           &(*state)->state_key->lan.addr,
                                            0, NULL,
                                            pd2.ip_sum, icmpsum,
                                            pd->ip_sum, 0, pd2.af);
                                } else {
                                        pf_change_icmp(pd2.dst, NULL,
-                                           saddr, &(*state)->gwy.addr,
+                                           saddr,
+                                           &(*state)->state_key->gwy.addr,
                                            0, NULL,
                                            pd2.ip_sum, icmpsum,
                                            pd->ip_sum, 0, pd2.af);
@@ -5451,7 +4875,7 @@ pf_test_state_other(struct pf_state **state, int direction, struct pfi_kif *kif,
     struct pf_pdesc *pd)
 {
        struct pf_state_peer    *src, *dst;
-       struct pf_state_cmp      key;
+       struct pf_state_key_cmp  key;
 
        key.af = pd->af;
        key.proto = pd->proto;
@@ -5469,7 +4893,7 @@ pf_test_state_other(struct pf_state **state, int direction, struct pfi_kif *kif,
 
        STATE_LOOKUP();
 
-       if (direction == (*state)->direction) {
+       if (direction == (*state)->state_key->direction) {
                src = &(*state)->src;
                dst = &(*state)->dst;
        } else {
@@ -5491,19 +4915,21 @@ pf_test_state_other(struct pf_state **state, int direction, struct pfi_kif *kif,
                (*state)->timeout = PFTM_OTHER_SINGLE;
 
        /* translate source/destination address, if necessary */
-       if (STATE_TRANSLATE(*state)) {
+       if (STATE_TRANSLATE((*state)->state_key)) {
                if (direction == PF_OUT)
                        switch (pd->af) {
 #ifdef INET
                        case AF_INET:
                                pf_change_a(&pd->src->v4.s_addr,
-                                   pd->ip_sum, (*state)->gwy.addr.v4.s_addr,
+                                   pd->ip_sum,
+                                   (*state)->state_key->gwy.addr.v4.s_addr,
                                    0);
                                break;
 #endif /* INET */
 #ifdef INET6
                        case AF_INET6:
-                               PF_ACPY(pd->src, &(*state)->gwy.addr, pd->af);
+                               PF_ACPY(pd->src,
+                                   &(*state)->state_key->gwy.addr, pd->af);
                                break;
 #endif /* INET6 */
                        }
@@ -5512,13 +4938,15 @@ pf_test_state_other(struct pf_state **state, int direction, struct pfi_kif *kif,
 #ifdef INET
                        case AF_INET:
                                pf_change_a(&pd->dst->v4.s_addr,
-                                   pd->ip_sum, (*state)->lan.addr.v4.s_addr,
+                                   pd->ip_sum,
+                                   (*state)->state_key->lan.addr.v4.s_addr,
                                    0);
                                break;
 #endif /* INET */
 #ifdef INET6
                        case AF_INET6:
-                               PF_ACPY(pd->dst, &(*state)->lan.addr, pd->af);
+                               PF_ACPY(pd->dst,
+                                   &(*state)->state_key->lan.addr, pd->af);
                                break;
 #endif /* INET6 */
                        }
@@ -5716,14 +5144,13 @@ pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
 
        if (((*m)->m_pkthdr.fw_flags & PF_MBUF_ROUTED) == 0) {
                (*m)->m_pkthdr.fw_flags |= PF_MBUF_ROUTED;
-               (*m)->m_pkthdr.pf_routed = 1;
+               (*m)->m_pkthdr.pf.routed = 1;
        } else {
-               if ((*m)->m_pkthdr.pf_routed > 3) {
+               if ((*m)->m_pkthdr.pf.routed++ > 3) {
                        m0 = *m;
                        *m = NULL;
                        goto bad;
                }
-               (*m)->m_pkthdr.pf_routed++;
        }
 
        if (r->rt == PF_DUPTO) {
@@ -5807,25 +5234,16 @@ pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
        m0->m_pkthdr.csum_flags |= CSUM_IP;
        sw_csum = m0->m_pkthdr.csum_flags & ~ifp->if_hwassist;
        if (sw_csum & CSUM_DELAY_DATA) {
-               /*
-                * XXX: in_delayed_cksum assumes HBO for ip->ip_len (at least)
-                */
-               NTOHS(ip->ip_len);
-               NTOHS(ip->ip_off);       /* XXX: needed? */
                in_delayed_cksum(m0);
-               HTONS(ip->ip_len);
-               HTONS(ip->ip_off);
                sw_csum &= ~CSUM_DELAY_DATA;
        }
        m0->m_pkthdr.csum_flags &= ifp->if_hwassist;
 
-       if (ntohs(ip->ip_len) <= ifp->if_mtu ||
+       if (ip->ip_len <= ifp->if_mtu ||
            (ifp->if_hwassist & CSUM_FRAGMENT &&
-               ((ip->ip_off & htons(IP_DF)) == 0))) {
-               /*
-                * ip->ip_len = htons(ip->ip_len);
-                * ip->ip_off = htons(ip->ip_off);
-                */
+               (ip->ip_off & IP_DF) == 0)) {
+               ip->ip_len = htons(ip->ip_len);
+               ip->ip_off = htons(ip->ip_off);
                ip->ip_sum = 0;
                if (sw_csum & CSUM_DELAY_IP) {
                        /* From KAME */
@@ -5837,7 +5255,7 @@ pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
                        }
                }
                crit_exit();
-               error = (*ifp->if_output)(ifp, m0, sintosa(dst), ro->ro_rt);
+               error = ifp->if_output(ifp, m0, sintosa(dst), ro->ro_rt);
                crit_enter();
                goto done;
        }
@@ -5846,12 +5264,9 @@ pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
         * Too large for interface; fragment if possible.
         * Must be able to put at least 8 bytes per fragment.
         */
-       if (ip->ip_off & htons(IP_DF)) {
+       if (ip->ip_off & IP_DF) {
                ipstat.ips_cantfrag++;
                if (r->rt != PF_DUPTO) {
-                       /* icmp_error() expects host byte ordering */
-                       NTOHS(ip->ip_len);
-                       NTOHS(ip->ip_off);
                        crit_exit();
                        icmp_error(m0, ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG, 0,
                            ifp->if_mtu);
@@ -5862,11 +5277,6 @@ pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
        }
 
        m1 = m0;
-       /*
-        * XXX: is cheaper + less error prone than own function
-        */
-       NTOHS(ip->ip_len);
-       NTOHS(ip->ip_off);
        error = ip_fragment(ip, &m0, ifp->if_mtu, ifp->if_hwassist, sw_csum);
        if (error) {
                goto bad;
@@ -5921,14 +5331,13 @@ pf_route6(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
 
        if (((*m)->m_pkthdr.fw_flags & PF_MBUF_ROUTED) == 0) {
                (*m)->m_pkthdr.fw_flags |= PF_MBUF_ROUTED;
-               (*m)->m_pkthdr.pf_routed = 1;
+               (*m)->m_pkthdr.pf.routed = 1;
        } else {
-               if ((*m)->m_pkthdr.pf_routed > 3) {
+               if ((*m)->m_pkthdr.pf.routed++ > 3) {
                        m0 = *m;
                        *m = NULL;
                        goto bad;
                }
-               (*m)->m_pkthdr.pf_routed++;
        }
 
        if (r->rt == PF_DUPTO) {
@@ -5956,8 +5365,7 @@ pf_route6(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
 
        /* Cheat. XXX why only in the v6 case??? */
        if (r->rt == PF_FASTROUTE) {
-               pd->pf_mtag->flags |= PF_TAG_GENERATED;
-               crit_exit();
+               m0->m_pkthdr.pf.flags |= PF_TAG_GENERATED;
                ip6_output(m0, NULL, NULL, 0, NULL, NULL, NULL);
                crit_enter();
                return;
@@ -6167,22 +5575,20 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0,
        struct ip               *h = NULL;
        struct pf_rule          *a = NULL, *r = &pf_default_rule, *tr, *nr;
        struct pf_state         *s = NULL;
+       struct pf_state_key     *sk = NULL;
        struct pf_ruleset       *ruleset = NULL;
        struct pf_pdesc          pd;
        int                      off, dirndx, pqid = 0;
-       
+
        if (!pf_status.running)
                return (PF_PASS);
 
        memset(&pd, 0, sizeof(pd));
-       if ((pd.pf_mtag = pf_get_mtag(m)) == NULL) {
-               DPFPRINTF(PF_DEBUG_URGENT,
-                   ("pf_test: pf_get_mtag returned NULL\n"));
-               return (PF_DROP);
-       }
-       if (pd.pf_mtag->flags & PF_TAG_GENERATED)
-               return (PF_PASS);
-       kif = (struct pfi_kif *)ifp->if_pf_kif;
+       if (ifp->if_type == IFT_CARP && ifp->if_carpdev)
+               kif = (struct pfi_kif *)ifp->if_carpdev->if_pf_kif;
+       else
+               kif = (struct pfi_kif *)ifp->if_pf_kif;
+
        if (kif == NULL) {
                DPFPRINTF(PF_DEBUG_URGENT,
                    ("pf_test: kif == NULL, if_xname %s\n", ifp->if_xname));
@@ -6200,16 +5606,18 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0,
                action = PF_DROP;
                REASON_SET(&reason, PFRES_SHORT);
                log = 1;
-               panic("debug");
                goto done;
        }
 
+       if (m->m_pkthdr.pf.flags & PF_TAG_GENERATED)
+               return (PF_PASS);
+
        /* We do IP header normalization and packet reassembly here */
        if (pf_normalize_ip(m0, dir, kif, &reason, &pd) != PF_PASS) {
                action = PF_DROP;
                goto done;
        }
-       m = *m0;
+       m = *m0;        /* pf_normalize messes with m0 */
        h = mtod(m, struct ip *);
 
        off = h->ip_hl << 2;
@@ -6217,7 +5625,6 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0,
                action = PF_DROP;
                REASON_SET(&reason, PFRES_SHORT);
                log = 1;
-               panic("debug");
                goto done;
        }
 
@@ -6237,6 +5644,7 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0,
                    &pd, &a, &ruleset);
                goto done;
        }
+
        switch (h->ip_p) {
 
        case IPPROTO_TCP: {
@@ -6248,12 +5656,6 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0,
                        log = action != PF_PASS;
                        goto done;
                }
-               if (dir == PF_IN && pf_check_proto_cksum(m, off,
-                   h->ip_len - off, IPPROTO_TCP, AF_INET)) {
-                       REASON_SET(&reason, PFRES_PROTCKSUM);
-                       action = PF_DROP;
-                       goto done;
-               }
                pd.p_len = pd.tot_len - off - (th.th_off << 2);
                if ((th.th_flags & TH_ACK) && pd.p_len == 0)
                        pqid = 1;
@@ -6269,10 +5671,9 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0,
                        r = s->rule.ptr;
                        a = s->anchor.ptr;
                        log = s->log;
-               } else if (s == NULL) {
-                       action = pf_test_tcp(&r, &s, dir, kif,
+               } else if (s == NULL)
+                       action = pf_test_rule(&r, &s, dir, kif,
                            m, off, h, &pd, &a, &ruleset, NULL, inp);
-                       }
                break;
        }
 
@@ -6285,12 +5686,6 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0,
                        log = action != PF_PASS;
                        goto done;
                }
-               if (dir == PF_IN && uh.uh_sum && pf_check_proto_cksum(m,
-                   off, 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)) {
@@ -6307,7 +5702,7 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0,
                        a = s->anchor.ptr;
                        log = s->log;
                } else if (s == NULL)
-                       action = pf_test_udp(&r, &s, dir, kif,
+                       action = pf_test_rule(&r, &s, dir, kif,
                            m, off, h, &pd, &a, &ruleset, NULL, inp);
                break;
        }
@@ -6321,12 +5716,6 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0,
                        log = action != PF_PASS;
                        goto done;
                }
-               if (dir == PF_IN && pf_check_proto_cksum(m, off,
-                   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,
                    &reason);
                if (action == PF_PASS) {
@@ -6337,8 +5726,8 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0,
                        a = s->anchor.ptr;
                        log = s->log;
                } else if (s == NULL)
-                       action = pf_test_icmp(&r, &s, dir, kif,
-                           m, off, h, &pd, &a, &ruleset, NULL);
+                       action = pf_test_rule(&r, &s, dir, kif,
+                           m, off, h, &pd, &a, &ruleset, NULL, inp);
                break;
        }
 
@@ -6352,8 +5741,8 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0,
                        a = s->anchor.ptr;
                        log = s->log;
                } else if (s == NULL)
-                       action = pf_test_other(&r, &s, dir, kif, m, off, h,
-                           &pd, &a, &ruleset, NULL);
+                       action = pf_test_rule(&r, &s, dir, kif, m, off, h,
+                           &pd, &a, &ruleset, NULL, inp);
                break;
        }
 
@@ -6368,22 +5757,22 @@ done:
        }
 
        if ((s && s->tag) || r->rtableid)
-               pf_tag_packet(m, pd.pf_mtag, s ? s->tag : 0, r->rtableid);
+               pf_tag_packet(m, s ? s->tag : 0, r->rtableid);
 
 #ifdef ALTQ
        if (action == PF_PASS && r->qid) {
+               m->m_pkthdr.fw_flags |= PF_MBUF_STRUCTURE;
                if (pqid || (pd.tos & IPTOS_LOWDELAY))
-                       pd.pf_mtag->qid = r->pqid;
+                       m->m_pkthdr.pf.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;
+                       m->m_pkthdr.pf.qid = r->qid;
+               m->m_pkthdr.pf.ecn_af = AF_INET;
+               m->m_pkthdr.pf.hdr = h;
                /* add connection hash for fairq */
                if (s) {
-                       KKASSERT(s->hash != 0);
-                       pd.pf_mtag->flags |= PF_TAG_STATE_HASHED;
-                       pd.pf_mtag->state_hash = s->hash;
+                       /* for fairq */
+                       m->m_pkthdr.pf.state_hash = s->hash;
+                       m->m_pkthdr.pf.flags |= PF_TAG_STATE_HASHED;
                }
        }
 #endif /* ALTQ */
@@ -6398,7 +5787,7 @@ done:
            (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)
-               pd.pf_mtag->flags |= PF_TAG_TRANSLATE_LOCALHOST;
+               m->m_pkthdr.pf.flags |= PF_TAG_TRANSLATE_LOCALHOST;
 
        if (log) {
                struct pf_rule *lr;
@@ -6424,6 +5813,7 @@ done:
                        a->bytes[dirndx] += pd.tot_len;
                }
                if (s != NULL) {
+                       sk = s->state_key;
                        if (s->nat_rule.ptr != NULL) {
                                s->nat_rule.ptr->packets[dirndx]++;
                                s->nat_rule.ptr->bytes[dirndx] += pd.tot_len;
@@ -6436,7 +5826,7 @@ done:
                                s->nat_src_node->packets[dirndx]++;
                                s->nat_src_node->bytes[dirndx] += pd.tot_len;
                        }
-                       dirndx = (dir == s->direction) ? 0 : 1;
+                       dirndx = (dir == sk->direction) ? 0 : 1;
                        s->packets[dirndx]++;
                        s->bytes[dirndx] += pd.tot_len;
                }
@@ -6451,10 +5841,10 @@ done:
                         */
                        if (r == &pf_default_rule) {
                                tr = nr;
-                               x = (s == NULL || s->direction == dir) ?
+                               x = (sk == NULL || sk->direction == dir) ?
                                    &pd.baddr : &pd.naddr;
                        } else
-                               x = (s == NULL || s->direction == dir) ?
+                               x = (sk == NULL || sk->direction == dir) ?
                                    &pd.naddr : &pd.baddr;
                        if (x == &pd.baddr || s == NULL) {
                                /* we need to change the address */
@@ -6465,13 +5855,14 @@ done:
                        }
                }
                if (tr->src.addr.type == PF_ADDR_TABLE)
-                       pfr_update_stats(tr->src.addr.p.tbl, (s == NULL ||
-                           s->direction == dir) ? pd.src : pd.dst, pd.af,
+                       pfr_update_stats(tr->src.addr.p.tbl, (sk == NULL ||
+                           sk->direction == dir) ?
+                           pd.src : pd.dst, pd.af,
                            pd.tot_len, dir == PF_OUT, r->action == PF_PASS,
                            tr->src.neg);
                if (tr->dst.addr.type == PF_ADDR_TABLE)
-                       pfr_update_stats(tr->dst.addr.p.tbl, (s == NULL ||
-                           s->direction == dir) ? pd.dst : pd.src, pd.af,
+                       pfr_update_stats(tr->dst.addr.p.tbl, (sk == NULL ||
+                           sk->direction == dir) ? pd.dst : pd.src, pd.af,
                            pd.tot_len, dir == PF_OUT, r->action == PF_PASS,
                            tr->dst.neg);
        }
@@ -6483,7 +5874,8 @@ done:
                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, &pd);
+               pf_route(m0, r, dir, kif->pfik_ifp, s, &pd);
+
        return (action);
 }
 #endif /* INET */
@@ -6499,23 +5891,20 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0,
        struct ip6_hdr          *h = NULL;
        struct pf_rule          *a = NULL, *r = &pf_default_rule, *tr, *nr;
        struct pf_state         *s = NULL;
+       struct pf_state_key     *sk = NULL;
        struct pf_ruleset       *ruleset = NULL;
        struct pf_pdesc          pd;
-       int                      off, terminal = 0, dirndx;
+       int                      off, terminal = 0, dirndx, rh_cnt = 0;
 
        if (!pf_status.running)
                return (PF_PASS);
 
        memset(&pd, 0, sizeof(pd));
-       if ((pd.pf_mtag = pf_get_mtag(m)) == NULL) {
-               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);
+       if (ifp->if_type == IFT_CARP && ifp->if_carpdev)
+               kif = (struct pfi_kif *)ifp->if_carpdev->if_pf_kif;
+       else
+               kif = (struct pfi_kif *)ifp->if_pf_kif;
 
-       kif = (struct pfi_kif *)ifp->if_pf_kif;
        if (kif == NULL) {
                DPFPRINTF(PF_DEBUG_URGENT,
                    ("pf_test6: kif == NULL, if_xname %s\n", ifp->if_xname));
@@ -6536,12 +5925,15 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0,
                goto done;
        }
 
+       if (m->m_pkthdr.pf.flags & PF_TAG_GENERATED)
+               return (PF_PASS);
+
        /* We do IP header normalization and packet reassembly here */
        if (pf_normalize_ip6(m0, dir, kif, &reason, &pd) != PF_PASS) {
                action = PF_DROP;
                goto done;
        }
-       m = *m0;
+       m = *m0;        /* pf_normalize messes with m0 */
        h = mtod(m, struct ip6_hdr *);
 
 #if 1
@@ -6578,11 +5970,20 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0,
                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;
                        }
@@ -6639,13 +6040,6 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0,
                        log = action != PF_PASS;
                        goto done;
                }
-               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;
-                       REASON_SET(&reason, PFRES_PROTCKSUM);
-                       goto done;
-               }
                pd.p_len = pd.tot_len - off - (th.th_off << 2);
                action = pf_normalize_tcp(dir, kif, m, 0, off, h, &pd);
                if (action == PF_DROP)
@@ -6660,7 +6054,7 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0,
                        a = s->anchor.ptr;
                        log = s->log;
                } else if (s == NULL)
-                       action = pf_test_tcp(&r, &s, dir, kif,
+                       action = pf_test_rule(&r, &s, dir, kif,
                            m, off, h, &pd, &a, &ruleset, NULL, inp);
                break;
        }
@@ -6674,13 +6068,6 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0,
                        log = action != PF_PASS;
                        goto done;
                }
-               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;
-                       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)) {
@@ -6697,7 +6084,7 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0,
                        a = s->anchor.ptr;
                        log = s->log;
                } else if (s == NULL)
-                       action = pf_test_udp(&r, &s, dir, kif,
+                       action = pf_test_rule(&r, &s, dir, kif,
                            m, off, h, &pd, &a, &ruleset, NULL, inp);
                break;
        }
@@ -6711,13 +6098,6 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0,
                        log = action != PF_PASS;
                        goto done;
                }
-               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;
-                       REASON_SET(&reason, PFRES_PROTCKSUM);
-                       goto done;
-               }
                action = pf_test_state_icmp(&s, dir, kif,
                    m, off, h, &pd, &reason);
                if (action == PF_PASS) {
@@ -6728,8 +6108,8 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0,
                        a = s->anchor.ptr;
                        log = s->log;
                } else if (s == NULL)
-                       action = pf_test_icmp(&r, &s, dir, kif,
-                           m, off, h, &pd, &a, &ruleset, NULL);
+                       action = pf_test_rule(&r, &s, dir, kif,
+                           m, off, h, &pd, &a, &ruleset, NULL, inp);
                break;
        }
 
@@ -6743,8 +6123,8 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0,
                        a = s->anchor.ptr;
                        log = s->log;
                } else if (s == NULL)
-                       action = pf_test_other(&r, &s, dir, kif, m, off, h,
-                           &pd, &a, &ruleset, NULL);
+                       action = pf_test_rule(&r, &s, dir, kif, m, off, h,
+                           &pd, &a, &ruleset, NULL, inp);
                break;
        }
 
@@ -6754,25 +6134,32 @@ done:
                n = NULL;
        }
 
-       /* 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) || r->rtableid)
-               pf_tag_packet(m, pd.pf_mtag, s ? s->tag : 0, r->rtableid);
+               pf_tag_packet(m, s ? s->tag : 0, r->rtableid);
 
 #ifdef ALTQ
        if (action == PF_PASS && r->qid) {
+               m->m_pkthdr.fw_flags |= PF_MBUF_STRUCTURE;
                if (pd.tos & IPTOS_LOWDELAY)
-                       pd.pf_mtag->qid = r->pqid;
+                       m->m_pkthdr.pf.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;
-               /* add connection hash for fairq */
+                       m->m_pkthdr.pf.qid = r->qid;
+               m->m_pkthdr.pf.ecn_af = AF_INET6;
+               m->m_pkthdr.pf.hdr = h;
                if (s) {
-                       KKASSERT(s->hash != 0);
-                       pd.pf_mtag->flags |= PF_TAG_STATE_HASHED;
-                       pd.pf_mtag->state_hash = s->hash;
+                       /* for fairq */
+                       m->m_pkthdr.pf.state_hash = s->hash;
+                       m->m_pkthdr.pf.flags |= PF_TAG_STATE_HASHED;
                }
        }
 #endif /* ALTQ */
@@ -6782,7 +6169,7 @@ done:
            (s->nat_rule.ptr->action == PF_RDR ||
            s->nat_rule.ptr->action == PF_BINAT) &&
            IN6_IS_ADDR_LOOPBACK(&pd.dst->v6))
-               pd.pf_mtag->flags |= PF_TAG_TRANSLATE_LOCALHOST;
+               m->m_pkthdr.pf.flags |= PF_TAG_TRANSLATE_LOCALHOST;
 
        if (log) {
                struct pf_rule *lr;
@@ -6808,6 +6195,7 @@ done:
                        a->bytes[dirndx] += pd.tot_len;
                }
                if (s != NULL) {
+                       sk = s->state_key;
                        if (s->nat_rule.ptr != NULL) {
                                s->nat_rule.ptr->packets[dirndx]++;
                                s->nat_rule.ptr->bytes[dirndx] += pd.tot_len;
@@ -6820,7 +6208,7 @@ done:
                                s->nat_src_node->packets[dirndx]++;
                                s->nat_src_node->bytes[dirndx] += pd.tot_len;
                        }
-                       dirndx = (dir == s->direction) ? 0 : 1;
+                       dirndx = (dir == sk->direction) ? 0 : 1;
                        s->packets[dirndx]++;
                        s->bytes[dirndx] += pd.tot_len;
                }
@@ -6835,10 +6223,10 @@ done:
                         */
                        if (r == &pf_default_rule) {
                                tr = nr;
-                               x = (s == NULL || s->direction == dir) ?
+                               x = (s == NULL || sk->direction == dir) ?
                                    &pd.baddr : &pd.naddr;
                        } else {
-                               x = (s == NULL || s->direction == dir) ?
+                               x = (s == NULL || sk->direction == dir) ?
                                    &pd.naddr : &pd.baddr;
                        }
                        if (x == &pd.baddr || s == NULL) {
@@ -6849,13 +6237,13 @@ done:
                        }
                }
                if (tr->src.addr.type == PF_ADDR_TABLE)
-                       pfr_update_stats(tr->src.addr.p.tbl, (s == NULL ||
-                           s->direction == dir) ? pd.src : pd.dst, pd.af,
+                       pfr_update_stats(tr->src.addr.p.tbl, (sk == NULL ||
+                           sk->direction == dir) ? pd.src : pd.dst, pd.af,
                            pd.tot_len, dir == PF_OUT, r->action == PF_PASS,
                            tr->src.neg);
                if (tr->dst.addr.type == PF_ADDR_TABLE)
-                       pfr_update_stats(tr->dst.addr.p.tbl, (s == NULL ||
-                           s->direction == dir) ? pd.dst : pd.src, pd.af,
+                       pfr_update_stats(tr->dst.addr.p.tbl, (sk == NULL ||
+                           sk->direction == dir) ? pd.dst : pd.src, pd.af,
                            pd.tot_len, dir == PF_OUT, r->action == PF_PASS,
                            tr->dst.neg);
        }
@@ -6867,7 +6255,7 @@ done:
                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, &pd);
+               pf_route6(m0, r, dir, kif->pfik_ifp, s, &pd);
 
        return (action);
 }
index a6b8672..521b7a2 100644 (file)
@@ -65,7 +65,6 @@
 #endif /* INET6 */
 
 struct pfi_kif          *pfi_all = NULL;
-struct pfi_statehead     pfi_statehead;
 vm_zone_t                pfi_addr_pl;
 struct pfi_ifhead        pfi_ifs;
 long                     pfi_update = 1;
@@ -107,7 +106,6 @@ pfi_initialize(void)
        if (pfi_all != NULL)    /* already initialized */
                return;
 
-       TAILQ_INIT(&pfi_statehead);
        pfi_buffer_max = 64;
        pfi_buffer = kmalloc(pfi_buffer_max * sizeof(*pfi_buffer),
            PFI_MTYPE, M_WAITOK);
@@ -229,8 +227,7 @@ pfi_kif_ref(struct pfi_kif *kif, enum pfi_kif_refs what)
                kif->pfik_rules++;
                break;
        case PFI_KIF_REF_STATE:
-               if (!kif->pfik_states++)
-                       TAILQ_INSERT_TAIL(&pfi_statehead, kif, pfik_w_states);
+               kif->pfik_states++;
                break;
        default:
                panic("pfi_kif_ref with unknown type");
@@ -258,8 +255,7 @@ pfi_kif_unref(struct pfi_kif *kif, enum pfi_kif_refs what)
                        kprintf("pfi_kif_unref: state refcount <= 0\n");
                        return;
                }
-               if (!--kif->pfik_states)
-                       TAILQ_REMOVE(&pfi_statehead, kif, pfik_w_states);
+               kif->pfik_states--;
                break;
        default:
                panic("pfi_kif_unref with unknown type");
index 8bfcd6e..c69546e 100644 (file)
@@ -1,6 +1,4 @@
-/*     $FreeBSD: src/sys/contrib/pf/net/pf_ioctl.c,v 1.12 2004/08/12 14:15:42 mlaier Exp $     */
-/*     $OpenBSD: pf_ioctl.c,v 1.112.2.2 2004/07/24 18:28:12 brad Exp $ */
-/*     $OpenBSD: pf_ioctl.c,v 1.175 2007/02/26 22:47:43 deraadt Exp $ */
+/*     $OpenBSD: pf_ioctl.c,v 1.182 2007/06/24 11:17:13 mcbride Exp $ */
 
 /*
  * Copyright (c) 2010 The DragonFly Project.  All rights reserved.
@@ -123,6 +121,10 @@ 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 *);
+void                    pf_state_export(struct pfsync_state *,
+                           struct pf_state_key *, struct pf_state *);
+void                    pf_state_import(struct pfsync_state *,
+                           struct pf_state_key *, struct pf_state *);
 
 struct pf_rule          pf_default_rule;
 struct lock             pf_consistency_lock;
@@ -221,6 +223,7 @@ cleanup_pf_zone(void)
        ZONE_DESTROY(pf_cent_pl);
        ZONE_DESTROY(pfr_ktable_pl);
        ZONE_DESTROY(pfr_kentry_pl);
+       ZONE_DESTROY(pfr_kentry_pl2);
        ZONE_DESTROY(pf_state_scrub_pl);
        ZONE_DESTROY(pfi_addr_pl);
 }
@@ -235,10 +238,12 @@ pfattach(void)
                ZONE_CREATE(pf_src_tree_pl,struct pf_src_node, "pfsrctrpl");
                ZONE_CREATE(pf_rule_pl,    struct pf_rule, "pfrulepl");
                ZONE_CREATE(pf_state_pl,   struct pf_state, "pfstatepl");
+               ZONE_CREATE(pf_state_key_pl, struct pf_state_key, "pfstatekeypl");
                ZONE_CREATE(pf_altq_pl,    struct pf_altq, "pfaltqpl");
                ZONE_CREATE(pf_pooladdr_pl,struct pf_pooladdr, "pfpooladdrpl");
                ZONE_CREATE(pfr_ktable_pl, struct pfr_ktable, "pfrktable");
                ZONE_CREATE(pfr_kentry_pl, struct pfr_kentry, "pfrkentry");
+               ZONE_CREATE(pfr_kentry_pl2, struct pfr_kentry, "pfrkentry2");
                ZONE_CREATE(pf_frent_pl,   struct pf_frent, "pffrent");
                ZONE_CREATE(pf_frag_pl,    struct pf_fragment, "pffrag");
                ZONE_CREATE(pf_cache_pl,   struct pf_fragment, "pffrcache");
@@ -931,6 +936,89 @@ pf_commit_rules(u_int32_t ticket, int rs_num, char *anchor)
        return (0);
 }
 
+void
+pf_state_export(struct pfsync_state *sp, struct pf_state_key *sk,
+   struct pf_state *s) 
+{
+       int secs = time_second;
+       bzero(sp, sizeof(struct pfsync_state));
+
+       /* copy from state key */
+       sp->lan.addr = sk->lan.addr;
+       sp->lan.port = sk->lan.port;
+       sp->gwy.addr = sk->gwy.addr;
+       sp->gwy.port = sk->gwy.port;
+       sp->ext.addr = sk->ext.addr;
+       sp->ext.port = sk->ext.port;
+       sp->proto = sk->proto;
+       sp->af = sk->af;
+       sp->direction = sk->direction;
+
+       /* copy from state */
+       memcpy(&sp->id, &s->id, sizeof(sp->id));
+       sp->creatorid = s->creatorid;
+       strlcpy(sp->ifname, s->kif->pfik_name, sizeof(sp->ifname));
+       pf_state_peer_to_pfsync(&s->src, &sp->src);
+       pf_state_peer_to_pfsync(&s->dst, &sp->dst);
+
+       sp->rule = s->rule.ptr->nr;
+       sp->nat_rule = (s->nat_rule.ptr == NULL) ?  -1 : s->nat_rule.ptr->nr;
+       sp->anchor = (s->anchor.ptr == NULL) ?  -1 : s->anchor.ptr->nr;
+
+       pf_state_counter_to_pfsync(s->bytes[0], sp->bytes[0]);
+       pf_state_counter_to_pfsync(s->bytes[1], sp->bytes[1]);
+       pf_state_counter_to_pfsync(s->packets[0], sp->packets[0]);
+       pf_state_counter_to_pfsync(s->packets[1], sp->packets[1]);
+       sp->creation = secs - s->creation;
+       sp->expire = pf_state_expires(s);
+       sp->log = s->log;
+       sp->allow_opts = s->allow_opts;
+       sp->timeout = s->timeout;
+
+       if (s->src_node)
+               sp->sync_flags |= PFSYNC_FLAG_SRCNODE;
+       if (s->nat_src_node)
+               sp->sync_flags |= PFSYNC_FLAG_NATSRCNODE;
+
+       if (sp->expire > secs)
+               sp->expire -= secs;
+       else
+               sp->expire = 0;
+
+}
+
+void
+pf_state_import(struct pfsync_state *sp, struct pf_state_key *sk,
+   struct pf_state *s) 
+{
+       /* copy to state key */
+       sk->lan.addr = sp->lan.addr;
+       sk->lan.port = sp->lan.port;
+       sk->gwy.addr = sp->gwy.addr;
+       sk->gwy.port = sp->gwy.port;
+       sk->ext.addr = sp->ext.addr;
+       sk->ext.port = sp->ext.port;
+       sk->proto = sp->proto;
+       sk->af = sp->af;
+       sk->direction = sp->direction;
+
+       /* copy to state */
+       memcpy(&s->id, &sp->id, sizeof(sp->id));
+       s->creatorid = sp->creatorid;
+       strlcpy(sp->ifname, s->kif->pfik_name, sizeof(sp->ifname));
+       pf_state_peer_from_pfsync(&sp->src, &s->src);
+       pf_state_peer_from_pfsync(&sp->dst, &s->dst);
+
+       s->rule.ptr = &pf_default_rule;
+       s->nat_rule.ptr = NULL;
+       s->anchor.ptr = NULL;
+       s->rt_kif = NULL;
+       s->creation = time_second;
+       s->pfsync_time = 0;
+       s->packets[0] = s->packets[1] = 0;
+       s->bytes[0] = s->bytes[1] = 0;
+}
+
 int
 pf_setup_pfsync_matching(struct pf_ruleset *rs)
 {
@@ -1219,6 +1307,8 @@ pfioctl(struct dev_ioctl_args *ap)
                if (rule->rt && !rule->direction)
                        error = EINVAL;
 #if NPFLOG > 0
+               if (!rule->log)
+                       rule->logif = 0;
                if (rule->logif >= PFLOGIFS_MAX)
                        error = EINVAL;
 #endif
@@ -1460,6 +1550,12 @@ pfioctl(struct dev_ioctl_args *ap)
                                        error = EBUSY;
                        if (newrule->rt && !newrule->direction)
                                error = EINVAL;
+#if NPFLOG > 0
+                       if (!newrule->log)
+                               newrule->logif = 0;
+                       if (newrule->logif >= PFLOGIFS_MAX)
+                               error = EINVAL;
+#endif
                        if (pf_rtlabel_add(&newrule->src.addr) ||
                            pf_rtlabel_add(&newrule->dst.addr))
                                error = EBUSY;
@@ -1558,21 +1654,20 @@ pfioctl(struct dev_ioctl_args *ap)
        }
 
        case DIOCCLRSTATES: {
-               struct pf_state         *state, *nexts;
+               struct pf_state         *s, *nexts;
                struct pfioc_state_kill *psk = (struct pfioc_state_kill *)addr;
                int                      killed = 0;
 
-               for (state = RB_MIN(pf_state_tree_id, &tree_id); state;
-                   state = nexts) {
-                       nexts = RB_NEXT(pf_state_tree_id, &tree_id, state);
+               for (s = RB_MIN(pf_state_tree_id, &tree_id); s; s = nexts) {
+                       nexts = RB_NEXT(pf_state_tree_id, &tree_id, s);
 
                        if (!psk->psk_ifname[0] || !strcmp(psk->psk_ifname,
-                           state->u.s.kif->pfik_name)) {
+                           s->kif->pfik_name)) {
 #if NPFSYNC
                                /* don't send out individual delete messages */
-                               state->sync_flags = PFSTATE_NOSYNC;
+                               s->sync_flags = PFSTATE_NOSYNC;
 #endif
-                               pf_unlink_state(state);
+                               pf_unlink_state(s);
                                killed++;
                        }
                }
@@ -1584,33 +1679,35 @@ pfioctl(struct dev_ioctl_args *ap)
        }
 
        case DIOCKILLSTATES: {
-               struct pf_state         *state, *nexts;
+               struct pf_state         *s, *nexts;
+               struct pf_state_key     *sk;
                struct pf_state_host    *src, *dst;
                struct pfioc_state_kill *psk = (struct pfioc_state_kill *)addr;
                int                      killed = 0;
 
-               for (state = RB_MIN(pf_state_tree_id, &tree_id); state;
-                   state = nexts) {
-                       nexts = RB_NEXT(pf_state_tree_id, &tree_id, state);
+               for (s = RB_MIN(pf_state_tree_id, &tree_id); s;
+                   s = nexts) {
+                       nexts = RB_NEXT(pf_state_tree_id, &tree_id, s);
+                       sk = s->state_key;
 
-                       if (state->direction == PF_OUT) {
-                               src = &state->lan;
-                               dst = &state->ext;
+                       if (sk->direction == PF_OUT) {
+                               src = &sk->lan;
+                               dst = &sk->ext;
                        } else {
-                               src = &state->ext;
-                               dst = &state->lan;
+                               src = &sk->ext;
+                               dst = &sk->lan;
                        }
-                       if ((!psk->psk_af || state->af == psk->psk_af)
+                       if ((!psk->psk_af || sk->af == psk->psk_af)
                            && (!psk->psk_proto || psk->psk_proto ==
-                           state->proto) &&
+                           sk->proto) &&
                            PF_MATCHA(psk->psk_src.neg,
                            &psk->psk_src.addr.v.a.addr,
                            &psk->psk_src.addr.v.a.mask,
-                           &src->addr, state->af) &&
+                           &src->addr, sk->af) &&
                            PF_MATCHA(psk->psk_dst.neg,
                            &psk->psk_dst.addr.v.a.addr,
                            &psk->psk_dst.addr.v.a.mask,
-                           &dst->addr, state->af) &&
+                           &dst->addr, sk->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],
@@ -1620,13 +1717,13 @@ pfioctl(struct dev_ioctl_args *ap)
                            psk->psk_dst.port[0], psk->psk_dst.port[1],
                            dst->port)) &&
                            (!psk->psk_ifname[0] || !strcmp(psk->psk_ifname,
-                           state->u.s.kif->pfik_name))) {
+                           s->kif->pfik_name))) {
 #if NPFSYNC > 0
                                /* send immediate delete of state */
-                               pfsync_delete_state(state);
-                               state->sync_flags |= PFSTATE_NOSYNC;
+                               pfsync_delete_state(s);
+                               s->sync_flags |= PFSTATE_NOSYNC;
 #endif
-                               pf_unlink_state(state);
+                               pf_unlink_state(s);
                                killed++;
                        }
                }
@@ -1636,40 +1733,38 @@ pfioctl(struct dev_ioctl_args *ap)
 
        case DIOCADDSTATE: {
                struct pfioc_state      *ps = (struct pfioc_state *)addr;
-               struct pf_state         *state;
+               struct pfsync_state     *sp = (struct pfsync_state *)ps->state;
+               struct pf_state         *s;
+               struct pf_state_key     *sk;
                struct pfi_kif          *kif;
 
-               if (ps->state.timeout >= PFTM_MAX &&
-                   ps->state.timeout != PFTM_UNTIL_PACKET) {
+               if (sp->timeout >= PFTM_MAX &&
+                   sp->timeout != PFTM_UNTIL_PACKET) {
                        error = EINVAL;
                        break;
                }
-               state = pool_get(&pf_state_pl, PR_NOWAIT);
-               if (state == NULL) {
+               s = pool_get(&pf_state_pl, PR_NOWAIT);
+               if (s == NULL) {
+                       error = ENOMEM;
+                       break;
+               }
+               bzero(s, sizeof(struct pf_state));
+               if ((sk = pf_alloc_state_key(s)) == NULL) {
                        error = ENOMEM;
                        break;
                }
-               kif = pfi_kif_get(ps->state.u.ifname);
+               pf_state_import(sp, sk, s);
+               kif = pfi_kif_get(sp->ifname);
                if (kif == NULL) {
-                       pool_put(&pf_state_pl, state);
+                       pool_put(&pf_state_pl, s);
+                       pool_put(&pf_state_key_pl, sk);
                        error = ENOENT;
                        break;
                }
-               bcopy(&ps->state, state, sizeof(struct pf_state));
-               bzero(&state->u, sizeof(state->u));
-               state->rule.ptr = &pf_default_rule;
-               state->nat_rule.ptr = NULL;
-               state->anchor.ptr = NULL;
-               state->rt_kif = NULL;
-               state->creation = time_second;
-               state->pfsync_time = 0;
-               state->packets[0] = state->packets[1] = 0;
-               state->bytes[0] = state->bytes[1] = 0;
-               state->hash = pf_state_hash(state);
-
-               if (pf_insert_state(kif, state)) {
+               if (pf_insert_state(kif, s)) {
                        pfi_kif_unref(kif, PFI_KIF_REF_NONE);
-                       pool_put(&pf_state_pl, state);
+                       pool_put(&pf_state_pl, s);
+                       pool_put(&pf_state_key_pl, sk);
                        error = ENOMEM;
                }
                break;
@@ -1677,48 +1772,34 @@ pfioctl(struct dev_ioctl_args *ap)
 
        case DIOCGETSTATE: {
                struct pfioc_state      *ps = (struct pfioc_state *)addr;
-               struct pf_state         *state;
+               struct pf_state         *s;
                u_int32_t                nr;
-               int                      secs;
 
                nr = 0;
-               RB_FOREACH(state, pf_state_tree_id, &tree_id) {
+               RB_FOREACH(s, pf_state_tree_id, &tree_id) {
                        if (nr >= ps->nr)
                                break;
                        nr++;
                }
-               if (state == NULL) {
+               if (s == NULL) {
                        error = EBUSY;
                        break;
                }
-               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) ?
-                   (uint32_t)(-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 > secs)
-                       ps->state.expire -= secs;
-               else
-                       ps->state.expire = 0;
+
+               pf_state_export((struct pfsync_state *)&ps->state,
+                   s->state_key, s);
                break;
        }
 
        case DIOCGETSTATES: {
                struct pfioc_states     *ps = (struct pfioc_states *)addr;
                struct pf_state         *state;
-               struct pf_state         *p, *pstore;
+               struct pfsync_state     *p, *pstore;
                u_int32_t                nr = 0;
-               int                      space = ps->ps_len;
 
-               if (space == 0) {
+               if (ps->ps_len == 0) {
                        nr = pf_status.states;
-                       ps->ps_len = sizeof(struct pf_state) * nr;
+                       ps->ps_len = sizeof(struct pfsync_state) * nr;
                        break;
                }
 
@@ -1729,26 +1810,11 @@ pfioctl(struct dev_ioctl_args *ap)
                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,
-                                   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 ==
-                                   NULL) ? -1 : state->anchor.ptr->nr;
-                               pstore->creation = secs - pstore->creation;
-                               pstore->expire = pf_state_expires(state);
-                               if (pstore->expire > secs)
-                                       pstore->expire -= secs;
-                               else
-                                       pstore->expire = 0;
+                               pf_state_export(pstore,
+                                   state->state_key, state);
                                error = copyout(pstore, p, sizeof(*p));
                                if (error) {
                                        kfree(pstore, M_TEMP);
@@ -1757,10 +1823,10 @@ pfioctl(struct dev_ioctl_args *ap)
                                p++;
                                nr++;
                        }
-                       state = TAILQ_NEXT(state, u.s.entry_list);
+                       state = TAILQ_NEXT(state, entry_list);
                }
 
-               ps->ps_len = sizeof(struct pf_state) * nr;
+               ps->ps_len = sizeof(struct pfsync_state) * nr;
 
                kfree(pstore, M_TEMP);
                break;
@@ -1800,8 +1866,9 @@ pfioctl(struct dev_ioctl_args *ap)
 
        case DIOCNATLOOK: {
                struct pfioc_natlook    *pnl = (struct pfioc_natlook *)addr;
+               struct pf_state_key     *sk;
                struct pf_state         *state;
-               struct pf_state_cmp      key;
+               struct pf_state_key_cmp  key;
                int                      m = 0, direction = pnl->direction;
 
                key.af = pnl->af;
@@ -1837,17 +1904,18 @@ pfioctl(struct dev_ioctl_args *ap)
                        if (m > 1)
                                error = E2BIG;  /* more than one state */
                        else if (state != NULL) {
+                               sk = state->state_key;
                                if (direction == PF_IN) {
-                                       PF_ACPY(&pnl->rsaddr, &state->lan.addr,
-                                           state->af);
-                                       pnl->rsport = state->lan.port;
+                                       PF_ACPY(&pnl->rsaddr, &sk->lan.addr,
+                                           sk->af);
+                                       pnl->rsport = sk->lan.port;
                                        PF_ACPY(&pnl->rdaddr, &pnl->daddr,
                                            pnl->af);
                                        pnl->rdport = pnl->dport;
                                } else {
-                                       PF_ACPY(&pnl->rdaddr, &state->gwy.addr,
-                                           state->af);
-                                       pnl->rdport = state->gwy.port;
+                                       PF_ACPY(&pnl->rdaddr, &sk->gwy.addr,
+                                           sk->af);
+                                       pnl->rdport = sk->gwy.port;
                                        PF_ACPY(&pnl->rsaddr, &pnl->saddr,
                                            pnl->af);
                                        pnl->rsport = pnl->sport;
@@ -3261,18 +3329,14 @@ pf_load(void)
 
        init_zone_var();
        lockinit(&pf_mod_lck, "pf task lck", 0, LK_CANRECURSE);
-       kprintf("pf_load() p1\n"); /*XXX*/
        pf_dev = make_dev(&pf_ops, 0, 0, 0, 0600, PF_NAME);
-       kprintf("pf_load() p2\n"); /*XXX*/
        error = pfattach();
-       kprintf("pf_load() p3\n"); /*XXX*/
        if (error) {
                dev_ops_remove_all(&pf_ops);
                lockuninit(&pf_mod_lck);
                return (error);
        }
        lockinit(&pf_consistency_lock, "pfconslck", 0, LK_CANRECURSE);
-       kprintf("pf_load() p4\n"); /*XXX*/
        return (0);
 }
 
index fdaae26..fe1294f 100644 (file)
@@ -1,8 +1,4 @@
-/*     $FreeBSD: src/sys/contrib/pf/net/pf_norm.c,v 1.10 2004/08/14 15:32:40 dwmalone Exp $    */
-/*     $OpenBSD: pf_norm.c,v 1.80.2.1 2004/04/30 21:46:33 brad Exp $ */
-/* add $OpenBSD: pf_norm.c,v 1.87 2004/05/11 07:34:11 dhartmei Exp $ */
-/*     $DragonFly: src/sys/net/pf/pf_norm.c,v 1.10 2008/09/04 09:08:22 hasso Exp $ */
-/*     $OpenBSD: pf_norm.c,v 1.107 2006/04/16 00:59:52 pascoe Exp $ */
+/*     $OpenBSD: pf_norm.c,v 1.109 2007/05/28 17:16:39 henning Exp $ */
 
 /*
  * Copyright (c) 2010 The DragonFly Project.  All rights reserved.
@@ -290,7 +286,7 @@ pf_remove_fragment(struct pf_fragment *frag)
        }
 }
 
-#define FR_IP_OFF(fr)  ((ntohs((fr)->fr_ip->ip_off) & IP_OFFMASK) << 3)
+#define FR_IP_OFF(fr)  (((fr)->fr_ip->ip_off & IP_OFFMASK) << 3)
 struct mbuf *
 pf_reassemble(struct mbuf **m0, struct pf_fragment **frag,
     struct pf_frent *frent, int mff)
@@ -852,7 +848,7 @@ pf_normalize_ip(struct mbuf **m0, int dir, struct pfi_kif *kif, u_short *reason,
                goto drop;
 
        /* Clear IP_DF if the rule uses the no-df option */
-       if (r->rule_flag & PFRULE_NODF && h->ip_off & htons(IP_DF)) {
+       if (r->rule_flag & PFRULE_NODF && h->ip_off & IP_DF) {
                u_int16_t ip_off = h->ip_off;
 
                h->ip_off &= ~IP_DF;
@@ -915,18 +911,6 @@ pf_normalize_ip(struct mbuf **m0, int dir, struct pfi_kif *kif, u_short *reason,
                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) {
-                       kprintf("%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;
 
@@ -935,7 +919,7 @@ pf_normalize_ip(struct mbuf **m0, int dir, struct pfi_kif *kif, u_short *reason,
                /* non-buffering fragment cache (drops or masks overlaps) */
                int     nomem = 0;
 
-               if (dir == PF_OUT && pd->pf_mtag->flags & PF_TAG_FRAGCACHE) {
+               if (dir == PF_OUT && m->m_pkthdr.pf.flags & PF_TAG_FRAGCACHE) {
                        /*
                         * Already passed the fragment cache in the
                         * input direction.  If we continued, it would
@@ -962,20 +946,8 @@ pf_normalize_ip(struct mbuf **m0, int dir, struct pfi_kif *kif, u_short *reason,
                        goto drop;
                }
 
-               /* use mtag from copied and trimmed mbuf chain */
-               pd->pf_mtag = pf_find_mtag(m);
-#ifdef DIAGNOSTIC
-               if (pd->pf_mtag == NULL) {
-                       kprintf("%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;
-                       }
-               }
-#endif
                if (dir == PF_IN)
-                       pd->pf_mtag->flags |= PF_TAG_FRAGCACHE;
+                       m->m_pkthdr.pf.flags |= PF_TAG_FRAGCACHE;
 
                if (frag != NULL && (frag->fr_flags & PFFRAG_DROP))
                        goto drop;
@@ -984,11 +956,11 @@ pf_normalize_ip(struct mbuf **m0, int dir, struct pfi_kif *kif, u_short *reason,
 
  no_fragment:
        /* At this point, only IP_DF is allowed in ip_off */
-       if (h->ip_off & IP_DF) {
+       if (h->ip_off & ~IP_DF) {
                u_int16_t ip_off = h->ip_off;
 
                h->ip_off &= IP_DF;
-               h->ip_sum = pf_cksum_fixup(h->ip_sum, ip_off, h->ip_off, 0);
+               h->ip_sum = pf_cksum_fixup(h->ip_sum, htons(ip_off), htons(h->ip_off), 0);
        }
 
        /* Enforce a minimum ttl, may cause endless packet loops */
@@ -1645,7 +1617,7 @@ pf_normalize_tcp_stateful(struct mbuf *m, int off, struct pf_pdesc *pd,
                 *    network conditions that re-order packets and
                 *    cause our view of them to decrease.  For now the
                 *    only lowerbound we can safely determine is that
-                *    the TS echo will never be less than the orginal
+                *    the TS echo will never be less than the original
                 *    TS.  XXX There is probably a better lowerbound.
                 *    Remove TS_MAX_CONN with better lowerbound check.
                 *        tescr >= other original TS
index 6d0122d..df27205 100644 (file)
@@ -1,8 +1,3 @@
-/*      $FreeBSD: src/sys/contrib/pf/net/pf_subr.c,v 1.1 2004/06/16 23:24:00 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 $     */
-/*     $DragonFly: src/sys/net/pf/pf_subr.c,v 1.2 2006/09/05 00:55:47 dillon Exp $ */
-
 /*
  * Copyright (c) 2004 The DragonFly Project.  All rights reserved.
  *
@@ -187,7 +182,7 @@ static int pf_isn_last_reseed;
 static u_int32_t pf_isn_offset;
 
 u_int32_t
-pf_new_isn(struct pf_state *s) /* From FreeBSD */
+pf_new_isn(struct pf_state_key *sk)    /* From FreeBSD */
 {
        MD5_CTX isn_ctx;
        u_int32_t md5_buffer[4];
@@ -200,12 +195,12 @@ pf_new_isn(struct pf_state *s)    /* From FreeBSD */
                pf_isn_last_reseed = ticks;
        }
 
-       if (s->direction == PF_IN) {
-               src = &s->ext;
-               dst = &s->gwy;
+       if (sk->direction == PF_IN) {
+               src = &sk->ext;
+               dst = &sk->gwy;
        } else {
-               src = &s->lan;
-               dst = &s->ext;
+               src = &sk->lan;
+               dst = &sk->ext;
        }
 
        /* Compute the md5 hash and return the ISN. */
@@ -213,7 +208,7 @@ pf_new_isn(struct pf_state *s)      /* From FreeBSD */
        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) {
+       if (sk->af == AF_INET6) {
                MD5Update(&isn_ctx, (u_char *) &dst->addr,
                          sizeof(struct in6_addr));
                MD5Update(&isn_ctx, (u_char *) &src->addr,
index 3e3543a..06e54b2 100644 (file)
@@ -1,7 +1,4 @@
-/*     $FreeBSD: src/sys/contrib/pf/net/pf_table.c,v 1.5 2004/07/28 06:14:44 kan Exp $ */
-/*     $OpenBSD: pf_table.c,v 1.47 2004/03/09 21:44:41 mcbride Exp $   */
-/*     $DragonFly: src/sys/net/pf/pf_table.c,v 1.5 2006/12/22 23:44:57 swildner Exp $ */
-/*     $OpenBSD: pf_table.c,v 1.68 2006/05/02 10:08:45 dhartmei Exp $  */
+/*     $OpenBSD: pf_table.c,v 1.70 2007/05/23 11:53:45 markus Exp $    */
 
 /*
  * Copyright (c) 2004 The DragonFly Project.  All rights reserved.
 #include <netinet/in.h>
 #include <net/pf/pfvar.h>
 
-#define ACCEPT_FLAGS(oklist)                   \
+#define ACCEPT_FLAGS(flags, oklist)                    \
        do {                                    \
                if ((flags & ~(oklist)) &       \
                    PFR_FLAG_ALLMASK)           \
                        return (EINVAL);        \
        } while (0)
 
-#define COPYIN(from, to, size)                 \
+#define COPYIN(from, to, size, flags)          \
        ((flags & PFR_FLAG_USERIOCTL) ?         \
        copyin((from), (to), (size)) :          \
        (bcopy((from), (to), (size)), 0))
 
-#define COPYOUT(from, to, size)                        \
+#define COPYOUT(from, to, size, flags)         \
        ((flags & PFR_FLAG_USERIOCTL) ?         \
        copyout((from), (to), (size)) :         \
        (bcopy((from), (to), (size)), 0))
@@ -212,7 +209,7 @@ pfr_clr_addrs(struct pfr_table *tbl, int *ndel, int flags)
        struct pfr_ktable       *kt;
        struct pfr_kentryworkq   workq;
 
-       ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY);
+       ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_DUMMY);
        if (pfr_validate_table(tbl, 0, flags & PFR_FLAG_USERIOCTL))
                return (EINVAL);
        kt = pfr_lookup_table(tbl);
@@ -248,7 +245,8 @@ pfr_add_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
        int                      i, rv, xadd = 0;
        long                     tzero = time_second;
 
-       ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY+PFR_FLAG_FEEDBACK);
+       ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_DUMMY |
+           PFR_FLAG_FEEDBACK);
        if (pfr_validate_table(tbl, 0, flags & PFR_FLAG_USERIOCTL))
                return (EINVAL);
        kt = pfr_lookup_table(tbl);
@@ -261,7 +259,7 @@ pfr_add_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
                return (ENOMEM);
        SLIST_INIT(&workq);
        for (i = 0; i < size; i++) {
-               if (COPYIN(addr+i, &ad, sizeof(ad)))
+               if (COPYIN(addr+i, &ad, sizeof(ad), flags))
                        senderr(EFAULT);
                if (pfr_validate_addr(&ad))
                        senderr(EINVAL);
@@ -278,7 +276,8 @@ pfr_add_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
                                ad.pfra_fback = PFR_FB_NONE;
                }
                if (p == NULL && q == NULL) {
-                       p = pfr_create_kentry(&ad, 0);
+                       p = pfr_create_kentry(&ad,
+                           !(flags & PFR_FLAG_USERIOCTL));
                        if (p == NULL)
                                senderr(ENOMEM);
                        if (pfr_route_kentry(tmpkt, p)) {
@@ -290,7 +289,7 @@ pfr_add_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
                        }
                }
                if (flags & PFR_FLAG_FEEDBACK)
-                       if (COPYOUT(&ad, addr+i, sizeof(ad)))
+                       if (COPYOUT(&ad, addr+i, sizeof(ad), flags))
                                senderr(EFAULT);
        }
        pfr_clean_node_mask(tmpkt, &workq);
@@ -325,7 +324,8 @@ pfr_del_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
        struct pfr_addr          ad;
        int                      i, rv, xdel = 0, log = 1;
 
-       ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY+PFR_FLAG_FEEDBACK);
+       ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_DUMMY |
+           PFR_FLAG_FEEDBACK);
        if (pfr_validate_table(tbl, 0, flags & PFR_FLAG_USERIOCTL))
                return (EINVAL);
        kt = pfr_lookup_table(tbl);
@@ -352,7 +352,7 @@ pfr_del_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
        } else {
                /* iterate over addresses to delete */
                for (i = 0; i < size; i++) {
-                       if (COPYIN(addr+i, &ad, sizeof(ad)))
+                       if (COPYIN(addr+i, &ad, sizeof(ad), flags))
                                return (EFAULT);
                        if (pfr_validate_addr(&ad))
                                return (EINVAL);
@@ -363,7 +363,7 @@ pfr_del_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
        }
        SLIST_INIT(&workq);
        for (i = 0; i < size; i++) {
-               if (COPYIN(addr+i, &ad, sizeof(ad)))
+               if (COPYIN(addr+i, &ad, sizeof(ad), flags))
                        senderr(EFAULT);
                if (pfr_validate_addr(&ad))
                        senderr(EINVAL);
@@ -385,7 +385,7 @@ pfr_del_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
                        xdel++;
                }
                if (flags & PFR_FLAG_FEEDBACK)
-                       if (COPYOUT(&ad, addr+i, sizeof(ad)))
+                       if (COPYOUT(&ad, addr+i, sizeof(ad), flags))
                                senderr(EFAULT);
        }
        if (!(flags & PFR_FLAG_DUMMY)) {
@@ -416,7 +416,8 @@ pfr_set_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
        int                      i, rv, xadd = 0, xdel = 0, xchange = 0;
        long                     tzero = time_second;
 
-       ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY+PFR_FLAG_FEEDBACK);
+       ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_DUMMY |
+           PFR_FLAG_FEEDBACK);
        if (pfr_validate_table(tbl, ignore_pfrt_flags, flags &
            PFR_FLAG_USERIOCTL))
                return (EINVAL);
@@ -433,7 +434,7 @@ pfr_set_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
        SLIST_INIT(&delq);
        SLIST_INIT(&changeq);
        for (i = 0; i < size; i++) {
-               if (COPYIN(addr+i, &ad, sizeof(ad)))
+               if (COPYIN(addr+i, &ad, sizeof(ad), flags))
                        senderr(EFAULT);
                if (pfr_validate_addr(&ad))
                        senderr(EINVAL);
@@ -456,7 +457,8 @@ pfr_set_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
                                ad.pfra_fback = PFR_FB_DUPLICATE;
                                goto _skip;
                        }
-                       p = pfr_create_kentry(&ad, 0);
+                       p = pfr_create_kentry(&ad,
+                           !(flags & PFR_FLAG_USERIOCTL));
                        if (p == NULL)
                                senderr(ENOMEM);
                        if (pfr_route_kentry(tmpkt, p)) {
@@ -470,7 +472,7 @@ pfr_set_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
                }
 _skip:
                if (flags & PFR_FLAG_FEEDBACK)
-                       if (COPYOUT(&ad, addr+i, sizeof(ad)))
+                       if (COPYOUT(&ad, addr+i, sizeof(ad), flags))
                                senderr(EFAULT);
        }
        pfr_enqueue_addrs(kt, &delq, &xdel, ENQUEUE_UNMARKED_ONLY);
@@ -483,7 +485,7 @@ _skip:
                SLIST_FOREACH(p, &delq, pfrke_workq) {
                        pfr_copyout_addr(&ad, p);
                        ad.pfra_fback = PFR_FB_DELETED;
-                       if (COPYOUT(&ad, addr+size+i, sizeof(ad)))
+                       if (COPYOUT(&ad, addr+size+i, sizeof(ad), flags))
                                senderr(EFAULT);
                        i++;
                }
@@ -527,7 +529,7 @@ pfr_tst_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
        struct pfr_addr          ad;
        int                      i, xmatch = 0;
 
-       ACCEPT_FLAGS(PFR_FLAG_REPLACE);
+       ACCEPT_FLAGS(flags, PFR_FLAG_REPLACE);
        if (pfr_validate_table(tbl, 0, 0))
                return (EINVAL);
        kt = pfr_lookup_table(tbl);
@@ -535,7 +537,7 @@ pfr_tst_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
                return (ESRCH);
 
        for (i = 0; i < size; i++) {
-               if (COPYIN(addr+i, &ad, sizeof(ad)))
+               if (COPYIN(addr+i, &ad, sizeof(ad), flags))
                        return (EFAULT);
                if (pfr_validate_addr(&ad))
                        return (EINVAL);
@@ -548,7 +550,7 @@ pfr_tst_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
                    (p->pfrke_not ? PFR_FB_NOTMATCH : PFR_FB_MATCH);
                if (p != NULL && !p->pfrke_not)
                        xmatch++;
-               if (COPYOUT(&ad, addr+i, sizeof(ad)))
+               if (COPYOUT(&ad, addr+i, sizeof(ad), flags))
                        return (EFAULT);
        }
        if (nmatch != NULL)
@@ -564,7 +566,7 @@ pfr_get_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int *size,
        struct pfr_walktree      w;
        int                      rv;
 
-       ACCEPT_FLAGS(0);
+       ACCEPT_FLAGS(flags, 0);
        if (pfr_validate_table(tbl, 0, 0))
                return (EINVAL);
        kt = pfr_lookup_table(tbl);
@@ -605,7 +607,8 @@ pfr_get_astats(struct pfr_table *tbl, struct pfr_astats *addr, int *size,
        int                      rv;
        long                     tzero = time_second;
 
-       ACCEPT_FLAGS(PFR_FLAG_ATOMIC); /* XXX PFR_FLAG_CLSTATS disabled */
+       /* XXX PFR_FLAG_CLSTATS disabled */
+       ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC);
        if (pfr_validate_table(tbl, 0, 0))
                return (EINVAL);
        kt = pfr_lookup_table(tbl);
@@ -654,7 +657,8 @@ pfr_clr_astats(struct pfr_table *tbl, struct pfr_addr *addr, int size,
        struct pfr_addr          ad;
        int                      i, rv, xzero = 0;
 
-       ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY+PFR_FLAG_FEEDBACK);
+       ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_DUMMY |
+           PFR_FLAG_FEEDBACK);
        if (pfr_validate_table(tbl, 0, 0))
                return (EINVAL);
        kt = pfr_lookup_table(tbl);
@@ -662,7 +666,7 @@ pfr_clr_astats(struct pfr_table *tbl, struct pfr_addr *addr, int size,
                return (ESRCH);
        SLIST_INIT(&workq);
        for (i = 0; i < size; i++) {
-               if (COPYIN(addr+i, &ad, sizeof(ad)))
+               if (COPYIN(addr+i, &ad, sizeof(ad), flags))
                        senderr(EFAULT);
                if (pfr_validate_addr(&ad))
                        senderr(EINVAL);
@@ -670,7 +674,7 @@ pfr_clr_astats(struct pfr_table *tbl, struct pfr_addr *addr, int size,
                if (flags & PFR_FLAG_FEEDBACK) {
                        ad.pfra_fback = (p != NULL) ?
                            PFR_FB_CLEARED : PFR_FB_NONE;
-                       if (COPYOUT(&ad, addr+i, sizeof(ad)))
+                       if (COPYOUT(&ad, addr+i, sizeof(ad), flags))
                                senderr(EFAULT);
                }
                if (p != NULL) {
@@ -931,10 +935,10 @@ pfr_reset_feedback(struct pfr_addr *addr, int size, int flags)
        int             i;
 
        for (i = 0; i < size; i++) {
-               if (COPYIN(addr+i, &ad, sizeof(ad)))
+               if (COPYIN(addr+i, &ad, sizeof(ad), flags))
                        break;
                ad.pfra_fback = PFR_FB_NONE;
-               if (COPYOUT(&ad, addr+i, sizeof(ad)))
+               if (COPYOUT(&ad, addr+i, sizeof(ad), flags))
                        break;
        }
 }
@@ -1075,7 +1079,7 @@ pfr_walktree(struct radix_node *rn, void *arg)
                        crit_exit();
                        as.pfras_tzero = ke->pfrke_tzero;
 
-                       if (COPYOUT(&as, w->pfrw_astats, sizeof(as)))
+                       if (COPYOUT(&as, w->pfrw_astats, sizeof(as), flags))
                                return (EFAULT);
                        w->pfrw_astats++;
                }
@@ -1118,7 +1122,8 @@ pfr_clr_tables(struct pfr_table *filter, int *ndel, int flags)
        struct pfr_ktable       *p;
        int                      xdel = 0;
 
-       ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY+PFR_FLAG_ALLRSETS);
+       ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_DUMMY |
+           PFR_FLAG_ALLRSETS);
        if (pfr_fix_anchor(filter->pfrt_anchor))
                return (EINVAL);
        if (pfr_table_count(filter, flags) < 0)
@@ -1156,11 +1161,11 @@ pfr_add_tables(struct pfr_table *tbl, int size, int *nadd, int flags)
        int                      i, rv, xadd = 0;
        long                     tzero = time_second;
 
-       ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY);
+       ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_DUMMY);
        SLIST_INIT(&addq);
        SLIST_INIT(&changeq);
        for (i = 0; i < size; i++) {
-               if (COPYIN(tbl+i, &key.pfrkt_t, sizeof(key.pfrkt_t)))
+               if (COPYIN(tbl+i, &key.pfrkt_t, sizeof(key.pfrkt_t), flags))
                        senderr(EFAULT);
                if (pfr_validate_table(&key.pfrkt_t, PFR_TFLAG_USRMASK,
                    flags & PFR_FLAG_USERIOCTL))
@@ -1235,10 +1240,10 @@ pfr_del_tables(struct pfr_table *tbl, int size, int *ndel, int flags)
        struct pfr_ktable       *p, *q, key;
        int                      i, xdel = 0;
 
-       ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY);
+       ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_DUMMY);
        SLIST_INIT(&workq);
        for (i = 0; i < size; i++) {
-               if (COPYIN(tbl+i, &key.pfrkt_t, sizeof(key.pfrkt_t)))
+               if (COPYIN(tbl+i, &key.pfrkt_t, sizeof(key.pfrkt_t), flags))
                        return (EFAULT);
                if (pfr_validate_table(&key.pfrkt_t, 0,
                    flags & PFR_FLAG_USERIOCTL))
@@ -1275,7 +1280,7 @@ pfr_get_tables(struct pfr_table *filter, struct pfr_table *tbl, int *size,
        struct pfr_ktable       *p;
        int                      n, nn;
 
-       ACCEPT_FLAGS(PFR_FLAG_ALLRSETS);
+       ACCEPT_FLAGS(flags, PFR_FLAG_ALLRSETS);
        if (pfr_fix_anchor(filter->pfrt_anchor))
                return (EINVAL);
        n = nn = pfr_table_count(filter, flags);
@@ -1290,7 +1295,7 @@ pfr_get_tables(struct pfr_table *filter, struct pfr_table *tbl, int *size,
                        continue;
                if (n-- <= 0)
                        continue;
-               if (COPYOUT(&p->pfrkt_t, tbl++, sizeof(*tbl)))
+               if (COPYOUT(&p->pfrkt_t, tbl++, sizeof(*tbl), flags))
                        return (EFAULT);
        }
        if (n) {
@@ -1310,8 +1315,8 @@ pfr_get_tstats(struct pfr_table *filter, struct pfr_tstats *tbl, int *size,
        int                      n, nn;
        long                     tzero = time_second;
 
-       ACCEPT_FLAGS(PFR_FLAG_ATOMIC|PFR_FLAG_ALLRSETS);
-                                       /* XXX PFR_FLAG_CLSTATS disabled */
+       /* XXX PFR_FLAG_CLSTATS disabled */
+       ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_ALLRSETS);
        if (pfr_fix_anchor(filter->pfrt_anchor))
                return (EINVAL);
        n = nn = pfr_table_count(filter, flags);
@@ -1331,7 +1336,7 @@ pfr_get_tstats(struct pfr_table *filter, struct pfr_tstats *tbl, int *size,
                        continue;
                if (!(flags & PFR_FLAG_ATOMIC))
                        crit_enter();
-               if (COPYOUT(&p->pfrkt_ts, tbl++, sizeof(*tbl))) {
+               if (COPYOUT(&p->pfrkt_ts, tbl++, sizeof(*tbl), flags)) {
                        crit_exit();
                        return (EFAULT);
                }
@@ -1360,10 +1365,11 @@ pfr_clr_tstats(struct pfr_table *tbl, int size, int *nzero, int flags)
        int                      i, xzero = 0;
        long                     tzero = time_second;
 
-       ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY+PFR_FLAG_ADDRSTOO);
+       ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_DUMMY |
+           PFR_FLAG_ADDRSTOO);
        SLIST_INIT(&workq);
        for (i = 0; i < size; i++) {
-               if (COPYIN(tbl+i, &key.pfrkt