Module Name:    src
Committed By:   rmind
Date:           Mon Oct 29 02:27:12 UTC 2012

Modified Files:
        src/sys/net/npf: npf.c npf.h npf_ctl.c npf_impl.h npf_tableset.c
        src/usr.sbin/npf/npfctl: npf_disassemble.c npfctl.c npfctl.h
        src/usr.sbin/npf/npftest/libnpftest: npf_table_test.c

Log Message:
Implement NPF table listing and preservation of entries on reload.
Bump the version.


To generate a diff of this commit:
cvs rdiff -u -r1.13 -r1.14 src/sys/net/npf/npf.c
cvs rdiff -u -r1.21 -r1.22 src/sys/net/npf/npf.h
cvs rdiff -u -r1.18 -r1.19 src/sys/net/npf/npf_ctl.c
cvs rdiff -u -r1.23 -r1.24 src/sys/net/npf/npf_impl.h
cvs rdiff -u -r1.14 -r1.15 src/sys/net/npf/npf_tableset.c
cvs rdiff -u -r1.9 -r1.10 src/usr.sbin/npf/npfctl/npf_disassemble.c
cvs rdiff -u -r1.20 -r1.21 src/usr.sbin/npf/npfctl/npfctl.c \
    src/usr.sbin/npf/npfctl/npfctl.h
cvs rdiff -u -r1.5 -r1.6 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.13 src/sys/net/npf/npf.c:1.14
--- src/sys/net/npf/npf.c:1.13	Sun Sep 16 13:47:41 2012
+++ src/sys/net/npf/npf.c	Mon Oct 29 02:27:11 2012
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf.c,v 1.13 2012/09/16 13:47:41 rmind Exp $	*/
+/*	$NetBSD: npf.c,v 1.14 2012/10/29 02:27:11 rmind Exp $	*/
 
 /*-
  * Copyright (c) 2009-2012 The NetBSD Foundation, Inc.
@@ -34,7 +34,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf.c,v 1.13 2012/09/16 13:47:41 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf.c,v 1.14 2012/10/29 02:27:11 rmind Exp $");
 
 #include <sys/param.h>
 #include <sys/types.h>
@@ -305,7 +305,9 @@ npf_reload(prop_dictionary_t dict, npf_r
 	rw_enter(&npf_lock, RW_WRITER);
 	onc = atomic_swap_ptr(&npf_core, nc);
 	if (onc) {
-		/* Reload only necessary NAT policies. */
+		/* Reload only the static tables. */
+		npf_tableset_reload(tset, onc->n_tables);
+		/* Reload only the necessary NAT policies. */
 		npf_ruleset_natreload(nset, onc->n_nat_rules);
 	}
 	/* Unlock.  Everything goes "live" now. */

Index: src/sys/net/npf/npf.h
diff -u src/sys/net/npf/npf.h:1.21 src/sys/net/npf/npf.h:1.22
--- src/sys/net/npf/npf.h:1.21	Sun Sep 16 13:47:41 2012
+++ src/sys/net/npf/npf.h	Mon Oct 29 02:27:11 2012
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf.h,v 1.21 2012/09/16 13:47:41 rmind Exp $	*/
+/*	$NetBSD: npf.h,v 1.22 2012/10/29 02:27:11 rmind Exp $	*/
 
 /*-
  * Copyright (c) 2009-2012 The NetBSD Foundation, Inc.
@@ -45,7 +45,7 @@
 #include <netinet/in_systm.h>
 #include <netinet/in.h>
 
-#define	NPF_VERSION		6
+#define	NPF_VERSION		7
 
 /*
  * Public declarations and definitions.
@@ -211,15 +211,29 @@ bool		npf_autounload_p(void);
  * IOCTL structures.
  */
 
+#define	NPF_IOCTL_TBLENT_LOOKUP		0
 #define	NPF_IOCTL_TBLENT_ADD		1
 #define	NPF_IOCTL_TBLENT_REM		2
