diff --git a/contrib/tcpdump/print-pfsync.c b/contrib/tcpdump/print-pfsync.c
--- a/contrib/tcpdump/print-pfsync.c
+++ b/contrib/tcpdump/print-pfsync.c
@@ -55,7 +55,7 @@
 static void	print_src_dst(netdissect_options *,
 		    const struct pfsync_state_peer *,
 		    const struct pfsync_state_peer *, uint8_t);
-static void	print_state(netdissect_options *, struct pfsync_state *);
+static void	print_state(netdissect_options *, union pfsync_state_union *, int);
 
 u_int
 pfsync_if_print(netdissect_options *ndo, const struct pcap_pkthdr *h,
@@ -100,7 +100,8 @@
 };
 
 static void	pfsync_print_clr(netdissect_options *, const void *);
-static void	pfsync_print_state(netdissect_options *, const void *);
+static void	pfsync_print_state_1301(netdissect_options *, const void *);
+static void	pfsync_print_state_1400(netdissect_options *, const void *);
 static void	pfsync_print_ins_ack(netdissect_options *, const void *);
 static void	pfsync_print_upd_c(netdissect_options *, const void *);
 static void	pfsync_print_upd_req(netdissect_options *, const void *);
@@ -110,9 +111,11 @@
 
 struct pfsync_actions actions[] = {
 	{ "clear all", sizeof(struct pfsync_clr),	pfsync_print_clr },
-	{ "insert", sizeof(struct pfsync_state),	pfsync_print_state },
+	{ "insert 13.1", sizeof(struct pfsync_state_1301),
+							pfsync_print_state_1301 },
 	{ "insert ack", sizeof(struct pfsync_ins_ack),	pfsync_print_ins_ack },
-	{ "update", sizeof(struct pfsync_ins_ack),	pfsync_print_state },
+	{ "update 13.1", sizeof(struct pfsync_state_1301),
+							pfsync_print_state_1301 },
 	{ "update compressed", sizeof(struct pfsync_upd_c),
 							pfsync_print_upd_c },
 	{ "request uncompressed", sizeof(struct pfsync_upd_req),
@@ -126,6 +129,8 @@
 							pfsync_print_bus },
 	{ "tdb", 0,					pfsync_print_tdb },
 	{ "eof", 0,					NULL },
+	{ "insert", sizeof(struct pfsync_state_1400),	pfsync_print_state_1400 },
+	{ "update", sizeof(struct pfsync_state_1400),	pfsync_print_state_1400 },
 };
 
 static void
@@ -212,12 +217,21 @@
 }
 
 static void
-pfsync_print_state(netdissect_options *ndo, const void *bp)
+pfsync_print_state_1301(netdissect_options *ndo, const void *bp)
 {
-	struct pfsync_state *st = (struct pfsync_state *)bp;
+	struct pfsync_state_1301 *st = (struct pfsync_state_1301 *)bp;
 
 	safeputchar(ndo, '\n');
-	print_state(ndo, st);
+	print_state(ndo, (union pfsync_state_union *)st, PFSYNC_MSG_VERSION_1301);
+}
+
+static void
+pfsync_print_state_1400(netdissect_options *ndo, const void *bp)
+{
+	struct pfsync_state_1301 *st = (struct pfsync_state_1301 *)bp;
+
+	safeputchar(ndo, '\n');
+	print_state(ndo, (union pfsync_state_union *)st, PFSYNC_MSG_VERSION_1400);
 }
 
 static void
@@ -374,56 +388,56 @@
 }
 
 static void
-print_state(netdissect_options *ndo, struct pfsync_state *s)
+print_state(netdissect_options *ndo, union pfsync_state_union *s, int version)
 {
 	struct pfsync_state_peer *src, *dst;
 	struct pfsync_state_key *sk, *nk;
 	int min, sec;
 
-	if (s->direction == PF_OUT) {
-		src = &s->src;
-		dst = &s->dst;
-		sk = &s->key[PF_SK_STACK];
-		nk = &s->key[PF_SK_WIRE];
-		if (s->proto == IPPROTO_ICMP || s->proto == IPPROTO_ICMPV6)
+	if (s->pfs_1301.direction == PF_OUT) {
+		src = &s->pfs_1301.src;
+		dst = &s->pfs_1301.dst;
+		sk = &s->pfs_1301.key[PF_SK_STACK];
+		nk = &s->pfs_1301.key[PF_SK_WIRE];
+		if (s->pfs_1301.proto == IPPROTO_ICMP || s->pfs_1301.proto == IPPROTO_ICMPV6)
 			sk->port[0] = nk->port[0];
 	} else {
-		src = &s->dst;
-		dst = &s->src;
-		sk = &s->key[PF_SK_WIRE];
-		nk = &s->key[PF_SK_STACK];
-		if (s->proto == IPPROTO_ICMP || s->proto == IPPROTO_ICMPV6)
+		src = &s->pfs_1301.dst;
+		dst = &s->pfs_1301.src;
+		sk = &s->pfs_1301.key[PF_SK_WIRE];
+		nk = &s->pfs_1301.key[PF_SK_STACK];
+		if (s->pfs_1301.proto == IPPROTO_ICMP || s->pfs_1301.proto == IPPROTO_ICMPV6)
 			sk->port[1] = nk->port[1];
 	}
-	ND_PRINT((ndo, "\t%s ", s->ifname));
-	ND_PRINT((ndo, "proto %u ", s->proto));
+	ND_PRINT((ndo, "\t%s ", s->pfs_1301.ifname));
+	ND_PRINT((ndo, "proto %u ", s->pfs_1301.proto));
 
-	print_host(ndo, &nk->addr[1], nk->port[1], s->af, NULL);
-	if (PF_ANEQ(&nk->addr[1], &sk->addr[1], s->af) ||
+	print_host(ndo, &nk->addr[1], nk->port[1], s->pfs_1301.af, NULL);
+	if (PF_ANEQ(&nk->addr[1], &sk->addr[1], s->pfs_1301.af) ||
 	    nk->port[1] != sk->port[1]) {
 		ND_PRINT((ndo, " ("));
-		print_host(ndo, &sk->addr[1], sk->port[1], s->af, NULL);
+		print_host(ndo, &sk->addr[1], sk->port[1], s->pfs_1301.af, NULL);
 		ND_PRINT((ndo, ")"));
 	}
-	if (s->direction == PF_OUT)
+	if (s->pfs_1301.direction == PF_OUT)
 		ND_PRINT((ndo, " -> "));
 	else
 		ND_PRINT((ndo, " <- "));
-	print_host(ndo, &nk->addr[0], nk->port[0], s->af, NULL);
-	if (PF_ANEQ(&nk->addr[0], &sk->addr[0], s->af) ||
+	print_host(ndo, &nk->addr[0], nk->port[0], s->pfs_1301.af, NULL);
+	if (PF_ANEQ(&nk->addr[0], &sk->addr[0], s->pfs_1301.af) ||
 	    nk->port[0] != sk->port[0]) {
 		ND_PRINT((ndo, " ("));
-		print_host(ndo, &sk->addr[0], sk->port[0], s->af, NULL);
+		print_host(ndo, &sk->addr[0], sk->port[0], s->pfs_1301.af, NULL);
 		ND_PRINT((ndo, ")"));
 	}
 
-	print_src_dst(ndo, src, dst, s->proto);
+	print_src_dst(ndo, src, dst, s->pfs_1301.proto);
 
 	if (ndo->ndo_vflag > 1) {
 		uint64_t packets[2];
 		uint64_t bytes[2];
-		uint32_t creation = ntohl(s->creation);
-		uint32_t expire = ntohl(s->expire);
+		uint32_t creation = ntohl(s->pfs_1301.creation);
+		uint32_t expire = ntohl(s->pfs_1301.expire);
 
 		sec = creation % 60;
 		creation /= 60;
@@ -436,23 +450,23 @@
 		expire /= 60;
 		ND_PRINT((ndo, ", expires in %.2u:%.2u:%.2u", expire, min, sec));
 
-		bcopy(s->packets[0], &packets[0], sizeof(uint64_t));
-		bcopy(s->packets[1], &packets[1], sizeof(uint64_t));
-		bcopy(s->bytes[0], &bytes[0], sizeof(uint64_t));
-		bcopy(s->bytes[1], &bytes[1], sizeof(uint64_t));
+		bcopy(s->pfs_1301.packets[0], &packets[0], sizeof(uint64_t));
+		bcopy(s->pfs_1301.packets[1], &packets[1], sizeof(uint64_t));
+		bcopy(s->pfs_1301.bytes[0], &bytes[0], sizeof(uint64_t));
+		bcopy(s->pfs_1301.bytes[1], &bytes[1], sizeof(uint64_t));
 		ND_PRINT((ndo, ", %ju:%ju pkts, %ju:%ju bytes",
 		    be64toh(packets[0]), be64toh(packets[1]),
 		    be64toh(bytes[0]), be64toh(bytes[1])));
-		if (s->anchor != ntohl(-1))
-			ND_PRINT((ndo, ", anchor %u", ntohl(s->anchor)));
-		if (s->rule != ntohl(-1))
-			ND_PRINT((ndo, ", rule %u", ntohl(s->rule)));
+		if (s->pfs_1301.anchor != ntohl(-1))
+			ND_PRINT((ndo, ", anchor %u", ntohl(s->pfs_1301.anchor)));
+		if (s->pfs_1301.rule != ntohl(-1))
+			ND_PRINT((ndo, ", rule %u", ntohl(s->pfs_1301.rule)));
 	}
 	if (ndo->ndo_vflag > 1) {
 		uint64_t id;
 
-		bcopy(&s->id, &id, sizeof(uint64_t));
+		bcopy(&s->pfs_1301.id, &id, sizeof(uint64_t));
 		ND_PRINT((ndo, "\n\tid: %016jx creatorid: %08x",
-		    (uintmax_t )be64toh(id), ntohl(s->creatorid)));
+		    (uintmax_t )be64toh(id), ntohl(s->pfs_1301.creatorid)));
 	}
 }
diff --git a/lib/libpfctl/libpfctl.h b/lib/libpfctl/libpfctl.h
--- a/lib/libpfctl/libpfctl.h
+++ b/lib/libpfctl/libpfctl.h
@@ -353,6 +353,18 @@
 	uint32_t		 pfsync_time;
 	uint16_t		 state_flags;
 	uint32_t		 sync_flags;
+	uint16_t		 qid;
+	uint16_t		 pqid;
+	uint16_t		 dnpipe;
+	uint16_t		 dnrpipe;
+	uint8_t			 log;
+	int32_t			 rtableid;
+	uint8_t			 min_ttl;
+	uint8_t			 set_tos;
+	uint16_t		 max_mss;
+	uint8_t			 set_prio[2];
+	uint8_t			 rt;
+	char			 rt_ifname[IFNAMSIZ];
 };
 
 TAILQ_HEAD(pfctl_statelist, pfctl_state);
diff --git a/lib/libpfctl/libpfctl.c b/lib/libpfctl/libpfctl.c
--- a/lib/libpfctl/libpfctl.c
+++ b/lib/libpfctl/libpfctl.c
@@ -1111,6 +1111,7 @@
 	ps->id = s->id;
 	strlcpy(ps->ifname, s->ifname, sizeof(ps->ifname));
 	strlcpy(ps->orig_ifname, s->orig_ifname, sizeof(ps->orig_ifname));
+	strlcpy(ps->rt_ifname, s->rt_ifname, sizeof(ps->rt_ifname));
 	pf_state_key_export_to_state_key(&ps->key[0], &s->key[0]);
 	pf_state_key_export_to_state_key(&ps->key[1], &s->key[1]);
 	pf_state_peer_export_to_state_peer(&ps->src, &s->src);
@@ -1131,8 +1132,19 @@
 	ps->key[0].af = s->af;
 	ps->key[1].af = s->af;
 	ps->direction = s->direction;
