Module Name:    src
Committed By:   rmind
Date:           Fri Jun 22 13:43:17 UTC 2012

Modified Files:
        src/sys/net/npf: npf.c npf.h npf_alg.c npf_impl.h npf_inet.c
            npf_instr.c npf_log.c npf_nat.c npf_sendpkt.c npf_session.c
            npf_state.c npf_state_tcp.c npf_tableset.c
        src/usr.sbin/npf/npftest/libnpftest: npf_table_test.c

Log Message:
NPF:
- Rename some functions for consistency and de-inline them.
- Fix few invalid asserts (add regressoin test).
- Use pserialize(9) for ALG interface.
- Minor fixes, sprinkle many comments.


To generate a diff of this commit:
cvs rdiff -u -r1.10 -r1.11 src/sys/net/npf/npf.c src/sys/net/npf/npf_instr.c \
    src/sys/net/npf/npf_sendpkt.c src/sys/net/npf/npf_tableset.c
cvs rdiff -u -r1.16 -r1.17 src/sys/net/npf/npf.h
cvs rdiff -u -r1.3 -r1.4 src/sys/net/npf/npf_alg.c src/sys/net/npf/npf_log.c
cvs rdiff -u -r1.15 -r1.16 src/sys/net/npf/npf_impl.h
cvs rdiff -u -r1.11 -r1.12 src/sys/net/npf/npf_inet.c
cvs rdiff -u -r1.12 -r1.13 src/sys/net/npf/npf_nat.c \
    src/sys/net/npf/npf_session.c
cvs rdiff -u -r1.7 -r1.8 src/sys/net/npf/npf_state.c
cvs rdiff -u -r1.6 -r1.7 src/sys/net/npf/npf_state_tcp.c
cvs rdiff -u -r1.1 -r1.2 src/usr.sbin/npf/npftest/libnpftest/npf_table_test.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/net/npf/npf.c
diff -u src/sys/net/npf/npf.c:1.10 src/sys/net/npf/npf.c:1.11
--- src/sys/net/npf/npf.c:1.10	Tue Mar 13 18:40:59 2012
+++ src/sys/net/npf/npf.c	Fri Jun 22 13:43:17 2012
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf.c,v 1.10 2012/03/13 18:40:59 elad Exp $	*/
+/*	$NetBSD: npf.c,v 1.11 2012/06/22 13:43:17 rmind 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.10 2012/03/13 18:40:59 elad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf.c,v 1.11 2012/06/22 13:43:17 rmind Exp $");
 
 #include <sys/param.h>
 #include <sys/types.h>
@@ -48,6 +48,7 @@ __KERNEL_RCSID(0, "$NetBSD: npf.c,v 1.10
 #include <sys/percpu.h>
 #include <sys/rwlock.h>
 #include <sys/socketvar.h>
+#include <sys/sysctl.h>
 #include <sys/uio.h>
 
 #include "npf_impl.h"
@@ -80,6 +81,7 @@ static int	npfctl_stats(void *);
 static krwlock_t		npf_lock		__cacheline_aligned;
 static npf_core_t *		npf_core		__cacheline_aligned;
 static percpu_t *		npf_stats_percpu	__read_mostly;
+static struct sysctllog *	npf_sysctl		__read_mostly;
 
 const struct cdevsw npf_cdevsw = {
 	npf_dev_open, npf_dev_close, npf_dev_read, nowrite, npf_dev_ioctl,
@@ -99,6 +101,8 @@ npf_init(void)
 
 	rw_init(&npf_lock);
 	npf_stats_percpu = percpu_alloc(NPF_STATS_SIZE);
+	npf_sysctl = NULL;
+
 	npf_tableset_sysinit();
 	npf_session_sysinit();
 	npf_nat_sysinit();
@@ -144,6 +148,10 @@ npf_fini(void)
 	npf_nat_sysfini();
 	npf_session_sysfini();
 	npf_tableset_sysfini();
+
+	if (npf_sysctl) {
+		sysctl_teardown(&npf_sysctl);
+	}
 	percpu_free(npf_stats_percpu, NPF_STATS_SIZE);
 	rw_destroy(&npf_lock);
 
Index: src/sys/net/npf/npf_instr.c
diff -u src/sys/net/npf/npf_instr.c:1.10 src/sys/net/npf/npf_instr.c:1.11
--- src/sys/net/npf/npf_instr.c:1.10	Mon Feb 20 00:18:20 2012
+++ src/sys/net/npf/npf_instr.c	Fri Jun 22 13:43:17 2012
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_instr.c,v 1.10 2012/02/20 00:18:20 rmind Exp $	*/
+/*	$NetBSD: npf_instr.c,v 1.11 2012/06/22 13:43:17 rmind Exp $	*/
 
 /*-
  * Copyright (c) 2009-2010 The NetBSD Foundation, Inc.
@@ -34,7 +34,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_instr.c,v 1.10 2012/02/20 00:18:20 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_instr.c,v 1.11 2012/06/22 13:43:17 rmind Exp $");
 
 #include <sys/param.h>
 #include <sys/types.h>
@@ -129,7 +129,7 @@ npf_match_ipmask(npf_cache_t *npc, nbuf_
 	}
 	addr = sd ? npc->npc_srcip : npc->npc_dstip;
 	if (mask != NPF_NO_NETMASK) {
-		npf_calculate_masked_addr(&cmpaddr, addr, mask);
+		npf_addr_mask(addr, mask, &cmpaddr);
 		addr = &cmpaddr;
 	}
 	return memcmp(netaddr, addr, npc->npc_ipsz) ? -1 : 0;
Index: src/sys/net/npf/npf_sendpkt.c
diff -u src/sys/net/npf/npf_sendpkt.c:1.10 src/sys/net/npf/npf_sendpkt.c:1.11
--- src/sys/net/npf/npf_sendpkt.c:1.10	Sun May  6 02:45:25 2012
+++ src/sys/net/npf/npf_sendpkt.c	Fri Jun 22 13:43:17 2012
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_sendpkt.c,v 1.10 2012/05/06 02:45:25 rmind Exp $	*/
+/*	$NetBSD: npf_sendpkt.c,v 1.11 2012/06/22 13:43:17 rmind Exp $	*/
 
 /*-
  * Copyright (c) 2010-2011 The NetBSD Foundation, Inc.
@@ -34,7 +34,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_sendpkt.c,v 1.10 2012/05/06 02:45:25 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_sendpkt.c,v 1.11 2012/06/22 13:43:17 rmind Exp $");
 
 #include <sys/param.h>
 #include <sys/types.h>
@@ -108,7 +108,7 @@ npf_return_tcp(npf_cache_t *npc)
 		memset(ip, 0, len);
 
 		/*
-		 * First fill of IPv4 header, for TCP checksum.
+		 * First, partially fill IPv4 header for TCP checksum.
 		 * Note: IP length contains TCP header length.
 		 */
 		ip->ip_p = IPPROTO_TCP;