+#define	NPF_IOCTL_TBLENT_LIST		3
+
+typedef struct npf_ioctl_ent {
+	int			alen;
+	npf_addr_t		addr;
+	npf_netmask_t		mask;
+} npf_ioctl_ent_t;
+
+typedef struct npf_ioctl_buf {
+	void *			buf;
+	size_t			len;
+} npf_ioctl_buf_t;
 
 typedef struct npf_ioctl_table {
 	int			nct_action;
 	u_int			nct_tid;
-	int			nct_alen;
-	npf_addr_t		nct_addr;
-	npf_netmask_t		nct_mask;
+	union {
+		npf_ioctl_ent_t	ent;
+		npf_ioctl_buf_t	buf;
+	} nct_data;
 } npf_ioctl_table_t;
 
 typedef enum {

Index: src/sys/net/npf/npf_ctl.c
diff -u src/sys/net/npf/npf_ctl.c:1.18 src/sys/net/npf/npf_ctl.c:1.19
--- src/sys/net/npf/npf_ctl.c:1.18	Sun Sep 16 13:47:41 2012
+++ src/sys/net/npf/npf_ctl.c	Mon Oct 29 02:27:12 2012
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_ctl.c,v 1.18 2012/09/16 13:47:41 rmind Exp $	*/
+/*	$NetBSD: npf_ctl.c,v 1.19 2012/10/29 02:27:12 rmind Exp $	*/
 
 /*-
  * Copyright (c) 2009-2012 The NetBSD Foundation, Inc.
@@ -37,7 +37,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_ctl.c,v 1.18 2012/09/16 13:47:41 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_ctl.c,v 1.19 2012/10/29 02:27:12 rmind Exp $");
 
 #include <sys/param.h>
 #include <sys/conf.h>
@@ -710,24 +710,33 @@ fail:
 int
 npfctl_table(void *data)
 {
-	npf_ioctl_table_t *nct = data;
+	const npf_ioctl_table_t *nct = data;
 	npf_tableset_t *tblset;
 	int error;
 
 	npf_core_enter(); /* XXXSMP */
 	tblset = npf_core_tableset();
 	switch (nct->nct_action) {
+	case NPF_IOCTL_TBLENT_LOOKUP:
+		error = npf_table_lookup(tblset, nct->nct_tid,
+		    nct->nct_data.ent.alen, &nct->nct_data.ent.addr);
 	case NPF_IOCTL_TBLENT_ADD:
 		error = npf_table_insert(tblset, nct->nct_tid,
-		    nct->nct_alen, &nct->nct_addr, nct->nct_mask);
+		    nct->nct_data.ent.alen, &nct->nct_data.ent.addr,
+		    nct->nct_data.ent.mask);
 		break;
 	case NPF_IOCTL_TBLENT_REM:
 		error = npf_table_remove(tblset, nct->nct_tid,
-		    nct->nct_alen, &nct->nct_addr, nct->nct_mask);
+		    nct->nct_data.ent.alen, &nct->nct_data.ent.addr,
+		    nct->nct_data.ent.mask);
+		break;
+	case NPF_IOCTL_TBLENT_LIST:
+		error = npf_table_list(tblset, nct->nct_tid,
+		    nct->nct_data.buf.buf, nct->nct_data.buf.len);
 		break;
 	default:
-		error = npf_table_lookup(tblset, nct->nct_tid,
-		    nct->nct_alen, &nct->nct_addr);
+		error = EINVAL;
+		break;
 	}
 	npf_core_exit(); /* XXXSMP */
 	return error;

Index: src/sys/net/npf/npf_impl.h
diff -u src/sys/net/npf/npf_impl.h:1.23 src/sys/net/npf/npf_impl.h:1.24
--- src/sys/net/npf/npf_impl.h:1.23	Sun Sep 16 13:47:41 2012
+++ src/sys/net/npf/npf_impl.h	Mon Oct 29 02:27:12 2012
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_impl.h,v 1.23 2012/09/16 13:47:41 rmind Exp $	*/
+/*	$NetBSD: npf_impl.h,v 1.24 2012/10/29 02:27:12 rmind Exp $	*/
 
 /*-
  * Copyright (c) 2009-2012 The NetBSD Foundation, Inc.
@@ -81,11 +81,9 @@ typedef struct npf_natpolicy	npf_natpoli
 typedef struct npf_session	npf_session_t;
 
 struct npf_sehash;
-struct npf_tblent;
 struct npf_table;
 
 typedef struct npf_sehash	npf_sehash_t;
-typedef struct npf_tblent	npf_tblent_t;
 typedef struct npf_table	npf_table_t;
 
 typedef npf_table_t *		npf_tableset_t;
@@ -208,15 +206,11 @@ extern const pt_tree_ops_t npf_table_ptr
 npf_tableset_t *npf_tableset_create(void);
 void		npf_tableset_destroy(npf_tableset_t *);
 int		npf_tableset_insert(npf_tableset_t *, npf_table_t *);
-npf_tableset_t *npf_tableset_reload(npf_tableset_t *);
+void		npf_tableset_reload(npf_tableset_t *, npf_tableset_t *);
 
 npf_table_t *	npf_table_create(u_int, int, size_t);
 void		npf_table_destroy(npf_table_t *);
-void		npf_table_ref(npf_table_t *);
-void		npf_table_unref(npf_table_t *);
 
-npf_table_t *	npf_table_get(npf_tableset_t *, u_int);
-void		npf_table_put(npf_table_t *);
 int		npf_table_check(const npf_tableset_t *, u_int, int);
 int		npf_table_insert(npf_tableset_t *, u_int,
 		    const int, const npf_addr_t *, const npf_netmask_t);
@@ -224,6 +218,7 @@ int		npf_table_remove(npf_tableset_t *, 
 		    const int, const npf_addr_t *, const npf_netmask_t);
 int		npf_table_lookup(npf_tableset_t *, u_int,
 		    const int, const npf_addr_t *);
+int		npf_table_list(npf_tableset_t *, u_int, void *, size_t);
 
 /* Ruleset interface. */
 npf_ruleset_t *	npf_ruleset_create(void);