-	ps->state_flags = s->state_flags;
-	ps->sync_flags = s->sync_flags;
+	ps->state_flags = ntohs(s->state_flags);
+	ps->sync_flags = ntohs(s->sync_flags);
+	ps->qid = ntohs(s->qid);
+	ps->pqid = ntohs(s->pqid);
+	ps->dnpipe = ntohs(s->dnpipe);
+	ps->dnrpipe = ntohs(s->dnrpipe);
+	ps->rtableid = ntohl(s->rtableid);
+	ps->min_ttl = s->min_ttl;
+	ps->set_tos = s->set_tos;
+	ps->max_mss = ntohs(s->max_mss);
+	ps->rt = s->rt;
+	ps->set_prio[0] = s->set_prio[0];
+	ps->set_prio[1] = s->set_prio[1];
 }
 
 int
diff --git a/sbin/ifconfig/ifpfsync.c b/sbin/ifconfig/ifpfsync.c
--- a/sbin/ifconfig/ifpfsync.c
+++ b/sbin/ifconfig/ifpfsync.c
@@ -57,6 +57,7 @@
 void setpfsync_syncpeer(const char *, int, int, const struct afswtch *);
 void setpfsync_maxupd(const char *, int, int, const struct afswtch *);
 void setpfsync_defer(const char *, int, int, const struct afswtch *);
+void setpfsync_version(const char *, int, int, const struct afswtch *);
 void pfsync_status(int);
 
 static int
@@ -323,6 +324,28 @@
 	nvlist_destroy(nvl);
 }
 
+/* ARGSUSED */
+void
+setpfsync_version(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	int version;
+	nvlist_t *nvl = nvlist_create(0);
+
+	/* Don't verify, kernel knows which versions are supported.*/
+	version = atoi(val);
+
+	if (pfsync_do_ioctl(s, SIOCGETPFSYNCNV, &nvl) == -1)
+		err(1, "SIOCGETPFSYNCNV");
+
+	nvlist_free_number(nvl, "version");
+	nvlist_add_number(nvl, "version", version);
+
+	if (pfsync_do_ioctl(s, SIOCSETPFSYNCNV, &nvl) == -1)
+		err(1, "SIOCSETPFSYNCNV");
+
+	nvlist_destroy(nvl);
+}
+
 void
 pfsync_status(int s)
 {
@@ -331,6 +354,7 @@
 	char syncpeer_str[NI_MAXHOST];
 	struct sockaddr_storage syncpeer;
 	int maxupdates;
+	int version;
 	int flags;
 	int error;
 
@@ -347,6 +371,8 @@
 		    IFNAMSIZ);
 	if (nvlist_exists_number(nvl, "maxupdates"))
 		maxupdates = nvlist_get_number(nvl, "maxupdates");
+	if (nvlist_exists_number(nvl, "version"))
+		version = nvlist_get_number(nvl, "version");
 	if (nvlist_exists_number(nvl, "flags"))
 		flags = nvlist_get_number(nvl, "flags");
 	if (nvlist_exists_nvlist(nvl, "syncpeer")) {
@@ -377,7 +403,8 @@
 	}
 
 	printf("maxupd: %d ", maxupdates);
-	printf("defer: %s\n", (flags & PFSYNCF_DEFER) ? "on" : "off");
+	printf("defer: %s ", (flags & PFSYNCF_DEFER) ? "on" : "off");
+	printf("version: %d\n", version);
 	printf("\tsyncok: %d\n", (flags & PFSYNCF_OK) ? 1 : 0);
 }
 
@@ -391,6 +418,7 @@
 	DEF_CMD_ARG("maxupd",		setpfsync_maxupd),
 	DEF_CMD("defer",	1,	setpfsync_defer),
 	DEF_CMD("-defer",	0,	setpfsync_defer),
+	DEF_CMD_ARG("version",		setpfsync_version),
 };
 static struct afswtch af_pfsync = {
 	.af_name	= "af_pfsync",
diff --git a/sbin/pfctl/pf_print_state.c b/sbin/pfctl/pf_print_state.c
--- a/sbin/pfctl/pf_print_state.c
+++ b/sbin/pfctl/pf_print_state.c
@@ -350,17 +350,34 @@
 		if (s->state_flags & PFSTATE_NODF)
 			printf(", no-df");
 		if (s->state_flags & PFSTATE_SETTOS)
-			printf(", set-tos");
+			printf(", set-tos 0x%2.2x", s->set_tos);
 		if (s->state_flags & PFSTATE_RANDOMID)
 			printf(", random-id");
 		if (s->state_flags & PFSTATE_SCRUB_TCP)
-			printf(", scrub-tcp");
+			printf(", reassemble-tcp");
 		if (s->state_flags & PFSTATE_SETPRIO)
-			printf(", set-prio");
+			printf(", set-prio (0x%02x 0x%02x)",
+			    s->set_prio[0], s->set_prio[1]);
+		if (s->dnpipe || s->dnrpipe) {
+			if (s->state_flags & PFSTATE_DN_IS_PIPE)
+				printf(", dummynet pipe (%d %d)",
+				s->dnpipe, s->dnrpipe);
+			if (s->state_flags & PFSTATE_DN_IS_QUEUE)
+				printf(", dummynet queue (%d %d)",
+				s->dnpipe, s->dnrpipe);
+		}
 		if (s->sync_flags & PFSYNC_FLAG_SRCNODE)
 			printf(", source-track");
 		if (s->sync_flags & PFSYNC_FLAG_NATSRCNODE)
 			printf(", sticky-address");
+		if (s->log)
+			printf(", log");
+		if (s->log & PF_LOG_ALL)
+			printf(" (all)");
+		if (s->min_ttl)
+			printf(", min-ttl %d", s->min_ttl);
+		if (s->max_mss)
+			printf(", max-mss %d", s->max_mss);
 		printf("\n");
 	}
 	if (opts & PF_OPT_VERBOSE2) {
@@ -368,8 +385,26 @@
 
 		bcopy(&s->id, &id, sizeof(u_int64_t));
 		printf("   id: %016jx creatorid: %08x", id, s->creatorid);
-		printf(" gateway: ");
-		print_host(&s->rt_addr, 0, af, opts);
+		if (s->rt) {
+			switch (s->rt) {
+				case PF_ROUTETO:
+					printf(" route-to: ");
+					break;
+				case PF_DUPTO:
+					printf(" dup-to: ");
+					break;
+				case PF_REPLYTO:
+					printf(" reply-to: ");
+					break;
+				default:
+					printf(" gateway: ");
+			}
+			print_host(&s->rt_addr, 0, af, opts);
+			if (s->rt_ifname[0])
+				printf("@%s", s->rt_ifname);
+		}
+		if (s->rtableid != -1)
+			printf(" rtable: %d", s->rtableid);
 		printf("\n");
 
 		if (strcmp(s->ifname, s->orig_ifname) != 0)
diff --git a/sys/net/if_pfsync.h b/sys/net/if_pfsync.h
--- a/sys/net/if_pfsync.h
+++ b/sys/net/if_pfsync.h
@@ -59,10 +59,18 @@
 #define	PFSYNC_VERSION		5
 #define	PFSYNC_DFLTTL		255
 
+enum pfsync_msg_versions {
+	PFSYNC_MSG_VERSION_UNSPECIFIED = 0,
+	PFSYNC_MSG_VERSION_1301 = 1301,
+	PFSYNC_MSG_VERSION_1400 = 1400,
+};
+
+#define PFSYNC_MSG_VERSION_DEFAULT PFSYNC_MSG_VERSION_1400
+
 #define	PFSYNC_ACT_CLR		0	/* clear all states */
-#define	PFSYNC_ACT_INS		1	/* insert state */
+#define	PFSYNC_ACT_INS_1301	1	/* insert state */
 #define	PFSYNC_ACT_INS_ACK	2	/* ack of inserted state */
-#define	PFSYNC_ACT_UPD		3	/* update state */
+#define	PFSYNC_ACT_UPD_1301	3	/* update state */
 #define	PFSYNC_ACT_UPD_C	4	/* "compressed" update state */
 #define	PFSYNC_ACT_UPD_REQ	5	/* request "uncompressed" state */
 #define	PFSYNC_ACT_DEL		6	/* delete state */
@@ -72,7 +80,9 @@
 #define	PFSYNC_ACT_BUS		10	/* bulk update status */
 #define	PFSYNC_ACT_TDB		11	/* TDB replay counter update */
 #define	PFSYNC_ACT_EOF		12	/* end of frame */
-#define	PFSYNC_ACT_MAX		13
+#define PFSYNC_ACT_INS_1400	13	/* insert state */
+#define PFSYNC_ACT_UPD_1400	14	/* update state */
+#define	PFSYNC_ACT_MAX		15
 
 /*
  * A pfsync frame is built from a header followed by several sections which
@@ -251,6 +261,7 @@
 	char		 	syncdev[IFNAMSIZ];
 	struct sockaddr_storage	syncpeer;
 	int		 	maxupdates;
+	int			version;
 	int		 	flags;
 };
 
@@ -269,13 +280,13 @@
 
 /*
  * this shows where a pf state is with respect to the syncing.
+ * pf_kstate->sync_state
  */
 #define	PFSYNC_S_INS	0x00
 #define	PFSYNC_S_IACK	0x01
 #define	PFSYNC_S_UPD	0x02
 #define	PFSYNC_S_UPD_C	0x03
 #define	PFSYNC_S_DEL_C	0x04
-#define	PFSYNC_S_COUNT	0x05
 
 #define	PFSYNC_S_DEFER	0xfe
 #define	PFSYNC_S_NONE	0xff
diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h
--- a/sys/net/pfvar.h
+++ b/sys/net/pfvar.h
@@ -641,6 +641,7 @@
 	uint16_t	 dnpipe;
 	uint16_t	 dnrpipe;	/* Reverse direction pipe */
 	uint32_t	 flags;
+	uint8_t		 set_prio[2];
 };
 
 union pf_keth_rule_ptr {
@@ -975,7 +976,7 @@
 
 struct pf_state_export {
 	uint64_t	 version;
-#define	PF_STATE_VERSION	20210706
+#define	PF_STATE_VERSION	20230404
 	uint64_t	 id;
 	char		 ifname[IFNAMSIZ];
 	char		 orig_ifname[IFNAMSIZ];
@@ -1002,8 +1003,19 @@
 	uint8_t		 sync_flags;
 	uint8_t		 updates;
 	uint16_t	 state_flags;
+	uint16_t	 qid;
+	uint16_t	 pqid;
+	uint16_t	 dnpipe;
+	uint16_t	 dnrpipe;
+	int32_t		 rtableid;
+	uint8_t		 min_ttl;
+	uint8_t		 set_tos;
+	uint16_t	 max_mss;
+	uint8_t		 set_prio[2];
+	uint8_t		 rt;
+	char		 rt_ifname[IFNAMSIZ];
 
-	uint8_t		 spare[110];
+	uint8_t		 spare[72];
 };
 _Static_assert(sizeof(struct pf_state_export) == 384, "size incorrect");
 
@@ -1057,12 +1069,14 @@
 	u_int8_t		 min_ttl;
 	u_int8_t		 set_tos;
 	u_int16_t		 max_mss;
+	u_int8_t		 rt;
+	u_int8_t		 set_prio[2];
 };
 
 /*
- * Size <= fits 12 objects per page on LP64. Try to not grow the struct beyond that.
+ * Size <= fits 11 objects per page on LP64. Try to not grow the struct beyond that.
  */
-_Static_assert(sizeof(struct pf_kstate) <= 336, "pf_kstate size crosses 336 bytes");
+_Static_assert(sizeof(struct pf_kstate) <= 368, "pf_kstate size crosses 368 bytes");
 #endif
 
 /*
@@ -1094,7 +1108,34 @@
 	u_int16_t	 port[2];
 };
 
-struct pfsync_state {
+struct pfsync_state_1301 {
+	u_int64_t	 id;
+	char		 ifname[IFNAMSIZ];
+	struct pfsync_state_key	key[2];
+	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	 __spare[2];
+	u_int8_t	 log;
+	u_int8_t	 state_flags;
+	u_int8_t	 timeout;
+	u_int8_t	 sync_flags;
+	u_int8_t	 updates;
+} __packed;
+
+struct pfsync_state_1400 {
+	/* The beginning of the struct is compatible with previous versions */
 	u_int64_t	 id;
 	char		 ifname[IFNAMSIZ];
 	struct pfsync_state_key	key[2];
@@ -1114,15 +1155,33 @@
 	u_int8_t	 direction;
 	u_int16_t	 state_flags;
 	u_int8_t	 log;