@@ -134,7 +134,9 @@ npf_return_tcp(npf_cache_t *npc)
 		th = (struct tcphdr *)(ip6 + 1);
 	}
 
-	/* Construct TCP header and compute the checksum. */
+	/*
+	 * Construct TCP header and compute the checksum.
+	 */
 	th->th_sport = oth->th_dport;
 	th->th_dport = oth->th_sport;
 	th->th_seq = htonl(ack);
@@ -148,7 +150,9 @@ npf_return_tcp(npf_cache_t *npc)
 	if (npf_iscached(npc, NPC_IP4)) {
 		th->th_sum = in_cksum(m, len);
 
-		/* Second fill of IPv4 header, fill correct IP length. */
+		/*
+		 * Second, fill the rest of IPv4 header and correct IP length.
+		 */
 		ip->ip_v = IPVERSION;
 		ip->ip_hl = sizeof(struct ip) >> 2;
 		ip->ip_tos = IPTOS_LOWDELAY;
Index: src/sys/net/npf/npf_tableset.c
diff -u src/sys/net/npf/npf_tableset.c:1.10 src/sys/net/npf/npf_tableset.c:1.11
--- src/sys/net/npf/npf_tableset.c:1.10	Mon Feb 20 00:18:20 2012
+++ src/sys/net/npf/npf_tableset.c	Fri Jun 22 13:43:17 2012
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_tableset.c,v 1.10 2012/02/20 00:18:20 rmind Exp $	*/
+/*	$NetBSD: npf_tableset.c,v 1.11 2012/06/22 13:43:17 rmind Exp $	*/
 
 /*-
  * Copyright (c) 2009-2012 The NetBSD Foundation, Inc.
@@ -39,7 +39,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_tableset.c,v 1.10 2012/02/20 00:18:20 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_tableset.c,v 1.11 2012/06/22 13:43:17 rmind Exp $");
 
 #include <sys/param.h>
 #include <sys/types.h>
@@ -164,7 +164,7 @@ table_rbtree_cmp_nodes(void *ctx, const 
 	const npf_tblent_t * const te1 = n1;
 	const npf_tblent_t * const te2 = n2;
 
-	return npf_compare_cidr(&te1->te_addr, te1->te_mask,
+	return npf_addr_cmp(&te1->te_addr, te1->te_mask,
 	    &te2->te_addr, te2->te_mask);
 }
 
@@ -174,7 +174,7 @@ table_rbtree_cmp_key(void *ctx, const vo
 	const npf_tblent_t * const te = n1;
 	const npf_addr_t *t2 = key;
 
-	return npf_compare_cidr(&te->te_addr, te->te_mask, t2, NPF_NO_NETMASK);
+	return npf_addr_cmp(&te->te_addr, te->te_mask, t2, NPF_NO_NETMASK);
 }
 
 static const rb_tree_ops_t table_rbtree_ops = {
@@ -366,7 +366,7 @@ npf_table_add_cidr(npf_tableset_t *tset,
 	switch (t->t_type) {
 	case NPF_TABLE_HASH:
 		/* Generate hash value from: address & mask. */
-		npf_calculate_masked_addr(&val, addr, mask);
+		npf_addr_mask(addr, mask, &val);
 		htbl = table_hash_bucket(t, &val, sizeof(npf_addr_t));
 		/* Lookup to check for duplicates. */
 		LIST_FOREACH(it, htbl, te_entry.hashq) {
@@ -428,7 +428,7 @@ npf_table_rem_cidr(npf_tableset_t *tset,
 	switch (t->t_type) {
 	case NPF_TABLE_HASH:
 		/* Generate hash value from: (address & mask). */
-		npf_calculate_masked_addr(&val, addr, mask);
+		npf_addr_mask(addr, mask, &val);
 		htbl = table_hash_bucket(t, &val, sizeof(npf_addr_t));
 		LIST_FOREACH(e, htbl, te_entry.hashq) {
 			if (e->te_mask != mask) {
@@ -446,7 +446,7 @@ npf_table_rem_cidr(npf_tableset_t *tset,
 		break;
 	case NPF_TABLE_TREE:
 		/* Key: (address & mask). */
-		npf_calculate_masked_addr(&val, addr, mask);
+		npf_addr_mask(addr, mask, &val);
 		e = rb_tree_find_node(&t->t_rbtree, &val);
 		if (__predict_true(e != NULL)) {
 			rb_tree_remove_node(&t->t_rbtree, e);
@@ -486,20 +486,23 @@ npf_table_match_addr(npf_tableset_t *tse
 	case NPF_TABLE_HASH:
 		htbl = table_hash_bucket(t, addr, sizeof(npf_addr_t));
 		LIST_FOREACH(e, htbl, te_entry.hashq) {
-			if (npf_compare_cidr(addr, e->te_mask, &e->te_addr,
+			if (npf_addr_cmp(addr, e->te_mask, &e->te_addr,
 			    NPF_NO_NETMASK) == 0)
 				break;
 		}
 		break;
 	case NPF_TABLE_TREE:
 		e = rb_tree_find_node(&t->t_rbtree, addr);
-		KASSERT(e && npf_compare_cidr(addr, e->te_mask, &e->te_addr,
-		    NPF_NO_NETMASK) == 0);
 		break;
 	default:
 		KASSERT(false);
 	}
 	npf_table_put(t);
 
-	return e ? 0 : ENOENT;
+	if (e == NULL) {
+		return ENOENT;
+	}
+	KASSERT(npf_addr_cmp(addr, e->te_mask, &e->te_addr,
+	    NPF_NO_NETMASK) == 0);
+	return 0;
 }

Index: src/sys/net/npf/npf.h
diff -u src/sys/net/npf/npf.h:1.16 src/sys/net/npf/npf.h:1.17
--- src/sys/net/npf/npf.h:1.16	Sat Apr 14 19:01:21 2012
+++ src/sys/net/npf/npf.h	Fri Jun 22 13:43:17 2012
@@ -1,7 +1,7 @@
-/*	$NetBSD: npf.h,v 1.16 2012/04/14 19:01:21 rmind Exp $	*/
+/*	$NetBSD: npf.h,v 1.17 2012/06/22 13:43:17 rmind 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
@@ -110,72 +110,6 @@ typedef struct {
 	} npc_l4;
 } npf_cache_t;
 
-static inline void
-npf_generate_mask(npf_addr_t *dst, const npf_netmask_t omask)
-{
-	uint_fast8_t length = omask;
-
-	/* Note: maximum length is 32 for IPv4 and 128 for IPv6. */
-	KASSERT(length <= NPF_MAX_NETMASK);
-
-	for (int i = 0; i < 4; i++) {
-		if (length >= 32) {
-			dst->s6_addr32[i] = htonl(0xffffffff);
-			length -= 32;
-		} else {
-			dst->s6_addr32[i] = htonl(0xffffffff << (32 - length));
-			length = 0;
-		}
-	}
-}
-
-static inline void
-npf_calculate_masked_addr(npf_addr_t *dst, const npf_addr_t *src,
-    const npf_netmask_t omask)
-{
-	npf_addr_t mask;
-
-	npf_generate_mask(&mask, omask);
-	for (int i = 0; i < 4; i++) {
-		dst->s6_addr32[i] = src->s6_addr32[i] & mask.s6_addr32[i];
-	}
-}
-
-/*
- * npf_compare_cidr: compare two addresses, either IPv4 or IPv6.
- *
- * => If the mask is NULL, ignore it.
- */
-static inline int
-npf_compare_cidr(const npf_addr_t *addr1, const npf_netmask_t mask1,
-    const npf_addr_t *addr2, const npf_netmask_t mask2)
-{
-	npf_addr_t realmask1, realmask2;
-
-	if (mask1 != NPF_NO_NETMASK) {
-		npf_generate_mask(&realmask1, mask1);
-	}
-	if (mask2 != NPF_NO_NETMASK) {
-		npf_generate_mask(&realmask2, mask2);
-	}
-	for (int i = 0; i < 4; i++) {
-		const uint32_t x = mask1 != NPF_NO_NETMASK ?
-		    addr1->s6_addr32[i] & realmask1.s6_addr32[i] :
-		    addr1->s6_addr32[i];
-		const uint32_t y = mask2 != NPF_NO_NETMASK ?
-		    addr2->s6_addr32[i] & realmask2.s6_addr32[i] :
-		    addr2->s6_addr32[i];
-		if (x < y) {
-			return -1;
-		}
-		if (x > y) {
-			return 1;
-		}
-	}
-
-	return 0;
-}
-
 static inline bool
 npf_iscached(const npf_cache_t *npc, const int inf)
 {

Index: src/sys/net/npf/npf_alg.c
diff -u src/sys/net/npf/npf_alg.c:1.3 src/sys/net/npf/npf_alg.c:1.4
--- src/sys/net/npf/npf_alg.c:1.3	Mon Feb 20 00:18:19 2012
+++ src/sys/net/npf/npf_alg.c	Fri Jun 22 13:43:17 2012
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_alg.c,v 1.3 2012/02/20 00:18:19 rmind Exp $	*/
+/*	$NetBSD: npf_alg.c,v 1.4 2012/06/22 13:43:17 rmind Exp $	*/
 
 /*-
  * Copyright (c) 2010 The NetBSD Foundation, Inc.
@@ -31,16 +31,17 @@
 
 /*
  * NPF interface for application level gateways (ALGs).
- *
- * XXX: locking
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_alg.c,v 1.3 2012/02/20 00:18:19 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_alg.c,v 1.4 2012/06/22 13:43:17 rmind Exp $");
 
 #include <sys/param.h>
+#include <sys/types.h>
+
 #include <sys/kmem.h>
-#include <sys/pool.h>
+#include <sys/pserialize.h>
+#include <sys/mutex.h>
 #include <net/pfil.h>
 
 #include "npf_impl.h"
@@ -55,12 +56,16 @@ struct npf_alg {
 	npf_algfunc_t			na_seid_func;
 };
 
-static LIST_HEAD(, npf_alg)		nat_alg_list	__read_mostly;
+static LIST_HEAD(, npf_alg)		nat_alg_list	__cacheline_aligned;
+static kmutex_t				nat_alg_lock	__cacheline_aligned;
+static pserialize_t			nat_alg_psz	__cacheline_aligned;
 
 void
 npf_alg_sysinit(void)
 {
 
+	mutex_init(&nat_alg_lock, MUTEX_DEFAULT, IPL_NONE);
+	nat_alg_psz = pserialize_create();
 	LIST_INIT(&nat_alg_list);
 }
 
@@ -69,6 +74,8 @@ npf_alg_sysfini(void)
 {
 
 	KASSERT(LIST_EMPTY(&nat_alg_list));
+	pserialize_destroy(nat_alg_psz);
+	mutex_destroy(&nat_alg_lock);
 }
 
 /*
@@ -88,7 +95,11 @@ npf_alg_register(npf_algfunc_t match, np
 	alg->na_out_func = out;
 	alg->na_in_func = in;
 	alg->na_seid_func = seid;
+
+	mutex_enter(&nat_alg_lock);
 	LIST_INSERT_HEAD(&nat_alg_list, alg, na_entry);
+	mutex_exit(&nat_alg_lock);
+
 	return alg;
 }
 
@@ -98,17 +109,15 @@ npf_alg_register(npf_algfunc_t match, np
 int
 npf_alg_unregister(npf_alg_t *alg)
 {
-	npf_alg_t *it;
 
-	LIST_FOREACH(it, &nat_alg_list, na_entry) {
-		if (alg == it)
-			break;
-	}
-	if (it != NULL) {
-		LIST_REMOVE(alg, na_entry);
-	}
-	/* TODO: Flush relevant sessions. */
+	mutex_enter(&nat_alg_lock);
+	LIST_REMOVE(alg, na_entry);
+	pserialize_perform(nat_alg_psz);
+	mutex_exit(&nat_alg_lock);
+
+	npf_nat_freealg(alg);
 	kmem_free(alg, sizeof(npf_alg_t));
+
 	return 0;
 }
 
@@ -119,15 +128,20 @@ bool
 npf_alg_match(npf_cache_t *npc, nbuf_t *nbuf, npf_nat_t *nt)
 {
 	npf_alg_t *alg;
-	npf_algfunc_t func;
+	bool match = false;
+	int s;
 
+	s = pserialize_read_enter();
 	LIST_FOREACH(alg, &nat_alg_list, na_entry) {
-		func = alg->na_match_func;
+		npf_algfunc_t func = alg->na_match_func;
+
 		if (func && func(npc, nbuf, nt)) {
-			return true;
+			match = true;
+			break;
 		}
 	}
-	return false;
+	pserialize_read_exit(s);
+	return match;
 }
 
 /*
@@ -137,7 +151,9 @@ void
 npf_alg_exec(npf_cache_t *npc, nbuf_t *nbuf, npf_nat_t *nt, const int di)
 {
 	npf_alg_t *alg;
+	int s;
 
+	s = pserialize_read_enter();
 	LIST_FOREACH(alg, &nat_alg_list, na_entry) {
 		if ((di & PFIL_OUT) != 0 && alg->na_out_func != NULL) {
 			(alg->na_out_func)(npc, nbuf, nt);
@@ -148,19 +164,25 @@ npf_alg_exec(npf_cache_t *npc, nbuf_t *n
 			continue;
 		}
 	}
+	pserialize_read_exit(s);
 }
 
 bool
 npf_alg_sessionid(npf_cache_t *npc, nbuf_t *nbuf, npf_cache_t *key)
 {
 	npf_alg_t *alg;
-	npf_algfunc_t func;
+	bool nkey = false;
+	int s;
 
+	s = pserialize_read_enter();
 	LIST_FOREACH(alg, &nat_alg_list, na_entry) {
-		func = alg->na_seid_func;
+		npf_algfunc_t func = alg->na_seid_func;
+
 		if (func && func(npc, nbuf, (npf_nat_t *)key)) {
-			return true;
+			nkey = true;
+			break;
 		}
 	}
-	return false;
+	pserialize_read_exit(s);
+	return nkey;
 }
Index: src/sys/net/npf/npf_log.c
diff -u src/sys/net/npf/npf_log.c:1.3 src/sys/net/npf/npf_log.c:1.4
--- src/sys/net/npf/npf_log.c:1.3	Mon Feb 20 00:18:20 2012
+++ src/sys/net/npf/npf_log.c	Fri Jun 22 13:43:17 2012
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_log.c,v 1.3 2012/02/20 00:18:20 rmind Exp $	*/
+/*	$NetBSD: npf_log.c,v 1.4 2012/06/22 13:43:17 rmind Exp $	*/
 
 /*-
  * Copyright (c) 2010-2011 The NetBSD Foundation, Inc.
@@ -34,7 +34,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_log.c,v 1.3 2012/02/20 00:18:20 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_log.c,v 1.4 2012/06/22 13:43:17 rmind Exp $");
 
 #include <sys/param.h>
 #include <sys/types.h>
@@ -58,7 +58,7 @@ typedef struct npflog_softc {
 	int				sc_unit;
 } npflog_softc_t;
 
-static int	npflog_clone_create(struct if_clone *, int );
+static int	npflog_clone_create(struct if_clone *, int);
 static int	npflog_clone_destroy(ifnet_t *);
 
 static LIST_HEAD(, npflog_softc)	npflog_if_list	__cacheline_aligned;
@@ -120,11 +120,13 @@ npflog_clone_create(struct if_clone *ifc
 	ifp->if_dlt = DLT_NULL;
 	ifp->if_ioctl = npflog_ioctl;
 
+	KERNEL_LOCK(1, NULL);
 	if_attach(ifp);
 	if_alloc_sadl(ifp);
 	bpf_attach(ifp, DLT_NULL, 0);
-
 	LIST_INSERT_HEAD(&npflog_if_list, sc, sc_entry);
+	KERNEL_UNLOCK_ONE(NULL);
+
 	return 0;
 }
 
@@ -133,9 +135,12 @@ npflog_clone_destroy(ifnet_t *ifp)
 {
 	npflog_softc_t *sc = ifp->if_softc;
 
+	KERNEL_LOCK(1, NULL);
 	LIST_REMOVE(sc, sc_entry);
 	bpf_detach(ifp);
 	if_detach(ifp);
+	KERNEL_UNLOCK_ONE(NULL);
+
 	mutex_destroy(&sc->sc_lock);
 	kmem_free(sc, sizeof(npflog_softc_t));
 	return 0;
@@ -148,13 +153,6 @@ npf_log_packet(npf_cache_t *npc, nbuf_t 
 	ifnet_t *ifp;
 	int family;
 
-	/* Find a pseudo-interface to log. */
-	ifp = if_byindex(if_idx);
-	if (ifp == NULL) {
-		/* No interface. */
-		return;
-	}
-
 	/* Set the address family. */
 	if (npf_iscached(npc, NPC_IP4)) {
 		family = AF_INET;
@@ -164,8 +162,17 @@ npf_log_packet(npf_cache_t *npc, nbuf_t 
 		family = AF_UNSPEC;
 	}
 
-	/* Pass through BPF. */
 	KERNEL_LOCK(1, NULL);
+
+	/* Find a pseudo-interface to log. */
+	ifp = if_byindex(if_idx);
+	if (ifp == NULL) {
+		/* No interface. */
+		KERNEL_UNLOCK_ONE(NULL);
+		return;
+	}
+
+	/* Pass through BPF. */
 	ifp->if_opackets++;
 	ifp->if_obytes += m->m_pkthdr.len;
 	bpf_mtap_af(ifp, family, m);

Index: src/sys/net/npf/npf_impl.h
diff -u src/sys/net/npf/npf_impl.h:1.15 src/sys/net/npf/npf_impl.h:1.16
--- src/sys/net/npf/npf_impl.h:1.15	Wed May 30 21:38:03 2012
+++ src/sys/net/npf/npf_impl.h	Fri Jun 22 13:43:17 2012
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_impl.h,v 1.15 2012/05/30 21:38:03 rmind Exp $	*/
+/*	$NetBSD: npf_impl.h,v 1.16 2012/06/22 13:43:17 rmind Exp $	*/
 
 /*-
  * Copyright (c) 2009-2012 The NetBSD Foundation, Inc.
@@ -177,7 +177,13 @@ uint16_t	npf_fixup16_cksum(uint16_t, uin
 uint16_t	npf_fixup32_cksum(uint16_t, uint32_t, uint32_t);
 uint16_t	npf_addr_cksum(uint16_t, int, npf_addr_t *, npf_addr_t *);
 uint32_t	npf_addr_sum(const int, const npf_addr_t *, const npf_addr_t *);
-int		npf_tcpsaw(npf_cache_t *, tcp_seq *, tcp_seq *, uint32_t *);
+int		npf_addr_cmp(const npf_addr_t *, const npf_netmask_t,
+		    const npf_addr_t *, const npf_netmask_t);
+void		npf_addr_mask(const npf_addr_t *, const npf_netmask_t,
+		    npf_addr_t *);
+
+int		npf_tcpsaw(const npf_cache_t *, tcp_seq *, tcp_seq *,
+		    uint32_t *);
 bool		npf_fetch_tcpopts(const npf_cache_t *, nbuf_t *,
 		    uint16_t *, int *);
 bool		npf_normalize(npf_cache_t *, nbuf_t *, bool, bool, u_int, u_int);
@@ -291,6 +297,7 @@ void		npf_nat_expire(npf_nat_t *);
 void		npf_nat_getorig(npf_nat_t *, npf_addr_t **, in_port_t *);
 void		npf_nat_gettrans(npf_nat_t *, npf_addr_t **, in_port_t *);
 void		npf_nat_setalg(npf_nat_t *, npf_alg_t *, uintptr_t);
+void		npf_nat_freealg(npf_alg_t *);
 
 int		npf_nat_save(prop_dictionary_t, prop_array_t, npf_nat_t *);
 npf_nat_t *	npf_nat_restore(prop_dictionary_t, npf_session_t *);

Index: src/sys/net/npf/npf_inet.c
diff -u src/sys/net/npf/npf_inet.c:1.11 src/sys/net/npf/npf_inet.c:1.12
--- src/sys/net/npf/npf_inet.c:1.11	Mon Feb 20 00:18:19 2012
+++ src/sys/net/npf/npf_inet.c	Fri Jun 22 13:43:17 2012
@@ -1,7 +1,7 @@
-/*	$NetBSD: npf_inet.c,v 1.11 2012/02/20 00:18:19 rmind Exp $	*/
+/*	$NetBSD: npf_inet.c,v 1.12 2012/06/22 13:43:17 rmind 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
@@ -31,10 +31,15 @@
 
 /*
  * Various procotol related helper routines.
+ *
+ * This layer manipulates npf_cache_t structure i.e. caches requested headers
+ * and stores which information was cached in the information bit field.
+ * It is also responsibility of this layer to update or invalidate the cache
+ * on rewrites (e.g. by translation routines).
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_inet.c,v 1.11 2012/02/20 00:18:19 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_inet.c,v 1.12 2012/06/22 13:43:17 rmind Exp $");
 
 #include <sys/param.h>
 #include <sys/types.h>
@@ -121,14 +126,86 @@ npf_addr_sum(const int sz, const npf_add
 	return mix;
 }
 
+static inline void
+npf_generate_mask(npf_addr_t *out, const npf_netmask_t mask)
+{
+	uint_fast8_t length = mask;
+
+	/* Note: maximum length is 32 for IPv4 and 128 for IPv6. */
+	KASSERT(length <= NPF_MAX_NETMASK);
+
+	for (int i = 0; i < 4; i++) {
+		if (length >= 32) {
+			out->s6_addr32[i] = htonl(0xffffffff);
+			length -= 32;
+		} else {
+			out->s6_addr32[i] = htonl(0xffffffff << (32 - length));
+			length = 0;
+		}
+	}
+}
+
+/*
+ * npf_addr_mask: apply the mask to a given address and store the result.
+ */
+void
+npf_addr_mask(const npf_addr_t *addr, const npf_netmask_t mask, npf_addr_t *out)
+{
+	npf_addr_t realmask;
+
+	npf_generate_mask(&realmask, mask);
+
+	for (int i = 0; i < 4; i++) {
+		out->s6_addr32[i] = addr->s6_addr32[i] & realmask.s6_addr32[i];
+	}
+}
+
+/*
+ * npf_addr_cmp: compare two addresses, either IPv4 or IPv6.
+ *
+ * => Ignore the mask, if NPF_NO_NETMASK is specified.
+ * => Return 0 if equal and -1 or 1 if less or greater accordingly.
+ */
+int
+npf_addr_cmp(const npf_addr_t *addr1, const npf_netmask_t mask1,
+    const npf_addr_t *addr2, const npf_netmask_t mask2)
+{
+	npf_addr_t realmask1, realmask2;
+
+	if (mask1 != NPF_NO_NETMASK) {
+		npf_generate_mask(&realmask1, mask1);
+	}
+	if (mask2 != NPF_NO_NETMASK) {
+		npf_generate_mask(&realmask2, mask2);
+	}
+
+	for (int i = 0; i < 4; i++) {
+		const uint32_t x = mask1 != NPF_NO_NETMASK ?
+		    addr1->s6_addr32[i] & realmask1.s6_addr32[i] :
+		    addr1->s6_addr32[i];
+		const uint32_t y = mask2 != NPF_NO_NETMASK ?
+		    addr2->s6_addr32[i] & realmask2.s6_addr32[i] :
+		    addr2->s6_addr32[i];
+		if (x < y) {
+			return -1;
+		}
+		if (x > y) {
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
 /*
  * npf_tcpsaw: helper to fetch SEQ, ACK, WIN and return TCP data length.
- * Returns all values in host byte-order.
+ *
+ * => Returns all values in host byte-order.
  */
 int
-npf_tcpsaw(npf_cache_t *npc, tcp_seq *seq, tcp_seq *ack, uint32_t *win)
+npf_tcpsaw(const npf_cache_t *npc, tcp_seq *seq, tcp_seq *ack, uint32_t *win)
 {
-	struct tcphdr *th = &npc->npc_l4.tcp;
+	const struct tcphdr *th = &npc->npc_l4.tcp;
 	u_int thlen;
 
 	KASSERT(npf_iscached(npc, NPC_TCP));
@@ -139,11 +216,10 @@ npf_tcpsaw(npf_cache_t *npc, tcp_seq *se
 	thlen = th->th_off << 2;
 
 	if (npf_iscached(npc, NPC_IP4)) {
-		struct ip *ip = &npc->npc_ip.v4;
+		const struct ip *ip = &npc->npc_ip.v4;
 		return ntohs(ip->ip_len) - npf_cache_hlen(npc) - thlen;
-	} else {
-		KASSERT(npf_iscached(npc, NPC_IP6));
-		struct ip6_hdr *ip6 = &npc->npc_ip.v6;
+	} else if (npf_iscached(npc, NPC_IP6)) {
+		const struct ip6_hdr *ip6 = &npc->npc_ip.v6;
 		return ntohs(ip6->ip6_plen) - thlen;
 	}
 	return 0;
@@ -179,6 +255,7 @@ next:
 	if (nbuf_advfetch(&nbuf, &n_ptr, step, sizeof(val), &val)) {
 		return false;
 	}
+
 	switch (val) {
 	case TCPOPT_EOL:
 		/* Done. */
@@ -225,6 +302,7 @@ next:
 		topts_len -= val;
 		step = val - 1;
 	}
+
 	/* Any options left? */
 	if (__predict_true(topts_len > 0)) {
 		goto next;
@@ -238,21 +316,21 @@ next:
 bool
 npf_fetch_ip(npf_cache_t *npc, nbuf_t *nbuf, void *n_ptr)
 {
-	struct ip *ip;
-	struct ip6_hdr *ip6;
 	uint8_t ver;
 
 	if (nbuf_fetch_datum(nbuf, n_ptr, sizeof(uint8_t), &ver)) {
 		return false;
 	}
+
 	switch (ver >> 4) {
-	case IPVERSION:
-		/* IPv4 */
-		ip = &npc->npc_ip.v4;
-		/* Fetch the header. */
+	case IPVERSION: {
+		struct ip *ip = &npc->npc_ip.v4;
+
+		/* Fetch IPv4 header. */
 		if (nbuf_fetch_datum(nbuf, n_ptr, sizeof(struct ip), ip)) {
 			return false;
 		}
+
 		/* Check header length and fragment offset. */
 		if ((u_int)(ip->ip_hl << 2) < sizeof(struct ip)) {
 			return false;
@@ -261,6 +339,7 @@ npf_fetch_ip(npf_cache_t *npc, nbuf_t *n
 			/* Note fragmentation. */
 			npc->npc_info |= NPC_IPFRAG;
 		}
+
 		/* Cache: layer 3 - IPv4. */
 		npc->npc_ipsz = sizeof(struct in_addr);
 		npc->npc_srcip = (npf_addr_t *)&ip->ip_src;
@@ -269,31 +348,31 @@ npf_fetch_ip(npf_cache_t *npc, nbuf_t *n
 		npc->npc_hlen = ip->ip_hl << 2;
 		npc->npc_next_proto = npc->npc_ip.v4.ip_p;
 		break;
+	}
 
-	case (IPV6_VERSION >> 4):
-		ip6 = &npc->npc_ip.v6;
+	case (IPV6_VERSION >> 4): {
+		struct ip6_hdr *ip6 = &npc->npc_ip.v6;
+		size_t toskip;
+		bool done;
+
+		/* Fetch IPv6 header. */
 		if (nbuf_fetch_datum(nbuf, n_ptr, sizeof(struct ip6_hdr), ip6)) {
 			return false;
 		}
 
-		bool done = false;
-		uint_fast8_t next_proto;
-		size_t toskip;
-
 		/* Initial next-protocol value. */
-		next_proto = ip6->ip6_nxt;
+		npc->npc_next_proto = ip6->ip6_nxt;
 		toskip = sizeof(struct ip6_hdr);
 		npc->npc_hlen = 0;
+		done = false;
 
+		/*
+		 * Advance by the length of the previous known header and
+		 * fetch by the lengh of next extension header.
+		 */
 		do {
 			struct ip6_ext ip6e;
 
-			npc->npc_next_proto = next_proto;
-
-			/*
-			 * Advance by the length of the previous known header
-			 * and fetch the next extension header's length.
-			 */
 			if (nbuf_advfetch(&nbuf, &n_ptr, toskip,
 			    sizeof(struct ip6_ext), &ip6e)) {
 				return false;
@@ -315,21 +394,28 @@ npf_fetch_ip(npf_cache_t *npc, nbuf_t *n
 				break;
 			}
 			npc->npc_hlen += toskip;
-			next_proto = ip6e.ip6e_nxt;
+			npc->npc_next_proto = ip6e.ip6e_nxt;
 
 		} while (!done);
 
+		/* Cache: layer 3 - IPv6. */
 		npc->npc_ipsz = sizeof(struct in6_addr);
 		npc->npc_srcip = (npf_addr_t *)&ip6->ip6_src;
 		npc->npc_dstip = (npf_addr_t *)&ip6->ip6_dst;
 		npc->npc_info |= NPC_IP6;
 		break;
+	}
 	default:
 		return false;
 	}
+
 	return true;
 }
 
+/*
+ * npf_fetch_tcp: fetch, check and cache TCP header.  If necessary,
+ * fetch and cache layer 3 as well.
+ */
 bool
 npf_fetch_tcp(npf_cache_t *npc, nbuf_t *nbuf, void *n_ptr)
 {
@@ -355,6 +441,10 @@ npf_fetch_tcp(npf_cache_t *npc, nbuf_t *
 	return true;
 }
 
+/*
+ * npf_fetch_udp: fetch, check and cache UDP header.  If necessary,
+ * fetch and cache layer 3 as well.
+ */
 bool
 npf_fetch_udp(npf_cache_t *npc, nbuf_t *nbuf, void *n_ptr)
 {
@@ -372,7 +462,7 @@ npf_fetch_udp(npf_cache_t *npc, nbuf_t *
 	uh = &npc->npc_l4.udp;
 	hlen = npf_cache_hlen(npc);
 
-	/* Fetch ICMP header. */
+	/* Fetch UDP header. */
 	if (nbuf_advfetch(&nbuf, &n_ptr, hlen, sizeof(struct udphdr), uh)) {
 		return false;
 	}
@@ -384,8 +474,6 @@ npf_fetch_udp(npf_cache_t *npc, nbuf_t *
 
 /*
  * npf_fetch_icmp: fetch ICMP code, type and possible query ID.
- *
- * => Stores both all fetched items into the cache.
  */
 bool
 npf_fetch_icmp(npf_cache_t *npc, nbuf_t *nbuf, void *n_ptr)
@@ -417,7 +505,7 @@ npf_fetch_icmp(npf_cache_t *npc, nbuf_t 
 
 /*
  * npf_cache_all: general routine to cache all relevant IP (v4 or v6)
- * and TCP, UDP or ICMP data.
+ * and TCP, UDP or ICMP headers.
  */
 int
 npf_cache_all(npf_cache_t *npc, nbuf_t *nbuf)

Index: src/sys/net/npf/npf_nat.c
diff -u src/sys/net/npf/npf_nat.c:1.12 src/sys/net/npf/npf_nat.c:1.13
--- src/sys/net/npf/npf_nat.c:1.12	Sun Mar 11 18:27:59 2012
+++ src/sys/net/npf/npf_nat.c	Fri Jun 22 13:43:17 2012
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_nat.c,v 1.12 2012/03/11 18:27:59 rmind Exp $	*/
+/*	$NetBSD: npf_nat.c,v 1.13 2012/06/22 13:43:17 rmind Exp $	*/
 
 /*-
  * Copyright (c) 2010-2011 The NetBSD Foundation, Inc.
@@ -76,7 +76,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_nat.c,v 1.12 2012/03/11 18:27:59 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_nat.c,v 1.13 2012/06/22 13:43:17 rmind Exp $");
 
 #include <sys/param.h>
 #include <sys/types.h>
@@ -267,6 +267,12 @@ npf_nat_freepolicy(npf_natpolicy_t *np)
 	kmem_free(np, sizeof(npf_natpolicy_t));
 }
 
+void
+npf_nat_freealg(npf_alg_t *alg)
+{
+	(void)alg; /* TODO */
+}
+
 /*
  * npf_nat_matchpolicy: compare two NAT policies.
  *
Index: src/sys/net/npf/npf_session.c
diff -u src/sys/net/npf/npf_session.c:1.12 src/sys/net/npf/npf_session.c:1.13
--- src/sys/net/npf/npf_session.c:1.12	Sun Mar 11 18:27:59 2012
+++ src/sys/net/npf/npf_session.c	Fri Jun 22 13:43:17 2012
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_session.c,v 1.12 2012/03/11 18:27:59 rmind Exp $	*/
+/*	$NetBSD: npf_session.c,v 1.13 2012/06/22 13:43:17 rmind Exp $	*/
 
 /*-
  * Copyright (c) 2010-2012 The NetBSD Foundation, Inc.
@@ -74,7 +74,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_session.c,v 1.12 2012/03/11 18:27:59 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_session.c,v 1.13 2012/06/22 13:43:17 rmind Exp $");
 
 #include <sys/param.h>
 #include <sys/types.h>
@@ -483,6 +483,7 @@ npf_session_inspect(npf_cache_t *npc, nb
 		atomic_inc_uint(&se->s_refcnt);
 	} else {
 		/* Silently block invalid packets. */
+		npf_stats_inc(NPF_STAT_INVALID_STATE);
 		*error = ENETUNREACH;
 		se = NULL;
 	}

Index: src/sys/net/npf/npf_state.c
diff -u src/sys/net/npf/npf_state.c:1.7 src/sys/net/npf/npf_state.c:1.8
--- src/sys/net/npf/npf_state.c:1.7	Wed May 30 21:38:03 2012
+++ src/sys/net/npf/npf_state.c	Fri Jun 22 13:43:17 2012
@@ -1,7 +1,7 @@
-/*	$NetBSD: npf_state.c,v 1.7 2012/05/30 21:38:03 rmind Exp $	*/
+/*	$NetBSD: npf_state.c,v 1.8 2012/06/22 13:43:17 rmind 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
@@ -34,7 +34,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_state.c,v 1.7 2012/05/30 21:38:03 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_state.c,v 1.8 2012/06/22 13:43:17 rmind Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -54,7 +54,7 @@ __KERNEL_RCSID(0, "$NetBSD: npf_state.c,
 #define	NPF_ANY_SESSION_ESTABLISHED	2
 #define	NPF_ANY_SESSION_NSTATES		3
 
-static const int npf_generic_fsm[NPF_ANY_SESSION_NSTATES][2] __read_mostly = {
+static const int npf_generic_fsm[NPF_ANY_SESSION_NSTATES][2] = {
 	[NPF_ANY_SESSION_CLOSED] = {
 		[NPF_FLOW_FORW]		= NPF_ANY_SESSION_NEW,
 	},
@@ -68,12 +68,19 @@ static const int npf_generic_fsm[NPF_ANY
 	},
 };
 
-static const u_int npf_generic_timeout[] __read_mostly = {
+static u_int npf_generic_timeout[] __read_mostly = {
 	[NPF_ANY_SESSION_CLOSED]	= 0,
 	[NPF_ANY_SESSION_NEW]		= 30,
 	[NPF_ANY_SESSION_ESTABLISHED]	= 60,
 };
 
+/*
+ * npf_state_init: initialise the state structure.
+ *
+ * Should normally be called on a first packet, which also determines the
+ * direction in a case of connection-orientated protocol.  Returns true on
+ * success and false otherwise (e.g. if protocol is not supported).
+ */
 bool
 npf_state_init(const npf_cache_t *npc, nbuf_t *nbuf, npf_state_t *nst)
 {
@@ -111,6 +118,12 @@ npf_state_destroy(npf_state_t *nst)
 	mutex_destroy(&nst->nst_lock);
 }
 
+/*
+ * npf_state_inspect: inspect the packet according to the protocol state.
+ *
+ * Return true if packet is considered to match the state (e.g. for TCP,
+ * the packet belongs to the tracked connection) and false otherwise.
+ */
 bool
 npf_state_inspect(const npf_cache_t *npc, nbuf_t *nbuf,
     npf_state_t *nst, const bool forw)
@@ -137,9 +150,6 @@ npf_state_inspect(const npf_cache_t *npc
 	NPF_TCP_STATE_SAMPLE(nst, ret);
 	mutex_exit(&nst->nst_lock);
 
-	if (__predict_false(!ret)) {
-		npf_stats_inc(NPF_STAT_INVALID_STATE);
-	}
 	return ret;
 }
 

Index: src/sys/net/npf/npf_state_tcp.c
diff -u src/sys/net/npf/npf_state_tcp.c:1.6 src/sys/net/npf/npf_state_tcp.c:1.7
--- src/sys/net/npf/npf_state_tcp.c:1.6	Tue Jun  5 22:46:54 2012
+++ src/sys/net/npf/npf_state_tcp.c	Fri Jun 22 13:43:17 2012
@@ -1,7 +1,7 @@
-/*	$NetBSD: npf_state_tcp.c,v 1.6 2012/06/05 22:46:54 rmind Exp $	*/
+/*	$NetBSD: npf_state_tcp.c,v 1.7 2012/06/22 13:43:17 rmind 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
@@ -34,7 +34,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_state_tcp.c,v 1.6 2012/06/05 22:46:54 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_state_tcp.c,v 1.7 2012/06/22 13:43:17 rmind Exp $");
 
 #include <sys/param.h>
 #include <sys/types.h>
@@ -440,6 +440,10 @@ npf_tcp_inwindow(const npf_cache_t *npc,
 	return true;
 }
 
+/*
+ * npf_state_tcp: inspect TCP segment, determine whether it belongs to
+ * the connection and track its state.
+ */
 bool
 npf_state_tcp(const npf_cache_t *npc, nbuf_t *nbuf, npf_state_t *nst, int di)
 {
@@ -447,7 +451,7 @@ npf_state_tcp(const npf_cache_t *npc, nb
 	const int tcpfl = th->th_flags, state = nst->nst_state;
 	int nstate;
 
-	KASSERT(mutex_owned(&nst->nst_lock));
+	KASSERT(nst->nst_state == 0 || mutex_owned(&nst->nst_lock));
 
 	/* Look for a transition to a new state. */
 	if (__predict_true((tcpfl & TH_RST) == 0)) {

Index: src/usr.sbin/npf/npftest/libnpftest/npf_table_test.c
diff -u src/usr.sbin/npf/npftest/libnpftest/npf_table_test.c:1.1 src/usr.sbin/npf/npftest/libnpftest/npf_table_test.c:1.2
--- src/usr.sbin/npf/npftest/libnpftest/npf_table_test.c:1.1	Sat Apr 14 21:57:29 2012
+++ src/usr.sbin/npf/npftest/libnpftest/npf_table_test.c	Fri Jun 22 13:43:17 2012
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_table_test.c,v 1.1 2012/04/14 21:57:29 rmind Exp $	*/
+/*	$NetBSD: npf_table_test.c,v 1.2 2012/06/22 13:43:17 rmind Exp $	*/
 
 /*
  * NPF tableset test.
@@ -55,6 +55,15 @@ npf_table_test(bool verbose)
 	error = npf_tableset_insert(tblset, t2);
 	assert(error == 0);
 
+	/* Attempt to match non-existing entries - should fail. */
+	addr->s6_addr32[0] = inet_addr(ip_list[0]);
+
+	error = npf_table_match_addr(tblset, HASH_TID, addr);
+	assert(error != 0);
+
+	error = npf_table_match_addr(tblset, TREE_TID, addr);
+	assert(error != 0);
+
 	/* Fill both tables with IP addresses. */
 	for (i = 0; i < __arraycount(ip_list); i++) {
 		addr->s6_addr32[0] = inet_addr(ip_list[i]);

Reply via email to