Index: src/sys/net/npf/npf_tableset.c
diff -u src/sys/net/npf/npf_tableset.c:1.14 src/sys/net/npf/npf_tableset.c:1.15
--- src/sys/net/npf/npf_tableset.c:1.14	Sun Aug 12 03:35:14 2012
+++ src/sys/net/npf/npf_tableset.c	Mon Oct 29 02:27:12 2012
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_tableset.c,v 1.14 2012/08/12 03:35:14 rmind Exp $	*/
+/*	$NetBSD: npf_tableset.c,v 1.15 2012/10/29 02:27:12 rmind Exp $	*/
 
 /*-
  * Copyright (c) 2009-2012 The NetBSD Foundation, Inc.
@@ -32,13 +32,16 @@
 /*
  * NPF tableset module.
  *
- * TODO:
- * - Dynamic hash growing/shrinking (i.e. re-hash functionality), maybe?
- * - Dynamic array resize.
+ * Notes
+ *
+ *	The tableset is an array of tables.  After the creation, the array
+ *	is immutable.  The caller is responsible to synchronise the access
+ *	to the tableset.  The table can either be a hash or a tree.  Its
+ *	entries are protected by a read-write lock.
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_tableset.c,v 1.14 2012/08/12 03:35:14 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_tableset.c,v 1.15 2012/10/29 02:27:12 rmind Exp $");
 
 #include <sys/param.h>
 #include <sys/types.h>
@@ -58,14 +61,14 @@ __KERNEL_RCSID(0, "$NetBSD: npf_tableset
  * Table structures.
  */
 
-struct npf_tblent {
+typedef struct npf_tblent {
 	union {
 		LIST_ENTRY(npf_tblent) hashq;
 		pt_node_t	node;
 	} te_entry;
 	int			te_alen;
 	npf_addr_t		te_addr;
-};
+} npf_tblent_t;
 
 LIST_HEAD(npf_hashl, npf_tblent);
 
@@ -74,12 +77,15 @@ struct npf_table {
 	/* Lock and reference count. */
 	krwlock_t		t_lock;
 	u_int			t_refcnt;
+	/* Total number of items. */
+	u_int			t_nitems;
 	/* Table ID. */
 	u_int			t_id;
 	/* The storage type can be: a) hash b) tree. */
 	int			t_type;
 	struct npf_hashl *	t_hashl;
 	u_long			t_hashmask;
+	/* Separate trees for IPv4 and IPv6. */
 	pt_tree_t		t_tree[2];
 };
 