-	u_int8_t	 state_flags_compat;
+	u_int8_t	 __spare;
 	u_int8_t	 timeout;
 	u_int8_t	 sync_flags;
 	u_int8_t	 updates;
+	/* The rest is not */
+	u_int16_t	 qid;
+	u_int16_t	 pqid;
+	u_int16_t	 dnpipe;
+	u_int16_t	 dnrpipe;
+	int32_t		 rtableid;
+	u_int8_t	 min_ttl;
+	u_int8_t	 set_tos;
+	u_int16_t	 max_mss;
+	u_int8_t	 set_prio[2];
+	u_int8_t	 rt;
+	char		 rt_ifname[IFNAMSIZ];
+
+} __packed;
+
+union pfsync_state_union {
+	struct pfsync_state_1301 pfs_1301;
+	struct pfsync_state_1400 pfs_1400;
 } __packed;
 
 #ifdef _KERNEL
 /* pfsync */
-typedef int		pfsync_state_import_t(struct pfsync_state *, int);
+typedef int		pfsync_state_import_t(union pfsync_state_union *, int, int);
 typedef	void		pfsync_insert_state_t(struct pf_kstate *);
 typedef	void		pfsync_update_state_t(struct pf_kstate *);
 typedef	void		pfsync_delete_state_t(struct pf_kstate *);
@@ -1144,8 +1203,8 @@
 #define V_pfsync_defer_ptr		VNET(pfsync_defer_ptr)
 extern pfsync_detach_ifnet_t	*pfsync_detach_ifnet_ptr;
 
-void			pfsync_state_export(struct pfsync_state *,
-			    struct pf_kstate *);
+void			pfsync_state_export(union pfsync_state_union *,
+			    struct pf_kstate *, int);
 void			pf_state_export(struct pf_state_export *,
 			    struct pf_kstate *);
 
