Pull up following revision(s) (requested by rmind in ticket #158): netbsd-6
authorriz <riz@NetBSD.org>
Tue, 03 Apr 2012 17:22:52 +0000
branchnetbsd-6
changeset 255621 ca9c658b117d
parent 255620 a3839093e775
child 255622 6c1ebb111eaf
Pull up following revision(s) (requested by rmind in ticket #158): sys/net/npf/npf_session.c: revision 1.12 sys/net/npf/npf_tableset.c: revision 1.10 sys/net/npf/npf_rproc.c: revision 1.2 usr.sbin/npf/npfctl/npf_parse.y: revision 1.4 sys/net/npf/npf_inet.c: revision 1.11 sys/net/npf/npf.h: revision 1.15 usr.sbin/npf/npfctl/npf_build.c: revision 1.5 sys/net/npf/npf_ruleset.c: revision 1.11 sys/net/npf/npf_instr.c: revision 1.10 usr.sbin/npf/npfctl/Makefile: revision 1.6 sys/net/npf/npf_processor.c: revision 1.10 sys/net/npf/npf_log.c: revision 1.3 lib/libnpf/npf.h: revision 1.7 sys/net/npf/npf_alg.c: revision 1.3 sys/net/npf/npf_sendpkt.c: revision 1.9 lib/libnpf/npf.c: revision 1.8 usr.sbin/npf/npfctl/npfctl.h: revision 1.13 sys/net/npf/npf_ctl.c: revision 1.13 usr.sbin/npf/npfctl/npf_ncgen.c: revision 1.8 sys/net/npf/npf_ctl.c: revision 1.14 sys/net/npf/npf_nat.c: revision 1.11 sys/net/npf/npf_nat.c: revision 1.12 sys/net/npf/npf_impl.h: revision 1.11 usr.sbin/npf/npfctl/npf_disassemble.c: revision 1.1 sys/net/npf/npf_impl.h: revision 1.12 usr.sbin/npf/npfctl/npf_disassemble.c: revision 1.2 sys/net/npf/npf_handler.c: revision 1.14 usr.sbin/npf/npfctl/npf_disassemble.c: revision 1.3 sys/net/npf/npf_handler.c: revision 1.15 sys/net/npf/npf_ncode.h: revision 1.6 sys/net/npf/npf.c: revision 1.8 sys/net/npf/npf.c: revision 1.9 sys/net/npf/npf_alg_icmp.c: revision 1.9 sys/net/npf/npf_session.c: revision 1.11 - Add NPF_DECISION_BLOCK and NPF_DECISION_PASS. Be more defensive in the packet handler. Change the default policy to block when the config is loaded and set it to pass when flush operation is performed. - Use kmem_zalloc(9) instead of kmem_alloc(9) in few places. - npf_rproc_{create,release}: use kmem_intr_{alloc,free} as the destruction of rule procedure might happen in the interrupt handler (under a very rare condition, if config reload races with the handler). - npf_session_establish: check whether layer 3 and 4 are cached. - npfctl_build_group: do not make groups as passing rules. - Remove some unecessary header inclusion. Simplify slightly: merge iface into addr_or_iface, use it in filt_addr. Add a small disassembler. definitions used by the disassembler. - better printing of type/code flags/mask - pass the instruction start pointer, instead of subtracting 1 to account for it - Save active config in proplib dictionary; add GETCONF ioctl to retrieve. - Few fixes. Improve some comments. don't leak the branch target array. Add NPF config retrieval routines.
lib/libnpf/npf.c
lib/libnpf/npf.h
sys/net/npf/npf.c
sys/net/npf/npf.h
sys/net/npf/npf_alg.c
sys/net/npf/npf_alg_icmp.c
sys/net/npf/npf_ctl.c
sys/net/npf/npf_handler.c
sys/net/npf/npf_impl.h
sys/net/npf/npf_inet.c
sys/net/npf/npf_instr.c
sys/net/npf/npf_log.c
sys/net/npf/npf_nat.c
sys/net/npf/npf_ncode.h
sys/net/npf/npf_processor.c
sys/net/npf/npf_rproc.c
sys/net/npf/npf_ruleset.c
sys/net/npf/npf_sendpkt.c
sys/net/npf/npf_session.c
sys/net/npf/npf_tableset.c
usr.sbin/npf/npfctl/Makefile
usr.sbin/npf/npfctl/npf_build.c
usr.sbin/npf/npfctl/npf_disassemble.c
usr.sbin/npf/npfctl/npf_ncgen.c
usr.sbin/npf/npfctl/npf_parse.y
usr.sbin/npf/npfctl/npfctl.h
--- a/lib/libnpf/npf.c	Tue Apr 03 16:36:20 2012 +0000
+++ b/lib/libnpf/npf.c	Tue Apr 03 17:22:52 2012 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf.c,v 1.7 2012/02/05 00:37:13 rmind Exp $	*/
+/*	$NetBSD: npf.c,v 1.7.2.1 2012/04/03 17:22:54 riz Exp $	*/
 
 /*-
  * Copyright (c) 2010-2012 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf.c,v 1.7 2012/02/05 00:37:13 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf.c,v 1.7.2.1 2012/04/03 17:22:54 riz Exp $");
 
 #include <sys/types.h>
 #include <netinet/in_systm.h>
@@ -48,6 +48,7 @@
 
 struct nl_config {
 	/* Rules, translations, tables, procedures. */
+	prop_dictionary_t	ncf_dict;
 	prop_array_t		ncf_rules_list;
 	prop_array_t		ncf_rproc_list;
 	prop_array_t		ncf_table_list;
@@ -139,6 +140,33 @@
 	return error;
 }
 
+nl_config_t *
+npf_config_retrieve(int fd, bool *active, bool *loaded)
+{
+	prop_dictionary_t npf_dict;
+	nl_config_t *ncf;
+	int error;
+
+	error = prop_dictionary_recv_ioctl(fd, IOC_NPF_GETCONF, &npf_dict);
+	if (error) {
+		return NULL;
+	}
+	ncf = calloc(1, sizeof(*ncf));
+	if (ncf == NULL) {
+		prop_object_release(npf_dict);
+		return NULL;
+	}
+	ncf->ncf_dict = npf_dict;
+	ncf->ncf_rules_list = prop_dictionary_get(npf_dict, "rules");
+	ncf->ncf_rproc_list = prop_dictionary_get(npf_dict, "rprocs");
+	ncf->ncf_table_list = prop_dictionary_get(npf_dict, "tables");
+	ncf->ncf_nat_list = prop_dictionary_get(npf_dict, "translation");
+
+	prop_dictionary_get_bool(npf_dict, "active", active);
+	*loaded = (ncf->ncf_rules_list != NULL);
+	return ncf;
+}
+
 int
 npf_config_flush(int fd)
 {
@@ -174,10 +202,14 @@
 npf_config_destroy(nl_config_t *ncf)
 {
 
-	prop_object_release(ncf->ncf_rules_list);
-	prop_object_release(ncf->ncf_rproc_list);
-	prop_object_release(ncf->ncf_table_list);
-	prop_object_release(ncf->ncf_nat_list);
+	if (ncf->ncf_dict == NULL) {
+		prop_object_release(ncf->ncf_rules_list);
+		prop_object_release(ncf->ncf_rproc_list);
+		prop_object_release(ncf->ncf_table_list);
+		prop_object_release(ncf->ncf_nat_list);
+	} else {
+		prop_object_release(ncf->ncf_dict);
+	}
 	if (ncf->ncf_err) {
 		prop_object_release(ncf->ncf_err);
 	}
@@ -304,6 +336,73 @@
 	return 0;
 }
 
+static int
+_npf_rule_foreach1(prop_array_t rules, unsigned nlevel, nl_rule_callback_t func)
+{
+	prop_dictionary_t rldict;
+	prop_object_iterator_t it;
+
+	if (!rules || prop_object_type(rules) != PROP_TYPE_ARRAY) {
+		return ENOENT;
+	}
+	it = prop_array_iterator(rules);
+	if (it == NULL) {
+		return ENOMEM;
+	}
+	while ((rldict = prop_object_iterator_next(it)) != NULL) {
+		prop_array_t subrules;
+		nl_rule_t nrl;
+
+		nrl.nrl_dict = rldict;
+		(*func)(&nrl, nlevel);
+
+		subrules = prop_dictionary_get(rldict, "subrules");
+		(void)_npf_rule_foreach1(subrules, nlevel + 1, func);
+	}
+	prop_object_iterator_release(it);
+	return 0;
+}
+
+int
+_npf_rule_foreach(nl_config_t *ncf, nl_rule_callback_t func)
+{
+
+	return _npf_rule_foreach1(ncf->ncf_rules_list, 0, func);
+}
+
+pri_t
+_npf_rule_getinfo(nl_rule_t *nrl, const char **rname, uint32_t *attr,
+    u_int *if_idx)
+{
+	prop_dictionary_t rldict = nrl->nrl_dict;
+	pri_t prio;
+
+	prop_dictionary_get_cstring_nocopy(rldict, "name", rname);
+	prop_dictionary_get_uint32(rldict, "attributes", attr);
+	prop_dictionary_get_int32(rldict, "priority", &prio);
+	prop_dictionary_get_uint32(rldict, "interface", if_idx);
+	return prio;
+}
+
+const void *
+_npf_rule_ncode(nl_rule_t *nrl, size_t *size)
+{
+	prop_dictionary_t rldict = nrl->nrl_dict;
+	prop_object_t obj = prop_dictionary_get(rldict, "ncode");
+	*size = prop_data_size(obj);
+	return prop_data_data_nocopy(obj);
+}
+
+const char *
+_npf_rule_rproc(nl_rule_t *nrl)
+{
+	prop_dictionary_t rldict = nrl->nrl_dict;
+	const char *rpname = NULL;
+
+	prop_dictionary_get_cstring_nocopy(rldict, "rproc", &rpname);
+	return rpname;
+}
+
 void
 npf_rule_destroy(nl_rule_t *rl)
 {
--- a/lib/libnpf/npf.h	Tue Apr 03 16:36:20 2012 +0000
+++ b/lib/libnpf/npf.h	Tue Apr 03 17:22:52 2012 +0000
@@ -1,7 +1,7 @@
-/*	$NetBSD: npf.h,v 1.6 2012/02/05 00:37:13 rmind Exp $	*/
+/*	$NetBSD: npf.h,v 1.6.2.1 2012/04/03 17:22:54 riz Exp $	*/
 
 /*-
- * Copyright (c) 2011 The NetBSD Foundation, Inc.
+ * Copyright (c) 2011-2012 The NetBSD Foundation, Inc.
  * All rights reserved.
  *
  * This material is based upon work partially supported by The
@@ -63,6 +63,8 @@
 	int		ne_ncode_errat;
 } nl_error_t;
 
+typedef void (*nl_rule_callback_t)(nl_rule_t *, unsigned);
+
 #endif
 
 #define	NPF_CODE_NCODE		1
@@ -75,6 +77,7 @@
 nl_config_t *	npf_config_create(void);
 int		npf_config_submit(nl_config_t *, int);
 void		npf_config_destroy(nl_config_t *);
+nl_config_t *	npf_config_retrieve(int, bool *, bool *);
 int		npf_config_flush(int);
 #ifdef _NPF_PRIVATE
 void		_npf_config_error(nl_config_t *, nl_error_t *);
@@ -86,6 +89,12 @@
 int		npf_rule_setproc(nl_config_t *, nl_rule_t *, const char *);
 bool		npf_rule_exists_p(nl_config_t *, const char *);
 int		npf_rule_insert(nl_config_t *, nl_rule_t *, nl_rule_t *, pri_t);
+#ifdef _NPF_PRIVATE
+int		_npf_rule_foreach(nl_config_t *, nl_rule_callback_t);
+pri_t		_npf_rule_getinfo(nl_rule_t *, const char **, uint32_t *, u_int *);
+const void *	_npf_rule_ncode(nl_rule_t *, size_t *);
+const char *	_npf_rule_rproc(nl_rule_t *);
+#endif
 void		npf_rule_destroy(nl_rule_t *);
 
 nl_rproc_t *	npf_rproc_create(const char *);
--- a/sys/net/npf/npf.c	Tue Apr 03 16:36:20 2012 +0000
+++ b/sys/net/npf/npf.c	Tue Apr 03 17:22:52 2012 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf.c,v 1.7 2012/01/15 00:49:48 rmind Exp $	*/
+/*	$NetBSD: npf.c,v 1.7.2.1 2012/04/03 17:22:53 riz Exp $	*/
 
 /*-
  * Copyright (c) 2009-2010 The NetBSD Foundation, Inc.
@@ -34,7 +34,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf.c,v 1.7 2012/01/15 00:49:48 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf.c,v 1.7.2.1 2012/04/03 17:22:53 riz Exp $");
 
 #include <sys/param.h>
 #include <sys/types.h>
@@ -70,6 +70,8 @@
 	npf_ruleset_t *		n_rules;
 	npf_tableset_t *	n_tables;
 	npf_ruleset_t *		n_nat_rules;
+	prop_dictionary_t	n_dict;
+	bool			n_default_pass;
 } npf_core_t;
 
 static void	npf_core_destroy(npf_core_t *);
@@ -92,6 +94,7 @@
 #endif
 	npf_ruleset_t *rset, *nset;
 	npf_tableset_t *tset;
+	prop_dictionary_t dict;
 	int error = 0;
 
 	rw_init(&npf_lock);
@@ -103,10 +106,11 @@
 	npflogattach(1);
 
 	/* Load empty configuration. */
+	dict = prop_dictionary_create();
 	rset = npf_ruleset_create();
 	tset = npf_tableset_create();
 	nset = npf_ruleset_create();
-	npf_reload(rset, tset, nset);
+	npf_reload(dict, rset, tset, nset, true);
 	KASSERT(npf_core != NULL);
 
 #ifdef _MODULE
@@ -124,20 +128,20 @@
 npf_fini(void)
 {
 
-	/*
-	 * At first, detach device, remove pfil hooks and unload existing
-	 * configuration, destroy structures.
-	 */
+	/* At first, detach device and remove pfil hooks. */
 #ifdef _MODULE
 	devsw_detach(NULL, &npf_cdevsw);
 #endif
-	npf_unregister_pfil();
-	npf_core_destroy(npf_core);
 	npflogdetach();
+	npf_pfil_unregister();
 
-	/* Note: order is particular. */
+	/* Flush all sessions, destroy configuration (ruleset, etc). */
+	npf_session_tracking(false);
+	npf_core_destroy(npf_core);
+
+	/* Finally, safe to destroy the subsystems. */
+	npf_alg_sysfini();
 	npf_nat_sysfini();
-	npf_alg_sysfini();
 	npf_session_sysfini();
 	npf_tableset_sysfini();
 	percpu_free(npf_stats_percpu, NPF_STATS_SIZE);
@@ -210,6 +214,9 @@
 	case IOC_NPF_RELOAD:
 		error = npfctl_reload(cmd, data);
 		break;
+	case IOC_NPF_GETCONF:
+		error = npfctl_getconf(cmd, data);
+		break;
 	case IOC_NPF_TABLE:
 		error = npfctl_table(data);
 		break;
@@ -254,6 +261,7 @@
 npf_core_destroy(npf_core_t *nc)
 {
 
+	prop_object_release(nc->n_dict);
 	npf_ruleset_destroy(nc->n_rules);
 	npf_ruleset_destroy(nc->n_nat_rules);
 	npf_tableset_destroy(nc->n_tables);
@@ -265,15 +273,18 @@
  * Then destroy old (unloaded) structures.
  */
 void
-npf_reload(npf_ruleset_t *rset, npf_tableset_t *tset, npf_ruleset_t *nset)
+npf_reload(prop_dictionary_t dict, npf_ruleset_t *rset,
+    npf_tableset_t *tset, npf_ruleset_t *nset, bool flush)
 {
 	npf_core_t *nc, *onc;
 
 	/* Setup a new core structure. */
-	nc = kmem_alloc(sizeof(npf_core_t), KM_SLEEP);
+	nc = kmem_zalloc(sizeof(npf_core_t), KM_SLEEP);
 	nc->n_rules = rset;
 	nc->n_tables = tset;
 	nc->n_nat_rules = nset;
+	nc->n_dict = dict;
+	nc->n_default_pass = flush;
 
 	/* Lock and load the core structure. */
 	rw_enter(&npf_lock, RW_WRITER);
@@ -330,6 +341,20 @@
 	return rw_lock_held(&npf_lock);
 }
 
+prop_dictionary_t
+npf_core_dict(void)
+{
+	KASSERT(rw_lock_held(&npf_lock));
+	return npf_core->n_dict;
+}
+
+bool
+npf_default_pass(void)
+{
+	KASSERT(rw_lock_held(&npf_lock));
+	return npf_core->n_default_pass;
+}
+
 /*
  * NPF statistics interface.
  */
--- a/sys/net/npf/npf.h	Tue Apr 03 16:36:20 2012 +0000
+++ b/sys/net/npf/npf.h	Tue Apr 03 17:22:52 2012 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf.h,v 1.14 2012/02/06 23:30:14 rmind Exp $	*/
+/*	$NetBSD: npf.h,v 1.14.2.1 2012/04/03 17:22:52 riz Exp $	*/
 
 /*-
  * Copyright (c) 2009-2011 The NetBSD Foundation, Inc.
@@ -306,5 +306,6 @@
 #define	IOC_NPF_SESSIONS_SAVE	_IOR('N', 105, struct plistref)
 #define	IOC_NPF_SESSIONS_LOAD	_IOW('N', 106, struct plistref)
 #define	IOC_NPF_UPDATE_RULE	_IOWR('N', 107, struct plistref)
+#define	IOC_NPF_GETCONF		_IOR('N', 108, struct plistref)
 
 #endif	/* _NPF_NET_H_ */
--- a/sys/net/npf/npf_alg.c	Tue Apr 03 16:36:20 2012 +0000
+++ b/sys/net/npf/npf_alg.c	Tue Apr 03 17:22:52 2012 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_alg.c,v 1.2 2010/11/11 06:30:39 rmind Exp $	*/
+/*	$NetBSD: npf_alg.c,v 1.2.16.1 2012/04/03 17:22:53 riz Exp $	*/
 
 /*-
  * Copyright (c) 2010 The NetBSD Foundation, Inc.
@@ -36,10 +36,9 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_alg.c,v 1.2 2010/11/11 06:30:39 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_alg.c,v 1.2.16.1 2012/04/03 17:22:53 riz Exp $");
 
 #include <sys/param.h>
-#include <sys/kernel.h>
 #include <sys/kmem.h>
 #include <sys/pool.h>
 #include <net/pfil.h>
@@ -83,7 +82,7 @@
 {
 	npf_alg_t *alg;
 
-	alg = kmem_alloc(sizeof(npf_alg_t), KM_SLEEP);
+	alg = kmem_zalloc(sizeof(npf_alg_t), KM_SLEEP);
 	alg->na_bptr = alg;
 	alg->na_match_func = match;
 	alg->na_out_func = out;
--- a/sys/net/npf/npf_alg_icmp.c	Tue Apr 03 16:36:20 2012 +0000
+++ b/sys/net/npf/npf_alg_icmp.c	Tue Apr 03 17:22:52 2012 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_alg_icmp.c,v 1.8 2011/11/29 20:05:30 rmind Exp $	*/
+/*	$NetBSD: npf_alg_icmp.c,v 1.8.4.1 2012/04/03 17:22:53 riz Exp $	*/
 
 /*-
  * Copyright (c) 2010 The NetBSD Foundation, Inc.
@@ -34,10 +34,9 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_alg_icmp.c,v 1.8 2011/11/29 20:05:30 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_alg_icmp.c,v 1.8.4.1 2012/04/03 17:22:53 riz Exp $");
 
 #include <sys/param.h>
-#include <sys/kernel.h>
 #include <sys/module.h>
 #include <sys/pool.h>
 
--- a/sys/net/npf/npf_ctl.c	Tue Apr 03 16:36:20 2012 +0000
+++ b/sys/net/npf/npf_ctl.c	Tue Apr 03 17:22:52 2012 +0000
@@ -1,7 +1,7 @@
-/*	$NetBSD: npf_ctl.c,v 1.12 2012/02/05 00:37:13 rmind Exp $	*/
+/*	$NetBSD: npf_ctl.c,v 1.12.2.1 2012/04/03 17:22:53 riz Exp $	*/
 
 /*-
- * Copyright (c) 2009-2011 The NetBSD Foundation, Inc.
+ * Copyright (c) 2009-2012 The NetBSD Foundation, Inc.
  * All rights reserved.
  *
  * This material is based upon work partially supported by The
@@ -37,11 +37,10 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_ctl.c,v 1.12 2012/02/05 00:37:13 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_ctl.c,v 1.12.2.1 2012/04/03 17:22:53 riz Exp $");
 
 #include <sys/param.h>
 #include <sys/conf.h>
-#include <sys/kernel.h>
 
 #include <prop/proplib.h>
 
@@ -67,10 +66,10 @@
 
 	if (onoff) {
 		/* Enable: add pfil hooks. */
-		error = npf_register_pfil();
+		error = npf_pfil_register();
 	} else {
 		/* Disable: remove pfil hooks. */
-		npf_unregister_pfil();
+		npf_pfil_unregister();
 		error = 0;
 	}
 	return error;
@@ -426,7 +425,7 @@
 npfctl_reload(u_long cmd, void *data)
 {
 	struct plistref *pref = data;
-	prop_dictionary_t dict, errdict;
+	prop_dictionary_t npf_dict, errdict;
 	prop_array_t natlist, tables, rprocs, rules;
 	npf_tableset_t *tblset = NULL;
 	npf_ruleset_t *rlset = NULL;
@@ -436,12 +435,12 @@
 
 	/* Retrieve the dictionary. */
 #ifdef _KERNEL
-	error = prop_dictionary_copyin_ioctl(pref, cmd, &dict);
+	error = prop_dictionary_copyin_ioctl(pref, cmd, &npf_dict);
 	if (error)
 		return error;
 #else
-	dict = prop_dictionary_internalize_from_file(data);
-	if (dict == NULL)
+	npf_dict = prop_dictionary_internalize_from_file(data);
+	if (npf_dict == NULL)
 		return EINVAL;
 #endif
 	/* Dictionary for error reporting. */
@@ -449,7 +448,7 @@
 
 	/* NAT policies. */
 	nset = npf_ruleset_create();
-	natlist = prop_dictionary_get(dict, "translation");
+	natlist = prop_dictionary_get(npf_dict, "translation");
 	error = npf_mk_natlist(nset, natlist, errdict);
 	if (error) {
 		goto fail;
@@ -457,7 +456,7 @@
 
 	/* Tables. */
 	tblset = npf_tableset_create();
-	tables = prop_dictionary_get(dict, "tables");
+	tables = prop_dictionary_get(npf_dict, "tables");
 	error = npf_mk_tables(tblset, tables, errdict);
 	if (error) {
 		goto fail;
@@ -465,21 +464,21 @@
 
 	/* Rules and rule procedures. */
 	rlset = npf_ruleset_create();
-	rprocs = prop_dictionary_get(dict, "rprocs");
-	rules = prop_dictionary_get(dict, "rules");
+	rprocs = prop_dictionary_get(npf_dict, "rprocs");
+	rules = prop_dictionary_get(npf_dict, "rules");
 	error = npf_mk_rules(rlset, rules, rprocs, errdict);
 	if (error) {
 		goto fail;
 	}
 
 	flush = false;
-	prop_dictionary_get_bool(dict, "flush", &flush);
+	prop_dictionary_get_bool(npf_dict, "flush", &flush);
 
 	/*
 	 * Finally - reload ruleset, tableset and NAT policies.
 	 * Operation will be performed as a single transaction.
 	 */
-	npf_reload(rlset, tblset, nset);
+	npf_reload(npf_dict, rlset, tblset, nset, flush);
 
 	/* Turn on/off session tracking accordingly. */
 	npf_session_tracking(!flush);
@@ -502,15 +501,35 @@
 	if (tblset) {
 		npf_tableset_destroy(tblset);
 	}
-	prop_object_release(dict);
+	if (error) {
+		prop_object_release(npf_dict);
+	}
 
 	/* Error report. */
 	prop_dictionary_set_int32(errdict, "errno", error);
+#ifdef _KERNEL
 	prop_dictionary_copyout_ioctl(pref, cmd, errdict);
+#endif
 	prop_object_release(errdict);
 	return 0;
 }
 
+int
+npfctl_getconf(u_long cmd, void *data)
+{
+	struct plistref *pref = data;
+	prop_dictionary_t npf_dict;
+	int error;
+
+	npf_core_enter();
+	npf_dict = npf_core_dict();
+	prop_dictionary_set_bool(npf_dict, "active", npf_pfil_registered_p());
+	error = prop_dictionary_copyout_ioctl(pref, cmd, npf_dict);
+	npf_core_exit();
+
+	return error;
+}
+
 /*
  * npfctl_update_rule: reload a specific rule identified by the name.
  */
@@ -561,7 +580,9 @@
 
 	/* Error report. */
 	prop_dictionary_set_int32(errdict, "errno", error);
+#ifdef _KERNEL
 	prop_dictionary_copyout_ioctl(pref, cmd, errdict);
+#endif
 	prop_object_release(errdict);
 	return error;
 }
--- a/sys/net/npf/npf_handler.c	Tue Apr 03 16:36:20 2012 +0000
+++ b/sys/net/npf/npf_handler.c	Tue Apr 03 17:22:52 2012 +0000
@@ -1,7 +1,7 @@
-/*	$NetBSD: npf_handler.c,v 1.13 2012/02/06 23:30:14 rmind Exp $	*/
+/*	$NetBSD: npf_handler.c,v 1.13.2.1 2012/04/03 17:22:53 riz Exp $	*/
 
 /*-
- * Copyright (c) 2009-2010 The NetBSD Foundation, Inc.
+ * Copyright (c) 2009-2012 The NetBSD Foundation, Inc.
  * All rights reserved.
  *
  * This material is based upon work partially supported by The
@@ -34,10 +34,10 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_handler.c,v 1.13 2012/02/06 23:30:14 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_handler.c,v 1.13.2.1 2012/04/03 17:22:53 riz Exp $");
 
+#include <sys/types.h>
 #include <sys/param.h>
-#include <sys/systm.h>
 
 #include <sys/mbuf.h>
 #include <sys/mutex.h>
@@ -61,8 +61,6 @@
 static struct pfil_head *	npf_ph_inet = NULL;
 static struct pfil_head *	npf_ph_inet6 = NULL;
 
-static bool			default_pass = true;
-
 int	npf_packet_handler(void *, struct mbuf **, ifnet_t *, int);
 
 /*
@@ -89,26 +87,28 @@
 	npf_ruleset_t *rlset;
 	npf_rule_t *rl;
 	npf_rproc_t *rp;
-	int retfl, error, ret;
+	int error, retfl;
+	int decision;
 
 	/*
 	 * Initialise packet information cache.
 	 * Note: it is enough to clear the info bits.
 	 */
 	npc.npc_info = 0;
+	decision = NPF_DECISION_BLOCK;
 	error = 0;
 	retfl = 0;
 	rp = NULL;
-	ret = 0;
 
 	/* Cache everything.  Determine whether it is an IP fragment. */
 	if (npf_cache_all(&npc, nbuf) & NPC_IPFRAG) {
+		int ret = -1;
+
 		/* Pass to IPv4 or IPv6 reassembly mechanism. */
 		if (npf_iscached(&npc, NPC_IP4)) {
 			struct ip *ip = nbuf_dataptr(*mp);
 			ret = ip_reass_packet(mp, ip);
-		} else {
-			KASSERT(npf_iscached(&npc, NPC_IP6));
+		} else if (npf_iscached(&npc, NPC_IP6)) {
 #ifdef INET6
 			/*
 			 * Note: frag6_input() offset is the start of the
@@ -116,11 +116,8 @@
 			 */
 			const u_int hlen = npf_cache_hlen(&npc);
 			ret = ip6_reass_packet(mp, hlen);
-#else
-			ret = -1;
 #endif
 		}
-
 		if (ret) {
 			error = EINVAL;
 			se = NULL;
@@ -137,7 +134,9 @@
 		 */
 		nbuf = (nbuf_t *)*mp;
 		npc.npc_info = 0;
-		(void)npf_cache_all(&npc, nbuf);
+
+		ret = npf_cache_all(&npc, nbuf);
+		KASSERT((ret & NPC_IPFRAG) == 0);
 	}
 
 	/* Inspect the list of sessions. */
@@ -146,8 +145,10 @@
 	/* If "passing" session found - skip the ruleset inspection. */
 	if (se && npf_session_pass(se, &rp)) {
 		npf_stats_inc(NPF_STAT_PASS_SESSION);
+		KASSERT(error == 0);
 		goto pass;
-	} else if (error) {
+	}
+	if (error) {
 		goto block;
 	}
 
@@ -156,13 +157,14 @@
 	rlset = npf_core_ruleset();
 	rl = npf_ruleset_inspect(&npc, nbuf, rlset, ifp, di, NPF_LAYER_3);
 	if (rl == NULL) {
+		bool default_pass = npf_default_pass();
 		npf_core_exit();
+
 		if (default_pass) {
 			npf_stats_inc(NPF_STAT_PASS_DEFAULT);
 			goto pass;
 		}
 		npf_stats_inc(NPF_STAT_BLOCK_DEFAULT);
-		error = ENETUNREACH;
 		goto block;
 	}
 
@@ -181,20 +183,21 @@
 	}
 	npf_stats_inc(NPF_STAT_PASS_RULESET);
 
-	/* Establish a "pass" session, if required. */
+	/*
+	 * Establish a "pass" session, if required.  Just proceed, if session
+	 * creation fails (e.g. due to unsupported protocol).
+	 *
+	 * Note: the reference on the rule procedure is transfered to the
+	 * session.  It will be released on session destruction.
+	 */
 	if ((retfl & NPF_RULE_KEEPSTATE) != 0 && !se) {
 		se = npf_session_establish(&npc, nbuf, di);
-		if (se == NULL) {
-			error = ENOMEM;
-			goto out;
+		if (se) {
+			npf_session_setpass(se, rp);
 		}
-		/*
-		 * Note: the reference to the rule procedure is transfered to
-		 * the session.  It will be released on session destruction.
-		 */
-		npf_session_setpass(se, rp);
 	}
 pass:
+	decision = NPF_DECISION_PASS;
 	KASSERT(error == 0);
 	/*
 	 * Perform NAT.
@@ -218,8 +221,8 @@
 		npf_rproc_release(rp);
 	}
 
-	/* Pass the packet, if no error. */
-	if (!error) {
+	/* Pass the packet if decided and there is no error. */
+	if (decision == NPF_DECISION_PASS && !error) {
 		/*
 		 * XXX: Disable for now, it will be set accordingly later,
 		 * for optimisations (to reduce inspection).
@@ -236,9 +239,10 @@
 	if (retfl) {
 		npf_return_block(&npc, nbuf, retfl);
 	}
-	if (error != ENETUNREACH) {
-		NPF_PRINTF(("NPF: error in handler '%d'\n", error));
+	if (error) {
 		npf_stats_inc(NPF_STAT_ERROR);
+	} else {
+		error = ENETUNREACH;
 	}
 	m_freem(*mp);
 	*mp = NULL;
@@ -247,10 +251,10 @@
 }
 
 /*
- * npf_register_pfil: register pfil(9) hooks.
+ * npf_pfil_register: register pfil(9) hooks.
  */
 int
-npf_register_pfil(void)
+npf_pfil_register(void)
 {
 	int error;
 
@@ -267,7 +271,7 @@
 	npf_ph_if = pfil_head_get(PFIL_TYPE_IFNET, 0);
 	npf_ph_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
 	npf_ph_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6);
-	if (npf_ph_if == NULL || npf_ph_inet == NULL) {
+	if (npf_ph_if == NULL || npf_ph_inet == NULL || npf_ph_inet6 == NULL) {
 		npf_ph_if = NULL;
 		error = ENOENT;
 		goto fail;
@@ -294,10 +298,10 @@
 }
 
 /*
- * npf_unregister: unregister pfil(9) hooks.
+ * npf_pfil_unregister: unregister pfil(9) hooks.
  */
 void
-npf_unregister_pfil(void)
+npf_pfil_unregister(void)
 {
 
 	mutex_enter(softnet_lock);
@@ -317,3 +321,9 @@
 	KERNEL_UNLOCK_ONE(NULL);
 	mutex_exit(softnet_lock);
 }
+
+bool
+npf_pfil_registered_p(void)
+{
+	return npf_ph_if != NULL;
+}
--- a/sys/net/npf/npf_impl.h	Tue Apr 03 16:36:20 2012 +0000
+++ b/sys/net/npf/npf_impl.h	Tue Apr 03 17:22:52 2012 +0000
@@ -1,7 +1,7 @@
-/*	$NetBSD: npf_impl.h,v 1.10 2012/02/06 23:30:14 rmind Exp $	*/
+/*	$NetBSD: npf_impl.h,v 1.10.2.1 2012/04/03 17:22:53 riz Exp $	*/
 
 /*-
- * Copyright (c) 2009-2011 The NetBSD Foundation, Inc.
+ * Copyright (c) 2009-2012 The NetBSD Foundation, Inc.
  * All rights reserved.
  *
  * This material is based upon work partially supported by The
@@ -91,6 +91,9 @@
  * DEFINITIONS.
  */
 
+#define	NPF_DECISION_BLOCK	0
+#define	NPF_DECISION_PASS	1
+
 typedef bool (*npf_algfunc_t)(npf_cache_t *, nbuf_t *, void *);
 
 #define	NPF_NCODE_LIMIT		1024
@@ -127,12 +130,17 @@
 npf_tableset_t *npf_core_tableset(void);
 void		npf_core_exit(void);
 bool		npf_core_locked(void);
-void		npf_reload(npf_ruleset_t *, npf_tableset_t *, npf_ruleset_t *);
+bool		npf_default_pass(void);
+prop_dictionary_t npf_core_dict(void);
+
+void		npf_reload(prop_dictionary_t, npf_ruleset_t *,
+		    npf_tableset_t *, npf_ruleset_t *, bool);
 
 void		npflogattach(int);
 void		npflogdetach(void);
 int		npfctl_switch(void *);
 int		npfctl_reload(u_long, void *);
+int		npfctl_getconf(u_long, void *);
 int		npfctl_sessions_save(u_long, void *);
 int		npfctl_sessions_load(u_long, void *);
 int		npfctl_update_rule(u_long, void *);
@@ -142,8 +150,9 @@
 void		npf_stats_dec(npf_stats_t);
 
 /* Packet filter hooks. */
-int		npf_register_pfil(void);
-void		npf_unregister_pfil(void);
+int		npf_pfil_register(void);
+void		npf_pfil_unregister(void);
+bool		npf_pfil_registered_p(void);
 void		npf_log_packet(npf_cache_t *, nbuf_t *, int);
 
 /* Protocol helpers. */
--- a/sys/net/npf/npf_inet.c	Tue Apr 03 16:36:20 2012 +0000
+++ b/sys/net/npf/npf_inet.c	Tue Apr 03 17:22:52 2012 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_inet.c,v 1.10 2011/11/29 20:05:30 rmind Exp $	*/
+/*	$NetBSD: npf_inet.c,v 1.10.4.1 2012/04/03 17:22:52 riz Exp $	*/
 
 /*-
  * Copyright (c) 2009-2011 The NetBSD Foundation, Inc.
@@ -34,10 +34,10 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_inet.c,v 1.10 2011/11/29 20:05:30 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_inet.c,v 1.10.4.1 2012/04/03 17:22:52 riz Exp $");
 
 #include <sys/param.h>
-#include <sys/kernel.h>
+#include <sys/types.h>
 
 #include <net/pfil.h>
 #include <net/if.h>
--- a/sys/net/npf/npf_instr.c	Tue Apr 03 16:36:20 2012 +0000
+++ b/sys/net/npf/npf_instr.c	Tue Apr 03 17:22:52 2012 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_instr.c,v 1.9 2012/01/15 00:49:48 rmind Exp $	*/
+/*	$NetBSD: npf_instr.c,v 1.9.2.1 2012/04/03 17:22:53 riz Exp $	*/
 
 /*-
  * Copyright (c) 2009-2010 The NetBSD Foundation, Inc.
@@ -34,10 +34,10 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_instr.c,v 1.9 2012/01/15 00:49:48 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_instr.c,v 1.9.2.1 2012/04/03 17:22:53 riz Exp $");
 
 #include <sys/param.h>
-#include <sys/kernel.h>
+#include <sys/types.h>
 
 #include <net/if.h>
 #include <net/ethertypes.h>
--- a/sys/net/npf/npf_log.c	Tue Apr 03 16:36:20 2012 +0000
+++ b/sys/net/npf/npf_log.c	Tue Apr 03 17:22:52 2012 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_log.c,v 1.2 2011/01/18 20:33:46 rmind Exp $	*/
+/*	$NetBSD: npf_log.c,v 1.2.14.1 2012/04/03 17:22:53 riz Exp $	*/
 
 /*-
  * Copyright (c) 2010-2011 The NetBSD Foundation, Inc.
@@ -34,10 +34,10 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_log.c,v 1.2 2011/01/18 20:33:46 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_log.c,v 1.2.14.1 2012/04/03 17:22:53 riz Exp $");
 
 #include <sys/param.h>
-#include <sys/kernel.h>
+#include <sys/types.h>
 
 #include <sys/conf.h>
 #include <sys/kmem.h>
--- a/sys/net/npf/npf_nat.c	Tue Apr 03 16:36:20 2012 +0000
+++ b/sys/net/npf/npf_nat.c	Tue Apr 03 17:22:52 2012 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_nat.c,v 1.10 2012/02/05 00:37:13 rmind Exp $	*/
+/*	$NetBSD: npf_nat.c,v 1.10.2.1 2012/04/03 17:22:53 riz Exp $	*/
 
 /*-
  * Copyright (c) 2010-2011 The NetBSD Foundation, Inc.
@@ -76,10 +76,10 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_nat.c,v 1.10 2012/02/05 00:37:13 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_nat.c,v 1.10.2.1 2012/04/03 17:22:53 riz Exp $");
 
 #include <sys/param.h>
-#include <sys/kernel.h>
+#include <sys/types.h>
 
 #include <sys/atomic.h>
 #include <sys/bitops.h>
@@ -112,7 +112,9 @@
 #define	PORTMAP_MEM_SIZE	\
     (sizeof(npf_portmap_t) + (PORTMAP_SIZE * sizeof(uint32_t)))
 
-/* NAT policy structure. */
+/*
+ * NAT policy structure.
+ */
 struct npf_natpolicy {
 	LIST_HEAD(, npf_nat)	n_nat_list;
 	kmutex_t		n_lock;
@@ -128,7 +130,9 @@
 #define	NPF_NP_CMP_START	offsetof(npf_natpolicy_t, n_type)
 #define	NPF_NP_CMP_SIZE		(sizeof(npf_natpolicy_t) - NPF_NP_CMP_START)
 
-/* NAT translation entry for a session. */ 
+/*
+ * NAT translation entry for a session.
+ */
 struct npf_nat {
 	/* Association (list entry and a link pointer) with NAT policy. */
 	LIST_ENTRY(npf_nat)	nt_entry;
@@ -302,7 +306,7 @@
 	/* If NAT policy has an old port map - drop the reference. */
 	mpm = mnp->n_portmap;
 	if (mpm) {
-		/* Note: in such case, we must not be a last reference. */
+		/* Note: at this point we cannot hold a last reference. */
 		KASSERT(mpm->p_refcnt > 1);
 		mpm->p_refcnt--;
 	}
@@ -440,10 +444,6 @@
 	nt->nt_session = NULL;
 	nt->nt_alg = NULL;
 
-	mutex_enter(&np->n_lock);
-	LIST_INSERT_HEAD(&np->n_nat_list, nt, nt_entry);
-	mutex_exit(&np->n_lock);
-
 	/* Save the original address which may be rewritten. */
 	if (np->n_type == NPF_NATOUT) {
 		/* Source (local) for Outbound NAT. */
@@ -461,8 +461,9 @@
 	    (proto != IPPROTO_TCP && proto != IPPROTO_UDP)) {
 		nt->nt_oport = 0;
 		nt->nt_tport = 0;
-		return nt;
+		goto out;
 	}
+
 	/* Save the relevant TCP/UDP port. */
 	if (proto == IPPROTO_TCP) {
 		struct tcphdr *th = &npc->npc_l4.tcp;
@@ -480,6 +481,10 @@
 	} else {
 		nt->nt_tport = np->n_tport;
 	}
+out:
+	mutex_enter(&np->n_lock);
+	LIST_INSERT_HEAD(&np->n_nat_list, nt, nt_entry);
+	mutex_exit(&np->n_lock);
 	return nt;
 }
 
@@ -526,6 +531,7 @@
 	if (!npf_rwrcksum(npc, nbuf, n_ptr, di, addr, port)) {
 		return EINVAL;
 	}
+
 	/*
 	 * Address translation: rewrite source/destination address, depending
 	 * on direction (PFIL_OUT - for source, PFIL_IN - for destination).
@@ -537,6 +543,7 @@
 		/* Done. */
 		return 0;
 	}
+
 	switch (npf_cache_ipproto(npc)) {
 	case IPPROTO_TCP:
 	case IPPROTO_UDP:
--- a/sys/net/npf/npf_ncode.h	Tue Apr 03 16:36:20 2012 +0000
+++ b/sys/net/npf/npf_ncode.h	Tue Apr 03 17:22:52 2012 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_ncode.h,v 1.5 2011/11/04 01:00:27 zoltan Exp $	*/
+/*	$NetBSD: npf_ncode.h,v 1.5.6.1 2012/04/03 17:22:53 riz Exp $	*/
 
 /*-
  * Copyright (c) 2009-2010 The NetBSD Foundation, Inc.
@@ -122,4 +122,237 @@
 #define	NPF_OPCODE_UDP_PORTS		0xa1
 #define	NPF_OPCODE_TCP_FLAGS		0xa2
 
-#endif
+#ifdef NPF_OPCODES_STRINGS
+
+# define	NPF_OPERAND_NONE		0
+# define	NPF_OPERAND_REGISTER		1
+# define	NPF_OPERAND_KEY			2
+# define	NPF_OPERAND_VALUE		3
+# define	NPF_OPERAND_SD			4
+# define		NPF_OPERAND_SD_SRC		1
+# define		NPF_OPERAND_SD_DST		0
+# define	NPF_OPERAND_REL_ADDRESS		5
+# define	NPF_OPERAND_NET_ADDRESS4	6
+# define	NPF_OPERAND_NET_ADDRESS6	7
+# define	NPF_OPERAND_ETHER_TYPE		8
+# define	NPF_OPERAND_SUBNET		9
+# define	NPF_OPERAND_LENGTH		10
+# define	NPF_OPERAND_TABLE_ID		11
+# define	NPF_OPERAND_ICMP4_TYPE_CODE	12
+# define	NPF_OPERAND_TCP_FLAGS_MASK	13
+# define	NPF_OPERAND_PORT_RANGE		14
+
+static const struct npf_instruction {
+	const char *name;
+	uint8_t op[4];
+} npf_instructions[256] = {
+	[NPF_OPCODE_RET] = {
+		.name = "ret",
+		.op = {
+			[0] = NPF_OPERAND_VALUE,
+		},
+	},
+	[NPF_OPCODE_ADVR] = {
+		.name = "advr",
+		.op = {
+			[0] = NPF_OPERAND_REGISTER,
+		},
+	},
+	[NPF_OPCODE_J] = {
+		.name = "j",
+		.op = {
+			[0] = NPF_OPERAND_REL_ADDRESS,
+		},
+	},
+	[NPF_OPCODE_INVL] = {
+		.name = "invl",
+	},
+	[NPF_OPCODE_TAG] = {
+		.name = "tag",
+		.op = {
+			[0] = NPF_OPERAND_KEY,
+			[1] = NPF_OPERAND_VALUE,
+		},
+	},
+	[NPF_OPCODE_MOVE] = {
+		.name = "move",
+		.op = {
+			[0] = NPF_OPERAND_VALUE, 
+			[1] = NPF_OPERAND_REGISTER,
+		},
+	},
+	[NPF_OPCODE_LW] = {
+		.name = "lw",
+		.op = {
+			[0] = NPF_OPERAND_LENGTH,
+			[1] = NPF_OPERAND_REGISTER,
+		},
+	},
+	[NPF_OPCODE_CMP] = {
+		.name = "cmp",
+		.op = {
+			[0] = NPF_OPERAND_VALUE,
+			[1] = NPF_OPERAND_REGISTER,
+		},
+	},
+	[NPF_OPCODE_CMPR] = {
+		.name = "cmpr",
+		.op = {
+			[0] = NPF_OPERAND_REGISTER,
+			[1] = NPF_OPERAND_REGISTER,
+		},
+	},
+	[NPF_OPCODE_BEQ] = {
+		.name = "beq",
+		.op = {
+			[0] = NPF_OPERAND_REL_ADDRESS,
+		},
+	},
+	[NPF_OPCODE_BNE] = {
+		.name = "bne",
+		.op = {
+			[0] = NPF_OPERAND_REL_ADDRESS,
+		},
+	},
+	[NPF_OPCODE_BGT] = {
+		.name = "bge",
+		.op = {
+			[0] = NPF_OPERAND_REL_ADDRESS,
+		},
+	},
+	[NPF_OPCODE_BLT] = {
+		.name = "blt",
+		.op = {
+			[0] = NPF_OPERAND_REL_ADDRESS,
+		},
+	},
+	[NPF_OPCODE_ADD] = {
+		.name = "add",
+		.op = {
+			[0] = NPF_OPERAND_VALUE,
+			[1] = NPF_OPERAND_REGISTER,
+		},
+	},
+	[NPF_OPCODE_SUB] = {
+		.name = "sub",
+		.op = {
+			[0] = NPF_OPERAND_VALUE,
+			[1] = NPF_OPERAND_REGISTER,
+		},
+	},
+	[NPF_OPCODE_MULT] = {
+		.name = "mult",
+		.op = {
+			[0] = NPF_OPERAND_VALUE,
+			[1] = NPF_OPERAND_REGISTER,
+		},
+	},
+	[NPF_OPCODE_DIV] = { .name = "div",
+		.op = {
+			[0] = NPF_OPERAND_VALUE,
+			[1] = NPF_OPERAND_REGISTER,
+		},
+	},
+	[NPF_OPCODE_NOT] = {
+		.name = "not",
+		.op = {
+			[0] = NPF_OPERAND_VALUE,
+			[1] = NPF_OPERAND_REGISTER,
+		},
+	},
+	[NPF_OPCODE_AND] = {
+		.name = "and",
+		.op = {
+			[0] = NPF_OPERAND_VALUE,
+			[1] = NPF_OPERAND_REGISTER,
+		},
+	},
+	[NPF_OPCODE_OR] = {
+		.name = "or",
+		.op = {
+			[0] = NPF_OPERAND_VALUE,
+			[1] = NPF_OPERAND_REGISTER,
+		},
+	},
+	[NPF_OPCODE_XOR] = {
+		.name = "xor",
+		.op = {
+			[0] = NPF_OPERAND_VALUE,
+			[1] = NPF_OPERAND_REGISTER,
+		},
+	},
+	[NPF_OPCODE_SLL] = {
+		.name = "sll",
+		.op = {
+			[0] = NPF_OPERAND_VALUE,
+			[1] = NPF_OPERAND_REGISTER,
+		},
+	},
+	[NPF_OPCODE_SRL] = {
+		.name = "srl",
+		.op = {
+			[0] = NPF_OPERAND_VALUE,
+			[1] = NPF_OPERAND_REGISTER,
+		},
+	},
+	[NPF_OPCODE_ETHER] = {
+		.name = "ether",
+		.op = {
+			[0] = NPF_OPERAND_SD,
+			[1] = NPF_OPERAND_NET_ADDRESS4,
+			[2] = NPF_OPERAND_ETHER_TYPE,
+		},
+	},
+	[NPF_OPCODE_IP4MASK] = {
+		.name = "ip4mask",
+		.op = {
+			[0] = NPF_OPERAND_SD,
+			[1] = NPF_OPERAND_NET_ADDRESS4,
+			[2] = NPF_OPERAND_SUBNET,
+		},
+	},
+	[NPF_OPCODE_TABLE] = {
+		.name = "table",
+		.op = {
+			[0] = NPF_OPERAND_SD,
+			[1] = NPF_OPERAND_TABLE_ID,
+		},
+	},
+	[NPF_OPCODE_ICMP4] = {
+		.name = "icmp4",
+		.op = {
+			[0] = NPF_OPERAND_ICMP4_TYPE_CODE,
+		},
+	},
+	[NPF_OPCODE_IP6MASK] = {
+		.name = "ip6mask",
+		.op = {
+			[0] = NPF_OPERAND_SD,
+			[1] = NPF_OPERAND_NET_ADDRESS6,
+			[2] = NPF_OPERAND_SUBNET,
+		},
+	},
+	[NPF_OPCODE_TCP_PORTS] = {
+		.name = "tcp_ports",
+		.op = {
+			[0] = NPF_OPERAND_SD,
+			[1] = NPF_OPERAND_PORT_RANGE,
+		},
+	},
+	[NPF_OPCODE_UDP_PORTS] = {
+		.name = "udp_ports",
+		.op = {
+			[0] = NPF_OPERAND_SD,
+			[1] = NPF_OPERAND_PORT_RANGE,
+		},
+	},
+	[NPF_OPCODE_TCP_FLAGS] = {
+		.name = "tcp_flags",
+		.op = {
+			[0] = NPF_OPERAND_TCP_FLAGS_MASK,
+		},
+	},
+};
+#endif /* NPF_OPCODES_STRINGS */
+
+#endif /* _NET_NPF_NCODE_H_ */
--- a/sys/net/npf/npf_processor.c	Tue Apr 03 16:36:20 2012 +0000
+++ b/sys/net/npf/npf_processor.c	Tue Apr 03 17:22:52 2012 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_processor.c,v 1.9 2012/02/05 00:37:13 rmind Exp $	*/
+/*	$NetBSD: npf_processor.c,v 1.9.2.1 2012/04/03 17:22:53 riz Exp $	*/
 
 /*-
  * Copyright (c) 2009-2010 The NetBSD Foundation, Inc.
@@ -47,17 +47,12 @@
  * N-code memory address and thus instructions should be word aligned.
  * All processing is done in 32 bit words, since both instructions (their
  * codes) and arguments use 32 bits words.
- *
- * TODO:
- * - There is some space for better a abstraction.  Duplicated opcode
- *   maintenance in npf_ncode_process() and nc_insn_check() might be avoided.
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_processor.c,v 1.9 2012/02/05 00:37:13 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_processor.c,v 1.9.2.1 2012/04/03 17:22:53 riz Exp $");
 
 #include <sys/param.h>
-#include <sys/kernel.h>
 #include <sys/types.h>
 #include <sys/kmem.h>
 
--- a/sys/net/npf/npf_rproc.c	Tue Apr 03 16:36:20 2012 +0000
+++ b/sys/net/npf/npf_rproc.c	Tue Apr 03 17:22:52 2012 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_rproc.c,v 1.1 2012/02/06 23:30:14 rmind Exp $	*/
+/*	$NetBSD: npf_rproc.c,v 1.1.2.1 2012/04/03 17:22:52 riz Exp $	*/
 
 /*-
  * Copyright (c) 2009-2012 The NetBSD Foundation, Inc.
@@ -37,11 +37,10 @@
 __KERNEL_RCSID(0, "$NetBSD");
 
 #include <sys/param.h>
-#include <sys/kernel.h>
+#include <sys/types.h>
 
 #include <sys/atomic.h>
 #include <sys/kmem.h>
-#include <sys/types.h>
 
 #include "npf_impl.h"
 
@@ -69,7 +68,7 @@
 	npf_rproc_t *rp;
 	const char *rname;
 
-	rp = kmem_zalloc(sizeof(npf_rproc_t), KM_SLEEP);
+	rp = kmem_intr_zalloc(sizeof(npf_rproc_t), KM_SLEEP);
 	rp->rp_refcnt = 1;
 
 	/* Name and flags. */
@@ -107,7 +106,7 @@
 	if (atomic_dec_uint_nv(&rp->rp_refcnt) != 0) {
 		return;
 	}
-	kmem_free(rp, sizeof(npf_rproc_t));
+	kmem_intr_free(rp, sizeof(npf_rproc_t));
 }
 
 void
--- a/sys/net/npf/npf_ruleset.c	Tue Apr 03 16:36:20 2012 +0000
+++ b/sys/net/npf/npf_ruleset.c	Tue Apr 03 17:22:52 2012 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_ruleset.c,v 1.10 2012/02/06 23:30:14 rmind Exp $	*/
+/*	$NetBSD: npf_ruleset.c,v 1.10.2.1 2012/04/03 17:22:53 riz Exp $	*/
 
 /*-
  * Copyright (c) 2009-2012 The NetBSD Foundation, Inc.
@@ -34,10 +34,10 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_ruleset.c,v 1.10 2012/02/06 23:30:14 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_ruleset.c,v 1.10.2.1 2012/04/03 17:22:53 riz Exp $");
 
 #include <sys/param.h>
-#include <sys/kernel.h>
+#include <sys/types.h>
 
 #include <sys/kmem.h>
 #include <sys/queue.h>
@@ -208,7 +208,7 @@
 	int errat __unused;
 
 	/* Allocate a rule structure. */
-	rl = kmem_alloc(sizeof(npf_rule_t), KM_SLEEP);
+	rl = kmem_zalloc(sizeof(npf_rule_t), KM_SLEEP);
 	TAILQ_INIT(&rl->r_subset.rs_queue);
 	rl->r_natp = NULL;
 
@@ -217,14 +217,14 @@
 	rl->r_ncode = nc;
 	rl->r_nc_size = nc_size;
 
-	/* Name (string, optional) */
+	/* Name (optional) */
 	if (prop_dictionary_get_cstring_nocopy(rldict, "name", &rname)) {
 		strlcpy(rl->r_name, rname, NPF_RNAME_LEN);
 	} else {
 		rl->r_name[0] = '\0';
 	}
 
-	/* Attributes, priority and interface ID. */
+	/* Attributes, priority and interface ID (optional). */
 	prop_dictionary_get_uint32(rldict, "attributes", &rl->r_attr);
 	prop_dictionary_get_int32(rldict, "priority", &rl->r_priority);
 	prop_dictionary_get_uint32(rldict, "interface", &rl->r_ifid);
--- a/sys/net/npf/npf_sendpkt.c	Tue Apr 03 16:36:20 2012 +0000
+++ b/sys/net/npf/npf_sendpkt.c	Tue Apr 03 17:22:52 2012 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_sendpkt.c,v 1.8 2011/11/29 20:05:30 rmind Exp $	*/
+/*	$NetBSD: npf_sendpkt.c,v 1.8.4.1 2012/04/03 17:22:53 riz Exp $	*/
 
 /*-
  * Copyright (c) 2010-2011 The NetBSD Foundation, Inc.
@@ -34,10 +34,10 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_sendpkt.c,v 1.8 2011/11/29 20:05:30 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_sendpkt.c,v 1.8.4.1 2012/04/03 17:22:53 riz Exp $");
 
 #include <sys/param.h>
-#include <sys/kernel.h>
+#include <sys/types.h>
 
 #include <netinet/in_systm.h>
 #include <netinet/in.h>
--- a/sys/net/npf/npf_session.c	Tue Apr 03 16:36:20 2012 +0000
+++ b/sys/net/npf/npf_session.c	Tue Apr 03 17:22:52 2012 +0000
@@ -1,7 +1,7 @@
-/*	$NetBSD: npf_session.c,v 1.10 2011/11/29 20:05:30 rmind Exp $	*/
+/*	$NetBSD: npf_session.c,v 1.10.4.1 2012/04/03 17:22:52 riz Exp $	*/
 
 /*-
- * Copyright (c) 2010-2011 The NetBSD Foundation, Inc.
+ * Copyright (c) 2010-2012 The NetBSD Foundation, Inc.
  * All rights reserved.
  *
  * This material is based upon work partially supported by The
@@ -49,7 +49,7 @@
  *	indicate that the packet of the backwards stream should be passed
  *	without inspection of the ruleset.  Another purpose is to associate
  *	NAT with a connection (which implies connection tracking).  Such
- *	sessions are created according to the NAT policies and they have a 1:1
+ *	sessions are created according to the NAT policies and they have a
  *	relationship with NAT translation structure via npf_session_t::s_nat.
  *	A single session can serve both purposes, which is a common case.
  *
@@ -61,9 +61,9 @@
  *	depending on session properties (e.g. last activity time, protocol)
  *	removes session entries and expires the actual sessions.
  *
- *	Each session has a reference count, which is taken on lookup and
- *	needs to be released by the caller.  Reference guarantees that
- *	session will not be destroyed, although it might be expired.
+ *	Each session has a reference count.  Reference is acquired on lookup
+ *	and should be released by the caller.  Reference guarantees that the
+ *	session will not be destroyed, although it may be expired.
  *
  * External session identifiers
  *
@@ -74,10 +74,10 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_session.c,v 1.10 2011/11/29 20:05:30 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_session.c,v 1.10.4.1 2012/04/03 17:22:52 riz Exp $");
 
 #include <sys/param.h>
-#include <sys/kernel.h>
+#include <sys/types.h>
 
 #include <netinet/in.h>
 #include <netinet/tcp.h>
@@ -93,7 +93,6 @@
 #include <sys/rwlock.h>
 #include <sys/queue.h>
 #include <sys/systm.h>
-#include <sys/types.h>
 
 #include "npf_impl.h"
 
@@ -197,7 +196,7 @@
 {
 
 	/* Disable tracking, flush all sessions. */
-	sess_tracking_stop();
+	npf_session_tracking(false);
 	KASSERT(sess_tracking == 0);
 	KASSERT(sess_gc_lwp == NULL);
 
@@ -277,7 +276,7 @@
 	npf_sehash_t *stbl, *sh;
 	u_int i;
 
-	stbl = kmem_alloc(SESS_HASH_BUCKETS * sizeof(*sh), KM_SLEEP);
+	stbl = kmem_zalloc(SESS_HASH_BUCKETS * sizeof(*sh), KM_SLEEP);
 	if (stbl == NULL) {
 		return NULL;
 	}
@@ -406,7 +405,10 @@
 	npf_sentry_t *sen;
 	npf_session_t *se;
 
-	/* Layer 3 and 4 should be already cached for session tracking. */
+	/*
+	 * If layer 3 and 4 are not cached - protocol is not supported
+	 * or packet is invalid.
+	 */
 	if (!sess_tracking || !npf_iscached(npc, NPC_IP46) ||
 	    !npf_iscached(npc, NPC_LAYER4)) {
 		return NULL;
@@ -491,7 +493,7 @@
 /*
  * npf_establish_session: create a new session, insert into the global list.
  *
- * => Sessions is created with the held reference (for caller).
+ * => Session is created with the reference held for the caller.
  */
 npf_session_t *
 npf_session_establish(const npf_cache_t *npc, nbuf_t *nbuf, const int di)
@@ -504,11 +506,14 @@
 	int proto, sz;
 	bool ok;
 
-	if (!sess_tracking) {
+	/*
+	 * If layer 3 and 4 are not cached - protocol is not supported
+	 * or packet is invalid.
+	 */
+	if (!sess_tracking || !npf_iscached(npc, NPC_IP46) ||
+	    !npf_iscached(npc, NPC_LAYER4)) {
 		return NULL;
 	}
-	KASSERT(npf_iscached(npc, NPC_IP46));
-	KASSERT(npf_iscached(npc, NPC_LAYER4));
 
 	/* Allocate and initialise new state. */
 	se = pool_cache_get(sess_cache, PR_NOWAIT);
--- a/sys/net/npf/npf_tableset.c	Tue Apr 03 16:36:20 2012 +0000
+++ b/sys/net/npf/npf_tableset.c	Tue Apr 03 17:22:52 2012 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_tableset.c,v 1.9 2012/01/15 00:49:49 rmind Exp $	*/
+/*	$NetBSD: npf_tableset.c,v 1.9.2.1 2012/04/03 17:22:52 riz Exp $	*/
 
 /*-
  * Copyright (c) 2009-2012 The NetBSD Foundation, Inc.
@@ -39,10 +39,10 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_tableset.c,v 1.9 2012/01/15 00:49:49 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_tableset.c,v 1.9.2.1 2012/04/03 17:22:52 riz Exp $");
 
 #include <sys/param.h>
-#include <sys/kernel.h>
+#include <sys/types.h>
 
 #include <sys/atomic.h>
 #include <sys/hash.h>
--- a/usr.sbin/npf/npfctl/Makefile	Tue Apr 03 16:36:20 2012 +0000
+++ b/usr.sbin/npf/npfctl/Makefile	Tue Apr 03 17:22:52 2012 +0000
@@ -1,16 +1,18 @@
-# $NetBSD: Makefile,v 1.5 2012/01/08 21:34:21 rmind Exp $
+# $NetBSD: Makefile,v 1.5.2.1 2012/04/03 17:22:54 riz Exp $
 
 PROG=		npfctl
 MAN=		npfctl.8 npf.conf.5
 
-SRCS=		npfctl.c npf_var.c npf_data.c npf_ncgen.c npf_build.c
+SRCS=		npfctl.c npf_var.c npf_data.c npf_ncgen.c npf_build.c \
+		npf_disassemble.c
 
 CPPFLAGS+=	-I${.CURDIR}
 SRCS+=		npf_scan.l npf_parse.y
 YHEADER=	1
+YFLAGS+=	-v
 
-LDADD+=		-lnpf -lprop -ly
-DPADD+=		${LIBNPF} ${LIBPROP}
+LDADD+=		-lnpf -lprop -lutil -ly
+DPADD+=		${LIBNPF} ${LIBPROP} ${LIBUTIL}
 
 WARNS?=		4
 NOLINT=		# disabled (note: deliberately)
--- a/usr.sbin/npf/npfctl/npf_build.c	Tue Apr 03 16:36:20 2012 +0000
+++ b/usr.sbin/npf/npfctl/npf_build.c	Tue Apr 03 17:22:52 2012 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_build.c,v 1.4 2012/02/06 00:37:52 rmind Exp $	*/
+/*	$NetBSD: npf_build.c,v 1.4.2.1 2012/04/03 17:22:53 riz Exp $	*/
 
 /*-
  * Copyright (c) 2011-2012 The NetBSD Foundation, Inc.
@@ -34,7 +34,7 @@
  */
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: npf_build.c,v 1.4 2012/02/06 00:37:52 rmind Exp $");
+__RCSID("$NetBSD: npf_build.c,v 1.4.2.1 2012/04/03 17:22:53 riz Exp $");
 
 #include <sys/types.h>
 #include <sys/ioctl.h>
@@ -400,9 +400,8 @@
 	} else if ((attr & attr_di) == 0) {
 		attr |= attr_di;
 	}
-	attr |= (NPF_RULE_PASS | NPF_RULE_FINAL);
 
-	rl = npf_rule_create(name, attr, if_idx);
+	rl = npf_rule_create(name, attr | NPF_RULE_FINAL, if_idx);
 	npf_rule_insert(npf_conf, NULL, rl, NPF_PRI_NEXT);
 	current_group = rl;
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr.sbin/npf/npfctl/npf_disassemble.c	Tue Apr 03 17:22:52 2012 +0000
@@ -0,0 +1,263 @@
+/*	$NetBSD: npf_disassemble.c,v 1.3.2.2 2012/04/03 17:22:54 riz Exp $	*/
+
+/*-
+ * Copyright (c) 2012 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Christos Zoulas.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: npf_disassemble.c,v 1.3.2.2 2012/04/03 17:22:54 riz Exp $");
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <err.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#include <util.h>
+
+#define NPF_OPCODES_STRINGS
+#include <net/npf_ncode.h>
+
+#include "npfctl.h"
+
+#define ADVANCE(n, rv) \
+	do { \
+		if (len < sizeof(*pc) * (n)) { \
+			warnx("ran out of bytes"); \
+			return rv; \
+		} \
+		pc += (n); \
+		len -= sizeof(*pc) * (n); \
+	} while (/*CONSTCOND*/0)
+
+static size_t
+npfctl_ncode_get_target(const uint32_t *pc, const uint32_t **t, size_t l)
+{
+	for (size_t i = 0; i < l; i++)
+		if (t[i] == pc)
+			return i;
+	return ~0;
+}
+
+static size_t
+npfctl_ncode_add_target(const uint32_t *pc, const uint32_t ***t, size_t *l,
+    size_t *m)
+{
+	size_t q = npfctl_ncode_get_target(pc, *t, *l);
+
+	if (q != (size_t)~0)
+		return q;
+
+	if (*l <= *m) {
+		*m += 10;
+		*t = xrealloc(*t, *m * sizeof(**t));
+	}
+	q = *l;
+	(*t)[(*l)++] = pc;
+	return q;
+}
+
+static const char *
+npfctl_ncode_operand(char *buf, size_t bufsiz, uint8_t op, const uint32_t *st,
+    const uint32_t *ipc, const uint32_t **pcv, size_t *lenv,
+    const uint32_t ***t, size_t *l, size_t *m)
+{
+	const uint32_t *pc = *pcv;
+	size_t len = *lenv;
+	struct sockaddr_storage ss;
+
+	switch (op) {
+	case NPF_OPERAND_NONE:
+		abort();
+
+	case NPF_OPERAND_REGISTER:
+		if (*pc & ~0x3) {
+			warnx("Bad register operand 0x%x at offset %td",
+			    *pc, pc - st);
+			return NULL;
+		}
+		snprintf(buf, bufsiz, "R%d", *pc);
+		ADVANCE(1, NULL);
+		break;
+				
+	case NPF_OPERAND_KEY:
+		snprintf(buf, bufsiz, "key=<0x%x>", *pc);
+		ADVANCE(1, NULL);
+		break;
+
+	case NPF_OPERAND_VALUE:
+		snprintf(buf, bufsiz, "value=<0x%x>", *pc);
+		ADVANCE(1, NULL);
+		break;
+
+	case NPF_OPERAND_SD:
+		if (*pc & ~0x1) {
+			warnx("Bad src/dst operand 0x%x at offset %td",
+			    *pc, pc - st);
+			return NULL;
+		}
+		snprintf(buf, bufsiz, "%s", *pc == NPF_OPERAND_SD_SRC ?
+		    "SRC" : "DST");
+		ADVANCE(1, NULL);
+		break;
+
+	case NPF_OPERAND_REL_ADDRESS:
+		snprintf(buf, bufsiz, "+%zu",
+		    npfctl_ncode_add_target(ipc + *pc, t, l, m));
+		ADVANCE(1, NULL);
+		break;
+
+	case NPF_OPERAND_NET_ADDRESS4: {
+		struct sockaddr_in *sin = (void *)&ss;
+		sin->sin_len = sizeof(*sin);
+		sin->sin_family = AF_INET;
+		sin->sin_port = 0;
+		memcpy(&sin->sin_addr, pc, sizeof(sin->sin_addr));
+		sockaddr_snprintf(buf, bufsiz, "%a", (struct sockaddr *)(void *)
+		    sin);
+		ADVANCE(sizeof(sin->sin_addr) / sizeof(*pc), NULL);
+		break;
+	}
+	case NPF_OPERAND_NET_ADDRESS6: {
+		struct sockaddr_in6 *sin6 = (void *)&ss;
+		sin6->sin6_len = sizeof(*sin6);
+		sin6->sin6_family = AF_INET6;
+		sin6->sin6_port = 0;
+		memcpy(&sin6->sin6_addr, pc, sizeof(sin6->sin6_addr));
+		sockaddr_snprintf(buf, bufsiz, "%a", (struct sockaddr *)(void *)
+		    sin6);
+		ADVANCE(sizeof(sin6->sin6_addr) / sizeof(*pc), NULL);
+		break;
+	}
+	case NPF_OPERAND_ETHER_TYPE:
+		snprintf(buf, bufsiz, "ether=0x%x", *pc);
+		ADVANCE(1, NULL);
+		break;
+
+	case NPF_OPERAND_SUBNET:
+		snprintf(buf, bufsiz, "/%d", *pc);
+		ADVANCE(1, NULL);
+		break;
+
+	case NPF_OPERAND_LENGTH:
+		snprintf(buf, bufsiz, "length=%d", *pc);
+		ADVANCE(1, NULL);
+		break;
+
+	case NPF_OPERAND_TABLE_ID:
+		snprintf(buf, bufsiz, "id=%d", *pc);
+		ADVANCE(1, NULL);
+		break;
+
+	case NPF_OPERAND_ICMP4_TYPE_CODE:
+		if (*pc & ~0xffff) {
+			warnx("Bad icmp/type operand 0x%x at offset %td",
+			    *pc, pc - st);
+			return NULL;
+		}
+		snprintf(buf, bufsiz, "type=%d, code=%d", *pc >> 8,
+		    *pc & 0xff);
+		ADVANCE(1, NULL);
+		break;
+
+	case NPF_OPERAND_TCP_FLAGS_MASK:
+		if (*pc & ~0xffff) {
+			warnx("Bad flags/mask operand 0x%x at offset %td",
+			    *pc, pc - st);
+			return NULL;
+		}
+		snprintf(buf, bufsiz, "type=%d, code=%d", *pc >> 8,
+		    *pc & 0xff);
+		ADVANCE(1, NULL);
+		break;
+
+	case NPF_OPERAND_PORT_RANGE:
+		snprintf(buf, bufsiz, "%d-%d", (*pc >> 16), *pc & 0xffff);
+		ADVANCE(1, NULL);
+		break;
+	default:
+		warnx("invalid operand %d at offset %td", op, pc - st);
+		return NULL;
+	}
+
+	*pcv = pc;
+	*lenv = len;
+	return buf;
+}
+
+int
+npfctl_ncode_disassemble(FILE *fp, const void *v, size_t len)
+{
+	const uint32_t *ipc, *pc = v;
+	const uint32_t *st = v;
+	const struct npf_instruction *ni;
+	char buf[256];
+	const uint32_t **targ;
+	size_t tlen, mlen, target;
+	int error = -1;
+
+	targ = NULL;
+	mlen = tlen = 0;
+	while (len) {
+		/* Get the opcode */
+		if (*pc & ~0xff) {
+			warnx("bad opcode 0x%x at offset (%td)", *pc,
+			    pc - st);
+			goto out;
+		}
+		ni = &npf_instructions[*pc];
+		if (ni->name == NULL) {
+			warnx("invalid opcode 0x%x at offset (%td)", *pc,
+			    pc - st);
+			goto out;
+		}
+		ipc = pc;
+		target = npfctl_ncode_get_target(pc, targ, tlen);
+		if (target != (size_t)~0)
+			printf("%zu:", target);
+		fprintf(fp, "\t%s", ni->name);
+		ADVANCE(1, -1);
+		for (size_t i = 0; i < __arraycount(ni->op); i++) {
+			const char *op;
+			if (ni->op[i] == NPF_OPERAND_NONE)
+				break;
+			op = npfctl_ncode_operand(buf, sizeof(buf), ni->op[i],
+			    st, ipc, &pc, &len, &targ, &tlen, &mlen);
+			if (op == NULL)
+				goto out;
+			fprintf(fp, "%s%s", i == 0 ? " " : ", ", op);
+		}
+		fprintf(fp, "\n");
+	}
+	error = 0;
+out:
+	free(targ);
+	return error;
+}
--- a/usr.sbin/npf/npfctl/npf_ncgen.c	Tue Apr 03 16:36:20 2012 +0000
+++ b/usr.sbin/npf/npfctl/npf_ncgen.c	Tue Apr 03 17:22:52 2012 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_ncgen.c,v 1.7 2012/01/09 01:47:09 rmind Exp $	*/
+/*	$NetBSD: npf_ncgen.c,v 1.7.2.1 2012/04/03 17:22:54 riz Exp $	*/
 
 /*-
  * Copyright (c) 2009-2012 The NetBSD Foundation, Inc.
@@ -34,7 +34,7 @@
  */
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: npf_ncgen.c,v 1.7 2012/01/09 01:47:09 rmind Exp $");
+__RCSID("$NetBSD: npf_ncgen.c,v 1.7.2.1 2012/04/03 17:22:54 riz Exp $");
 
 #include <stdlib.h>
 #include <stddef.h>
@@ -388,10 +388,14 @@
 void
 npfctl_ncgen_print(const void *code, size_t len)
 {
+#if 0
 	const uint32_t *op = code;
 
 	while (len) {
 		printf("\t> |0x%02x|\n", (u_int)*op++);
 		len -= sizeof(*op);
 	}
+#else
+	npfctl_ncode_disassemble(stdout, code, len);
+#endif
 }
--- a/usr.sbin/npf/npfctl/npf_parse.y	Tue Apr 03 16:36:20 2012 +0000
+++ b/usr.sbin/npf/npfctl/npf_parse.y	Tue Apr 03 17:22:52 2012 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_parse.y,v 1.3 2012/01/15 00:49:48 rmind Exp $	*/
+/*	$NetBSD: npf_parse.y,v 1.3.2.1 2012/04/03 17:22:53 riz Exp $	*/
 
 /*-
  * Copyright (c) 2011-2012 The NetBSD Foundation, Inc.
@@ -138,7 +138,7 @@
 %type	<num>		ifindex, port, opt_quick, on_iface
 %type	<num>		block_or_pass, rule_dir, block_opts, family, opt_family
 %type	<num>		opt_keep_state, icmp_type, table_type
-%type	<var>		addr_or_iface, port_range, iface, icmp_type_and_code
+%type	<var>		addr_or_iface, port_range, icmp_type_and_code
 %type	<var>		filt_addr, addr_and_mask, tcp_flags, tcp_flags_and_mask
 %type	<var>		modulearg_opts, procs, proc_op, modulearg, moduleargs
 %type	<filtopts>	filt_opts, all_or_filt_opts
@@ -536,10 +536,9 @@
 	;
 
 filt_addr
-	: iface		{ $$ = $1; }
-	| addr_and_mask	{ $$ = $1; }
-	| TABLE_ID 	{ $$ = npfctl_parse_table_id($1); }
-	| ANY		{ $$ = NULL; }
+	: addr_or_iface		{ $$ = $1; }
+	| TABLE_ID		{ $$ = npfctl_parse_table_id($1); }
+	| ANY			{ $$ = NULL; }
 	;
 
 addr_and_mask
@@ -563,7 +562,33 @@
 
 addr_or_iface
 	: addr_and_mask	{ assert($1 != NULL); $$ = $1; }
-	| iface		{ assert($1 != NULL); $$ = $1; }
+	| iface_name
+	{
+		$$ = npfctl_parse_iface($1);
+	}
+	| VAR_ID
+	{
+		npfvar_t *vp = npfvar_lookup($1);
+		const int type = npfvar_get_type(vp);
+
+		switch (type) {
+		case NPFVAR_VAR_ID:
+		case NPFVAR_STRING:
+			$$ = npfctl_parse_iface(npfvar_expand_string(vp));
+			break;
+		case NPFVAR_FAM:
+			$$ = vp;
+			break;
+		case -1:
+			yyerror("undefined variable '%s' for interface", $1);
+			break;
+		default:
+			yyerror("wrong variable '%s' type '%s' or interface",
+			    $1, npfvar_type(type));
+			$$ = NULL;
+			break;
+		}
+	}
 	;
 
 addr
@@ -650,36 +675,6 @@
 	}
 	;
 
-iface
-	: iface_name
-	{
-		$$ = npfctl_parse_iface($1);
-	}
-	| VAR_ID
-	{
-		npfvar_t *vp = npfvar_lookup($1);
-		const int type = npfvar_get_type(vp);
-
-		switch (type) {
-		case NPFVAR_VAR_ID:
-		case NPFVAR_STRING:
-			$$ = npfctl_parse_iface(npfvar_expand_string(vp));
-			break;
-		case NPFVAR_FAM:
-			$$ = vp;
-			break;
-		case -1:
-			yyerror("undefined variable '%s' for interface", $1);
-			break;
-		default:
-			yyerror("wrong variable '%s' type '%s' or interface",
-			    $1, npfvar_type(type));
-			$$ = NULL;
-			break;
-		}
-	}
-	;
-
 ifindex
 	: iface_name
 	{
--- a/usr.sbin/npf/npfctl/npfctl.h	Tue Apr 03 16:36:20 2012 +0000
+++ b/usr.sbin/npf/npfctl/npfctl.h	Tue Apr 03 17:22:52 2012 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npfctl.h,v 1.11 2012/02/05 00:37:13 rmind Exp $	*/
+/*	$NetBSD: npfctl.h,v 1.11.2.1 2012/04/03 17:22:54 riz Exp $	*/
 
 /*-
  * Copyright (c) 2009-2012 The NetBSD Foundation, Inc.
@@ -153,5 +153,6 @@
 void		npfctl_build_nat(int, u_int, const filt_opts_t *,
 		    npfvar_t *, npfvar_t *);
 void		npfctl_build_table(const char *, u_int, const char *);
+int		npfctl_ncode_disassemble(FILE *, const void *, size_t);
 
 #endif