@@ -126,7 +132,7 @@ npf_tableset_destroy(npf_tableset_t *tbl
 	 */
 	for (tid = 0; tid < NPF_TABLE_SLOTS; tid++) {
 		t = tblset[tid];
-		if (t != NULL) {
+		if (t && --t->t_refcnt == 0) {
 			npf_table_destroy(t);
 		}
 	}
@@ -148,6 +154,7 @@ npf_tableset_insert(npf_tableset_t *tbls
 
 	if (tblset[tid] == NULL) {
 		tblset[tid] = t;
+		t->t_refcnt++;
 		error = 0;
 	} else {
 		error = EEXIST;
@@ -156,6 +163,30 @@ npf_tableset_insert(npf_tableset_t *tbls
 }
 
 /*
+ * npf_tableset_reload: iterate all tables and if the new table is of the
+ * same type and has no items, then we preserve the old one and its entries.
+ *
+ * => The caller is responsible for providing synchronisation.
+ */
+void
+npf_tableset_reload(npf_tableset_t *ntset, npf_tableset_t *otset)
+{
+	for (int i = 0; i < NPF_TABLE_SLOTS; i++) {
+		npf_table_t *t = ntset[i], *ot = otset[i];
+
+		if (t == NULL || ot == NULL) {
+			continue;
+		}
+		if (t->t_nitems || t->t_type != ot->t_type) {
+			continue;
+		}
+		ntset[i] = ot;
+		ot->t_refcnt++;
+		npf_table_destroy(t);
+	}
+}
+
+/*
  * Few helper routines.
  */
 
@@ -228,8 +259,8 @@ npf_table_create(u_int tid, int type, si
 	}
 	rw_init(&t->t_lock);
 	t->t_type = type;
-	t->t_refcnt = 1;
 	t->t_id = tid;
+
 	return t;
 }
 
@@ -241,7 +272,7 @@ npf_table_destroy(npf_table_t *t)
 {
 
 	switch (t->t_type) {
-	case NPF_TABLE_HASH: {
+	case NPF_TABLE_HASH:
 		for (unsigned n = 0; n <= t->t_hashmask; n++) {
 			npf_tblent_t *ent;
 
@@ -252,12 +283,10 @@ npf_table_destroy(npf_table_t *t)
 		}
 		hashdone(t->t_hashl, HASH_LIST, t->t_hashmask);
 		break;
-	}
-	case NPF_TABLE_TREE: {
+	case NPF_TABLE_TREE:
 		table_tree_destroy(&t->t_tree[0]);
 		table_tree_destroy(&t->t_tree[1]);
 		break;
-	}
 	default:
 		KASSERT(false);
 	}
@@ -266,63 +295,6 @@ npf_table_destroy(npf_table_t *t)
 }
 
 /*
- * npf_table_ref: holds the reference on table.
- *
- * => Table must be locked.
- */
-void
-npf_table_ref(npf_table_t *t)
-{
-
-	KASSERT(rw_lock_held(&t->t_lock));
-	atomic_inc_uint(&t->t_refcnt);
-}
-
-/*
- * npf_table_unref: drop reference from the table and destroy the table if
- * it is the last reference.
- */
-void
-npf_table_unref(npf_table_t *t)
-{
-
-	if (atomic_dec_uint_nv(&t->t_refcnt) != 0) {
-		return;
-	}
-	npf_table_destroy(t);
-}
-
-/*
- * npf_table_get: find the table according to ID and "get it" by locking it.
- */
-npf_table_t *
-npf_table_get(npf_tableset_t *tset, u_int tid)
-{
-	npf_table_t *t;
-
-	KASSERT(tset != NULL);
-
-	if ((u_int)tid >= NPF_TABLE_SLOTS) {
-		return NULL;
-	}
-	t = tset[tid];
-	if (t != NULL) {
-		rw_enter(&t->t_lock, RW_READER);
-	}
-	return t;
-}
-
-/*
- * npf_table_put: "put table back" by unlocking it.
- */
-void
-npf_table_put(npf_table_t *t)
-{
-
-	rw_exit(&t->t_lock);
-}
-
-/*
  * npf_table_check: validate ID and type.
  */
 int
@@ -342,7 +314,7 @@ npf_table_check(const npf_tableset_t *ts
 }
 
 static int
-npf_table_validate_cidr(const u_int aidx, const npf_addr_t *addr,
+table_cidr_check(const u_int aidx, const npf_addr_t *addr,
     const npf_netmask_t mask)
 {
 
@@ -375,7 +347,11 @@ npf_table_insert(npf_tableset_t *tset, u
 	npf_table_t *t;
 	int error;
 
-	error = npf_table_validate_cidr(aidx, addr, mask);
+	if ((u_int)tid >= NPF_TABLE_SLOTS || (t = tset[tid]) == NULL) {
+		return EINVAL;
+	}
+
+	error = table_cidr_check(aidx, addr, mask);
 	if (error) {
 		return error;
 	}
@@ -383,16 +359,10 @@ npf_table_insert(npf_tableset_t *tset, u
 	memcpy(&ent->te_addr, addr, alen);
 	ent->te_alen = alen;
 
-	/* Get the table (acquire the lock). */
-	t = npf_table_get(tset, tid);
-	if (t == NULL) {
-		pool_cache_put(tblent_cache, ent);
-		return EINVAL;
-	}
-
 	/*
 	 * Insert the entry.  Return an error on duplicate.
 	 */
+	rw_enter(&t->t_lock, RW_WRITER);
 	switch (t->t_type) {
 	case NPF_TABLE_HASH: {
 		struct npf_hashl *htbl;
@@ -406,6 +376,7 @@ npf_table_insert(npf_tableset_t *tset, u
 		}
 		if (!table_hash_lookup(t, addr, alen, &htbl)) {
 			LIST_INSERT_HEAD(htbl, ent, te_entry.hashq);
+			t->t_nitems++;
 		} else {
 			error = EEXIST;
 		}
@@ -418,18 +389,21 @@ npf_table_insert(npf_tableset_t *tset, u
 		/*
 		 * If no mask specified, use maximum mask.
 		 */
-		if (mask != NPF_NO_NETMASK) {
-			ok = ptree_insert_mask_node(tree, ent, mask);
+		ok = (mask != NPF_NO_NETMASK) ?
+		    ptree_insert_mask_node(tree, ent, mask) :
+		    ptree_insert_node(tree, ent);
+		if (ok) {
+			t->t_nitems++;
+			error = 0;
 		} else {
-			ok = ptree_insert_node(tree, ent);
+			error = EEXIST;
 		}
-		error = ok ? 0 : EEXIST;
 		break;
 	}
 	default:
 		KASSERT(false);
 	}
-	npf_table_put(t);
+	rw_exit(&t->t_lock);
 
 	if (error) {
 		pool_cache_put(tblent_cache, ent);
@@ -449,15 +423,16 @@ npf_table_remove(npf_tableset_t *tset, u
 	npf_table_t *t;
 	int error;
 
-	error = npf_table_validate_cidr(aidx, addr, mask);
+	error = table_cidr_check(aidx, addr, mask);
 	if (error) {
 		return error;
 	}
-	t = npf_table_get(tset, tid);
-	if (t == NULL) {
+
+	if ((u_int)tid >= NPF_TABLE_SLOTS || (t = tset[tid]) == NULL) {
 		return EINVAL;
 	}
 
+	rw_enter(&t->t_lock, RW_WRITER);
 	switch (t->t_type) {
 	case NPF_TABLE_HASH: {
 		struct npf_hashl *htbl;
@@ -465,6 +440,7 @@ npf_table_remove(npf_tableset_t *tset, u
 		ent = table_hash_lookup(t, addr, alen, &htbl);
 		if (__predict_true(ent != NULL)) {
 			LIST_REMOVE(ent, te_entry.hashq);
+			t->t_nitems--;
 		}
 		break;
 	}
@@ -474,6 +450,7 @@ npf_table_remove(npf_tableset_t *tset, u
 		ent = ptree_find_node(tree, addr);
 		if (__predict_true(ent != NULL)) {
 			ptree_remove_node(tree, ent);
+			t->t_nitems--;
 		}
 		break;
 	}
@@ -481,7 +458,7 @@ npf_table_remove(npf_tableset_t *tset, u
 		KASSERT(false);
 		ent = NULL;
 	}
-	npf_table_put(t);
+	rw_exit(&t->t_lock);
 
 	if (ent == NULL) {
 		return ENOENT;
@@ -506,10 +483,11 @@ npf_table_lookup(npf_tableset_t *tset, u
 		return EINVAL;
 	}
 
-	t = npf_table_get(tset, tid);
-	if (__predict_false(t == NULL)) {
+	if ((u_int)tid >= NPF_TABLE_SLOTS || (t = tset[tid]) == NULL) {
 		return EINVAL;
 	}
+
+	rw_enter(&t->t_lock, RW_READER);
 	switch (t->t_type) {
 	case NPF_TABLE_HASH: {
 		struct npf_hashl *htbl;
@@ -524,7 +502,85 @@ npf_table_lookup(npf_tableset_t *tset, u
 		KASSERT(false);
 		ent = NULL;
 	}
-	npf_table_put(t);
+	rw_exit(&t->t_lock);
 
 	return ent ? 0 : ENOENT;
 }
+
+static int
+table_ent_copyout(npf_tblent_t *ent, npf_netmask_t mask,
+    void *ubuf, size_t len, size_t *off)
+{
+	void *ubufp = (uint8_t *)ubuf + *off;
+	npf_ioctl_ent_t uent;
+
+	if ((*off += sizeof(npf_ioctl_ent_t)) > len) {
+		return ENOMEM;
+	}
+	uent.alen = ent->te_alen;
+	memcpy(&uent.addr, &ent->te_addr, sizeof(npf_addr_t));
+	uent.mask = mask;
+
+	return copyout(&uent, ubufp, sizeof(npf_ioctl_ent_t));
+}
+
+static int
+table_tree_list(pt_tree_t *tree, npf_netmask_t maxmask, void *ubuf,
+    size_t len, size_t *off)
+{
+	npf_tblent_t *ent = NULL;
+	int error = 0;
+
+	while ((ent = ptree_iterate(tree, ent, PT_ASCENDING)) != NULL) {
+		pt_bitlen_t blen;
+
+		if (!ptree_mask_node_p(tree, ent, &blen)) {
+			blen = maxmask;
+		}
+		error = table_ent_copyout(ent, blen, ubuf, len, off);
+		if (error)
+			break;
+	}
+	return error;
+}
+
+/*
+ * npf_table_list: copy a list of all table entries into a userspace buffer.
+ */
+int
+npf_table_list(npf_tableset_t *tset, u_int tid, void *ubuf, size_t len)
+{
+	npf_table_t *t;
+	size_t off = 0;
+	int error = 0;
+
+	if ((u_int)tid >= NPF_TABLE_SLOTS || (t = tset[tid]) == NULL) {
+		return EINVAL;
+	}
+
+	rw_enter(&t->t_lock, RW_READER);
+	switch (t->t_type) {
+	case NPF_TABLE_HASH:
+		for (unsigned n = 0; n <= t->t_hashmask; n++) {
+			npf_tblent_t *ent;
+
+			LIST_FOREACH(ent, &t->t_hashl[n], te_entry.hashq)
+				if ((error = table_ent_copyout(ent, 0, ubuf,
+				    len, &off)) != 0)
+					break;
+		}
+		break;
+	case NPF_TABLE_TREE:
+		error = table_tree_list(&t->t_tree[0], 32, ubuf, len, &off);
+		if (error)
+			break;
+		error = table_tree_list(&t->t_tree[1], 128, ubuf, len, &off);
+		if (error)
+			break;
+	default:
+		KASSERT(false);
+	}
+	rw_exit(&t->t_lock);
+
+	return error;
+}

Index: src/usr.sbin/npf/npfctl/npf_disassemble.c
diff -u src/usr.sbin/npf/npfctl/npf_disassemble.c:1.9 src/usr.sbin/npf/npfctl/npf_disassemble.c:1.10
--- src/usr.sbin/npf/npfctl/npf_disassemble.c:1.9	Mon Aug 13 01:18:32 2012
+++ src/usr.sbin/npf/npfctl/npf_disassemble.c	Mon Oct 29 02:27:12 2012
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_disassemble.c,v 1.9 2012/08/13 01:18:32 rmind Exp $	*/
+/*	$NetBSD: npf_disassemble.c,v 1.10 2012/10/29 02:27:12 rmind Exp $	*/
 
 /*-
  * Copyright (c) 2012 The NetBSD Foundation, Inc.
@@ -35,7 +35,7 @@
  * FIXME: config generation should be redesigned..
  */
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: npf_disassemble.c,v 1.9 2012/08/13 01:18:32 rmind Exp $");
+__RCSID("$NetBSD: npf_disassemble.c,v 1.10 2012/10/29 02:27:12 rmind Exp $");
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -664,31 +664,11 @@ npfctl_show_nat(nl_rule_t *nrl, unsigned
 	}
 	_npf_nat_getinfo(nt, &type, &flags, &taddr, &alen, &port);
 
-	struct sockaddr_storage ss;
-	char taddrbuf[64], tportbuf[16];
-
-	if (alen == 4) {
-		struct sockaddr_in *sin = (void *)&ss;
-		sin->sin_len = sizeof(*sin);
-		sin->sin_family = AF_INET;
-		sin->sin_port = 0;
-		memcpy(&sin->sin_addr, &taddr, sizeof(sin->sin_addr));
-		sockaddr_snprintf(taddrbuf, sizeof(taddrbuf),
-		    "%a", (struct sockaddr *)sin);
-	} else {
-		assert(alen == 16);
-		struct sockaddr_in6 *sin6 = (void *)&ss;
-		sin6->sin6_len = sizeof(*sin6);
-		sin6->sin6_family = AF_INET6;
-		sin6->sin6_port = 0;
-		memcpy(&sin6->sin6_addr, &taddr, sizeof(sin6->sin6_addr));
-		sockaddr_snprintf(taddrbuf, sizeof(taddrbuf),
-		    "%a", (struct sockaddr *)sin6);
-	}
+	char *taddrbuf, tportbuf[16];
 
+	taddrbuf = npfctl_print_addrmask(alen, &taddr, 0);
 	if (port) {
-		snprintf(tportbuf, sizeof(tportbuf),
-		    " port %d", ntohs(port));
+		snprintf(tportbuf, sizeof(tportbuf), " port %d", ntohs(port));
 	}
 
 	const char *seg1 = "any", *seg2 = "any", *sp1 = "", *sp2 = "", *mt;
@@ -708,6 +688,7 @@ npfctl_show_nat(nl_rule_t *nrl, unsigned
 	}
 	printf("map %s dynamic %s%s %s %s%s pass ", ifname,
 	    seg1, sp1, mt, seg2, sp2);
+	free(taddrbuf);
 
 	const void *nc;
 	size_t nclen;

Index: src/usr.sbin/npf/npfctl/npfctl.c
diff -u src/usr.sbin/npf/npfctl/npfctl.c:1.20 src/usr.sbin/npf/npfctl/npfctl.c:1.21
--- src/usr.sbin/npf/npfctl/npfctl.c:1.20	Sun Sep 16 13:47:41 2012
+++ src/usr.sbin/npf/npfctl/npfctl.c	Mon Oct 29 02:27:12 2012
@@ -1,4 +1,4 @@
-/*	$NetBSD: npfctl.c,v 1.20 2012/09/16 13:47:41 rmind Exp $	*/
+/*	$NetBSD: npfctl.c,v 1.21 2012/10/29 02:27:12 rmind Exp $	*/
 
 /*-
  * Copyright (c) 2009-2012 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: npfctl.c,v 1.20 2012/09/16 13:47:41 rmind Exp $");
+__RCSID("$NetBSD: npfctl.c,v 1.21 2012/10/29 02:27:12 rmind Exp $");
 
 #include <sys/ioctl.h>
 #include <sys/stat.h>
@@ -44,6 +44,8 @@ __RCSID("$NetBSD: npfctl.c,v 1.20 2012/0
 #include <unistd.h>
 #include <errno.h>
 
+#include <util.h>
+
 #include "npfctl.h"
 
 extern int		yylineno, yycolumn;
@@ -142,10 +144,10 @@ usage(void)
 	    "\t%s ( sess-save | sess-load )\n",
 	    progname);
 	fprintf(stderr,
-	    "\t%s table <tid> [ flush ]\n",
+	    "\t%s table <tid> { add | rem | test } <address/mask>\n",
 	    progname);
 	fprintf(stderr,
-	    "\t%s table <tid> { add | rem | test } <address/mask>\n",
+	    "\t%s table <tid> { list | flush }\n",
 	    progname);
 
 	exit(EXIT_FAILURE);
@@ -255,62 +257,136 @@ npfctl_print_error(const nl_error_t *ne)
 	}
 }
 
+char *
+npfctl_print_addrmask(int alen, npf_addr_t *addr, npf_netmask_t mask)
+{
+	struct sockaddr_storage ss;
+	char *buf = zalloc(64);
+	int len;
+
+	switch (alen) {
+	case 4: {
+		struct sockaddr_in *sin = (void *)&ss;
+		sin->sin_len = sizeof(*sin);
+		sin->sin_family = AF_INET;
+		sin->sin_port = 0;
+		memcpy(&sin->sin_addr, addr, sizeof(sin->sin_addr));
+		break;
+	}
+	case 16: {
+		struct sockaddr_in6 *sin6 = (void *)&ss;
+		sin6->sin6_len = sizeof(*sin6);
+		sin6->sin6_family = AF_INET6;
+		sin6->sin6_port = 0;
+		memcpy(&sin6->sin6_addr, addr, sizeof(sin6->sin6_addr));
+		break;
+	}
+	default:
+		assert(false);
+	}
+	len = sockaddr_snprintf(buf, 64, "%a", (struct sockaddr *)&ss);
+	if (mask) {
+		snprintf(&buf[len], 64 - len, "/%u", mask);
+	}
+	return buf;
+}
+
 __dead static void
-npfctl_table(int fd, char **argv)
+npfctl_table(int fd, int argc, char **argv)
 {
 	static const struct tblops_s {
 		const char *	cmd;
 		int		action;
 	} tblops[] = {
-		{ "add",	NPF_IOCTL_TBLENT_ADD },
-		{ "rem",	NPF_IOCTL_TBLENT_REM },
-		{ "test",	0 },
-		{ NULL,		0 }
+		{ "add",	NPF_IOCTL_TBLENT_ADD		},
+		{ "rem",	NPF_IOCTL_TBLENT_REM		},
+		{ "test",	NPF_IOCTL_TBLENT_LOOKUP		},
+		{ "list",	NPF_IOCTL_TBLENT_LIST		},
+		{ NULL,		0				}
 	};
 	npf_ioctl_table_t nct;
 	fam_addr_mask_t fam;
-	char *cmd = argv[3];
-	char *arg = argv[3];
+	size_t buflen = 512;
+	char *cmd, *arg;
 	int n, alen;
 
+	/* Default action is list. */
 	memset(&nct, 0, sizeof(npf_ioctl_table_t));
-	nct.nct_tid = atoi(argv[2]);
+	nct.nct_tid = atoi(argv[0]);
+	cmd = argv[1];
 
 	for (n = 0; tblops[n].cmd != NULL; n++) {
-		if (strcmp(cmd, tblops[n].cmd) == 0) {
-			nct.nct_action = tblops[n].action;
-			arg = argv[4];
-			break;
+		if (strcmp(cmd, tblops[n].cmd) != 0) {
+			continue;
+		}
+		nct.nct_action = tblops[n].action;
+		break;
+	}
+	if (tblops[n].cmd == NULL) {
+		errx(EXIT_FAILURE, "invalid command '%s'", cmd);
+	}
+	if (nct.nct_action != NPF_IOCTL_TBLENT_LIST) {
+		if (argc < 3) {
+			usage();
 		}
+		arg = argv[2];
 	}
-	if (!npfctl_parse_cidr(arg, &fam, &alen)) {
-		errx(EXIT_FAILURE, "invalid CIDR '%s'", arg);
+again:
+	if (nct.nct_action == NPF_IOCTL_TBLENT_LIST) {
+		nct.nct_data.buf.buf = zalloc(buflen);
+		nct.nct_data.buf.len = buflen;
+	} else {
+		if (!npfctl_parse_cidr(arg, &fam, &alen)) {
+			errx(EXIT_FAILURE, "invalid CIDR '%s'", arg);
+		}
+		nct.nct_data.ent.alen = alen;
+		memcpy(&nct.nct_data.ent.addr, &fam.fam_addr, sizeof(npf_addr_t));
+		nct.nct_data.ent.mask = fam.fam_mask;
 	}
-	memcpy(&nct.nct_addr, &fam.fam_addr, sizeof(npf_addr_t));
-	nct.nct_mask = fam.fam_mask;
-	nct.nct_alen = alen;
 
 	if (ioctl(fd, IOC_NPF_TABLE, &nct) != -1) {
 		errno = 0;
 	}
 	switch (errno) {
-	case EEXIST:
-		warnx("entry already exists or is conflicting");
+	case 0:
 		break;
+	case EEXIST:
+		errx(EXIT_FAILURE, "entry already exists or is conflicting");
 	case ENOENT:
-		warnx("no matching entry was not found");
-		break;
+		errx(EXIT_FAILURE, "no matching entry was not found");
 	case EINVAL:
-		warnx("invalid address, mask or table ID");
-		break;
-	case 0:
-		printf("%s: %s\n", getprogname(), nct.nct_action == 0 ?
-		    "matching entry found" : "success");
-		break;
+		errx(EXIT_FAILURE, "invalid address, mask or table ID");
+	case ENOMEM:
+		if (nct.nct_action == NPF_IOCTL_TBLENT_LIST) {
+			/* XXX */
+			free(nct.nct_data.buf.buf);
+			buflen <<= 1;
+			goto again;
+		}
+		/* FALLTHROUGH */
 	default:
-		warn("error");
+		err(EXIT_FAILURE, "ioctl");
+	}
+
+	if (nct.nct_action == NPF_IOCTL_TBLENT_LIST) {
+		npf_ioctl_ent_t *ent = nct.nct_data.buf.buf;
+		char *buf;
+
+		while (nct.nct_data.buf.len--) {
+			if (!ent->alen)
+				break;
+			buf = npfctl_print_addrmask(ent->alen,
+			    &ent->addr, ent->mask);
+			puts(buf);
+			ent++;
+		}
+		free(nct.nct_data.buf.buf);
+	} else {
+		printf("%s: %s\n", getprogname(),
+		    nct.nct_action == NPF_IOCTL_TBLENT_LOOKUP ?
+		    "matching entry found" : "success");
 	}
-	exit(errno ? EXIT_FAILURE : EXIT_SUCCESS);
+	exit(EXIT_SUCCESS);
 }
 
 static void
@@ -355,10 +431,11 @@ npfctl(int action, int argc, char **argv
 		ret = npf_config_flush(fd);
 		break;
 	case NPFCTL_TABLE:
-		if (argc < 5) {
+		if ((argc -= 2) < 2) {
 			usage();
 		}
-		npfctl_table(fd, argv);
+		argv += 2;
+		npfctl_table(fd, argc, argv);
 		break;
 	case NPFCTL_STATS:
 		ret = npfctl_print_stats(fd);
Index: src/usr.sbin/npf/npfctl/npfctl.h
diff -u src/usr.sbin/npf/npfctl/npfctl.h:1.20 src/usr.sbin/npf/npfctl/npfctl.h:1.21
--- src/usr.sbin/npf/npfctl/npfctl.h:1.20	Sun Sep 16 13:47:41 2012
+++ src/usr.sbin/npf/npfctl/npfctl.h	Mon Oct 29 02:27:12 2012
@@ -1,4 +1,4 @@
-/*	$NetBSD: npfctl.h,v 1.20 2012/09/16 13:47:41 rmind Exp $	*/
+/*	$NetBSD: npfctl.h,v 1.21 2012/10/29 02:27:12 rmind Exp $	*/
 
 /*-
  * Copyright (c) 2009-2012 The NetBSD Foundation, Inc.
@@ -96,6 +96,7 @@ char *		xstrdup(const char *);
 char *		xstrndup(const char *, size_t);
 
 void		npfctl_print_error(const nl_error_t *);
+char *		npfctl_print_addrmask(int, npf_addr_t *, npf_netmask_t);
 bool		npfctl_table_exists_p(const char *);
 int		npfctl_protono(const char *);
 in_port_t	npfctl_portno(const char *);

Index: src/usr.sbin/npf/npftest/libnpftest/npf_table_test.c
diff -u src/usr.sbin/npf/npftest/libnpftest/npf_table_test.c:1.5 src/usr.sbin/npf/npftest/libnpftest/npf_table_test.c:1.6
--- src/usr.sbin/npf/npftest/libnpftest/npf_table_test.c:1.5	Tue Aug 21 20:52:11 2012
+++ src/usr.sbin/npf/npftest/libnpftest/npf_table_test.c	Mon Oct 29 02:27:11 2012
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_table_test.c,v 1.5 2012/08/21 20:52:11 rmind Exp $	*/
+/*	$NetBSD: npf_table_test.c,v 1.6 2012/10/29 02:27:11 rmind Exp $	*/
 
 /*
  * NPF tableset test.
@@ -44,6 +44,32 @@ static const uint16_t ip6_list[][8] = {
 #define	HASH_TID		1
 #define	TREE_TID		2
 
+static bool
+npf_table_test_fill4(npf_tableset_t *tblset, npf_addr_t *addr)
+{
+	const int alen = sizeof(struct in_addr);
+	const int nm = NPF_NO_NETMASK;
+	bool fail = false;
+
+	/* Fill both tables with IP addresses. */
+	for (unsigned i = 0; i < __arraycount(ip_list); i++) {
+		int error;
+
+		addr->s6_addr32[0] = inet_addr(ip_list[i]);
+
+		error = npf_table_insert(tblset, HASH_TID, alen, addr, nm);
+		fail |= !(error == 0);
+		error = npf_table_insert(tblset, HASH_TID, alen, addr, nm);
+		fail |= !(error != 0);
+
+		error = npf_table_insert(tblset, TREE_TID, alen, addr, nm);
+		fail |= !(error == 0);
+		error = npf_table_insert(tblset, TREE_TID, alen, addr, nm);
+		fail |= !(error != 0);
+	}
+	return fail;
+}
+
 bool
 npf_table_test(bool verbose)
 {
@@ -55,8 +81,6 @@ npf_table_test(bool verbose)
 	bool fail = false;
 	u_int i;
 
-	npf_tableset_sysinit();
-
 	tblset = npf_tableset_create();
 	fail |= !(tblset != NULL);
 
@@ -87,19 +111,7 @@ npf_table_test(bool verbose)
 	fail |= !(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]);
-
-		error = npf_table_insert(tblset, HASH_TID, alen, addr, nm);
-		fail |= !(error == 0);
-		error = npf_table_insert(tblset, HASH_TID, alen, addr, nm);
-		fail |= !(error != 0);
-
-		error = npf_table_insert(tblset, TREE_TID, alen, addr, nm);
-		fail |= !(error == 0);
-		error = npf_table_insert(tblset, TREE_TID, alen, addr, nm);
-		fail |= !(error != 0);
-	}
+	fail |= npf_table_test_fill4(tblset, addr);
 
 	/* Attempt to add duplicates - should fail. */
 	addr->s6_addr32[0] = inet_addr(ip_list[0]);
@@ -111,15 +123,6 @@ npf_table_test(bool verbose)
 	error = npf_table_insert(tblset, TREE_TID, alen, addr, nm);
 	fail |= !(error != 0);
 
-	/* Reference checks. */
-	t1 = npf_table_get(tblset, HASH_TID);
-	fail |= !(t1 != NULL);
-	npf_table_put(t1);
-
-	t2 = npf_table_get(tblset, TREE_TID);
-	fail |= !(t2 != NULL);
-	npf_table_put(t2);
-
 	/* Match (validate) each IP entry. */
 	for (i = 0; i < __arraycount(ip_list); i++) {
 		addr->s6_addr32[0] = inet_addr(ip_list[i]);
@@ -206,7 +209,6 @@ npf_table_test(bool verbose)
 	}
 
 	npf_tableset_destroy(tblset);
-	npf_tableset_sysfini();
 
 	return !fail;
 }

Reply via email to