@@ -1665,7 +1724,7 @@
 };
 
 struct pfioc_state {
-	struct pfsync_state	state;
+	struct pfsync_state_1301	state;
 };
 
 struct pfioc_src_node_kill {
@@ -1704,9 +1763,11 @@
 struct pfioc_states {
 	int	ps_len;
 	union {
-		caddr_t			 ps_buf;
-		struct pfsync_state	*ps_states;
-	};
+		caddr_t				 psu_buf;
+		struct pfsync_state_1301	*psu_states;
+	} ps_u;
+#define ps_buf		ps_u.psu_buf
+#define ps_states	ps_u.psu_states
 };
 
 struct pfioc_states_v2 {
diff --git a/sys/netpfil/pf/if_pfsync.c b/sys/netpfil/pf/if_pfsync.c
--- a/sys/netpfil/pf/if_pfsync.c
+++ b/sys/netpfil/pf/if_pfsync.c
@@ -122,23 +122,23 @@
 
 static int	pfsync_upd_tcp(struct pf_kstate *, struct pfsync_state_peer *,
 		    struct pfsync_state_peer *);
-static int	pfsync_in_clr(struct mbuf *, int, int, int);
-static int	pfsync_in_ins(struct mbuf *, int, int, int);
-static int	pfsync_in_iack(struct mbuf *, int, int, int);
-static int	pfsync_in_upd(struct mbuf *, int, int, int);
-static int	pfsync_in_upd_c(struct mbuf *, int, int, int);
-static int	pfsync_in_ureq(struct mbuf *, int, int, int);
-static int	pfsync_in_del_c(struct mbuf *, int, int, int);
-static int	pfsync_in_bus(struct mbuf *, int, int, int);
-static int	pfsync_in_tdb(struct mbuf *, int, int, int);
-static int	pfsync_in_eof(struct mbuf *, int, int, int);
-static int	pfsync_in_error(struct mbuf *, int, int, int);
+static int	pfsync_in_clr(struct mbuf *, int, int, int, int);
+static int	pfsync_in_ins(struct mbuf *, int, int, int, int);
+static int	pfsync_in_iack(struct mbuf *, int, int, int, int);
+static int	pfsync_in_upd(struct mbuf *, int, int, int, int);
+static int	pfsync_in_upd_c(struct mbuf *, int, int, int, int);
+static int	pfsync_in_ureq(struct mbuf *, int, int, int, int);
+static int	pfsync_in_del_c(struct mbuf *, int, int, int, int);
+static int	pfsync_in_bus(struct mbuf *, int, int, int, int);
+static int	pfsync_in_tdb(struct mbuf *, int, int, int, int);
+static int	pfsync_in_eof(struct mbuf *, int, int, int, int);
+static int	pfsync_in_error(struct mbuf *, int, int, int, int);
 
-static int (*pfsync_acts[])(struct mbuf *, int, int, int) = {
+static int (*pfsync_acts[])(struct mbuf *, int, int, int, int) = {
 	pfsync_in_clr,			/* PFSYNC_ACT_CLR */
-	pfsync_in_ins,			/* PFSYNC_ACT_INS */
+	pfsync_in_ins,			/* PFSYNC_ACT_INS_1301 */
 	pfsync_in_iack,			/* PFSYNC_ACT_INS_ACK */
-	pfsync_in_upd,			/* PFSYNC_ACT_UPD */
+	pfsync_in_upd,			/* PFSYNC_ACT_UPD_1301 */
 	pfsync_in_upd_c,		/* PFSYNC_ACT_UPD_C */
 	pfsync_in_ureq,			/* PFSYNC_ACT_UPD_REQ */
 	pfsync_in_error,		/* PFSYNC_ACT_DEL */
@@ -147,7 +147,9 @@
 	pfsync_in_error,		/* PFSYNC_ACT_DEL_F */
 	pfsync_in_bus,			/* PFSYNC_ACT_BUS */
 	pfsync_in_tdb,			/* PFSYNC_ACT_TDB */
-	pfsync_in_eof			/* PFSYNC_ACT_EOF */
+	pfsync_in_eof,			/* PFSYNC_ACT_EOF */
+	pfsync_in_ins,			/* PFSYNC_ACT_INS_1400 */
+	pfsync_in_upd,			/* PFSYNC_ACT_UPD_1400 */
 };
 
 struct pfsync_q {
@@ -156,21 +158,51 @@
 	u_int8_t	action;
 };
 
-/* we have one of these for every PFSYNC_S_ */
-static void	pfsync_out_state(struct pf_kstate *, void *);
+/* We have the following sync queues */
+enum pfsync_q_id {
+	PFSYNC_Q_INS_1301,
+	PFSYNC_Q_INS_1400,
+	PFSYNC_Q_IACK,
+	PFSYNC_Q_UPD_1301,
+	PFSYNC_Q_UPD_1400,
+	PFSYNC_Q_UPD_C,
+	PFSYNC_Q_DEL_C,
+	PFSYNC_Q_COUNT,
+};
+
+/* Functions for building messages for given queue */
+static void	pfsync_out_state_1301(struct pf_kstate *, void *);
+static void	pfsync_out_state_1400(struct pf_kstate *, void *);
 static void	pfsync_out_iack(struct pf_kstate *, void *);
 static void	pfsync_out_upd_c(struct pf_kstate *, void *);
 static void	pfsync_out_del_c(struct pf_kstate *, void *);
 
+/* Attach those functions to queue */
 static struct pfsync_q pfsync_qs[] = {
-	{ pfsync_out_state, sizeof(struct pfsync_state),   PFSYNC_ACT_INS },
-	{ pfsync_out_iack,  sizeof(struct pfsync_ins_ack), PFSYNC_ACT_INS_ACK },
-	{ pfsync_out_state, sizeof(struct pfsync_state),   PFSYNC_ACT_UPD },
-	{ pfsync_out_upd_c, sizeof(struct pfsync_upd_c),   PFSYNC_ACT_UPD_C },
-	{ pfsync_out_del_c, sizeof(struct pfsync_del_c),   PFSYNC_ACT_DEL_C }
+	{ pfsync_out_state_1301, sizeof(struct pfsync_state_1301), PFSYNC_ACT_INS_1301 },
+	{ pfsync_out_state_1400, sizeof(struct pfsync_state_1400), PFSYNC_ACT_INS_1400 },
+	{ pfsync_out_iack,       sizeof(struct pfsync_ins_ack),    PFSYNC_ACT_INS_ACK },
+	{ pfsync_out_state_1301, sizeof(struct pfsync_state_1301), PFSYNC_ACT_UPD_1301 },
+	{ pfsync_out_state_1400, sizeof(struct pfsync_state_1400), PFSYNC_ACT_UPD_1400 },
+	{ pfsync_out_upd_c,      sizeof(struct pfsync_upd_c),      PFSYNC_ACT_UPD_C },
+	{ pfsync_out_del_c,      sizeof(struct pfsync_del_c),      PFSYNC_ACT_DEL_C }
 };
 
-static void	pfsync_q_ins(struct pf_kstate *, int, bool);
+/* Map queue to pf_kstate->sync_state */
+static u_int8_t pfsync_qid_sstate[] = {
+	PFSYNC_S_INS,   /* PFSYNC_Q_INS_1301 */
+	PFSYNC_S_INS,   /* PFSYNC_Q_INS_1400 */
+	PFSYNC_S_IACK,  /* PFSYNC_Q_IACK */
+	PFSYNC_S_UPD,   /* PFSYNC_Q_UPD_1301 */
+	PFSYNC_S_UPD,   /* PFSYNC_Q_UPD_1400 */
+	PFSYNC_S_UPD_C, /* PFSYNC_Q_UPD_C */
+	PFSYNC_S_DEL_C, /* PFSYNC_Q_DEL_C */
+};
+
+/* Map pf_kstate->sync_state to queue */
+static enum pfsync_q_id pfsync_sstate_to_qid(u_int8_t);
+
+static void	pfsync_q_ins(struct pf_kstate *, int sync_state, bool);
 static void	pfsync_q_del(struct pf_kstate *, bool, struct pfsync_bucket *);
 
 static void	pfsync_update_state(struct pf_kstate *);
@@ -200,7 +232,7 @@
 #define	PFSYNCF_BUCKET_PUSH	0x00000001
 
 	size_t			b_len;
-	TAILQ_HEAD(, pf_kstate)			b_qs[PFSYNC_S_COUNT];
+	TAILQ_HEAD(, pf_kstate)			b_qs[PFSYNC_Q_COUNT];
 	TAILQ_HEAD(, pfsync_upd_req_item)	b_upd_req_list;
 	TAILQ_HEAD(, pfsync_deferral)		b_deferrals;
 	u_int			b_deferred;
@@ -220,6 +252,7 @@
 	uint8_t			sc_maxupdates;
 	union inet_template     sc_template;
 	struct mtx		sc_mtx;
+	uint32_t		sc_version;
 
 	/* Queued data */
 	struct pfsync_bucket	*sc_buckets;
@@ -336,7 +369,8 @@
 	struct pfsync_softc *sc;
 	struct ifnet *ifp;
 	struct pfsync_bucket *b;
-	int c, q;
+	int c;
+	enum pfsync_q_id q;
 
 	if (unit != 0)
 		return (EINVAL);
@@ -347,6 +381,7 @@
 	sc = malloc(sizeof(struct pfsync_softc), M_PFSYNC, M_WAITOK | M_ZERO);
 	sc->sc_flags |= PFSYNCF_OK;
 	sc->sc_maxupdates = 128;
+	sc->sc_version = PFSYNC_MSG_VERSION_DEFAULT;
 
 	ifp = sc->sc_ifp = if_alloc(IFT_PFSYNC);
 	if (ifp == NULL) {
@@ -379,7 +414,7 @@
 		b->b_sc = sc;
 		b->b_len = PFSYNC_MINPKT;
 
-		for (q = 0; q < PFSYNC_S_COUNT; q++)
+		for (q = 0; q < PFSYNC_Q_COUNT; q++)
 			TAILQ_INIT(&b->b_qs[q]);
 
 		TAILQ_INIT(&b->b_upd_req_list);
@@ -465,7 +500,7 @@
 }
 
 static int
-pfsync_state_import(struct pfsync_state *sp, int flags)
+pfsync_state_import(union pfsync_state_union *sp, int flags, int msg_version)
 {
 	struct pfsync_softc *sc = V_pfsyncif;
 #ifndef	__NO_STRICT_ALIGNMENT
@@ -480,17 +515,17 @@
 
 	PF_RULES_RASSERT();
 
-	if (sp->creatorid == 0) {
+	if (sp->pfs_1301.creatorid == 0) {
 		if (V_pf_status.debug >= PF_DEBUG_MISC)
 			printf("%s: invalid creator id: %08x\n", __func__,
-			    ntohl(sp->creatorid));
+			    ntohl(sp->pfs_1301.creatorid));
 		return (EINVAL);
 	}
 
-	if ((kif = pfi_kkif_find(sp->ifname)) == NULL) {
+	if ((kif = pfi_kkif_find(sp->pfs_1301.ifname)) == NULL) {
 		if (V_pf_status.debug >= PF_DEBUG_MISC)
 			printf("%s: unknown interface: %s\n", __func__,
-			    sp->ifname);
+			    sp->pfs_1301.ifname);
 		if (flags & PFSYNC_SI_IOCTL)
 			return (EINVAL);
 		return (0);	/* skip this state */
@@ -500,11 +535,11 @@
 	 * If the ruleset checksums match or the state is coming from the ioctl,
 	 * it's safe to associate the state with the rule of that number.
 	 */
-	if (sp->rule != htonl(-1) && sp->anchor == htonl(-1) &&
-	    (flags & (PFSYNC_SI_IOCTL | PFSYNC_SI_CKSUM)) && ntohl(sp->rule) <
+	if (sp->pfs_1301.rule != htonl(-1) && sp->pfs_1301.anchor == htonl(-1) &&
+	    (flags & (PFSYNC_SI_IOCTL | PFSYNC_SI_CKSUM)) && ntohl(sp->pfs_1301.rule) <
 	    pf_main_ruleset.rules[PF_RULESET_FILTER].active.rcount)
 		r = pf_main_ruleset.rules[
-		    PF_RULESET_FILTER].active.ptr_array[ntohl(sp->rule)];
+		    PF_RULESET_FILTER].active.ptr_array[ntohl(sp->pfs_1301.rule)];
 	else
 		r = &V_pf_default_rule;
 
@@ -523,16 +558,16 @@
 		goto cleanup;
 
 #ifndef	__NO_STRICT_ALIGNMENT
-	bcopy(&sp->key, key, sizeof(struct pfsync_state_key) * 2);
+	bcopy(&sp->pfs_1301.key, key, sizeof(struct pfsync_state_key) * 2);
 	kw = &key[PF_SK_WIRE];
 	ks = &key[PF_SK_STACK];
 #else
-	kw = &sp->key[PF_SK_WIRE];
-	ks = &sp->key[PF_SK_STACK];
+	kw = &sp->pfs_1301.key[PF_SK_WIRE];
+	ks = &sp->pfs_1301.key[PF_SK_STACK];
 #endif
 
-	if (PF_ANEQ(&kw->addr[0], &ks->addr[0], sp->af) ||
-	    PF_ANEQ(&kw->addr[1], &ks->addr[1], sp->af) ||
+	if (PF_ANEQ(&kw->addr[0], &ks->addr[0], sp->pfs_1301.af) ||
+	    PF_ANEQ(&kw->addr[1], &ks->addr[1], sp->pfs_1301.af) ||
 	    kw->port[0] != ks->port[0] ||
 	    kw->port[1] != ks->port[1]) {
 		sks = uma_zalloc(V_pf_state_key_z, M_NOWAIT);
@@ -542,8 +577,8 @@
 		sks = skw;
 
 	/* allocate memory for scrub info */
-	if (pfsync_alloc_scrub_memory(&sp->src, &st->src) ||
-	    pfsync_alloc_scrub_memory(&sp->dst, &st->dst))
+	if (pfsync_alloc_scrub_memory(&sp->pfs_1301.src, &st->src) ||
+	    pfsync_alloc_scrub_memory(&sp->pfs_1301.dst, &st->dst))
 		goto cleanup;
 
 	/* Copy to state key(s). */
@@ -551,69 +586,110 @@
 	skw->addr[1] = kw->addr[1];
 	skw->port[0] = kw->port[0];
 	skw->port[1] = kw->port[1];
-	skw->proto = sp->proto;
-	skw->af = sp->af;
+	skw->proto = sp->pfs_1301.proto;
+	skw->af = sp->pfs_1301.af;
 	if (sks != skw) {
 		sks->addr[0] = ks->addr[0];
 		sks->addr[1] = ks->addr[1];
 		sks->port[0] = ks->port[0];
 		sks->port[1] = ks->port[1];
-		sks->proto = sp->proto;
-		sks->af = sp->af;
+		sks->proto = sp->pfs_1301.proto;
+		sks->af = sp->pfs_1301.af;
 	}
 
 	/* copy to state */
-	bcopy(&sp->rt_addr, &st->rt_addr, sizeof(st->rt_addr));
-	st->creation = time_uptime - ntohl(sp->creation);
+	bcopy(&sp->pfs_1301.rt_addr, &st->rt_addr, sizeof(st->rt_addr));
+	st->creation = time_uptime - ntohl(sp->pfs_1301.creation);
 	st->expire = time_uptime;
-	if (sp->expire) {
+	if (sp->pfs_1301.expire) {
 		uint32_t timeout;
 
-		timeout = r->timeout[sp->timeout];
+		timeout = r->timeout[sp->pfs_1301.timeout];
 		if (!timeout)
-			timeout = V_pf_default_rule.timeout[sp->timeout];
+			timeout = V_pf_default_rule.timeout[sp->pfs_1301.timeout];
 
 		/* sp->expire may have been adaptively scaled by export. */
-		st->expire -= timeout - ntohl(sp->expire);
+		st->expire -= timeout - ntohl(sp->pfs_1301.expire);
 	}
 
-	st->direction = sp->direction;
-	st->log = sp->log;
-	st->timeout = sp->timeout;
-	/* 8 from old peers, 16 bits from new peers */
-	st->state_flags = sp->state_flags_compat | ntohs(sp->state_flags);
+	st->direction = sp->pfs_1301.direction;
+	st->log = sp->pfs_1301.log;
+	st->timeout = sp->pfs_1301.timeout;
 
-	if (r == &V_pf_default_rule) {
-		/* ToS and Prio are not sent over struct pfsync_state */
-		st->state_flags &= ~PFSTATE_SETMASK;
-	} else {
-		/* Most actions are applied form state, not from rule. Until
-		 * pfsync can forward all those actions and their parameters we
-		 * must relay on restoring them from the found rule.
-		 * It's a copy of pf_rule_to_actions() */
-		st->qid = r->qid;
-		st->pqid = r->pqid;
-		st->rtableid = r->rtableid;
-		if (r->scrub_flags & PFSTATE_SETTOS)
-			st->set_tos = r->set_tos;
-		st->min_ttl = r->min_ttl;
-		st->max_mss = r->max_mss;
-		st->state_flags |= (r->scrub_flags & (PFSTATE_NODF|PFSTATE_RANDOMID|
-		    PFSTATE_SETTOS|PFSTATE_SCRUB_TCP|PFSTATE_SETPRIO));
-		st->dnpipe = r->dnpipe;
-		st->dnrpipe = r->dnrpipe;
-		/* FIXME: dnflags are not part of state, can't update them */
+	switch (msg_version) {
+		case PFSYNC_MSG_VERSION_1301:
+			st->state_flags = sp->pfs_1301.state_flags;
+			/*
+			 * In FreeBSD 13 pfsync lacks many attributes. Copy them
+			 * from the rule if possible. If rule can't be matched
+			 * clear any set options as we can't recover their
+			 * parameters.
+			*/
+			if (r == &V_pf_default_rule) {
+				st->state_flags &= ~PFSTATE_SETMASK;
+			} else {
+				/*
+				 * Similar to pf_rule_to_actions(). This code
+				 * won't set the actions properly if they come
+				 * from multiple "match" rules as only rule
+				 * creating the state is send over pfsync.
+				 */
+				st->qid = r->qid;
+				st->pqid = r->pqid;
+				st->rtableid = r->rtableid;
+				if (r->scrub_flags & PFSTATE_SETTOS)
+					st->set_tos = r->set_tos;
+				st->min_ttl = r->min_ttl;
+				st->max_mss = r->max_mss;
+				st->state_flags |= (r->scrub_flags &
+				    (PFSTATE_NODF|PFSTATE_RANDOMID|
+				    PFSTATE_SETTOS|PFSTATE_SCRUB_TCP|
+				    PFSTATE_SETPRIO));
+				if (r->dnpipe || r->dnrpipe) {
+					if (r->free_flags & PFRULE_DN_IS_PIPE)
+						st->state_flags |= PFSTATE_DN_IS_PIPE;
+					else
+						st->state_flags &= ~PFSTATE_DN_IS_PIPE;
+				}
+				st->dnpipe = r->dnpipe;
+				st->dnrpipe = r->dnrpipe;
+			}
+			break;
+		case PFSYNC_MSG_VERSION_1400:
+			st->state_flags = ntohs(sp->pfs_1400.state_flags);
+			st->qid = ntohs(sp->pfs_1400.qid);
+			st->pqid = ntohs(sp->pfs_1400.pqid);
+			st->dnpipe = ntohs(sp->pfs_1400.dnpipe);
+			st->dnrpipe = ntohs(sp->pfs_1400.dnrpipe);
+			st->rtableid = ntohl(sp->pfs_1400.rtableid);
+			st->min_ttl = sp->pfs_1400.min_ttl;
+			st->set_tos = sp->pfs_1400.set_tos;
+			st->max_mss = ntohs(sp->pfs_1400.max_mss);
+			st->set_prio[0] = sp->pfs_1400.set_prio[0];
+			st->set_prio[1] = sp->pfs_1400.set_prio[1];
+			st->rt = sp->pfs_1400.rt;
+			if (st->rt && (st->rt_kif = pfi_kkif_find(sp->pfs_1400.rt_ifname)) == NULL) {
+				if (V_pf_status.debug >= PF_DEBUG_MISC)
+					printf("%s: unknown route interface: %s\n",
+					    __func__, sp->pfs_1400.rt_ifname);
+				if (flags & PFSYNC_SI_IOCTL)
+					return (EINVAL);
+				return (0);	/* skip this state */
+			}
+			break;
+		default:
+			panic("%s: Unsupported pfsync_msg_version %d",
+			    __func__, msg_version);
 	}
 
-	st->id = sp->id;
-	st->creatorid = sp->creatorid;
-	pf_state_peer_ntoh(&sp->src, &st->src);
-	pf_state_peer_ntoh(&sp->dst, &st->dst);
+	st->id = sp->pfs_1301.id;
+	st->creatorid = sp->pfs_1301.creatorid;
+	pf_state_peer_ntoh(&sp->pfs_1301.src, &st->src);
+	pf_state_peer_ntoh(&sp->pfs_1301.dst, &st->dst);
 
 	st->rule.ptr = r;
 	st->nat_rule.ptr = NULL;
 	st->anchor.ptr = NULL;
-	st->rt_kif = NULL;
 
 	st->pfsync_time = time_uptime;
 	st->sync_state = PFSYNC_S_NONE;
@@ -745,7 +821,7 @@
 
 		count = ntohs(subh.count);
 		V_pfsyncstats.pfsyncs_iacts[subh.action] += count;
-		rv = (*pfsync_acts[subh.action])(m, offset, count, flags);
+		rv = (*pfsync_acts[subh.action])(m, offset, count, flags, subh.action);
 		if (rv == -1) {
 			PF_RULES_RUNLOCK();
 			return (IPPROTO_DONE);
@@ -762,7 +838,7 @@
 #endif
 
 static int
-pfsync_in_clr(struct mbuf *m, int offset, int count, int flags)
+pfsync_in_clr(struct mbuf *m, int offset, int count, int flags, int action)
 {
 	struct pfsync_clr *clr;
 	struct mbuf *mp;
@@ -804,36 +880,50 @@
 }
 
 static int
-pfsync_in_ins(struct mbuf *m, int offset, int count, int flags)
+pfsync_in_ins(struct mbuf *m, int offset, int count, int flags, int action)
 {
 	struct mbuf *mp;
-	struct pfsync_state *sa, *sp;
-	int len = sizeof(*sp) * count;
-	int i, offp;
+	union pfsync_state_union *sa, *sp;
+	int i, offp, len, msg_version;
+
+	switch (action) {
+		case PFSYNC_ACT_INS_1301:
+			len = sizeof(struct pfsync_state_1301) * count;
+			msg_version = PFSYNC_MSG_VERSION_1301;
+			break;
+		case PFSYNC_ACT_INS_1400:
+			len = sizeof(struct pfsync_state_1400) * count;
+			msg_version = PFSYNC_MSG_VERSION_1400;
+			break;
+		default:
+			V_pfsyncstats.pfsyncs_badact++;
+			return (-1);
+	}
 
 	mp = m_pulldown(m, offset, len, &offp);
 	if (mp == NULL) {
 		V_pfsyncstats.pfsyncs_badlen++;
 		return (-1);
 	}
-	sa = (struct pfsync_state *)(mp->m_data + offp);
+	sa = (union pfsync_state_union *)(mp->m_data + offp);
 
 	for (i = 0; i < count; i++) {
 		sp = &sa[i];
 
 		/* Check for invalid values. */
-		if (sp->timeout >= PFTM_MAX ||
-		    sp->src.state > PF_TCPS_PROXY_DST ||
-		    sp->dst.state > PF_TCPS_PROXY_DST ||
-		    sp->direction > PF_OUT ||
-		    (sp->af != AF_INET && sp->af != AF_INET6)) {
+		if (sp->pfs_1301.timeout >= PFTM_MAX ||
+		    sp->pfs_1301.src.state > PF_TCPS_PROXY_DST ||
+		    sp->pfs_1301.dst.state > PF_TCPS_PROXY_DST ||
+		    sp->pfs_1301.direction > PF_OUT ||
+		    (sp->pfs_1301.af != AF_INET &&
+		    sp->pfs_1301.af != AF_INET6)) {
 			if (V_pf_status.debug >= PF_DEBUG_MISC)
 				printf("%s: invalid value\n", __func__);
 			V_pfsyncstats.pfsyncs_badval++;
 			continue;
 		}
 
-		if (pfsync_state_import(sp, flags) == ENOMEM)
+		if (pfsync_state_import(sp, flags, msg_version) == ENOMEM)
 			/* Drop out, but process the rest of the actions. */
 			break;
 	}
@@ -842,7 +932,7 @@
 }
 
 static int
-pfsync_in_iack(struct mbuf *m, int offset, int count, int flags)
+pfsync_in_iack(struct mbuf *m, int offset, int count, int flags, int action)
 {
 	struct pfsync_ins_ack *ia, *iaa;
 	struct pf_kstate *st;
@@ -913,31 +1003,42 @@
 }
 
 static int
-pfsync_in_upd(struct mbuf *m, int offset, int count, int flags)
+pfsync_in_upd(struct mbuf *m, int offset, int count, int flags, int action)
 {
 	struct pfsync_softc *sc = V_pfsyncif;
-	struct pfsync_state *sa, *sp;
+	union pfsync_state_union *sa, *sp;
 	struct pf_kstate *st;
-	int sync;
-
 	struct mbuf *mp;
-	int len = count * sizeof(*sp);
-	int offp, i;
+	int sync, offp, i, len, msg_version;
+
+	switch (action) {
+		case PFSYNC_ACT_UPD_1301:
+			len = sizeof(struct pfsync_state_1301) * count;
+			msg_version = PFSYNC_MSG_VERSION_1301;
+			break;
+		case PFSYNC_ACT_UPD_1400:
+			len = sizeof(struct pfsync_state_1400) * count;
+			msg_version = PFSYNC_MSG_VERSION_1400;
+			break;
+		default:
+			V_pfsyncstats.pfsyncs_badact++;
+			return (-1);
+	}
 
 	mp = m_pulldown(m, offset, len, &offp);
 	if (mp == NULL) {
 		V_pfsyncstats.pfsyncs_badlen++;
 		return (-1);
 	}
-	sa = (struct pfsync_state *)(mp->m_data + offp);
+	sa = (union pfsync_state_union *)(mp->m_data + offp);
 
 	for (i = 0; i < count; i++) {
 		sp = &sa[i];
 
 		/* check for invalid values */
-		if (sp->timeout >= PFTM_MAX ||
-		    sp->src.state > PF_TCPS_PROXY_DST ||
-		    sp->dst.state > PF_TCPS_PROXY_DST) {
+		if (sp->pfs_1301.timeout >= PFTM_MAX ||
+		    sp->pfs_1301.src.state > PF_TCPS_PROXY_DST ||
+		    sp->pfs_1301.dst.state > PF_TCPS_PROXY_DST) {
 			if (V_pf_status.debug >= PF_DEBUG_MISC) {
 				printf("pfsync_input: PFSYNC_ACT_UPD: "
 				    "invalid value\n");
@@ -946,10 +1047,10 @@
 			continue;
 		}
 
-		st = pf_find_state_byid(sp->id, sp->creatorid);
+		st = pf_find_state_byid(sp->pfs_1301.id, sp->pfs_1301.creatorid);
 		if (st == NULL) {
 			/* insert the update */
-			if (pfsync_state_import(sp, flags))
+			if (pfsync_state_import(sp, flags, msg_version))
 				V_pfsyncstats.pfsyncs_badstate++;
 			continue;
 		}
@@ -959,7 +1060,7 @@
 		}
 
 		if (st->key[PF_SK_WIRE]->proto == IPPROTO_TCP)
-			sync = pfsync_upd_tcp(st, &sp->src, &sp->dst);
+			sync = pfsync_upd_tcp(st, &sp->pfs_1301.src, &sp->pfs_1301.dst);
 		else {
 			sync = 0;
 
@@ -967,20 +1068,20 @@
 			 * Non-TCP protocol state machine always go
 			 * forwards
 			 */
-			if (st->src.state > sp->src.state)
+			if (st->src.state > sp->pfs_1301.src.state)
 				sync++;
 			else
-				pf_state_peer_ntoh(&sp->src, &st->src);
-			if (st->dst.state > sp->dst.state)
+				pf_state_peer_ntoh(&sp->pfs_1301.src, &st->src);
+			if (st->dst.state > sp->pfs_1301.dst.state)
 				sync++;
 			else
-				pf_state_peer_ntoh(&sp->dst, &st->dst);
+				pf_state_peer_ntoh(&sp->pfs_1301.dst, &st->dst);
 		}
 		if (sync < 2) {
-			pfsync_alloc_scrub_memory(&sp->dst, &st->dst);
-			pf_state_peer_ntoh(&sp->dst, &st->dst);
+			pfsync_alloc_scrub_memory(&sp->pfs_1301.dst, &st->dst);
+			pf_state_peer_ntoh(&sp->pfs_1301.dst, &st->dst);
 			st->expire = time_uptime;
-			st->timeout = sp->timeout;
+			st->timeout = sp->pfs_1301.timeout;
 		}
 		st->pfsync_time = time_uptime;
 
@@ -999,7 +1100,7 @@
 }
 
 static int
-pfsync_in_upd_c(struct mbuf *m, int offset, int count, int flags)
+pfsync_in_upd_c(struct mbuf *m, int offset, int count, int flags, int action)
 {
 	struct pfsync_softc *sc = V_pfsyncif;
 	struct pfsync_upd_c *ua, *up;
@@ -1086,7 +1187,7 @@
 }
 
 static int
-pfsync_in_ureq(struct mbuf *m, int offset, int count, int flags)
+pfsync_in_ureq(struct mbuf *m, int offset, int count, int flags, int action)
 {
 	struct pfsync_upd_req *ur, *ura;
 	struct mbuf *mp;
@@ -1127,7 +1228,7 @@
 }
 
 static int
-pfsync_in_del_c(struct mbuf *m, int offset, int count, int flags)
+pfsync_in_del_c(struct mbuf *m, int offset, int count, int flags, int action)
 {
 	struct mbuf *mp;
 	struct pfsync_del_c *sa, *sp;
@@ -1159,7 +1260,7 @@
 }
 
 static int
-pfsync_in_bus(struct mbuf *m, int offset, int count, int flags)
+pfsync_in_bus(struct mbuf *m, int offset, int count, int flags, int action)
 {
 	struct pfsync_softc *sc = V_pfsyncif;
 	struct pfsync_bus *bus;
@@ -1188,7 +1289,7 @@
 		callout_reset(&sc->sc_bulkfail_tmo, 4 * hz +
 		    V_pf_limits[PF_LIMIT_STATES].limit /
 		    ((sc->sc_ifp->if_mtu - PFSYNC_MINPKT) /
-		    sizeof(struct pfsync_state)),
+		    sizeof(union pfsync_state_union)),
 		    pfsync_bulk_fail, sc);
 		if (V_pf_status.debug >= PF_DEBUG_MISC)
 			printf("pfsync: received bulk update start\n");
@@ -1221,7 +1322,7 @@
 }
 
 static int
-pfsync_in_tdb(struct mbuf *m, int offset, int count, int flags)
+pfsync_in_tdb(struct mbuf *m, int offset, int count, int flags, int action)
 {
 	int len = count * sizeof(struct pfsync_tdb);
 
@@ -1286,7 +1387,7 @@
 #endif
 
 static int
-pfsync_in_eof(struct mbuf *m, int offset, int count, int flags)
+pfsync_in_eof(struct mbuf *m, int offset, int count, int flags, int action)
 {
 	/* check if we are at the right place in the packet */
 	if (offset != m->m_pkthdr.len)
@@ -1298,7 +1399,7 @@
 }
 
 static int
-pfsync_in_error(struct mbuf *m, int offset, int count, int flags)
+pfsync_in_error(struct mbuf *m, int offset, int count, int flags, int action)
 {
 	V_pfsyncstats.pfsyncs_badact++;
 
@@ -1379,6 +1480,7 @@
 			nvlist_add_string(nvl, "syncdev", sc->sc_sync_if->if_xname);
 		nvlist_add_number(nvl, "maxupdates", sc->sc_maxupdates);
 		nvlist_add_number(nvl, "flags", sc->sc_flags);
+		nvlist_add_number(nvl, "version", sc->sc_version);
 		if ((nvl_syncpeer = pfsync_sockaddr_to_syncpeer_nvlist(&sc->sc_sync_peer)) != NULL)
 			nvlist_add_nvlist(nvl, "syncpeer", nvl_syncpeer);
 
@@ -1464,11 +1566,19 @@
 }
 
 static void
-pfsync_out_state(struct pf_kstate *st, void *buf)
+pfsync_out_state_1301(struct pf_kstate *st, void *buf)
 {
-	struct pfsync_state *sp = buf;
+	union pfsync_state_union *sp = buf;
 
-	pfsync_state_export(sp, st);
+	pfsync_state_export(sp, st, PFSYNC_MSG_VERSION_1301);
+}
+
+static void
+pfsync_out_state_1400(struct pf_kstate *st, void *buf)
+{
+	union pfsync_state_union *sp = buf;
+
+	pfsync_state_export(sp, st, PFSYNC_MSG_VERSION_1400);
 }
 
 static void
@@ -1509,16 +1619,17 @@
 	struct pf_kstate *st, *next;
 	struct pfsync_upd_req_item *ur;
 	struct pfsync_bucket *b;
-	int c, q;
+	int c;
+	enum pfsync_q_id q;
 
 	for (c = 0; c < pfsync_buckets; c++) {
 		b = &sc->sc_buckets[c];
-		for (q = 0; q < PFSYNC_S_COUNT; q++) {
+		for (q = 0; q < PFSYNC_Q_COUNT; q++) {
 			if (TAILQ_EMPTY(&b->b_qs[q]))
 				continue;
 
 			TAILQ_FOREACH_SAFE(st, &b->b_qs[q], sync_list, next) {
-				KASSERT(st->sync_state == q,
+				KASSERT(st->sync_state == pfsync_qid_sstate[q],
 					("%s: st->sync_state == q",
 						__func__));
 				st->sync_state = PFSYNC_S_NONE;
@@ -1548,8 +1659,8 @@
 	struct pf_kstate *st, *st_next;
 	struct pfsync_upd_req_item *ur;
 	struct pfsync_bucket *b = &sc->sc_buckets[c];
-	int aflen, offset;
-	int q, count = 0;
+	int aflen, offset, count = 0;
+	enum pfsync_q_id q;
 
 	KASSERT(sc != NULL, ("%s: null sc", __func__));
 	KASSERT(b->b_len > PFSYNC_MINPKT,
@@ -1591,7 +1702,6 @@
 		return;
 	}
 
-
 	/* build the pfsync header */
 	ph = (struct pfsync_header *)(m->m_data + offset);
 	bzero(ph, sizeof(*ph));
@@ -1602,7 +1712,7 @@
 	bcopy(V_pf_status.pf_chksum, ph->pfcksum, PF_MD5_DIGEST_LENGTH);
 
 	/* walk the queues */
-	for (q = 0; q < PFSYNC_S_COUNT; q++) {
+	for (q = 0; q < PFSYNC_Q_COUNT; q++) {
 		if (TAILQ_EMPTY(&b->b_qs[q]))
 			continue;
 
@@ -1611,7 +1721,7 @@
 
 		count = 0;
 		TAILQ_FOREACH_SAFE(st, &b->b_qs[q], sync_list, st_next) {
-			KASSERT(st->sync_state == q,
+			KASSERT(st->sync_state == pfsync_qid_sstate[q],
 				("%s: st->sync_state == q",
 					__func__));
 			/*
@@ -2015,7 +2125,7 @@
 		panic("%s: unexpected sync state %d", __func__, st->sync_state);
 	}
 
-	if ((sc->sc_ifp->if_mtu - b->b_len) < sizeof(struct pfsync_state))
+	if ((sc->sc_ifp->if_mtu - b->b_len) < sizeof(union pfsync_state_union))
 		full = true;
 
 	PFSYNC_BUCKET_UNLOCK(b);
@@ -2087,10 +2197,48 @@
 	pfsync_send_plus(&r, sizeof(r));
 }
 
-static void
-pfsync_q_ins(struct pf_kstate *st, int q, bool ref)
+static enum pfsync_q_id
+pfsync_sstate_to_qid(u_int8_t sync_state)
 {
 	struct pfsync_softc *sc = V_pfsyncif;
+
+	switch (sync_state) {
+		case PFSYNC_S_INS:
+			switch (sc->sc_version) {
+				case PFSYNC_MSG_VERSION_1301:
+					return PFSYNC_Q_INS_1301;
+				case PFSYNC_MSG_VERSION_1400:
+					return PFSYNC_Q_INS_1400;
+			}
+			break;
+		case PFSYNC_S_IACK:
+			return PFSYNC_Q_IACK;
+		case PFSYNC_S_UPD:
+			switch (sc->sc_version) {
+				case PFSYNC_MSG_VERSION_1301:
+					return PFSYNC_Q_UPD_1301;
+				case PFSYNC_MSG_VERSION_1400:
+					return PFSYNC_Q_UPD_1400;
+			}
+			break;
+		case PFSYNC_S_UPD_C:
+			return PFSYNC_Q_UPD_C;
+		case PFSYNC_S_DEL_C:
+			return PFSYNC_Q_DEL_C;
+		default:
+			panic("%s: Unsupported st->sync_state 0x%02x",
+			__func__, sync_state);
+	}
+
+	panic("%s: Unsupported pfsync_msg_version %d",
+	    __func__, sc->sc_version);
+}
+
+static void
+pfsync_q_ins(struct pf_kstate *st, int sync_state, bool ref)
+{
+	enum pfsync_q_id q = pfsync_sstate_to_qid(sync_state);
+	struct pfsync_softc *sc = V_pfsyncif;
 	size_t nlen = pfsync_qs[q].len;
 	struct pfsync_bucket *b = pfsync_get_bucket(sc, st);
 
@@ -2112,7 +2260,7 @@
 
 	b->b_len += nlen;
 	TAILQ_INSERT_TAIL(&b->b_qs[q], st, sync_list);
-	st->sync_state = q;
+	st->sync_state = pfsync_qid_sstate[q];
 	if (ref)
 		pf_ref_state(st);
 }
@@ -2120,12 +2268,13 @@
 static void
 pfsync_q_del(struct pf_kstate *st, bool unref, struct pfsync_bucket *b)
 {
-	int q = st->sync_state;
+	enum pfsync_q_id q;
 
 	PFSYNC_BUCKET_LOCK_ASSERT(b);
 	KASSERT(st->sync_state != PFSYNC_S_NONE,
 		("%s: st->sync_state != PFSYNC_S_NONE", __func__));
 
+	q =  pfsync_sstate_to_qid(st->sync_state);
 	b->b_len -= pfsync_qs[q].len;
 	TAILQ_REMOVE(&b->b_qs[q], st, sync_list);
 	st->sync_state = PFSYNC_S_NONE;
@@ -2522,6 +2671,20 @@
 		imf = ip_mfilter_alloc(M_WAITOK, 0, 0);
 
 	PFSYNC_LOCK(sc);
+
+	switch (status->version) {
+		case PFSYNC_MSG_VERSION_UNSPECIFIED:
+			sc->sc_version = PFSYNC_MSG_VERSION_DEFAULT;
+			break;
+		case PFSYNC_MSG_VERSION_1301:
+		case PFSYNC_MSG_VERSION_1400:
+			sc->sc_version = status->version;
+			break;
+		default:
+			PFSYNC_UNLOCK(sc);
+			return (EINVAL);
+	}
+
 	struct sockaddr_in *sc_sin = (struct sockaddr_in *)&sc->sc_sync_peer;
 	sc_sin->sin_family = AF_INET;
 	sc_sin->sin_len = sizeof(*sc_sin);
diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c
--- a/sys/netpfil/pf/pf.c
+++ b/sys/netpfil/pf/pf.c
@@ -3592,6 +3592,8 @@
 void
 pf_rule_to_actions(struct pf_krule *r, struct pf_rule_actions *a)
 {
+	a->flags |= (r->scrub_flags & (PFSTATE_NODF|PFSTATE_RANDOMID|
+	    PFSTATE_SETTOS|PFSTATE_SCRUB_TCP|PFSTATE_SETPRIO));
 	if (r->qid)
 		a->qid = r->qid;
 	if (r->pqid)
@@ -3599,14 +3601,12 @@
 	if (r->rtableid >= 0)
 		a->rtableid = r->rtableid;
 	a->log |= r->log;
-	if (r->scrub_flags & PFSTATE_SETTOS)
+	if (a->flags & PFSTATE_SETTOS)
 		a->set_tos = r->set_tos;
 	if (r->min_ttl)
 		a->min_ttl = r->min_ttl;
 	if (r->max_mss)
 		a->max_mss = r->max_mss;
-	a->flags |= (r->scrub_flags & (PFSTATE_NODF|PFSTATE_RANDOMID|
-	    PFSTATE_SETTOS|PFSTATE_SCRUB_TCP|PFSTATE_SETPRIO));
 	if (r->dnpipe)
 		a->dnpipe = r->dnpipe;
 	if (r->dnrpipe)
@@ -3617,6 +3617,10 @@
 		else
 			a->flags &= ~PFSTATE_DN_IS_PIPE;
 	}
+	if (a->flags & PFSTATE_SETPRIO) {
+		a->set_prio[0] = r->set_prio[0];
+		a->set_prio[1] = r->set_prio[1];
+	}
 }
 
 int
@@ -4636,6 +4640,8 @@
 	s->pqid = pd->act.pqid;
 	s->dnpipe = pd->act.dnpipe;
 	s->dnrpipe = pd->act.dnrpipe;
+	s->set_prio[0] = pd->act.set_prio[0];
+	s->set_prio[1] = pd->act.set_prio[1];
 	s->state_flags |= pd->act.flags;
 	if (nr != NULL)
 		s->log |= nr->log & PF_LOG_ALL;
@@ -4704,6 +4710,7 @@
 			goto csfailed;
 		}
 		s->rt_kif = r->rpool.cur->kif;
+		s->rt = r->rt;
 	}
 
 	s->creation = time_uptime;
@@ -6439,9 +6446,20 @@
 	struct pf_ksrc_node	*sn = NULL;
 	int			 error = 0;
 	uint16_t		 ip_len, ip_off;
+	int			 r_rt, r_dir;
 
 	KASSERT(m && *m && r && oifp, ("%s: invalid parameters", __func__));
-	KASSERT(dir == PF_IN || dir == PF_OUT, ("%s: invalid direction",
+
+	if (s) {
+		r_rt = s->rt;
+		r_dir = s->direction;
+	} else {
+		r_rt = r->rt;
+		r_dir = r->direction;
+	}
+
+	KASSERT(dir == PF_IN || dir == PF_OUT ||
+	    r_dir == PF_IN || r_dir == PF_OUT, ("%s: invalid direction",
 	    __func__));
 
 	if ((pd->pf_mtag == NULL &&
@@ -6452,7 +6470,7 @@
 		goto bad_locked;
 	}
 
-	if (r->rt == PF_DUPTO) {
+	if (r_rt == PF_DUPTO) {
 		if ((pd->pf_mtag->flags & PF_DUPLICATED)) {
 			if (s == NULL) {
 				ifp = r->rpool.cur->kif ?
@@ -6482,7 +6500,7 @@
 			}
 		}
 	} else {
-		if ((r->rt == PF_REPLYTO) == (r->direction == dir)) {
+		if ((r_rt == PF_REPLYTO) == (r_dir == dir)) {
 			pf_dummynet(pd, dir, s, r, m);
 			if (s)
 				PF_STATE_UNLOCK(s);
@@ -6581,7 +6599,7 @@
 	if ((ip_off & IP_DF) || (m0->m_pkthdr.csum_flags & CSUM_TSO)) {
 		error = EMSGSIZE;
 		KMOD_IPSTAT_INC(ips_cantfrag);
-		if (r->rt != PF_DUPTO) {
+		if (r_rt != PF_DUPTO) {
 			if (s && pd->nat_rule != NULL)
 				PACKET_UNDO_NAT(m0, pd,
 				    (ip->ip_hl << 2) + (ip_off & IP_OFFMASK),
@@ -6617,7 +6635,7 @@
 		KMOD_IPSTAT_INC(ips_fragmented);
 
 done:
-	if (r->rt != PF_DUPTO)
+	if (r_rt != PF_DUPTO)
 		*m = NULL;
 	return;
 
@@ -6641,9 +6659,20 @@
 	struct ifnet		*ifp = NULL;
 	struct pf_addr		 naddr;
 	struct pf_ksrc_node	*sn = NULL;
+	int			 r_rt, r_dir;
 
 	KASSERT(m && *m && r && oifp, ("%s: invalid parameters", __func__));
-	KASSERT(dir == PF_IN || dir == PF_OUT, ("%s: invalid direction",
+
+	if (s) {
+		r_rt = s->rt;
+		r_dir = s->direction;
+	} else {
+		r_rt = r->rt;
+		r_dir = r->direction;
+	}
+
+	KASSERT(dir == PF_IN || dir == PF_OUT ||
+	    r_dir == PF_IN || r_dir == PF_OUT, ("%s: invalid direction",
 	    __func__));
 
 	if ((pd->pf_mtag == NULL &&
@@ -6654,7 +6683,7 @@
 		goto bad_locked;
 	}
 
-	if (r->rt == PF_DUPTO) {
+	if (r_rt == PF_DUPTO) {
 		if ((pd->pf_mtag->flags & PF_DUPLICATED)) {
 			if (s == NULL) {
 				ifp = r->rpool.cur->kif ?
@@ -6684,7 +6713,7 @@
 			}
 		}
 	} else {
-		if ((r->rt == PF_REPLYTO) == (r->direction == dir)) {
+		if ((r_rt == PF_REPLYTO) == (r_dir == dir)) {
 			pf_dummynet(pd, dir, s, r, m);
 			if (s)
 				PF_STATE_UNLOCK(s);
@@ -6768,7 +6797,7 @@
 	}
 	else {
 		in6_ifstat_inc(ifp, ifs6_in_toobig);
-		if (r->rt != PF_DUPTO) {
+		if (r_rt != PF_DUPTO) {
 			if (s && pd->nat_rule != NULL)
 				PACKET_UNDO_NAT(m0, pd,
 				    ((caddr_t)ip6 - m0->m_data) +
@@ -6780,7 +6809,7 @@
 	}
 
 done:
-	if (r->rt != PF_DUPTO)
+	if (r_rt != PF_DUPTO)
 		*m = NULL;
 	return;
 
@@ -7100,7 +7129,16 @@
 	struct pf_kstate	*s = NULL;
 	struct pf_kruleset	*ruleset = NULL;
 	struct pf_pdesc		 pd;
-	int			 off, dirndx, pqid = 0;
+	int			 off, dirndx;
+	uint16_t		 scrub_flags;
+	uint16_t		 qid;
+	uint16_t		 pqid;
+	uint16_t		 tag;
+	int32_t			 rtableid;
+	uint8_t			 min_ttl;
+	uint8_t			 set_tos;
+	uint8_t			 rt;
+	uint8_t			 set_prio[2];
 
 	PF_RULES_RLOCK_TRACKER;
 	KASSERT(dir == PF_IN || dir == PF_OUT, ("%s: bad direction %d\n", __func__, dir));
@@ -7392,36 +7430,43 @@
 	}
 
 	if (s) {
-		pf_scrub_ip(&m, s->state_flags, s->min_ttl, s->set_tos);
-		if (s->rtableid >= 0)
-			M_SETFIB(m, s->rtableid);
-#ifdef ALTQ
-		if (s->qid) {
-			pd.act.pqid = s->pqid;
-			pd.act.qid = s->qid;
-		}
-#endif
+		scrub_flags = s->state_flags;
+		min_ttl = s->min_ttl;
+		set_tos = s->set_tos;
+		rtableid = s->rtableid;
+		pqid = s->pqid;
+		qid = s->qid;
+		tag = s->tag;
+		rt = s->rt;
+		set_prio[0] = s->set_prio[0];
+		set_prio[1] = s->set_prio[1];
 	} else {
-		pf_scrub_ip(&m, r->scrub_flags, r->min_ttl, r->set_tos);
-		if (r->rtableid >= 0)
-			M_SETFIB(m, r->rtableid);
-#ifdef ALTQ
-		if (r->qid) {
-			pd.act.pqid = r->pqid;
-			pd.act.qid = r->qid;
-		}
-#endif
+		scrub_flags = r->scrub_flags;
+		min_ttl = r->min_ttl;
+		set_tos = r->set_tos;
+		rtableid = r->rtableid;
+		pqid = r->pqid;
+		qid = r->qid;
+		tag = r->tag;
+		rt = r->rt;
+		set_prio[0] = r->set_prio[0];
+		set_prio[1] = r->set_prio[1];
 	}
 
-	if (s && s->tag > 0 && pf_tag_packet(m, &pd, s->tag)) {
+	if (tag > 0 && pf_tag_packet(m, &pd, tag)) {
 		action = PF_DROP;
 		REASON_SET(&reason, PFRES_MEMORY);
 	}
 
-	if (r->scrub_flags & PFSTATE_SETPRIO) {
+	pf_scrub_ip(&m, scrub_flags, min_ttl, set_tos);
+
+	if (rtableid >= 0)
+		M_SETFIB(m, rtableid);
+
+	if (scrub_flags & PFSTATE_SETPRIO) {
 		if (pd.tos & IPTOS_LOWDELAY)
 			pqid = 1;
-		if (vlan_set_pcp(m, r->set_prio[pqid])) {
+		if (vlan_set_pcp(m, set_prio[pqid])) {
 			action = PF_DROP;
 			REASON_SET(&reason, PFRES_MEMORY);
 			log = PF_LOG_FORCE;
@@ -7431,6 +7476,11 @@
 	}
 
 #ifdef ALTQ
+	if (qid) {
+		pd.act.pqid = pqid;
+		pd.act.qid = qid;
+	}
+
 	if (action == PF_PASS && pd.act.qid) {
 		if (pd.pf_mtag == NULL &&
 		    ((pd.pf_mtag = pf_get_mtag(m)) == NULL)) {
@@ -7602,7 +7652,7 @@
 		break;
 	default:
 		/* pf_route() returns unlocked. */
-		if (r->rt) {
+		if (rt) {
 			pf_route(m0, r, dir, kif->pfik_ifp, s, &pd, inp);
 			return (action);
 		}
@@ -7635,7 +7685,16 @@
 	struct pf_kstate	*s = NULL;
 	struct pf_kruleset	*ruleset = NULL;
 	struct pf_pdesc		 pd;
-	int			 off, terminal = 0, dirndx, rh_cnt = 0, pqid = 0;
+	int			 off, terminal = 0, dirndx, rh_cnt = 0;
+	uint16_t		 scrub_flags;
+	uint16_t		 qid;
+	uint16_t		 pqid;
+	uint16_t		 tag;
+	int32_t			 rtableid;
+	uint8_t			 min_ttl;
+	uint8_t			 set_tos;
+	uint8_t			 rt;
+	uint8_t			 set_prio[2];
 
 	PF_RULES_RLOCK_TRACKER;
 	KASSERT(dir == PF_IN || dir == PF_OUT, ("%s: bad direction %d\n", __func__, dir));
@@ -7923,37 +7982,44 @@
 		    ("pf: dropping packet with dangerous v6 headers\n"));
 	}
 
-	if (s && s->tag > 0 && pf_tag_packet(m, &pd, s->tag)) {
+	if (s) {
+		scrub_flags = s->state_flags;
+		min_ttl = s->min_ttl;
+		set_tos = s->set_tos;
+		rtableid = s->rtableid;
+		pqid = s->pqid;
+		qid = s->qid;
+		tag = s->tag;
+		rt = s->rt;
+		set_prio[0] = s->set_prio[0];
+		set_prio[1] = s->set_prio[1];
+	} else {
+		scrub_flags = r->scrub_flags;
+		min_ttl = r->min_ttl;
+		set_tos = r->set_tos;
+		rtableid = r->rtableid;
+		pqid = r->pqid;
+		qid = r->qid;
+		tag = r->tag;
+		rt = r->rt;
+		set_prio[0] = r->set_prio[0];
+		set_prio[1] = r->set_prio[1];
+	}
+
+	if (tag > 0 && pf_tag_packet(m, &pd, tag)) {
 		action = PF_DROP;
 		REASON_SET(&reason, PFRES_MEMORY);
 	}
 
-	if (s) {
-		pf_scrub_ip6(&m, s->state_flags, s->min_ttl, s->set_tos);
-		if (s->rtableid >= 0)
-			M_SETFIB(m, s->rtableid);
-#ifdef ALTQ
-		if (s->qid) {
-			pd.act.pqid = s->pqid;
-			pd.act.qid = s->qid;
-		}
-#endif
-	} else {
-		pf_scrub_ip6(&m, r->scrub_flags, r->min_ttl, r->set_tos);
-		if (r->rtableid >= 0)
-			M_SETFIB(m, r->rtableid);
-#ifdef ALTQ
-		if (r->qid) {
-			pd.act.pqid = r->pqid;
-			pd.act.qid = r->qid;
-		}
-#endif
-	}
+	pf_scrub_ip6(&m, scrub_flags, min_ttl, set_tos);
 
-	if (r->scrub_flags & PFSTATE_SETPRIO) {
+	if (rtableid >= 0)
+		M_SETFIB(m, rtableid);
+
+	if (scrub_flags & PFSTATE_SETPRIO) {
 		if (pd.tos & IPTOS_LOWDELAY)
 			pqid = 1;
-		if (vlan_set_pcp(m, r->set_prio[pqid])) {
+		if (vlan_set_pcp(m, set_prio[pqid])) {
 			action = PF_DROP;
 			REASON_SET(&reason, PFRES_MEMORY);
 			log = PF_LOG_FORCE;
@@ -7963,6 +8029,11 @@
 	}
 
 #ifdef ALTQ
+	if (qid) {
+		pd.act.pqid = pqid;
+		pd.act.qid = qid;
+	}
+
 	if (action == PF_PASS && pd.act.qid) {
 		if (pd.pf_mtag == NULL &&
 		    ((pd.pf_mtag = pf_get_mtag(m)) == NULL)) {
@@ -8082,7 +8153,7 @@
 		break;
 	default:
 		/* pf_route6() returns unlocked. */
-		if (r->rt) {
+		if (rt) {
 			pf_route6(m0, r, dir, kif->pfik_ifp, s, &pd, inp);
 			return (action);
 		}
diff --git a/sys/netpfil/pf/pf_ioctl.c b/sys/netpfil/pf/pf_ioctl.c
--- a/sys/netpfil/pf/pf_ioctl.c
+++ b/sys/netpfil/pf/pf_ioctl.c
@@ -3720,8 +3720,8 @@
 	}
 
 	case DIOCADDSTATE: {
-		struct pfioc_state	*ps = (struct pfioc_state *)addr;
-		struct pfsync_state	*sp = &ps->state;
+		struct pfioc_state		*ps = (struct pfioc_state *)addr;
+		struct pfsync_state_1301	*sp = &ps->state;
 
 		if (sp->timeout >= PFTM_MAX) {
 			error = EINVAL;
@@ -3729,7 +3729,9 @@
 		}
 		if (V_pfsync_state_import_ptr != NULL) {
 			PF_RULES_RLOCK();
-			error = V_pfsync_state_import_ptr(sp, PFSYNC_SI_IOCTL);
+			error = V_pfsync_state_import_ptr(
+			    (union pfsync_state_union *)sp, PFSYNC_SI_IOCTL,
+			    PFSYNC_MSG_VERSION_1301);
 			PF_RULES_RUNLOCK();
 		} else
 			error = EOPNOTSUPP;
@@ -3746,7 +3748,8 @@
 			break;
 		}
 
-		pfsync_state_export(&ps->state, s);
+		pfsync_state_export((union pfsync_state_union*)&ps->state,
+		    s, PFSYNC_MSG_VERSION_1301);
 		PF_STATE_UNLOCK(s);
 		break;
 	}
@@ -3759,20 +3762,20 @@
 	case DIOCGETSTATES: {
 		struct pfioc_states	*ps = (struct pfioc_states *)addr;
 		struct pf_kstate	*s;
-		struct pfsync_state	*pstore, *p;
+		struct pfsync_state_1301	*pstore, *p;
 		int			 i, nr;
 		size_t			 slice_count = 16, count;
 		void			*out;
 
 		if (ps->ps_len <= 0) {
 			nr = uma_zone_get_cur(V_pf_state_z);
-			ps->ps_len = sizeof(struct pfsync_state) * nr;
+			ps->ps_len = sizeof(struct pfsync_state_1301) * nr;
 			break;
 		}
 
 		out = ps->ps_states;
 		pstore = mallocarray(slice_count,
-		    sizeof(struct pfsync_state), M_TEMP, M_WAITOK | M_ZERO);
+		    sizeof(struct pfsync_state_1301), M_TEMP, M_WAITOK | M_ZERO);
 		nr = 0;
 
 		for (i = 0; i <= pf_hashmask; i++) {
@@ -3797,7 +3800,7 @@
 				free(pstore, M_TEMP);
 				slice_count = count * 2;
 				pstore = mallocarray(slice_count,
-				    sizeof(struct pfsync_state), M_TEMP,
+				    sizeof(struct pfsync_state_1301), M_TEMP,
 				    M_WAITOK | M_ZERO);
 				goto DIOCGETSTATES_retry;
 			}
@@ -3811,19 +3814,20 @@
 				if (s->timeout == PFTM_UNLINKED)
 					continue;
 
-				pfsync_state_export(p, s);
+				pfsync_state_export((union pfsync_state_union*)p,
+				    s, PFSYNC_MSG_VERSION_1301);
 				p++;
 				nr++;
 			}
 			PF_HASHROW_UNLOCK(ih);
 			error = copyout(pstore, out,
-			    sizeof(struct pfsync_state) * count);
+			    sizeof(struct pfsync_state_1301) * count);
 			if (error)
 				break;
 			out = ps->ps_states + nr;
 		}
 DIOCGETSTATES_full:
-		ps->ps_len = sizeof(struct pfsync_state) * nr;
+		ps->ps_len = sizeof(struct pfsync_state_1301) * nr;
 		free(pstore, M_TEMP);
 
 		break;
@@ -5663,64 +5667,90 @@
 }
 
 void
-pfsync_state_export(struct pfsync_state *sp, struct pf_kstate *st)
+pfsync_state_export(union pfsync_state_union *sp, struct pf_kstate *st, int msg_version)
 {
-	bzero(sp, sizeof(struct pfsync_state));
+	bzero(sp, sizeof(union pfsync_state_union));
 
 	/* copy from state key */
-	sp->key[PF_SK_WIRE].addr[0] = st->key[PF_SK_WIRE]->addr[0];
-	sp->key[PF_SK_WIRE].addr[1] = st->key[PF_SK_WIRE]->addr[1];
-	sp->key[PF_SK_WIRE].port[0] = st->key[PF_SK_WIRE]->port[0];
-	sp->key[PF_SK_WIRE].port[1] = st->key[PF_SK_WIRE]->port[1];
-	sp->key[PF_SK_STACK].addr[0] = st->key[PF_SK_STACK]->addr[0];
-	sp->key[PF_SK_STACK].addr[1] = st->key[PF_SK_STACK]->addr[1];
-	sp->key[PF_SK_STACK].port[0] = st->key[PF_SK_STACK]->port[0];
-	sp->key[PF_SK_STACK].port[1] = st->key[PF_SK_STACK]->port[1];
-	sp->proto = st->key[PF_SK_WIRE]->proto;
-	sp->af = st->key[PF_SK_WIRE]->af;
+	sp->pfs_1301.key[PF_SK_WIRE].addr[0] = st->key[PF_SK_WIRE]->addr[0];
+	sp->pfs_1301.key[PF_SK_WIRE].addr[1] = st->key[PF_SK_WIRE]->addr[1];
+	sp->pfs_1301.key[PF_SK_WIRE].port[0] = st->key[PF_SK_WIRE]->port[0];
+	sp->pfs_1301.key[PF_SK_WIRE].port[1] = st->key[PF_SK_WIRE]->port[1];
+	sp->pfs_1301.key[PF_SK_STACK].addr[0] = st->key[PF_SK_STACK]->addr[0];
+	sp->pfs_1301.key[PF_SK_STACK].addr[1] = st->key[PF_SK_STACK]->addr[1];
+	sp->pfs_1301.key[PF_SK_STACK].port[0] = st->key[PF_SK_STACK]->port[0];
+	sp->pfs_1301.key[PF_SK_STACK].port[1] = st->key[PF_SK_STACK]->port[1];
+	sp->pfs_1301.proto = st->key[PF_SK_WIRE]->proto;
+	sp->pfs_1301.af = st->key[PF_SK_WIRE]->af;
 
 	/* copy from state */
-	strlcpy(sp->ifname, st->kif->pfik_name, sizeof(sp->ifname));
-	bcopy(&st->rt_addr, &sp->rt_addr, sizeof(sp->rt_addr));
-	sp->creation = htonl(time_uptime - st->creation);
-	sp->expire = pf_state_expires(st);
-	if (sp->expire <= time_uptime)
-		sp->expire = htonl(0);
+	strlcpy(sp->pfs_1301.ifname, st->kif->pfik_name, sizeof(sp->pfs_1301.ifname));
+	bcopy(&st->rt_addr, &sp->pfs_1301.rt_addr, sizeof(sp->pfs_1301.rt_addr));
+	sp->pfs_1301.creation = htonl(time_uptime - st->creation);
+	sp->pfs_1301.expire = pf_state_expires(st);
+	if (sp->pfs_1301.expire <= time_uptime)
+		sp->pfs_1301.expire = htonl(0);
 	else
-		sp->expire = htonl(sp->expire - time_uptime);
+		sp->pfs_1301.expire = htonl(sp->pfs_1301.expire - time_uptime);
+
+	sp->pfs_1301.direction = st->direction;
+	sp->pfs_1301.log = st->log;
+	sp->pfs_1301.timeout = st->timeout;
+
+	switch (msg_version) {
+		case PFSYNC_MSG_VERSION_1301:
+			sp->pfs_1301.state_flags = st->state_flags;
+			break;
+		case PFSYNC_MSG_VERSION_1400:
+			sp->pfs_1400.state_flags = htons(st->state_flags);
+			sp->pfs_1400.qid = htons(st->qid);
+			sp->pfs_1400.pqid = htons(st->pqid);
+			sp->pfs_1400.dnpipe = htons(st->dnpipe);
+			sp->pfs_1400.dnrpipe = htons(st->dnrpipe);
+			sp->pfs_1400.rtableid = htonl(st->rtableid);
+			sp->pfs_1400.min_ttl = st->min_ttl;
+			sp->pfs_1400.set_tos = st->set_tos;
+			sp->pfs_1400.max_mss = htons(st->max_mss);
+			sp->pfs_1400.set_prio[0] = st->set_prio[0];
+			sp->pfs_1400.set_prio[1] = st->set_prio[1];
+			sp->pfs_1400.rt = st->rt;
+			if (st->rt_kif)
+				strlcpy(sp->pfs_1400.rt_ifname,
+				    st->rt_kif->pfik_name,
+				    sizeof(sp->pfs_1400.rt_ifname));
+			break;
+		default:
+			panic("%s: Unsupported pfsync_msg_version %d",
+			    __func__, msg_version);
+	}
 
-	sp->direction = st->direction;
-	sp->log = st->log;
-	sp->timeout = st->timeout;
-	sp->state_flags_compat = st->state_flags;
-	sp->state_flags = htons(st->state_flags);
 	if (st->src_node)
-		sp->sync_flags |= PFSYNC_FLAG_SRCNODE;
+		sp->pfs_1301.sync_flags |= PFSYNC_FLAG_SRCNODE;
 	if (st->nat_src_node)
-		sp->sync_flags |= PFSYNC_FLAG_NATSRCNODE;
+		sp->pfs_1301.sync_flags |= PFSYNC_FLAG_NATSRCNODE;
 
-	sp->id = st->id;
-	sp->creatorid = st->creatorid;
-	pf_state_peer_hton(&st->src, &sp->src);
-	pf_state_peer_hton(&st->dst, &sp->dst);
+	sp->pfs_1301.id = st->id;
+	sp->pfs_1301.creatorid = st->creatorid;
+	pf_state_peer_hton(&st->src, &sp->pfs_1301.src);
+	pf_state_peer_hton(&st->dst, &sp->pfs_1301.dst);
 
 	if (st->rule.ptr == NULL)
-		sp->rule = htonl(-1);
+		sp->pfs_1301.rule = htonl(-1);
 	else
-		sp->rule = htonl(st->rule.ptr->nr);
+		sp->pfs_1301.rule = htonl(st->rule.ptr->nr);
 	if (st->anchor.ptr == NULL)
-		sp->anchor = htonl(-1);
+		sp->pfs_1301.anchor = htonl(-1);
 	else
-		sp->anchor = htonl(st->anchor.ptr->nr);
+		sp->pfs_1301.anchor = htonl(st->anchor.ptr->nr);
 	if (st->nat_rule.ptr == NULL)
-		sp->nat_rule = htonl(-1);
+		sp->pfs_1301.nat_rule = htonl(-1);
 	else
-		sp->nat_rule = htonl(st->nat_rule.ptr->nr);
+		sp->pfs_1301.nat_rule = htonl(st->nat_rule.ptr->nr);
 
-	pf_state_counter_hton(st->packets[0], sp->packets[0]);
-	pf_state_counter_hton(st->packets[1], sp->packets[1]);
-	pf_state_counter_hton(st->bytes[0], sp->bytes[0]);
-	pf_state_counter_hton(st->bytes[1], sp->bytes[1]);
+	pf_state_counter_hton(st->packets[0], sp->pfs_1301.packets[0]);
+	pf_state_counter_hton(st->packets[1], sp->pfs_1301.packets[1]);
+	pf_state_counter_hton(st->bytes[0], sp->pfs_1301.bytes[0]);
+	pf_state_counter_hton(st->bytes[1], sp->pfs_1301.bytes[1]);
 }
 
 void
@@ -5757,9 +5787,9 @@
 	sp->direction = st->direction;
 	sp->log = st->log;
 	sp->timeout = st->timeout;
-	/* 8 bits for old peers, 16 bits for new peers */
+	/* 8 bits for the old libpfctl, 16 bits for the new libpfctl */
 	sp->state_flags_compat = st->state_flags;
-	sp->state_flags = st->state_flags;
+	sp->state_flags = htons(st->state_flags);
 	if (st->src_node)
 		sp->sync_flags |= PFSYNC_FLAG_SRCNODE;
 	if (st->nat_src_node)
@@ -5787,6 +5817,22 @@
 	sp->packets[1] = st->packets[1];
 	sp->bytes[0] = st->bytes[0];
 	sp->bytes[1] = st->bytes[1];
+
+	sp->qid = htons(st->qid);
+	sp->pqid = htons(st->pqid);
+	sp->dnpipe = htons(st->dnpipe);
+	sp->dnrpipe = htons(st->dnrpipe);
+	sp->rtableid = htonl(st->rtableid);
+	sp->min_ttl = st->min_ttl;
+	sp->set_tos = st->set_tos;
+	sp->max_mss = htons(st->max_mss);
+	sp->rt = st->rt;
+	if (st->rt_kif)
+		strlcpy(sp->rt_ifname, st->rt_kif->pfik_name,
+		    sizeof(sp->rt_ifname));
+	sp->set_prio[0] = st->set_prio[0];
+	sp->set_prio[1] = st->set_prio[1];
+
 }
 
 static void
diff --git a/sys/netpfil/pf/pfsync_nv.c b/sys/netpfil/pf/pfsync_nv.c
--- a/sys/netpfil/pf/pfsync_nv.c
+++ b/sys/netpfil/pf/pfsync_nv.c
@@ -130,6 +130,7 @@
 		return (EINVAL);
 
 	status->maxupdates = nvlist_get_number(nvl, "maxupdates");
+	status->version = nvlist_get_number(nvl, "version");
 	status->flags = nvlist_get_number(nvl, "flags");
 
 	if (nvlist_exists_string(nvl, "syncdev"))
diff --git a/usr.bin/netstat/if.c b/usr.bin/netstat/if.c
--- a/usr.bin/netstat/if.c
+++ b/usr.bin/netstat/if.c
@@ -81,9 +81,9 @@
 #ifdef PF
 static const char* pfsyncacts[] = {
 	/* PFSYNC_ACT_CLR */		"clear all request",
-	/* PFSYNC_ACT_INS */		"state insert",
+	/* PFSYNC_ACT_INS_1301 */	"13.1 state insert",
 	/* PFSYNC_ACT_INS_ACK */	"state inserted ack",
-	/* PFSYNC_ACT_UPD */		"state update",
+	/* PFSYNC_ACT_UPD_1301 */	"13.1 state update",
 	/* PFSYNC_ACT_UPD_C */		"compressed state update",
 	/* PFSYNC_ACT_UPD_REQ */	"uncompressed state request",
 	/* PFSYNC_ACT_DEL */		"state delete",
@@ -93,13 +93,15 @@
 	/* PFSYNC_ACT_BUS */		"bulk update mark",
 	/* PFSYNC_ACT_TDB */		"TDB replay counter update",
 	/* PFSYNC_ACT_EOF */		"end of frame mark",
+	/* PFSYNC_ACT_INS_1400 */	"state insert",
+	/* PFSYNC_ACT_UPD_1400 */	"state update",
 };
 
 static const char* pfsyncacts_name[] = {
 	/* PFSYNC_ACT_CLR */		"clear-all-request",
-	/* PFSYNC_ACT_INS */		"state-insert",
+	/* PFSYNC_ACT_INS_1301 */	"state-insert-1301",
 	/* PFSYNC_ACT_INS_ACK */	"state-inserted-ack",
-	/* PFSYNC_ACT_UPD */		"state-update",
+	/* PFSYNC_ACT_UPD_1301 */	"state-update-1301",
 	/* PFSYNC_ACT_UPD_C */		"compressed-state-update",
 	/* PFSYNC_ACT_UPD_REQ */	"uncompressed-state-request",
 	/* PFSYNC_ACT_DEL */		"state-delete",
@@ -109,6 +111,8 @@
 	/* PFSYNC_ACT_BUS */		"bulk-update-mark",
 	/* PFSYNC_ACT_TDB */		"TDB-replay-counter-update",
 	/* PFSYNC_ACT_EOF */		"end-of-frame-mark",
+	/* PFSYNC_ACT_INS_1400 */	"state-insert",
+	/* PFSYNC_ACT_UPD_1400 */	"state-update",
 };
 
 static void