Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 12 Aug 2014 10:22:46 +0000 (UTC)
From:      Alexander V. Chernikov <melifaro@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-projects@freebsd.org
Subject:   svn commit: r269856 - projects/ipfw/sys/netpfil/ipfw
Message-ID:  <53e9eaf6.6a2b.688c09fc@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: melifaro
Date: Tue Aug 12 10:22:46 2014
New Revision: 269856
URL: http://svnweb.freebsd.org/changeset/base/269856

Log:
  No functional changes, do better functions grouping.

Modified:
  projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c

Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c
==============================================================================
--- projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c	Tue Aug 12 09:48:54 2014	(r269855)
+++ projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c	Tue Aug 12 10:22:46 2014	(r269856)
@@ -204,6 +204,14 @@ store_tei_result(struct tentry_info *tei
 	tei->flags |= flag;
 }
 
+/*
+ * Creates and references table with default parameters.
+ * Saves table config, algo and allocated kidx info @ptc, @pta and
+ * @pkidx if non-zero.
+ * Used for table auto-creation to support old binaries.
+ *
+ * Returns 0 on success.
+ */
 static int
 create_table_compat(struct ip_fw_chain *ch, struct tid_info *ti,
     struct table_config **ptc, struct table_algo **pta, uint16_t *pkidx)
@@ -212,6 +220,7 @@ create_table_compat(struct ip_fw_chain *
 	int error;
 
 	memset(&xi, 0, sizeof(xi));
+	/* Set u32 as default value type for legacy clients */
 	xi.vtype = IPFW_VTYPE_U32;
 
 	error = create_table_internal(ch, ti, NULL, &xi, ptc, pta, pkidx, 1);
@@ -1523,163 +1532,6 @@ ipfw_describe_table(struct ip_fw_chain *
 	return (0);
 }
 
-struct dump_args {
-	struct table_info *ti;
-	struct table_config *tc;
-	struct sockopt_data *sd;
-	uint32_t cnt;
-	uint16_t uidx;
-	int error;
-	ipfw_table_entry *ent;
-	uint32_t size;
-	ipfw_obj_tentry tent;
-};
-
-int
-ipfw_dump_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
-    struct sockopt_data *sd)
-{
-	int error;
-
-	switch (op3->version) {
-	case 0:
-		error = ipfw_dump_table_v0(ch, sd);
-		break;
-	case 1:
-		error = ipfw_dump_table_v1(ch, sd);
-		break;
-	default:
-		error = ENOTSUP;
-	}
-
-	return (error);
-}
-
-/*
- * Dumps all table data
- * Data layout (v1)(current):
- * Request: [ ipfw_obj_header ], size = ipfw_xtable_info.size
- * Reply: [ ipfw_obj_header ipfw_xtable_info ipfw_obj_tentry x N ]
- *
- * Returns 0 on success
- */
-static int
-ipfw_dump_table_v1(struct ip_fw_chain *ch, struct sockopt_data *sd)
-{
-	struct _ipfw_obj_header *oh;
-	ipfw_xtable_info *i;
-	struct tid_info ti;
-	struct table_config *tc;
-	struct table_algo *ta;
-	struct dump_args da;
-	uint32_t sz;
-
-	sz = sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info);
-	oh = (struct _ipfw_obj_header *)ipfw_get_sopt_header(sd, sz);
-	if (oh == NULL)
-		return (EINVAL);
-
-	i = (ipfw_xtable_info *)(oh + 1);
-	objheader_to_ti(oh, &ti);
-
-	IPFW_UH_RLOCK(ch);
-	if ((tc = find_table(CHAIN_TO_NI(ch), &ti)) == NULL) {
-		IPFW_UH_RUNLOCK(ch);
-		return (ESRCH);
-	}
-	export_table_info(ch, tc, i);
-
-	if (sd->valsize < i->size) {
-
-		/*
-		 * Submitted buffer size is not enough.
-		 * WE've already filled in @i structure with
-		 * relevant table info including size, so we
-		 * can return. Buffer will be flushed automatically.
-		 */
-		IPFW_UH_RUNLOCK(ch);
-		return (ENOMEM);
-	}
-
-	/*
-	 * Do the actual dump in eXtended format
-	 */
-	memset(&da, 0, sizeof(da));
-	da.ti = KIDX_TO_TI(ch, tc->no.kidx);
-	da.tc = tc;
-	da.sd = sd;
-
-	ta = tc->ta;
-
-	ta->foreach(tc->astate, da.ti, dump_table_tentry, &da);
-	IPFW_UH_RUNLOCK(ch);
-
-	return (da.error);
-}
-
-/*
- * Dumps all table data
- * Data layout (version 0)(legacy):
- * Request: [ ipfw_xtable ], size = IP_FW_TABLE_XGETSIZE()
- * Reply: [ ipfw_xtable ipfw_table_xentry x N ]
- *
- * Returns 0 on success
- */
-static int
-ipfw_dump_table_v0(struct ip_fw_chain *ch, struct sockopt_data *sd)
-{
-	ipfw_xtable *xtbl;
-	struct tid_info ti;
-	struct table_config *tc;
-	struct table_algo *ta;
-	struct dump_args da;
-	size_t sz;
-
-	xtbl = (ipfw_xtable *)ipfw_get_sopt_header(sd, sizeof(ipfw_xtable));
-	if (xtbl == NULL)
-		return (EINVAL);
-
-	memset(&ti, 0, sizeof(ti));
-	ti.uidx = xtbl->tbl;
-	
-	IPFW_UH_RLOCK(ch);
-	if ((tc = find_table(CHAIN_TO_NI(ch), &ti)) == NULL) {
-		IPFW_UH_RUNLOCK(ch);
-		return (0);
-	}
-	sz = tc->count * sizeof(ipfw_table_xentry) + sizeof(ipfw_xtable);
-
-	xtbl->cnt = tc->count;
-	xtbl->size = sz;
-	xtbl->type = tc->no.type;
-	xtbl->tbl = ti.uidx;
-
-	if (sd->valsize < sz) {
-
-		/*
-		 * Submitted buffer size is not enough.
-		 * WE've already filled in @i structure with
-		 * relevant table info including size, so we
-		 * can return. Buffer will be flushed automatically.
-		 */
-		IPFW_UH_RUNLOCK(ch);
-		return (ENOMEM);
-	}
-
-	/* Do the actual dump in eXtended format */
-	memset(&da, 0, sizeof(da));
-	da.ti = KIDX_TO_TI(ch, tc->no.kidx);
-	da.tc = tc;
-	da.sd = sd;
-
-	ta = tc->ta;
-
-	ta->foreach(tc->astate, da.ti, dump_table_xentry, &da);
-	IPFW_UH_RUNLOCK(ch);
-
-	return (0);
-}
-
 /*
  * Modifies existing table.
  * Data layout (v0)(current):
@@ -1927,6 +1779,41 @@ ipfw_export_table_ntlv(struct ip_fw_chai
 }
 
 /*
+ * Marks every table kidx used in @rule with bit in @bmask.
+ * Used to generate bitmask of referenced tables for given ruleset.
+ * 
+ * Returns number of newly-referenced tables.
+ */
+int
+ipfw_mark_table_kidx(struct ip_fw_chain *chain, struct ip_fw *rule,
+    uint32_t *bmask)
+{
+	int cmdlen, l, count;
+	ipfw_insn *cmd;
+	uint16_t kidx;
+	uint8_t type;
+
+	l = rule->cmd_len;
+	cmd = rule->cmd;
+	cmdlen = 0;
+	count = 0;
+	for ( ;	l > 0 ; l -= cmdlen, cmd += cmdlen) {
+		cmdlen = F_LEN(cmd);
+
+		if (classify_table_opcode(cmd, &kidx, &type) != 0)
+			continue;
+
+		if ((bmask[kidx / 32] & (1 << (kidx % 32))) == 0)
+			count++;
+
+		bmask[kidx / 32] |= 1 << (kidx % 32);
+	}
+
+	return (count);
+}
+
+
+/*
  * Exports table @tc info into standard ipfw_xtable_info format.
  */
 static void
@@ -2022,43 +1909,201 @@ export_tables(struct ip_fw_chain *ch, ip
 	return (0);
 }
 
-/*
- * Legacy IP_FW_TABLE_GETSIZE handler
- */
-int
-ipfw_count_table(struct ip_fw_chain *ch, struct tid_info *ti, uint32_t *cnt)
-{
+struct dump_args {
+	struct table_info *ti;
 	struct table_config *tc;
+	struct sockopt_data *sd;
+	uint32_t cnt;
+	uint16_t uidx;
+	int error;
+	ipfw_table_entry *ent;
+	uint32_t size;
+	ipfw_obj_tentry tent;
+};
 
-	if ((tc = find_table(CHAIN_TO_NI(ch), ti)) == NULL)
-		return (ESRCH);
-	*cnt = tc->count;
-	return (0);
-}
-
-/*
- * Legacy IP_FW_TABLE_XGETSIZE handler
- */
 int
-ipfw_count_xtable(struct ip_fw_chain *ch, struct tid_info *ti, uint32_t *cnt)
+ipfw_dump_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
+    struct sockopt_data *sd)
 {
-	struct table_config *tc;
+	int error;
 
-	if ((tc = find_table(CHAIN_TO_NI(ch), ti)) == NULL) {
-		*cnt = 0;
-		return (0); /* 'table all list' requires success */
+	switch (op3->version) {
+	case 0:
+		error = ipfw_dump_table_v0(ch, sd);
+		break;
+	case 1:
+		error = ipfw_dump_table_v1(ch, sd);
+		break;
+	default:
+		error = ENOTSUP;
 	}
-	*cnt = tc->count * sizeof(ipfw_table_xentry);
-	if (tc->count > 0)
-		*cnt += sizeof(ipfw_xtable);
-	return (0);
+
+	return (error);
 }
 
+/*
+ * Dumps all table data
+ * Data layout (v1)(current):
+ * Request: [ ipfw_obj_header ], size = ipfw_xtable_info.size
+ * Reply: [ ipfw_obj_header ipfw_xtable_info ipfw_obj_tentry x N ]
+ *
+ * Returns 0 on success
+ */
 static int
-dump_table_entry(void *e, void *arg)
+ipfw_dump_table_v1(struct ip_fw_chain *ch, struct sockopt_data *sd)
 {
-	struct dump_args *da;
-	struct table_config *tc;
+	struct _ipfw_obj_header *oh;
+	ipfw_xtable_info *i;
+	struct tid_info ti;
+	struct table_config *tc;
+	struct table_algo *ta;
+	struct dump_args da;
+	uint32_t sz;
+
+	sz = sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info);
+	oh = (struct _ipfw_obj_header *)ipfw_get_sopt_header(sd, sz);
+	if (oh == NULL)
+		return (EINVAL);
+
+	i = (ipfw_xtable_info *)(oh + 1);
+	objheader_to_ti(oh, &ti);
+
+	IPFW_UH_RLOCK(ch);
+	if ((tc = find_table(CHAIN_TO_NI(ch), &ti)) == NULL) {
+		IPFW_UH_RUNLOCK(ch);
+		return (ESRCH);
+	}
+	export_table_info(ch, tc, i);
+
+	if (sd->valsize < i->size) {
+
+		/*
+		 * Submitted buffer size is not enough.
+		 * WE've already filled in @i structure with
+		 * relevant table info including size, so we
+		 * can return. Buffer will be flushed automatically.
+		 */
+		IPFW_UH_RUNLOCK(ch);
+		return (ENOMEM);
+	}
+
+	/*
+	 * Do the actual dump in eXtended format
+	 */
+	memset(&da, 0, sizeof(da));
+	da.ti = KIDX_TO_TI(ch, tc->no.kidx);
+	da.tc = tc;
+	da.sd = sd;
+
+	ta = tc->ta;
+
+	ta->foreach(tc->astate, da.ti, dump_table_tentry, &da);
+	IPFW_UH_RUNLOCK(ch);
+
+	return (da.error);
+}
+
+/*
+ * Dumps all table data
+ * Data layout (version 0)(legacy):
+ * Request: [ ipfw_xtable ], size = IP_FW_TABLE_XGETSIZE()
+ * Reply: [ ipfw_xtable ipfw_table_xentry x N ]
+ *
+ * Returns 0 on success
+ */
+static int
+ipfw_dump_table_v0(struct ip_fw_chain *ch, struct sockopt_data *sd)
+{
+	ipfw_xtable *xtbl;
+	struct tid_info ti;
+	struct table_config *tc;
+	struct table_algo *ta;
+	struct dump_args da;
+	size_t sz;
+
+	xtbl = (ipfw_xtable *)ipfw_get_sopt_header(sd, sizeof(ipfw_xtable));
+	if (xtbl == NULL)
+		return (EINVAL);
+
+	memset(&ti, 0, sizeof(ti));
+	ti.uidx = xtbl->tbl;
+	
+	IPFW_UH_RLOCK(ch);
+	if ((tc = find_table(CHAIN_TO_NI(ch), &ti)) == NULL) {
+		IPFW_UH_RUNLOCK(ch);
+		return (0);
+	}
+	sz = tc->count * sizeof(ipfw_table_xentry) + sizeof(ipfw_xtable);
+
+	xtbl->cnt = tc->count;
+	xtbl->size = sz;
+	xtbl->type = tc->no.type;
+	xtbl->tbl = ti.uidx;
+
+	if (sd->valsize < sz) {
+
+		/*
+		 * Submitted buffer size is not enough.
+		 * WE've already filled in @i structure with
+		 * relevant table info including size, so we
+		 * can return. Buffer will be flushed automatically.
+		 */
+		IPFW_UH_RUNLOCK(ch);
+		return (ENOMEM);
+	}
+
+	/* Do the actual dump in eXtended format */
+	memset(&da, 0, sizeof(da));
+	da.ti = KIDX_TO_TI(ch, tc->no.kidx);
+	da.tc = tc;
+	da.sd = sd;
+
+	ta = tc->ta;
+
+	ta->foreach(tc->astate, da.ti, dump_table_xentry, &da);
+	IPFW_UH_RUNLOCK(ch);
+
+	return (0);
+}
+
+
+/*
+ * Legacy IP_FW_TABLE_GETSIZE handler
+ */
+int
+ipfw_count_table(struct ip_fw_chain *ch, struct tid_info *ti, uint32_t *cnt)
+{
+	struct table_config *tc;
+
+	if ((tc = find_table(CHAIN_TO_NI(ch), ti)) == NULL)
+		return (ESRCH);
+	*cnt = tc->count;
+	return (0);
+}
+
+/*
+ * Legacy IP_FW_TABLE_XGETSIZE handler
+ */
+int
+ipfw_count_xtable(struct ip_fw_chain *ch, struct tid_info *ti, uint32_t *cnt)
+{
+	struct table_config *tc;
+
+	if ((tc = find_table(CHAIN_TO_NI(ch), ti)) == NULL) {
+		*cnt = 0;
+		return (0); /* 'table all list' requires success */
+	}
+	*cnt = tc->count * sizeof(ipfw_table_xentry);
+	if (tc->count > 0)
+		*cnt += sizeof(ipfw_xtable);
+	return (0);
+}
+
+static int
+dump_table_entry(void *e, void *arg)
+{
+	struct dump_args *da;
+	struct table_config *tc;
 	struct table_algo *ta;
 	ipfw_table_entry *ent;
 	int error;
@@ -2610,11 +2655,7 @@ alloc_table_config(struct ip_fw_chain *c
 	tc->tflags = tflags;
 	tc->ta = ta;
 	strlcpy(tc->tablename, name, sizeof(tc->tablename));
-	/* Set default value type to u32 for compability reasons */
-	if (vtype == 0)
-		tc->vtype = IPFW_VTYPE_U32;
-	else
-		tc->vtype = vtype;
+	tc->vtype = vtype;
 
 	if (ti->tlvs == NULL) {
 		tc->no.compat = 1;
@@ -2707,196 +2748,67 @@ unlink_table(struct ip_fw_chain *ch, str
 		tc->ta->change_ti(tc->astate, NULL);
 }
 
+struct swap_table_args {
+	int set;
+	int new_set;
+	int mv;
+};
+
 /*
- * Finds and bumps refcount for tables referenced by given @rule.
- * Allocates new indexes for non-existing tables.
- * Fills in @oib array with userland/kernel indexes.
- * First free oidx pointer is saved back in @oib.
+ * Change set for each matching table.
  *
- * Returns 0 on success.
+ * Ensure we dispatch each table once by setting/checking ochange
+ * fields.
  */
-static int
-bind_table_rule(struct ip_fw_chain *ch, struct ip_fw *rule,
-    struct rule_check_info *ci, struct obj_idx **oib, struct tid_info *ti)
+static void
+swap_table_set(struct namedobj_instance *ni, struct named_object *no,
+    void *arg)
 {
 	struct table_config *tc;
-	struct namedobj_instance *ni;
-	struct named_object *no;
-	int cmdlen, error, l, numnew;
-	uint16_t kidx;
-	ipfw_insn *cmd;
-	struct obj_idx *pidx, *pidx_first, *p;
+	struct swap_table_args *sta;
 
-	pidx_first = *oib;
-	pidx = pidx_first;
-	l = rule->cmd_len;
-	cmd = rule->cmd;
-	cmdlen = 0;
-	error = 0;
-	numnew = 0;
+	tc = (struct table_config *)no;
+	sta = (struct swap_table_args *)arg;
 
-	IPFW_UH_WLOCK(ch);
-	ni = CHAIN_TO_NI(ch);
+	if (no->set != sta->set && (no->set != sta->new_set || sta->mv != 0))
+		return;
 
-	/*
-	 * Increase refcount on each referenced table.
-	 * Allocate table indexes for non-existing tables.
-	 */
-	for ( ;	l > 0 ; l -= cmdlen, cmd += cmdlen) {
-		cmdlen = F_LEN(cmd);
+	if (tc->ochanged != 0)
+		return;
 
-		if (classify_table_opcode(cmd, &ti->uidx, &ti->type) != 0)
-			continue;
+	tc->ochanged = 1;
+	ipfw_objhash_del(ni, no);
+	if (no->set == sta->set)
+		no->set = sta->new_set;
+	else
+		no->set = sta->set;
+	ipfw_objhash_add(ni, no);
+}
 
-		pidx->uidx = ti->uidx;
-		pidx->type = ti->type;
+/*
+ * Cleans up ochange field for all tables.
+ */
+static void
+clean_table_set_data(struct namedobj_instance *ni, struct named_object *no,
+    void *arg)
+{
+	struct table_config *tc;
+	struct swap_table_args *sta;
 
-		if ((tc = find_table(ni, ti)) != NULL) {
-			if (tc->no.type != ti->type) {
-				/* Incompatible types */
-				error = EINVAL;
-				break;
-			}
+	tc = (struct table_config *)no;
+	sta = (struct swap_table_args *)arg;
 
-			/* Reference found table and save kidx */
-			tc->no.refcnt++;
-			pidx->kidx = tc->no.kidx;
-			pidx++;
-			continue;
-		}
+	tc->ochanged = 0;
+}
 
-		/*
-		 * Compability stuff for old clients:
-		 * prepare to manually create non-existing tables.
-		 */
-		pidx++;
-		numnew++;
-	}
-
-	if (error != 0) {
-		/* Unref everything we have already done */
-		for (p = *oib; p < pidx; p++) {
-			if (p->kidx == 0)
-				continue;
-
-			/* Find & unref by existing idx */
-			no = ipfw_objhash_lookup_kidx(ni, p->kidx);
-			KASSERT(no != NULL, ("Ref'd table %d disappeared",
-			    p->kidx));
-
-			no->refcnt--;
-		}
-	}
-
-	IPFW_UH_WUNLOCK(ch);
-
-	if (numnew == 0) {
-		*oib = pidx;
-		return (error);
-	}
-
-	/*
-	 * Compatibility stuff: do actual creation for non-existing,
-	 * but referenced tables.
-	 */
-	for (p = pidx_first; p < pidx; p++) {
-		if (p->kidx != 0)
-			continue;
-
-		ti->uidx = p->uidx;
-		ti->type = p->type;
-		ti->atype = 0;
-
-		error = create_table_compat(ch, ti, NULL, NULL, &kidx);
-		if (error == 0) {
-			p->kidx = kidx;
-			continue;
-		}
-
-		/* Error. We have to drop references */
-		IPFW_UH_WLOCK(ch);
-		for (p = pidx_first; p < pidx; p++) {
-			if (p->kidx == 0)
-				continue;
-
-			/* Find & unref by existing idx */
-			no = ipfw_objhash_lookup_kidx(ni, p->kidx);
-			KASSERT(no != NULL, ("Ref'd table %d disappeared",
-			    p->kidx));
-
-			no->refcnt--;
-		}
-		IPFW_UH_WUNLOCK(ch);
-
-		return (error);
-	}
-
-	*oib = pidx;
-
-	return (error);
-}
-
-struct swap_table_args {
-	int set;
-	int new_set;
-	int mv;
-};
-
-/*
- * Change set for each matching table.
- *
- * Ensure we dispatch each table once by setting/checking ochange
- * fields.
- */
-static void
-swap_table_set(struct namedobj_instance *ni, struct named_object *no,
-    void *arg)
-{
-	struct table_config *tc;
-	struct swap_table_args *sta;
-
-	tc = (struct table_config *)no;
-	sta = (struct swap_table_args *)arg;
-
-	if (no->set != sta->set && (no->set != sta->new_set || sta->mv != 0))
-		return;
-
-	if (tc->ochanged != 0)
-		return;
-
-	tc->ochanged = 1;
-	ipfw_objhash_del(ni, no);
-	if (no->set == sta->set)
-		no->set = sta->new_set;
-	else
-		no->set = sta->set;
-	ipfw_objhash_add(ni, no);
-}
-
-/*
- * Cleans up ochange field for all tables.
- */
-static void
-clean_table_set_data(struct namedobj_instance *ni, struct named_object *no,
-    void *arg)
-{
-	struct table_config *tc;
-	struct swap_table_args *sta;
-
-	tc = (struct table_config *)no;
-	sta = (struct swap_table_args *)arg;
-
-	tc->ochanged = 0;
-}
-
-/*
- * Swaps tables within two sets.
- */
-void
-ipfw_swap_tables_sets(struct ip_fw_chain *ch, uint32_t set,
-    uint32_t new_set, int mv)
-{
-	struct swap_table_args sta;
+/*
+ * Swaps tables within two sets.
+ */
+void
+ipfw_swap_tables_sets(struct ip_fw_chain *ch, uint32_t set,
+    uint32_t new_set, int mv)
+{
+	struct swap_table_args sta;
 
 	IPFW_UH_WLOCK_ASSERT(ch);
 
@@ -3026,6 +2938,172 @@ ipfw_move_tables_sets(struct ip_fw_chain
 }
 
 /*
+ * Finds and bumps refcount for tables referenced by given @rule.
+ * Allocates new indexes for non-existing tables.
+ * Fills in @oib array with userland/kernel indexes.
+ * First free oidx pointer is saved back in @oib.
+ *
+ * Returns 0 on success.
+ */
+static int
+bind_table_rule(struct ip_fw_chain *ch, struct ip_fw *rule,
+    struct rule_check_info *ci, struct obj_idx **oib, struct tid_info *ti)
+{
+	struct table_config *tc;
+	struct namedobj_instance *ni;
+	struct named_object *no;
+	int cmdlen, error, l, numnew;
+	uint16_t kidx;
+	ipfw_insn *cmd;
+	struct obj_idx *pidx, *pidx_first, *p;
+
+	pidx_first = *oib;
+	pidx = pidx_first;
+	l = rule->cmd_len;
+	cmd = rule->cmd;
+	cmdlen = 0;
+	error = 0;
+	numnew = 0;
+
+	IPFW_UH_WLOCK(ch);
+	ni = CHAIN_TO_NI(ch);
+
+	/*
+	 * Increase refcount on each referenced table.
+	 * Allocate table indexes for non-existing tables.
+	 */
+	for ( ;	l > 0 ; l -= cmdlen, cmd += cmdlen) {
+		cmdlen = F_LEN(cmd);
+
+		if (classify_table_opcode(cmd, &ti->uidx, &ti->type) != 0)
+			continue;
+
+		pidx->uidx = ti->uidx;
+		pidx->type = ti->type;
+
+		if ((tc = find_table(ni, ti)) != NULL) {
+			if (tc->no.type != ti->type) {
+				/* Incompatible types */
+				error = EINVAL;
+				break;
+			}
+
+			/* Reference found table and save kidx */
+			tc->no.refcnt++;
+			pidx->kidx = tc->no.kidx;
+			pidx++;
+			continue;
+		}
+
+		/*
+		 * Compability stuff for old clients:
+		 * prepare to manually create non-existing tables.
+		 */
+		pidx++;
+		numnew++;
+	}
+
+	if (error != 0) {
+		/* Unref everything we have already done */
+		for (p = *oib; p < pidx; p++) {
+			if (p->kidx == 0)
+				continue;
+
+			/* Find & unref by existing idx */
+			no = ipfw_objhash_lookup_kidx(ni, p->kidx);
+			KASSERT(no != NULL, ("Ref'd table %d disappeared",
+			    p->kidx));
+
+			no->refcnt--;
+		}
+	}
+
+	IPFW_UH_WUNLOCK(ch);
+
+	if (numnew == 0) {
+		*oib = pidx;
+		return (error);
+	}
+
+	/*
+	 * Compatibility stuff: do actual creation for non-existing,
+	 * but referenced tables.
+	 */
+	for (p = pidx_first; p < pidx; p++) {
+		if (p->kidx != 0)
+			continue;
+
+		ti->uidx = p->uidx;
+		ti->type = p->type;
+		ti->atype = 0;
+
+		error = create_table_compat(ch, ti, NULL, NULL, &kidx);
+		if (error == 0) {
+			p->kidx = kidx;
+			continue;
+		}
+
+		/* Error. We have to drop references */
+		IPFW_UH_WLOCK(ch);
+		for (p = pidx_first; p < pidx; p++) {
+			if (p->kidx == 0)
+				continue;
+
+			/* Find & unref by existing idx */
+			no = ipfw_objhash_lookup_kidx(ni, p->kidx);
+			KASSERT(no != NULL, ("Ref'd table %d disappeared",
+			    p->kidx));
+
+			no->refcnt--;
+		}
+		IPFW_UH_WUNLOCK(ch);
+
+		return (error);
+	}
+
+	*oib = pidx;
+
+	return (error);
+}
+
+/*
+ * Remove references from every table used in @rule.
+ */
+void
+ipfw_unbind_table_rule(struct ip_fw_chain *chain, struct ip_fw *rule)
+{
+	int cmdlen, l;
+	ipfw_insn *cmd;
+	struct namedobj_instance *ni;
+	struct named_object *no;
+	uint16_t kidx;
+	uint8_t type;
+
+	IPFW_UH_WLOCK_ASSERT(chain);
+	ni = CHAIN_TO_NI(chain);
+
+	l = rule->cmd_len;
+	cmd = rule->cmd;
+	cmdlen = 0;
+	for ( ;	l > 0 ; l -= cmdlen, cmd += cmdlen) {
+		cmdlen = F_LEN(cmd);
+
+		if (classify_table_opcode(cmd, &kidx, &type) != 0)
+			continue;
+
+		no = ipfw_objhash_lookup_kidx(ni, kidx); 
+
+		KASSERT(no != NULL, ("table id %d not found", kidx));
+		KASSERT(no->type == type, ("wrong type %d (%d) for table id %d",
+		    no->type, type, kidx));
+		KASSERT(no->refcnt > 0, ("refcount for table %d is %d",
+		    kidx, no->refcnt));
+
+		no->refcnt--;
+	}
+}
+
+/*
  * Compatibility function for old ipfw(8) binaries.
  * Rewrites table kernel indices with userland ones.
  * Convert tables matching '/^\d+$/' to their atoi() value.
@@ -3077,40 +3155,6 @@ ipfw_rewrite_table_kidx(struct ip_fw_cha
 }
 
 /*
- * Marks every table kidx used in @rule with bit in @bmask.
- * Used to generate bitmask of referenced tables for given ruleset.
- * 
- * Returns number of newly-referenced tables.
- */
-int
-ipfw_mark_table_kidx(struct ip_fw_chain *chain, struct ip_fw *rule,
-    uint32_t *bmask)
-{
-	int cmdlen, l, count;
-	ipfw_insn *cmd;
-	uint16_t kidx;
-	uint8_t type;
-
-	l = rule->cmd_len;
-	cmd = rule->cmd;
-	cmdlen = 0;
-	count = 0;
-	for ( ;	l > 0 ; l -= cmdlen, cmd += cmdlen) {
-		cmdlen = F_LEN(cmd);
-
-		if (classify_table_opcode(cmd, &kidx, &type) != 0)
-			continue;
-
-		if ((bmask[kidx / 32] & (1 << (kidx % 32))) == 0)
-			count++;
-
-		bmask[kidx / 32] |= 1 << (kidx % 32);
-	}
-
-	return (count);
-}
-
-/*
  * Checks is opcode is referencing table of appropriate type.
  * Adds reference count for found table if true.
  * Rewrites user-supplied opcode values with kernel ones.
@@ -3186,40 +3230,4 @@ free:
 	return (error);
 }
 
-/*
- * Remove references from every table used in @rule.
- */
-void
-ipfw_unbind_table_rule(struct ip_fw_chain *chain, struct ip_fw *rule)
-{
-	int cmdlen, l;
-	ipfw_insn *cmd;
-	struct namedobj_instance *ni;
-	struct named_object *no;
-	uint16_t kidx;
-	uint8_t type;
-
-	IPFW_UH_WLOCK_ASSERT(chain);
-	ni = CHAIN_TO_NI(chain);
-
-	l = rule->cmd_len;
-	cmd = rule->cmd;
-	cmdlen = 0;
-	for ( ;	l > 0 ; l -= cmdlen, cmd += cmdlen) {
-		cmdlen = F_LEN(cmd);
-
-		if (classify_table_opcode(cmd, &kidx, &type) != 0)
-			continue;
-
-		no = ipfw_objhash_lookup_kidx(ni, kidx); 
-
-		KASSERT(no != NULL, ("table id %d not found", kidx));
-		KASSERT(no->type == type, ("wrong type %d (%d) for table id %d",
-		    no->type, type, kidx));
-		KASSERT(no->refcnt > 0, ("refcount for table %d is %d",
-		    kidx, no->refcnt));
-
-		no->refcnt--;
-	}
-}
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?53e9eaf6.6a2b.688c09fc>