xref: /freebsd/sys/netpfil/ipfw/ip_fw_table.c (revision 81d3153d)
13b3a8eb9SGleb Smirnoff /*-
23b3a8eb9SGleb Smirnoff  * Copyright (c) 2004 Ruslan Ermilov and Vsevolod Lobko.
33b3a8eb9SGleb Smirnoff  *
43b3a8eb9SGleb Smirnoff  * Redistribution and use in source and binary forms, with or without
53b3a8eb9SGleb Smirnoff  * modification, are permitted provided that the following conditions
63b3a8eb9SGleb Smirnoff  * are met:
73b3a8eb9SGleb Smirnoff  * 1. Redistributions of source code must retain the above copyright
83b3a8eb9SGleb Smirnoff  *    notice, this list of conditions and the following disclaimer.
93b3a8eb9SGleb Smirnoff  * 2. Redistributions in binary form must reproduce the above copyright
103b3a8eb9SGleb Smirnoff  *    notice, this list of conditions and the following disclaimer in the
113b3a8eb9SGleb Smirnoff  *    documentation and/or other materials provided with the distribution.
123b3a8eb9SGleb Smirnoff  *
133b3a8eb9SGleb Smirnoff  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
143b3a8eb9SGleb Smirnoff  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
153b3a8eb9SGleb Smirnoff  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
163b3a8eb9SGleb Smirnoff  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
173b3a8eb9SGleb Smirnoff  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
183b3a8eb9SGleb Smirnoff  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
193b3a8eb9SGleb Smirnoff  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
203b3a8eb9SGleb Smirnoff  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
213b3a8eb9SGleb Smirnoff  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
223b3a8eb9SGleb Smirnoff  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
233b3a8eb9SGleb Smirnoff  * SUCH DAMAGE.
243b3a8eb9SGleb Smirnoff  */
253b3a8eb9SGleb Smirnoff 
263b3a8eb9SGleb Smirnoff #include <sys/cdefs.h>
273b3a8eb9SGleb Smirnoff __FBSDID("$FreeBSD$");
283b3a8eb9SGleb Smirnoff 
293b3a8eb9SGleb Smirnoff /*
30563b5ab1SAlexander V. Chernikov  * Lookup table support for ipfw.
313b3a8eb9SGleb Smirnoff  *
32ac35ff17SAlexander V. Chernikov  * This file contains handlers for all generic tables' operations:
33563b5ab1SAlexander V. Chernikov  * add/del/flush entries, list/dump tables etc..
343b3a8eb9SGleb Smirnoff  *
35563b5ab1SAlexander V. Chernikov  * Table data modification is protected by both UH and runtimg lock
36563b5ab1SAlexander V. Chernikov  * while reading configuration/data is protected by UH lock.
37563b5ab1SAlexander V. Chernikov  *
38563b5ab1SAlexander V. Chernikov  * Lookup algorithms for all table types are located in ip_fw_table_algo.c
393b3a8eb9SGleb Smirnoff  */
403b3a8eb9SGleb Smirnoff 
413b3a8eb9SGleb Smirnoff #include "opt_ipfw.h"
423b3a8eb9SGleb Smirnoff 
433b3a8eb9SGleb Smirnoff #include <sys/param.h>
443b3a8eb9SGleb Smirnoff #include <sys/systm.h>
453b3a8eb9SGleb Smirnoff #include <sys/malloc.h>
463b3a8eb9SGleb Smirnoff #include <sys/kernel.h>
473b3a8eb9SGleb Smirnoff #include <sys/lock.h>
483b3a8eb9SGleb Smirnoff #include <sys/rwlock.h>
493b3a8eb9SGleb Smirnoff #include <sys/socket.h>
50f1220db8SAlexander V. Chernikov #include <sys/socketvar.h>
513b3a8eb9SGleb Smirnoff #include <sys/queue.h>
523b3a8eb9SGleb Smirnoff #include <net/if.h>	/* ip_fw.h requires IFNAMSIZ */
533b3a8eb9SGleb Smirnoff #include <net/route.h>
543b3a8eb9SGleb Smirnoff #include <net/vnet.h>
553b3a8eb9SGleb Smirnoff 
563b3a8eb9SGleb Smirnoff #include <netinet/in.h>
573b3a8eb9SGleb Smirnoff #include <netinet/ip_var.h>	/* struct ipfw_rule_ref */
583b3a8eb9SGleb Smirnoff #include <netinet/ip_fw.h>
593b3a8eb9SGleb Smirnoff 
603b3a8eb9SGleb Smirnoff #include <netpfil/ipfw/ip_fw_private.h>
61ea761a5dSAlexander V. Chernikov #include <netpfil/ipfw/ip_fw_table.h>
623b3a8eb9SGleb Smirnoff 
633b3a8eb9SGleb Smirnoff 
643b3a8eb9SGleb Smirnoff  /*
65b074b7bbSAlexander V. Chernikov  * Table has the following `type` concepts:
66b074b7bbSAlexander V. Chernikov  *
679f7d47b0SAlexander V. Chernikov  * `no.type` represents lookup key type (cidr, ifp, uid, etc..)
689f7d47b0SAlexander V. Chernikov  * `ta->atype` represents exact lookup algorithm.
69b074b7bbSAlexander V. Chernikov  *     For example, we can use more efficient search schemes if we plan
70b074b7bbSAlexander V. Chernikov  *     to use some specific table for storing host-routes only.
719490a627SAlexander V. Chernikov  * `ftype` (at the moment )is pure userland field helping to properly
729490a627SAlexander V. Chernikov  *     format value data e.g. "value is IPv4 nexthop" or "value is DSCP"
739490a627SAlexander V. Chernikov  *     or "value is port".
74b074b7bbSAlexander V. Chernikov  *
75b074b7bbSAlexander V. Chernikov  */
76b074b7bbSAlexander V. Chernikov struct table_config {
77b074b7bbSAlexander V. Chernikov 	struct named_object	no;
78ac35ff17SAlexander V. Chernikov 	uint8_t		vtype;		/* format table type */
79b074b7bbSAlexander V. Chernikov 	uint8_t		linked;		/* 1 if already linked */
809f7d47b0SAlexander V. Chernikov 	uint16_t	spare0;
81b074b7bbSAlexander V. Chernikov 	uint32_t	count;		/* Number of records */
82b074b7bbSAlexander V. Chernikov 	char		tablename[64];	/* table name */
839f7d47b0SAlexander V. Chernikov 	struct table_algo	*ta;	/* Callbacks for given algo */
849f7d47b0SAlexander V. Chernikov 	void		*astate;	/* algorithm state */
859f7d47b0SAlexander V. Chernikov 	struct table_info	ti;	/* data to put to table_info */
86b074b7bbSAlexander V. Chernikov };
87b074b7bbSAlexander V. Chernikov #define	TABLE_SET(set)	((V_fw_tables_sets != 0) ? set : 0)
88b074b7bbSAlexander V. Chernikov 
89b074b7bbSAlexander V. Chernikov struct tables_config {
90b074b7bbSAlexander V. Chernikov 	struct namedobj_instance	*namehash;
919f7d47b0SAlexander V. Chernikov 	int				algo_count;
929f7d47b0SAlexander V. Chernikov 	struct table_algo 		*algo[256];
93b074b7bbSAlexander V. Chernikov };
94b074b7bbSAlexander V. Chernikov 
95b074b7bbSAlexander V. Chernikov static struct table_config *find_table(struct namedobj_instance *ni,
96b074b7bbSAlexander V. Chernikov     struct tid_info *ti);
97b074b7bbSAlexander V. Chernikov static struct table_config *alloc_table_config(struct namedobj_instance *ni,
989490a627SAlexander V. Chernikov     struct tid_info *ti, struct table_algo *ta, char *adata);
99b074b7bbSAlexander V. Chernikov static void free_table_config(struct namedobj_instance *ni,
100b074b7bbSAlexander V. Chernikov     struct table_config *tc);
101b074b7bbSAlexander V. Chernikov static void link_table(struct ip_fw_chain *chain, struct table_config *tc);
102b074b7bbSAlexander V. Chernikov static void unlink_table(struct ip_fw_chain *chain, struct table_config *tc);
103b074b7bbSAlexander V. Chernikov static void free_table_state(void **state, void **xstate, uint8_t type);
1042d99a349SAlexander V. Chernikov static int export_tables(struct ip_fw_chain *ch, ipfw_obj_lheader *olh,
1052d99a349SAlexander V. Chernikov     struct sockopt_data *sd);
106ac35ff17SAlexander V. Chernikov static void export_table_info(struct ip_fw_chain *ch, struct table_config *tc,
107ac35ff17SAlexander V. Chernikov     ipfw_xtable_info *i);
10881d3153dSAlexander V. Chernikov static int dump_table_tentry(void *e, void *arg);
109f1220db8SAlexander V. Chernikov static int dump_table_xentry(void *e, void *arg);
110b074b7bbSAlexander V. Chernikov 
1112d99a349SAlexander V. Chernikov static int ipfw_dump_table_v0(struct ip_fw_chain *ch, struct sockopt_data *sd);
1122d99a349SAlexander V. Chernikov static int ipfw_dump_table_v1(struct ip_fw_chain *ch, struct sockopt_data *sd);
113ac35ff17SAlexander V. Chernikov static int ipfw_modify_table_v0(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
114ac35ff17SAlexander V. Chernikov     struct sockopt_data *sd);
115ac35ff17SAlexander V. Chernikov static int ipfw_modify_table_v1(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
116ac35ff17SAlexander V. Chernikov     struct sockopt_data *sd);
117ac35ff17SAlexander V. Chernikov 
118ac35ff17SAlexander V. Chernikov static int destroy_table(struct ip_fw_chain *ch, struct tid_info *ti);
119d3a4f924SAlexander V. Chernikov 
1209f7d47b0SAlexander V. Chernikov static struct table_algo *find_table_algo(struct tables_config *tableconf,
1219490a627SAlexander V. Chernikov     struct tid_info *ti, char *name);
122b074b7bbSAlexander V. Chernikov 
123b074b7bbSAlexander V. Chernikov #define	CHAIN_TO_TCFG(chain)	((struct tables_config *)(chain)->tblcfg)
124b074b7bbSAlexander V. Chernikov #define	CHAIN_TO_NI(chain)	(CHAIN_TO_TCFG(chain)->namehash)
1259f7d47b0SAlexander V. Chernikov #define	KIDX_TO_TI(ch, k)	(&(((struct table_info *)(ch)->tablestate)[k]))
126b074b7bbSAlexander V. Chernikov 
127b074b7bbSAlexander V. Chernikov 
1283b3a8eb9SGleb Smirnoff 
1293b3a8eb9SGleb Smirnoff int
1301832a7b3SAlexander V. Chernikov add_table_entry(struct ip_fw_chain *ch, struct tid_info *ti,
131b074b7bbSAlexander V. Chernikov     struct tentry_info *tei)
1323b3a8eb9SGleb Smirnoff {
133b074b7bbSAlexander V. Chernikov 	struct table_config *tc, *tc_new;
1349f7d47b0SAlexander V. Chernikov 	struct table_algo *ta;
135b074b7bbSAlexander V. Chernikov 	struct namedobj_instance *ni;
136b074b7bbSAlexander V. Chernikov 	uint16_t kidx;
1379f7d47b0SAlexander V. Chernikov 	int error;
1389f7d47b0SAlexander V. Chernikov 	char ta_buf[128];
1393b3a8eb9SGleb Smirnoff 
1409f7d47b0SAlexander V. Chernikov 	IPFW_UH_WLOCK(ch);
1419f7d47b0SAlexander V. Chernikov 	ni = CHAIN_TO_NI(ch);
1429f7d47b0SAlexander V. Chernikov 
1439f7d47b0SAlexander V. Chernikov 	/*
1449f7d47b0SAlexander V. Chernikov 	 * Find and reference existing table.
1459f7d47b0SAlexander V. Chernikov 	 */
1469f7d47b0SAlexander V. Chernikov 	ta = NULL;
1479f7d47b0SAlexander V. Chernikov 	if ((tc = find_table(ni, ti)) != NULL) {
1489f7d47b0SAlexander V. Chernikov 		/* check table type */
1499f7d47b0SAlexander V. Chernikov 		if (tc->no.type != ti->type) {
1509f7d47b0SAlexander V. Chernikov 			IPFW_UH_WUNLOCK(ch);
1513b3a8eb9SGleb Smirnoff 			return (EINVAL);
1523b3a8eb9SGleb Smirnoff 		}
1533b3a8eb9SGleb Smirnoff 
1549f7d47b0SAlexander V. Chernikov 		/* Reference and unlock */
1559f7d47b0SAlexander V. Chernikov 		tc->no.refcnt++;
1569f7d47b0SAlexander V. Chernikov 		ta = tc->ta;
1579f7d47b0SAlexander V. Chernikov 	}
1589f7d47b0SAlexander V. Chernikov 	IPFW_UH_WUNLOCK(ch);
1593b3a8eb9SGleb Smirnoff 
1609f7d47b0SAlexander V. Chernikov 	tc_new = NULL;
161ac35ff17SAlexander V. Chernikov 	if (tc == NULL) {
1629f7d47b0SAlexander V. Chernikov 		/* Table not found. We have to create new one */
1639490a627SAlexander V. Chernikov 		if ((ta = find_table_algo(CHAIN_TO_TCFG(ch), ti, NULL)) == NULL)
1649f7d47b0SAlexander V. Chernikov 			return (ENOTSUP);
1653b3a8eb9SGleb Smirnoff 
1669490a627SAlexander V. Chernikov 		tc_new = alloc_table_config(ni, ti, ta, NULL);
1679f7d47b0SAlexander V. Chernikov 		if (tc_new == NULL)
1689f7d47b0SAlexander V. Chernikov 			return (ENOMEM);
1699f7d47b0SAlexander V. Chernikov 	}
1703b3a8eb9SGleb Smirnoff 
1719f7d47b0SAlexander V. Chernikov 	/* Prepare record (allocate memory) */
1729f7d47b0SAlexander V. Chernikov 	memset(&ta_buf, 0, sizeof(ta_buf));
1739f7d47b0SAlexander V. Chernikov 	error = ta->prepare_add(tei, &ta_buf);
1749f7d47b0SAlexander V. Chernikov 	if (error != 0) {
1759f7d47b0SAlexander V. Chernikov 		if (tc_new != NULL)
1769f7d47b0SAlexander V. Chernikov 			free_table_config(ni, tc_new);
1779f7d47b0SAlexander V. Chernikov 		return (error);
1783b3a8eb9SGleb Smirnoff 	}
1793b3a8eb9SGleb Smirnoff 
180b074b7bbSAlexander V. Chernikov 	IPFW_UH_WLOCK(ch);
1813b3a8eb9SGleb Smirnoff 
182b074b7bbSAlexander V. Chernikov 	ni = CHAIN_TO_NI(ch);
1833b3a8eb9SGleb Smirnoff 
1849f7d47b0SAlexander V. Chernikov 	if (tc == NULL) {
185ac35ff17SAlexander V. Chernikov 		/* Check if another table has been allocated by other thread */
186b074b7bbSAlexander V. Chernikov 		if ((tc = find_table(ni, ti)) != NULL) {
1879f7d47b0SAlexander V. Chernikov 
1889f7d47b0SAlexander V. Chernikov 			/*
1899f7d47b0SAlexander V. Chernikov 			 * Check if algoritm is the same since we've
1909f7d47b0SAlexander V. Chernikov 			 * already allocated state using @ta algoritm
1919f7d47b0SAlexander V. Chernikov 			 * callbacks.
1929f7d47b0SAlexander V. Chernikov 			 */
1939f7d47b0SAlexander V. Chernikov 			if (tc->ta != ta) {
194b074b7bbSAlexander V. Chernikov 				IPFW_UH_WUNLOCK(ch);
195ac35ff17SAlexander V. Chernikov 				error = EINVAL;
196ac35ff17SAlexander V. Chernikov 				goto done;
1973b3a8eb9SGleb Smirnoff 			}
1983b3a8eb9SGleb Smirnoff 		} else {
199ac35ff17SAlexander V. Chernikov 			/* Table still does not exists */
200b074b7bbSAlexander V. Chernikov 
201b074b7bbSAlexander V. Chernikov 			/* Allocate table index. */
202ac35ff17SAlexander V. Chernikov 			if (ipfw_objhash_alloc_idx(ni, &kidx) != 0) {
203b074b7bbSAlexander V. Chernikov 				/* Index full. */
204b074b7bbSAlexander V. Chernikov 				IPFW_UH_WUNLOCK(ch);
205ac35ff17SAlexander V. Chernikov 				printf("Unable to allocate index for table %s"
206ac35ff17SAlexander V. Chernikov 				    "in set %u. Consider increasing "
207b074b7bbSAlexander V. Chernikov 				    "net.inet.ip.fw.tables_max",
208ac35ff17SAlexander V. Chernikov 				    tc_new->no.name, ti->set);
209ac35ff17SAlexander V. Chernikov 				error = EBUSY;
210ac35ff17SAlexander V. Chernikov 				goto done;
2113b3a8eb9SGleb Smirnoff 			}
212ac35ff17SAlexander V. Chernikov 
213ac35ff17SAlexander V. Chernikov 			/* Set tc_new to zero not to free it afterwards. */
214ac35ff17SAlexander V. Chernikov 			tc = tc_new;
215ac35ff17SAlexander V. Chernikov 			tc_new = NULL;
216b074b7bbSAlexander V. Chernikov 			/* Save kidx */
217b074b7bbSAlexander V. Chernikov 			tc->no.kidx = kidx;
218b074b7bbSAlexander V. Chernikov 		}
219b074b7bbSAlexander V. Chernikov 	} else {
2209f7d47b0SAlexander V. Chernikov 		/* Drop reference we've used in first search */
2219f7d47b0SAlexander V. Chernikov 		tc->no.refcnt--;
222b074b7bbSAlexander V. Chernikov 	}
223b074b7bbSAlexander V. Chernikov 
224b074b7bbSAlexander V. Chernikov 	/* We've got valid table in @tc. Let's add data */
2259f7d47b0SAlexander V. Chernikov 	kidx = tc->no.kidx;
2269f7d47b0SAlexander V. Chernikov 	ta = tc->ta;
2279f7d47b0SAlexander V. Chernikov 
228b074b7bbSAlexander V. Chernikov 	IPFW_WLOCK(ch);
229b074b7bbSAlexander V. Chernikov 
230ac35ff17SAlexander V. Chernikov 	if (tc->linked == 0)
231b074b7bbSAlexander V. Chernikov 		link_table(ch, tc);
232b074b7bbSAlexander V. Chernikov 
2339f7d47b0SAlexander V. Chernikov 	error = ta->add(tc->astate, KIDX_TO_TI(ch, kidx), tei, &ta_buf);
2343b3a8eb9SGleb Smirnoff 
2353b3a8eb9SGleb Smirnoff 	IPFW_WUNLOCK(ch);
2369f7d47b0SAlexander V. Chernikov 
237ac35ff17SAlexander V. Chernikov 	/* Update number of records. */
238ac35ff17SAlexander V. Chernikov 	if (error == 0 && (tei->flags & TEI_FLAGS_UPDATED) == 0)
2399f7d47b0SAlexander V. Chernikov 		tc->count++;
2409f7d47b0SAlexander V. Chernikov 
241b074b7bbSAlexander V. Chernikov 	IPFW_UH_WUNLOCK(ch);
242b074b7bbSAlexander V. Chernikov 
243ac35ff17SAlexander V. Chernikov done:
244b074b7bbSAlexander V. Chernikov 	if (tc_new != NULL)
245ac35ff17SAlexander V. Chernikov 		free_table_config(ni, tc_new);
246ac35ff17SAlexander V. Chernikov 	/* Run cleaning callback anyway */
2479f7d47b0SAlexander V. Chernikov 	ta->flush_entry(tei, &ta_buf);
248b074b7bbSAlexander V. Chernikov 
2499f7d47b0SAlexander V. Chernikov 	return (error);
2503b3a8eb9SGleb Smirnoff }
2513b3a8eb9SGleb Smirnoff 
2523b3a8eb9SGleb Smirnoff int
2531832a7b3SAlexander V. Chernikov del_table_entry(struct ip_fw_chain *ch, struct tid_info *ti,
254b074b7bbSAlexander V. Chernikov     struct tentry_info *tei)
2553b3a8eb9SGleb Smirnoff {
256b074b7bbSAlexander V. Chernikov 	struct table_config *tc;
2579f7d47b0SAlexander V. Chernikov 	struct table_algo *ta;
258b074b7bbSAlexander V. Chernikov 	struct namedobj_instance *ni;
259b074b7bbSAlexander V. Chernikov 	uint16_t kidx;
2609f7d47b0SAlexander V. Chernikov 	int error;
2619f7d47b0SAlexander V. Chernikov 	char ta_buf[128];
2623b3a8eb9SGleb Smirnoff 
2639f7d47b0SAlexander V. Chernikov 	IPFW_UH_WLOCK(ch);
264b074b7bbSAlexander V. Chernikov 	ni = CHAIN_TO_NI(ch);
265b074b7bbSAlexander V. Chernikov 	if ((tc = find_table(ni, ti)) == NULL) {
2669f7d47b0SAlexander V. Chernikov 		IPFW_UH_WUNLOCK(ch);
2673b3a8eb9SGleb Smirnoff 		return (ESRCH);
2683b3a8eb9SGleb Smirnoff 	}
2693b3a8eb9SGleb Smirnoff 
270b074b7bbSAlexander V. Chernikov 	if (tc->no.type != ti->type) {
2719f7d47b0SAlexander V. Chernikov 		IPFW_UH_WUNLOCK(ch);
2723b3a8eb9SGleb Smirnoff 		return (EINVAL);
2733b3a8eb9SGleb Smirnoff 	}
2749f7d47b0SAlexander V. Chernikov 
2759f7d47b0SAlexander V. Chernikov 	ta = tc->ta;
2769f7d47b0SAlexander V. Chernikov 
2779f7d47b0SAlexander V. Chernikov 	memset(&ta_buf, 0, sizeof(ta_buf));
2789f7d47b0SAlexander V. Chernikov 	if ((error = ta->prepare_del(tei, &ta_buf)) != 0) {
2799f7d47b0SAlexander V. Chernikov 		IPFW_UH_WUNLOCK(ch);
2809f7d47b0SAlexander V. Chernikov 		return (error);
2819f7d47b0SAlexander V. Chernikov 	}
2829f7d47b0SAlexander V. Chernikov 
283b074b7bbSAlexander V. Chernikov 	kidx = tc->no.kidx;
284b074b7bbSAlexander V. Chernikov 
285b074b7bbSAlexander V. Chernikov 	IPFW_WLOCK(ch);
2869f7d47b0SAlexander V. Chernikov 	error = ta->del(tc->astate, KIDX_TO_TI(ch, kidx), tei, &ta_buf);
2873b3a8eb9SGleb Smirnoff 	IPFW_WUNLOCK(ch);
2883b3a8eb9SGleb Smirnoff 
2899f7d47b0SAlexander V. Chernikov 	if (error == 0)
2909f7d47b0SAlexander V. Chernikov 		tc->count--;
291b074b7bbSAlexander V. Chernikov 
2929f7d47b0SAlexander V. Chernikov 	IPFW_UH_WUNLOCK(ch);
2933b3a8eb9SGleb Smirnoff 
2949f7d47b0SAlexander V. Chernikov 	ta->flush_entry(tei, &ta_buf);
295ac35ff17SAlexander V. Chernikov 
296ac35ff17SAlexander V. Chernikov 	return (error);
297ac35ff17SAlexander V. Chernikov }
298ac35ff17SAlexander V. Chernikov 
299ac35ff17SAlexander V. Chernikov int
300ac35ff17SAlexander V. Chernikov ipfw_modify_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
301ac35ff17SAlexander V. Chernikov     struct sockopt_data *sd)
302ac35ff17SAlexander V. Chernikov {
303ac35ff17SAlexander V. Chernikov 	int error;
304ac35ff17SAlexander V. Chernikov 
305ac35ff17SAlexander V. Chernikov 	switch (op3->version) {
306ac35ff17SAlexander V. Chernikov 	case 0:
307ac35ff17SAlexander V. Chernikov 		error = ipfw_modify_table_v0(ch, op3, sd);
308ac35ff17SAlexander V. Chernikov 		break;
309ac35ff17SAlexander V. Chernikov 	case 1:
310ac35ff17SAlexander V. Chernikov 		error = ipfw_modify_table_v1(ch, op3, sd);
311ac35ff17SAlexander V. Chernikov 		break;
312ac35ff17SAlexander V. Chernikov 	default:
313ac35ff17SAlexander V. Chernikov 		error = ENOTSUP;
314ac35ff17SAlexander V. Chernikov 	}
315ac35ff17SAlexander V. Chernikov 
316ac35ff17SAlexander V. Chernikov 	return (error);
317ac35ff17SAlexander V. Chernikov }
318ac35ff17SAlexander V. Chernikov 
319ac35ff17SAlexander V. Chernikov /*
320ac35ff17SAlexander V. Chernikov  * Adds or deletes record in table.
321ac35ff17SAlexander V. Chernikov  * Data layout (v0):
322ac35ff17SAlexander V. Chernikov  * Request: [ ip_fw3_opheader ipfw_table_xentry ]
323ac35ff17SAlexander V. Chernikov  *
324ac35ff17SAlexander V. Chernikov  * Returns 0 on success
325ac35ff17SAlexander V. Chernikov  */
326ac35ff17SAlexander V. Chernikov static int
327ac35ff17SAlexander V. Chernikov ipfw_modify_table_v0(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
328ac35ff17SAlexander V. Chernikov     struct sockopt_data *sd)
329ac35ff17SAlexander V. Chernikov {
330ac35ff17SAlexander V. Chernikov 	ipfw_table_xentry *xent;
331ac35ff17SAlexander V. Chernikov 	struct tentry_info tei;
332ac35ff17SAlexander V. Chernikov 	struct tid_info ti;
333ac35ff17SAlexander V. Chernikov 	int error, hdrlen, read;
334ac35ff17SAlexander V. Chernikov 
335ac35ff17SAlexander V. Chernikov 	hdrlen = offsetof(ipfw_table_xentry, k);
336ac35ff17SAlexander V. Chernikov 
337ac35ff17SAlexander V. Chernikov 	/* Check minimum header size */
338ac35ff17SAlexander V. Chernikov 	if (sd->valsize < (sizeof(*op3) + hdrlen))
339ac35ff17SAlexander V. Chernikov 		return (EINVAL);
340ac35ff17SAlexander V. Chernikov 
341ac35ff17SAlexander V. Chernikov 	read = sizeof(ip_fw3_opheader);
342ac35ff17SAlexander V. Chernikov 
343ac35ff17SAlexander V. Chernikov 	/* Check if xentry len field is valid */
344ac35ff17SAlexander V. Chernikov 	xent = (ipfw_table_xentry *)(op3 + 1);
345ac35ff17SAlexander V. Chernikov 	if (xent->len < hdrlen || xent->len + read > sd->valsize)
346ac35ff17SAlexander V. Chernikov 		return (EINVAL);
347ac35ff17SAlexander V. Chernikov 
348ac35ff17SAlexander V. Chernikov 	memset(&tei, 0, sizeof(tei));
349ac35ff17SAlexander V. Chernikov 	tei.paddr = &xent->k;
350ac35ff17SAlexander V. Chernikov 	tei.masklen = xent->masklen;
351ac35ff17SAlexander V. Chernikov 	tei.value = xent->value;
352ac35ff17SAlexander V. Chernikov 	/* Old requests compability */
353ac35ff17SAlexander V. Chernikov 	if (xent->type == IPFW_TABLE_CIDR) {
354ac35ff17SAlexander V. Chernikov 		if (xent->len - hdrlen == sizeof(in_addr_t))
355ac35ff17SAlexander V. Chernikov 			tei.subtype = AF_INET;
356ac35ff17SAlexander V. Chernikov 		else
357ac35ff17SAlexander V. Chernikov 			tei.subtype = AF_INET6;
358ac35ff17SAlexander V. Chernikov 	}
359ac35ff17SAlexander V. Chernikov 
360ac35ff17SAlexander V. Chernikov 	memset(&ti, 0, sizeof(ti));
361ac35ff17SAlexander V. Chernikov 	ti.uidx = xent->tbl;
362ac35ff17SAlexander V. Chernikov 	ti.type = xent->type;
363ac35ff17SAlexander V. Chernikov 
364ac35ff17SAlexander V. Chernikov 	error = (op3->opcode == IP_FW_TABLE_XADD) ?
3651832a7b3SAlexander V. Chernikov 	    add_table_entry(ch, &ti, &tei) :
3661832a7b3SAlexander V. Chernikov 	    del_table_entry(ch, &ti, &tei);
367ac35ff17SAlexander V. Chernikov 
368ac35ff17SAlexander V. Chernikov 	return (error);
369ac35ff17SAlexander V. Chernikov }
370ac35ff17SAlexander V. Chernikov 
371ac35ff17SAlexander V. Chernikov /*
372ac35ff17SAlexander V. Chernikov  * Adds or deletes record in table.
373ac35ff17SAlexander V. Chernikov  * Data layout (v1)(current):
374ac35ff17SAlexander V. Chernikov  * Request: [ ipfw_obj_header ipfw_obj_tentry ]
375ac35ff17SAlexander V. Chernikov  *
376ac35ff17SAlexander V. Chernikov  * Returns 0 on success
377ac35ff17SAlexander V. Chernikov  */
378ac35ff17SAlexander V. Chernikov static int
379ac35ff17SAlexander V. Chernikov ipfw_modify_table_v1(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
380ac35ff17SAlexander V. Chernikov     struct sockopt_data *sd)
381ac35ff17SAlexander V. Chernikov {
382ac35ff17SAlexander V. Chernikov 	ipfw_obj_tentry *tent;
383ac35ff17SAlexander V. Chernikov 	ipfw_obj_header *oh;
384ac35ff17SAlexander V. Chernikov 	struct tentry_info tei;
385ac35ff17SAlexander V. Chernikov 	struct tid_info ti;
386ac35ff17SAlexander V. Chernikov 	int error, read;
387ac35ff17SAlexander V. Chernikov 
388ac35ff17SAlexander V. Chernikov 	/* Check minimum header size */
389ac35ff17SAlexander V. Chernikov 	if (sd->valsize < (sizeof(*oh) + sizeof(*tent)))
390ac35ff17SAlexander V. Chernikov 		return (EINVAL);
391ac35ff17SAlexander V. Chernikov 
392ac35ff17SAlexander V. Chernikov 	/* Check if passed data is too long */
393ac35ff17SAlexander V. Chernikov 	if (sd->valsize != sd->kavail)
394ac35ff17SAlexander V. Chernikov 		return (EINVAL);
395ac35ff17SAlexander V. Chernikov 
396ac35ff17SAlexander V. Chernikov 	oh = (ipfw_obj_header *)sd->kbuf;
397ac35ff17SAlexander V. Chernikov 
398ac35ff17SAlexander V. Chernikov 	/* Basic length checks for TLVs */
399ac35ff17SAlexander V. Chernikov 	if (oh->ntlv.head.length != sizeof(oh->ntlv))
400ac35ff17SAlexander V. Chernikov 		return (EINVAL);
401ac35ff17SAlexander V. Chernikov 
402ac35ff17SAlexander V. Chernikov 	read = sizeof(*oh);
403ac35ff17SAlexander V. Chernikov 
404ac35ff17SAlexander V. Chernikov 	/* Assume tentry may grow to support larger keys */
405ac35ff17SAlexander V. Chernikov 	tent = (ipfw_obj_tentry *)(oh + 1);
406ac35ff17SAlexander V. Chernikov 	if (tent->head.length < sizeof(*tent) ||
407ac35ff17SAlexander V. Chernikov 	    tent->head.length + read > sd->valsize)
408ac35ff17SAlexander V. Chernikov 		return (EINVAL);
409ac35ff17SAlexander V. Chernikov 
41081d3153dSAlexander V. Chernikov 	/* Convert data into kernel request objects */
411ac35ff17SAlexander V. Chernikov 	memset(&tei, 0, sizeof(tei));
412ac35ff17SAlexander V. Chernikov 	tei.paddr = &tent->k;
413ac35ff17SAlexander V. Chernikov 	tei.subtype = tent->subtype;
414ac35ff17SAlexander V. Chernikov 	tei.masklen = tent->masklen;
41581d3153dSAlexander V. Chernikov 	if (tent->head.flags & IPFW_TF_UPDATE)
416ac35ff17SAlexander V. Chernikov 		tei.flags |= TEI_FLAGS_UPDATE;
417ac35ff17SAlexander V. Chernikov 	tei.value = tent->value;
418ac35ff17SAlexander V. Chernikov 
41981d3153dSAlexander V. Chernikov 	objheader_to_ti(oh, &ti);
420ac35ff17SAlexander V. Chernikov 	ti.type = oh->ntlv.type;
42181d3153dSAlexander V. Chernikov 	ti.uidx = tent->idx;
422ac35ff17SAlexander V. Chernikov 
423ac35ff17SAlexander V. Chernikov 	error = (oh->opheader.opcode == IP_FW_TABLE_XADD) ?
4241832a7b3SAlexander V. Chernikov 	    add_table_entry(ch, &ti, &tei) :
4251832a7b3SAlexander V. Chernikov 	    del_table_entry(ch, &ti, &tei);
426ac35ff17SAlexander V. Chernikov 
427ac35ff17SAlexander V. Chernikov 	return (error);
428ac35ff17SAlexander V. Chernikov }
429ac35ff17SAlexander V. Chernikov 
43081d3153dSAlexander V. Chernikov /*
43181d3153dSAlexander V. Chernikov  * Looks up an entry in given table.
43281d3153dSAlexander V. Chernikov  * Data layout (v0)(current):
43381d3153dSAlexander V. Chernikov  * Request: [ ipfw_obj_header ipfw_obj_tentry ]
43481d3153dSAlexander V. Chernikov  * Reply: [ ipfw_obj_header ipfw_obj_tentry ]
43581d3153dSAlexander V. Chernikov  *
43681d3153dSAlexander V. Chernikov  * Returns 0 on success
43781d3153dSAlexander V. Chernikov  */
43881d3153dSAlexander V. Chernikov int
43981d3153dSAlexander V. Chernikov ipfw_find_table_entry(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
44081d3153dSAlexander V. Chernikov     struct sockopt_data *sd)
44181d3153dSAlexander V. Chernikov {
44281d3153dSAlexander V. Chernikov 	ipfw_obj_tentry *tent;
44381d3153dSAlexander V. Chernikov 	ipfw_obj_header *oh;
44481d3153dSAlexander V. Chernikov 	struct tid_info ti;
44581d3153dSAlexander V. Chernikov 	struct table_config *tc;
44681d3153dSAlexander V. Chernikov 	struct table_algo *ta;
44781d3153dSAlexander V. Chernikov 	struct table_info *kti;
44881d3153dSAlexander V. Chernikov 	struct namedobj_instance *ni;
44981d3153dSAlexander V. Chernikov 	int error, plen;
45081d3153dSAlexander V. Chernikov 	void *paddr;
45181d3153dSAlexander V. Chernikov 	size_t sz;
45281d3153dSAlexander V. Chernikov 
45381d3153dSAlexander V. Chernikov 	/* Check minimum header size */
45481d3153dSAlexander V. Chernikov 	sz = sizeof(*oh) + sizeof(*tent);
45581d3153dSAlexander V. Chernikov 	if (sd->valsize != sz)
45681d3153dSAlexander V. Chernikov 		return (EINVAL);
45781d3153dSAlexander V. Chernikov 
45881d3153dSAlexander V. Chernikov 	oh = (struct _ipfw_obj_header *)ipfw_get_sopt_header(sd, sz);
45981d3153dSAlexander V. Chernikov 	tent = (ipfw_obj_tentry *)(oh + 1);
46081d3153dSAlexander V. Chernikov 
46181d3153dSAlexander V. Chernikov 	/* Basic length checks for TLVs */
46281d3153dSAlexander V. Chernikov 	if (oh->ntlv.head.length != sizeof(oh->ntlv))
46381d3153dSAlexander V. Chernikov 		return (EINVAL);
46481d3153dSAlexander V. Chernikov 
46581d3153dSAlexander V. Chernikov 	objheader_to_ti(oh, &ti);
46681d3153dSAlexander V. Chernikov 	ti.type = oh->ntlv.type;
46781d3153dSAlexander V. Chernikov 	ti.uidx = tent->idx;
46881d3153dSAlexander V. Chernikov 
46981d3153dSAlexander V. Chernikov 	IPFW_UH_RLOCK(ch);
47081d3153dSAlexander V. Chernikov 	ni = CHAIN_TO_NI(ch);
47181d3153dSAlexander V. Chernikov 
47281d3153dSAlexander V. Chernikov 	/*
47381d3153dSAlexander V. Chernikov 	 * Find existing table and check its type .
47481d3153dSAlexander V. Chernikov 	 */
47581d3153dSAlexander V. Chernikov 	ta = NULL;
47681d3153dSAlexander V. Chernikov 	if ((tc = find_table(ni, &ti)) == NULL) {
47781d3153dSAlexander V. Chernikov 		IPFW_UH_RUNLOCK(ch);
47881d3153dSAlexander V. Chernikov 		return (ESRCH);
47981d3153dSAlexander V. Chernikov 	}
48081d3153dSAlexander V. Chernikov 
48181d3153dSAlexander V. Chernikov 	/* check table type */
48281d3153dSAlexander V. Chernikov 	if (tc->no.type != ti.type) {
48381d3153dSAlexander V. Chernikov 		IPFW_UH_RUNLOCK(ch);
48481d3153dSAlexander V. Chernikov 		return (EINVAL);
48581d3153dSAlexander V. Chernikov 	}
48681d3153dSAlexander V. Chernikov 
48781d3153dSAlexander V. Chernikov 	/* Check lookup key for validness */
48881d3153dSAlexander V. Chernikov 	plen = 0;
48981d3153dSAlexander V. Chernikov 	paddr = &tent->k;
49081d3153dSAlexander V. Chernikov 	switch (ti.type)
49181d3153dSAlexander V. Chernikov 	{
49281d3153dSAlexander V. Chernikov 	case IPFW_TABLE_CIDR:
49381d3153dSAlexander V. Chernikov 		if (tent->subtype == AF_INET)
49481d3153dSAlexander V. Chernikov 			plen = sizeof(struct in_addr);
49581d3153dSAlexander V. Chernikov 		else if (tent->subtype == AF_INET6)
49681d3153dSAlexander V. Chernikov 			plen = sizeof(struct in6_addr);
49781d3153dSAlexander V. Chernikov 		else {
49881d3153dSAlexander V. Chernikov 			IPFW_UH_RUNLOCK(ch);
49981d3153dSAlexander V. Chernikov 			return (EINVAL);
50081d3153dSAlexander V. Chernikov 		}
50181d3153dSAlexander V. Chernikov 		break;
50281d3153dSAlexander V. Chernikov 	case IPFW_TABLE_INTERFACE:
50381d3153dSAlexander V. Chernikov 		/* Check key first */
50481d3153dSAlexander V. Chernikov 		plen = sizeof(tent->k.iface);
50581d3153dSAlexander V. Chernikov 		if (strnlen(tent->k.iface, plen) == plen) {
50681d3153dSAlexander V. Chernikov 			IPFW_UH_RUNLOCK(ch);
50781d3153dSAlexander V. Chernikov 			return (EINVAL);
50881d3153dSAlexander V. Chernikov 		}
50981d3153dSAlexander V. Chernikov 
51081d3153dSAlexander V. Chernikov 		break;
51181d3153dSAlexander V. Chernikov 	default:
51281d3153dSAlexander V. Chernikov 		IPFW_UH_RUNLOCK(ch);
51381d3153dSAlexander V. Chernikov 		return (ENOTSUP);
51481d3153dSAlexander V. Chernikov 	}
51581d3153dSAlexander V. Chernikov 	kti = KIDX_TO_TI(ch, tc->no.kidx);
51681d3153dSAlexander V. Chernikov 	ta = tc->ta;
51781d3153dSAlexander V. Chernikov 
51881d3153dSAlexander V. Chernikov 	error = ta->find_tentry(tc->astate, kti, paddr, plen, tent);
51981d3153dSAlexander V. Chernikov 
52081d3153dSAlexander V. Chernikov 	IPFW_UH_RUNLOCK(ch);
52181d3153dSAlexander V. Chernikov 
52281d3153dSAlexander V. Chernikov 	return (error);
52381d3153dSAlexander V. Chernikov }
52481d3153dSAlexander V. Chernikov 
525ac35ff17SAlexander V. Chernikov int
526ac35ff17SAlexander V. Chernikov ipfw_flush_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
527ac35ff17SAlexander V. Chernikov     struct sockopt_data *sd)
528ac35ff17SAlexander V. Chernikov {
529ac35ff17SAlexander V. Chernikov 	int error;
530ac35ff17SAlexander V. Chernikov 	struct _ipfw_obj_header *oh;
531ac35ff17SAlexander V. Chernikov 	struct tid_info ti;
532ac35ff17SAlexander V. Chernikov 
533ac35ff17SAlexander V. Chernikov 	if (sd->valsize != sizeof(*oh))
534ac35ff17SAlexander V. Chernikov 		return (EINVAL);
535ac35ff17SAlexander V. Chernikov 
536ac35ff17SAlexander V. Chernikov 	oh = (struct _ipfw_obj_header *)op3;
537ac35ff17SAlexander V. Chernikov 	objheader_to_ti(oh, &ti);
538ac35ff17SAlexander V. Chernikov 
5391832a7b3SAlexander V. Chernikov 	if (op3->opcode == IP_FW_TABLE_XDESTROY)
540ac35ff17SAlexander V. Chernikov 		error = destroy_table(ch, &ti);
5411832a7b3SAlexander V. Chernikov 	else if (op3->opcode == IP_FW_TABLE_XFLUSH)
542ac35ff17SAlexander V. Chernikov 		error = flush_table(ch, &ti);
543ac35ff17SAlexander V. Chernikov 	else
544ac35ff17SAlexander V. Chernikov 		return (ENOTSUP);
545ac35ff17SAlexander V. Chernikov 
546ac35ff17SAlexander V. Chernikov 	return (error);
5473b3a8eb9SGleb Smirnoff }
5483b3a8eb9SGleb Smirnoff 
549b074b7bbSAlexander V. Chernikov /*
5509f7d47b0SAlexander V. Chernikov  * Flushes all entries in given table.
551ac35ff17SAlexander V. Chernikov  * Data layout (v0)(current):
552ac35ff17SAlexander V. Chernikov  * Request: [ ip_fw3_opheader ]
553ac35ff17SAlexander V. Chernikov  *
554ac35ff17SAlexander V. Chernikov  * Returns 0 on success
555b074b7bbSAlexander V. Chernikov  */
5561832a7b3SAlexander V. Chernikov int
557ac35ff17SAlexander V. Chernikov flush_table(struct ip_fw_chain *ch, struct tid_info *ti)
5583b3a8eb9SGleb Smirnoff {
559b074b7bbSAlexander V. Chernikov 	struct namedobj_instance *ni;
560b074b7bbSAlexander V. Chernikov 	struct table_config *tc;
5619f7d47b0SAlexander V. Chernikov 	struct table_algo *ta;
5629f7d47b0SAlexander V. Chernikov 	struct table_info ti_old, ti_new, *tablestate;
5639f7d47b0SAlexander V. Chernikov 	void *astate_old, *astate_new;
564b074b7bbSAlexander V. Chernikov 	int error;
565b074b7bbSAlexander V. Chernikov 	uint16_t kidx;
5663b3a8eb9SGleb Smirnoff 
5673b3a8eb9SGleb Smirnoff 	/*
5689f7d47b0SAlexander V. Chernikov 	 * Stage 1: save table algoritm.
569b074b7bbSAlexander V. Chernikov 	 * Reference found table to ensure it won't disappear.
5703b3a8eb9SGleb Smirnoff 	 */
571b074b7bbSAlexander V. Chernikov 	IPFW_UH_WLOCK(ch);
572b074b7bbSAlexander V. Chernikov 	ni = CHAIN_TO_NI(ch);
573b074b7bbSAlexander V. Chernikov 	if ((tc = find_table(ni, ti)) == NULL) {
574b074b7bbSAlexander V. Chernikov 		IPFW_UH_WUNLOCK(ch);
575b074b7bbSAlexander V. Chernikov 		return (ESRCH);
576b074b7bbSAlexander V. Chernikov 	}
5779f7d47b0SAlexander V. Chernikov 	ta = tc->ta;
578b074b7bbSAlexander V. Chernikov 	tc->no.refcnt++;
579b074b7bbSAlexander V. Chernikov 	IPFW_UH_WUNLOCK(ch);
5803b3a8eb9SGleb Smirnoff 
581b074b7bbSAlexander V. Chernikov 	/*
5829f7d47b0SAlexander V. Chernikov 	 * Stage 2: allocate new table instance using same algo.
5839490a627SAlexander V. Chernikov 	 * TODO: pass startup parametes somehow.
584b074b7bbSAlexander V. Chernikov 	 */
5859f7d47b0SAlexander V. Chernikov 	memset(&ti_new, 0, sizeof(struct table_info));
5869490a627SAlexander V. Chernikov 	if ((error = ta->init(&astate_new, &ti_new, NULL)) != 0) {
587b074b7bbSAlexander V. Chernikov 		IPFW_UH_WLOCK(ch);
588b074b7bbSAlexander V. Chernikov 		tc->no.refcnt--;
589b074b7bbSAlexander V. Chernikov 		IPFW_UH_WUNLOCK(ch);
590b074b7bbSAlexander V. Chernikov 		return (error);
591b074b7bbSAlexander V. Chernikov 	}
592b074b7bbSAlexander V. Chernikov 
593b074b7bbSAlexander V. Chernikov 	/*
594b074b7bbSAlexander V. Chernikov 	 * Stage 3: swap old state pointers with newly-allocated ones.
595b074b7bbSAlexander V. Chernikov 	 * Decrease refcount.
596b074b7bbSAlexander V. Chernikov 	 */
597b074b7bbSAlexander V. Chernikov 	IPFW_UH_WLOCK(ch);
598b074b7bbSAlexander V. Chernikov 
599b074b7bbSAlexander V. Chernikov 	ni = CHAIN_TO_NI(ch);
600b074b7bbSAlexander V. Chernikov 	kidx = tc->no.kidx;
6019f7d47b0SAlexander V. Chernikov 	tablestate = (struct table_info *)ch->tablestate;
602b074b7bbSAlexander V. Chernikov 
6039f7d47b0SAlexander V. Chernikov 	IPFW_WLOCK(ch);
6049f7d47b0SAlexander V. Chernikov 	ti_old = tablestate[kidx];
6059f7d47b0SAlexander V. Chernikov 	tablestate[kidx] = ti_new;
6069f7d47b0SAlexander V. Chernikov 	IPFW_WUNLOCK(ch);
607b074b7bbSAlexander V. Chernikov 
6089f7d47b0SAlexander V. Chernikov 	astate_old = tc->astate;
6099f7d47b0SAlexander V. Chernikov 	tc->astate = astate_new;
6109f7d47b0SAlexander V. Chernikov 	tc->ti = ti_new;
6119f7d47b0SAlexander V. Chernikov 	tc->count = 0;
612b074b7bbSAlexander V. Chernikov 	tc->no.refcnt--;
613b074b7bbSAlexander V. Chernikov 
614b074b7bbSAlexander V. Chernikov 	IPFW_UH_WUNLOCK(ch);
6153b3a8eb9SGleb Smirnoff 
616b074b7bbSAlexander V. Chernikov 	/*
617b074b7bbSAlexander V. Chernikov 	 * Stage 4: perform real flush.
618b074b7bbSAlexander V. Chernikov 	 */
6199f7d47b0SAlexander V. Chernikov 	ta->destroy(astate_old, &ti_old);
6203b3a8eb9SGleb Smirnoff 
6213b3a8eb9SGleb Smirnoff 	return (0);
6223b3a8eb9SGleb Smirnoff }
6233b3a8eb9SGleb Smirnoff 
624b074b7bbSAlexander V. Chernikov /*
6259f7d47b0SAlexander V. Chernikov  * Destroys table specified by @ti.
626ac35ff17SAlexander V. Chernikov  * Data layout (v0)(current):
627ac35ff17SAlexander V. Chernikov  * Request: [ ip_fw3_opheader ]
628ac35ff17SAlexander V. Chernikov  *
629ac35ff17SAlexander V. Chernikov  * Returns 0 on success
630b074b7bbSAlexander V. Chernikov  */
631ac35ff17SAlexander V. Chernikov static int
632ac35ff17SAlexander V. Chernikov destroy_table(struct ip_fw_chain *ch, struct tid_info *ti)
633b074b7bbSAlexander V. Chernikov {
634b074b7bbSAlexander V. Chernikov 	struct namedobj_instance *ni;
635b074b7bbSAlexander V. Chernikov 	struct table_config *tc;
636b074b7bbSAlexander V. Chernikov 
637b074b7bbSAlexander V. Chernikov 	IPFW_UH_WLOCK(ch);
638b074b7bbSAlexander V. Chernikov 
639b074b7bbSAlexander V. Chernikov 	ni = CHAIN_TO_NI(ch);
640b074b7bbSAlexander V. Chernikov 	if ((tc = find_table(ni, ti)) == NULL) {
641b074b7bbSAlexander V. Chernikov 		IPFW_UH_WUNLOCK(ch);
642b074b7bbSAlexander V. Chernikov 		return (ESRCH);
643b074b7bbSAlexander V. Chernikov 	}
644b074b7bbSAlexander V. Chernikov 
6459f7d47b0SAlexander V. Chernikov 	/* Do not permit destroying referenced tables */
6469f7d47b0SAlexander V. Chernikov 	if (tc->no.refcnt > 0) {
647b074b7bbSAlexander V. Chernikov 		IPFW_UH_WUNLOCK(ch);
648b074b7bbSAlexander V. Chernikov 		return (EBUSY);
649b074b7bbSAlexander V. Chernikov 	}
650b074b7bbSAlexander V. Chernikov 
651b074b7bbSAlexander V. Chernikov 	IPFW_WLOCK(ch);
652b074b7bbSAlexander V. Chernikov 	unlink_table(ch, tc);
653b074b7bbSAlexander V. Chernikov 	IPFW_WUNLOCK(ch);
654b074b7bbSAlexander V. Chernikov 
655b074b7bbSAlexander V. Chernikov 	/* Free obj index */
656ac35ff17SAlexander V. Chernikov 	if (ipfw_objhash_free_idx(ni, tc->no.kidx) != 0)
657b074b7bbSAlexander V. Chernikov 		printf("Error unlinking kidx %d from table %s\n",
658b074b7bbSAlexander V. Chernikov 		    tc->no.kidx, tc->tablename);
659b074b7bbSAlexander V. Chernikov 
660b074b7bbSAlexander V. Chernikov 	IPFW_UH_WUNLOCK(ch);
661b074b7bbSAlexander V. Chernikov 
662b074b7bbSAlexander V. Chernikov 	free_table_config(ni, tc);
663b074b7bbSAlexander V. Chernikov 
664b074b7bbSAlexander V. Chernikov 	return (0);
665b074b7bbSAlexander V. Chernikov }
666b074b7bbSAlexander V. Chernikov 
667b074b7bbSAlexander V. Chernikov static void
668b074b7bbSAlexander V. Chernikov destroy_table_locked(struct namedobj_instance *ni, struct named_object *no,
669b074b7bbSAlexander V. Chernikov     void *arg)
670b074b7bbSAlexander V. Chernikov {
671b074b7bbSAlexander V. Chernikov 
672b074b7bbSAlexander V. Chernikov 	unlink_table((struct ip_fw_chain *)arg, (struct table_config *)no);
673ac35ff17SAlexander V. Chernikov 	if (ipfw_objhash_free_idx(ni, no->kidx) != 0)
674b074b7bbSAlexander V. Chernikov 		printf("Error unlinking kidx %d from table %s\n",
675b074b7bbSAlexander V. Chernikov 		    no->kidx, no->name);
676b074b7bbSAlexander V. Chernikov 	free_table_config(ni, (struct table_config *)no);
677b074b7bbSAlexander V. Chernikov }
678b074b7bbSAlexander V. Chernikov 
6793b3a8eb9SGleb Smirnoff void
6803b3a8eb9SGleb Smirnoff ipfw_destroy_tables(struct ip_fw_chain *ch)
6813b3a8eb9SGleb Smirnoff {
6823b3a8eb9SGleb Smirnoff 
683b074b7bbSAlexander V. Chernikov 	/* Remove all tables from working set */
684b074b7bbSAlexander V. Chernikov 	IPFW_UH_WLOCK(ch);
685b074b7bbSAlexander V. Chernikov 	IPFW_WLOCK(ch);
686b074b7bbSAlexander V. Chernikov 	ipfw_objhash_foreach(CHAIN_TO_NI(ch), destroy_table_locked, ch);
687b074b7bbSAlexander V. Chernikov 	IPFW_WUNLOCK(ch);
688b074b7bbSAlexander V. Chernikov 	IPFW_UH_WUNLOCK(ch);
6893b3a8eb9SGleb Smirnoff 
6903b3a8eb9SGleb Smirnoff 	/* Free pointers itself */
6919f7d47b0SAlexander V. Chernikov 	free(ch->tablestate, M_IPFW);
6929f7d47b0SAlexander V. Chernikov 
6939f7d47b0SAlexander V. Chernikov 	ipfw_table_algo_destroy(ch);
694b074b7bbSAlexander V. Chernikov 
695b074b7bbSAlexander V. Chernikov 	ipfw_objhash_destroy(CHAIN_TO_NI(ch));
696b074b7bbSAlexander V. Chernikov 	free(CHAIN_TO_TCFG(ch), M_IPFW);
6973b3a8eb9SGleb Smirnoff }
6983b3a8eb9SGleb Smirnoff 
6993b3a8eb9SGleb Smirnoff int
7003b3a8eb9SGleb Smirnoff ipfw_init_tables(struct ip_fw_chain *ch)
7013b3a8eb9SGleb Smirnoff {
702b074b7bbSAlexander V. Chernikov 	struct tables_config *tcfg;
703b074b7bbSAlexander V. Chernikov 
7043b3a8eb9SGleb Smirnoff 	/* Allocate pointers */
7059f7d47b0SAlexander V. Chernikov 	ch->tablestate = malloc(V_fw_tables_max * sizeof(struct table_info),
7069f7d47b0SAlexander V. Chernikov 	    M_IPFW, M_WAITOK | M_ZERO);
707b074b7bbSAlexander V. Chernikov 
708b074b7bbSAlexander V. Chernikov 	tcfg = malloc(sizeof(struct tables_config), M_IPFW, M_WAITOK | M_ZERO);
709b074b7bbSAlexander V. Chernikov 	tcfg->namehash = ipfw_objhash_create(V_fw_tables_max);
710b074b7bbSAlexander V. Chernikov 	ch->tblcfg = tcfg;
711b074b7bbSAlexander V. Chernikov 
7129f7d47b0SAlexander V. Chernikov 	ipfw_table_algo_init(ch);
7139f7d47b0SAlexander V. Chernikov 
7143b3a8eb9SGleb Smirnoff 	return (0);
7153b3a8eb9SGleb Smirnoff }
7163b3a8eb9SGleb Smirnoff 
7173b3a8eb9SGleb Smirnoff int
7183b3a8eb9SGleb Smirnoff ipfw_resize_tables(struct ip_fw_chain *ch, unsigned int ntables)
7193b3a8eb9SGleb Smirnoff {
7203b3a8eb9SGleb Smirnoff 	unsigned int ntables_old, tbl;
721b074b7bbSAlexander V. Chernikov 	struct namedobj_instance *ni;
7229f7d47b0SAlexander V. Chernikov 	void *new_idx, *old_tablestate, *tablestate;
723b074b7bbSAlexander V. Chernikov 	int new_blocks;
7243b3a8eb9SGleb Smirnoff 
7253b3a8eb9SGleb Smirnoff 	/* Check new value for validity */
7263b3a8eb9SGleb Smirnoff 	if (ntables > IPFW_TABLES_MAX)
7273b3a8eb9SGleb Smirnoff 		ntables = IPFW_TABLES_MAX;
7283b3a8eb9SGleb Smirnoff 
7293b3a8eb9SGleb Smirnoff 	/* Allocate new pointers */
7309f7d47b0SAlexander V. Chernikov 	tablestate = malloc(ntables * sizeof(struct table_info),
7319f7d47b0SAlexander V. Chernikov 	    M_IPFW, M_WAITOK | M_ZERO);
7329f7d47b0SAlexander V. Chernikov 
733b074b7bbSAlexander V. Chernikov 	ipfw_objhash_bitmap_alloc(ntables, (void *)&new_idx, &new_blocks);
7343b3a8eb9SGleb Smirnoff 
7359f7d47b0SAlexander V. Chernikov 	IPFW_UH_WLOCK(ch);
7363b3a8eb9SGleb Smirnoff 
7373b3a8eb9SGleb Smirnoff 	tbl = (ntables >= V_fw_tables_max) ? V_fw_tables_max : ntables;
738b074b7bbSAlexander V. Chernikov 	ni = CHAIN_TO_NI(ch);
739b074b7bbSAlexander V. Chernikov 
7409f7d47b0SAlexander V. Chernikov 	/* Temporary restrict decreasing max_tables */
7419f7d47b0SAlexander V. Chernikov 	if (ntables < V_fw_tables_max) {
7429f7d47b0SAlexander V. Chernikov 
7439f7d47b0SAlexander V. Chernikov 		/*
7449f7d47b0SAlexander V. Chernikov 		 * FIXME: Check if we really can shrink
7459f7d47b0SAlexander V. Chernikov 		 */
7469f7d47b0SAlexander V. Chernikov 		IPFW_UH_WUNLOCK(ch);
747b074b7bbSAlexander V. Chernikov 		return (EINVAL);
748b074b7bbSAlexander V. Chernikov 	}
7493b3a8eb9SGleb Smirnoff 
7509f7d47b0SAlexander V. Chernikov 	/* Copy table info/indices */
7519f7d47b0SAlexander V. Chernikov 	memcpy(tablestate, ch->tablestate, sizeof(struct table_info) * tbl);
7529f7d47b0SAlexander V. Chernikov 	ipfw_objhash_bitmap_merge(ni, &new_idx, &new_blocks);
7533b3a8eb9SGleb Smirnoff 
7549f7d47b0SAlexander V. Chernikov 	IPFW_WLOCK(ch);
7559f7d47b0SAlexander V. Chernikov 
7569f7d47b0SAlexander V. Chernikov 	/* Change pointers */
7579f7d47b0SAlexander V. Chernikov 	old_tablestate = ch->tablestate;
7589f7d47b0SAlexander V. Chernikov 	ch->tablestate = tablestate;
7599f7d47b0SAlexander V. Chernikov 	ipfw_objhash_bitmap_swap(ni, &new_idx, &new_blocks);
7603b3a8eb9SGleb Smirnoff 
7613b3a8eb9SGleb Smirnoff 	ntables_old = V_fw_tables_max;
7623b3a8eb9SGleb Smirnoff 	V_fw_tables_max = ntables;
7633b3a8eb9SGleb Smirnoff 
7643b3a8eb9SGleb Smirnoff 	IPFW_WUNLOCK(ch);
7659f7d47b0SAlexander V. Chernikov 	IPFW_UH_WUNLOCK(ch);
7663b3a8eb9SGleb Smirnoff 
7673b3a8eb9SGleb Smirnoff 	/* Free old pointers */
7689f7d47b0SAlexander V. Chernikov 	free(old_tablestate, M_IPFW);
769b074b7bbSAlexander V. Chernikov 	ipfw_objhash_bitmap_free(new_idx, new_blocks);
7703b3a8eb9SGleb Smirnoff 
7713b3a8eb9SGleb Smirnoff 	return (0);
7723b3a8eb9SGleb Smirnoff }
7733b3a8eb9SGleb Smirnoff 
7743b3a8eb9SGleb Smirnoff int
7753b3a8eb9SGleb Smirnoff ipfw_lookup_table(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr,
7763b3a8eb9SGleb Smirnoff     uint32_t *val)
7773b3a8eb9SGleb Smirnoff {
7789f7d47b0SAlexander V. Chernikov 	struct table_info *ti;
7793b3a8eb9SGleb Smirnoff 
7809f7d47b0SAlexander V. Chernikov 	ti = &(((struct table_info *)ch->tablestate)[tbl]);
7819f7d47b0SAlexander V. Chernikov 
7829f7d47b0SAlexander V. Chernikov 	return (ti->lookup(ti, &addr, sizeof(in_addr_t), val));
7833b3a8eb9SGleb Smirnoff }
7849f7d47b0SAlexander V. Chernikov 
7859f7d47b0SAlexander V. Chernikov int
7869f7d47b0SAlexander V. Chernikov ipfw_lookup_table_extended(struct ip_fw_chain *ch, uint16_t tbl, uint16_t plen,
7879f7d47b0SAlexander V. Chernikov     void *paddr, uint32_t *val)
7889f7d47b0SAlexander V. Chernikov {
7899f7d47b0SAlexander V. Chernikov 	struct table_info *ti;
7909f7d47b0SAlexander V. Chernikov 
7919f7d47b0SAlexander V. Chernikov 	ti = &(((struct table_info *)ch->tablestate)[tbl]);
7929f7d47b0SAlexander V. Chernikov 
7939f7d47b0SAlexander V. Chernikov 	return (ti->lookup(ti, paddr, plen, val));
7949f7d47b0SAlexander V. Chernikov }
7959f7d47b0SAlexander V. Chernikov 
7969f7d47b0SAlexander V. Chernikov /*
7979f7d47b0SAlexander V. Chernikov  * Info/List/dump support for tables.
7989f7d47b0SAlexander V. Chernikov  *
7999f7d47b0SAlexander V. Chernikov  */
8009f7d47b0SAlexander V. Chernikov 
801f1220db8SAlexander V. Chernikov /*
802d3a4f924SAlexander V. Chernikov  * High-level 'get' cmds sysctl handlers
803d3a4f924SAlexander V. Chernikov  */
804d3a4f924SAlexander V. Chernikov 
805d3a4f924SAlexander V. Chernikov /*
806d3a4f924SAlexander V. Chernikov  * Get buffer size needed to list info for all tables.
807ac35ff17SAlexander V. Chernikov  * Data layout (v0)(current):
808d3a4f924SAlexander V. Chernikov  * Request: [ empty ], size = sizeof(ipfw_obj_lheader)
809d3a4f924SAlexander V. Chernikov  * Reply: [ ipfw_obj_lheader ]
810d3a4f924SAlexander V. Chernikov  *
811d3a4f924SAlexander V. Chernikov  * Returns 0 on success
812f1220db8SAlexander V. Chernikov  */
813f1220db8SAlexander V. Chernikov int
8142d99a349SAlexander V. Chernikov ipfw_listsize_tables(struct ip_fw_chain *ch, struct sockopt_data *sd)
815f1220db8SAlexander V. Chernikov {
816f1220db8SAlexander V. Chernikov 	struct _ipfw_obj_lheader *olh;
817f1220db8SAlexander V. Chernikov 
8182d99a349SAlexander V. Chernikov 	olh = (struct _ipfw_obj_lheader *)ipfw_get_sopt_header(sd,sizeof(*olh));
8192d99a349SAlexander V. Chernikov 	if (olh == NULL)
820d3a4f924SAlexander V. Chernikov 		return (EINVAL);
821d3a4f924SAlexander V. Chernikov 
822f1220db8SAlexander V. Chernikov 	olh->size = sizeof(*olh); /* Make export_table store needed size */
823f1220db8SAlexander V. Chernikov 
824f1220db8SAlexander V. Chernikov 	IPFW_UH_RLOCK(ch);
8252d99a349SAlexander V. Chernikov 	export_tables(ch, olh, sd);
826f1220db8SAlexander V. Chernikov 	IPFW_UH_RUNLOCK(ch);
827f1220db8SAlexander V. Chernikov 
8282d99a349SAlexander V. Chernikov 	return (0);
829f1220db8SAlexander V. Chernikov }
830f1220db8SAlexander V. Chernikov 
831d3a4f924SAlexander V. Chernikov /*
832d3a4f924SAlexander V. Chernikov  * Lists all tables currently available in kernel.
833ac35ff17SAlexander V. Chernikov  * Data layout (v0)(current):
834d3a4f924SAlexander V. Chernikov  * Request: [ ipfw_obj_lheader ], size = ipfw_obj_lheader.size
835d3a4f924SAlexander V. Chernikov  * Reply: [ ipfw_obj_lheader ipfw_xtable_info x N ]
836d3a4f924SAlexander V. Chernikov  *
837d3a4f924SAlexander V. Chernikov  * Returns 0 on success
838d3a4f924SAlexander V. Chernikov  */
839f1220db8SAlexander V. Chernikov int
8402d99a349SAlexander V. Chernikov ipfw_list_tables(struct ip_fw_chain *ch, struct sockopt_data *sd)
841f1220db8SAlexander V. Chernikov {
842f1220db8SAlexander V. Chernikov 	struct _ipfw_obj_lheader *olh;
843d3a4f924SAlexander V. Chernikov 	uint32_t sz;
844f1220db8SAlexander V. Chernikov 	int error;
845f1220db8SAlexander V. Chernikov 
8462d99a349SAlexander V. Chernikov 	olh = (struct _ipfw_obj_lheader *)ipfw_get_sopt_header(sd,sizeof(*olh));
8472d99a349SAlexander V. Chernikov 	if (olh == NULL)
848d3a4f924SAlexander V. Chernikov 		return (EINVAL);
849d3a4f924SAlexander V. Chernikov 
850f1220db8SAlexander V. Chernikov 	IPFW_UH_RLOCK(ch);
851f1220db8SAlexander V. Chernikov 	sz = ipfw_objhash_count(CHAIN_TO_NI(ch));
8522d99a349SAlexander V. Chernikov 
8532d99a349SAlexander V. Chernikov 	if (sd->valsize < sz) {
8542d99a349SAlexander V. Chernikov 		IPFW_UH_RUNLOCK(ch);
8552d99a349SAlexander V. Chernikov 		return (ENOMEM);
8562d99a349SAlexander V. Chernikov 	}
8572d99a349SAlexander V. Chernikov 
8582d99a349SAlexander V. Chernikov 	error = export_tables(ch, olh, sd);
859f1220db8SAlexander V. Chernikov 	IPFW_UH_RUNLOCK(ch);
860f1220db8SAlexander V. Chernikov 
861f1220db8SAlexander V. Chernikov 	return (error);
862f1220db8SAlexander V. Chernikov }
863f1220db8SAlexander V. Chernikov 
864f1220db8SAlexander V. Chernikov /*
8652d99a349SAlexander V. Chernikov  * Store table info to buffer provided by @sd.
866ac35ff17SAlexander V. Chernikov  * Data layout (v0)(current):
867d3a4f924SAlexander V. Chernikov  * Request: [ ipfw_obj_header ipfw_xtable_info(empty)]
868d3a4f924SAlexander V. Chernikov  * Reply: [ ipfw_obj_header ipfw_xtable_info ]
869d3a4f924SAlexander V. Chernikov  *
870d3a4f924SAlexander V. Chernikov  * Returns 0 on success.
871d3a4f924SAlexander V. Chernikov  */
872d3a4f924SAlexander V. Chernikov int
8732d99a349SAlexander V. Chernikov ipfw_describe_table(struct ip_fw_chain *ch, struct sockopt_data *sd)
874d3a4f924SAlexander V. Chernikov {
875d3a4f924SAlexander V. Chernikov 	struct _ipfw_obj_header *oh;
876d3a4f924SAlexander V. Chernikov 	struct table_config *tc;
877d3a4f924SAlexander V. Chernikov 	struct tid_info ti;
878d3a4f924SAlexander V. Chernikov 	size_t sz;
879d3a4f924SAlexander V. Chernikov 
880d3a4f924SAlexander V. Chernikov 	sz = sizeof(*oh) + sizeof(ipfw_xtable_info);
8812d99a349SAlexander V. Chernikov 	oh = (struct _ipfw_obj_header *)ipfw_get_sopt_header(sd, sz);
8822d99a349SAlexander V. Chernikov 	if (oh == NULL)
883d3a4f924SAlexander V. Chernikov 		return (EINVAL);
884d3a4f924SAlexander V. Chernikov 
885d3a4f924SAlexander V. Chernikov 	objheader_to_ti(oh, &ti);
886d3a4f924SAlexander V. Chernikov 
887d3a4f924SAlexander V. Chernikov 	IPFW_UH_RLOCK(ch);
888d3a4f924SAlexander V. Chernikov 	if ((tc = find_table(CHAIN_TO_NI(ch), &ti)) == NULL) {
889d3a4f924SAlexander V. Chernikov 		IPFW_UH_RUNLOCK(ch);
890d3a4f924SAlexander V. Chernikov 		return (ESRCH);
891d3a4f924SAlexander V. Chernikov 	}
892d3a4f924SAlexander V. Chernikov 
893ac35ff17SAlexander V. Chernikov 	export_table_info(ch, tc, (ipfw_xtable_info *)(oh + 1));
894d3a4f924SAlexander V. Chernikov 	IPFW_UH_RUNLOCK(ch);
895d3a4f924SAlexander V. Chernikov 
8962d99a349SAlexander V. Chernikov 	return (0);
897d3a4f924SAlexander V. Chernikov }
898d3a4f924SAlexander V. Chernikov 
899f1220db8SAlexander V. Chernikov struct dump_args {
900f1220db8SAlexander V. Chernikov 	struct table_info *ti;
901f1220db8SAlexander V. Chernikov 	struct table_config *tc;
9022d99a349SAlexander V. Chernikov 	struct sockopt_data *sd;
903f1220db8SAlexander V. Chernikov 	uint32_t cnt;
904f1220db8SAlexander V. Chernikov 	uint16_t uidx;
90581d3153dSAlexander V. Chernikov 	int error;
9062d99a349SAlexander V. Chernikov 	ipfw_table_entry *ent;
9072d99a349SAlexander V. Chernikov 	uint32_t size;
90881d3153dSAlexander V. Chernikov 	ipfw_obj_tentry tent;
909f1220db8SAlexander V. Chernikov };
910f1220db8SAlexander V. Chernikov 
911f1220db8SAlexander V. Chernikov int
9122d99a349SAlexander V. Chernikov ipfw_dump_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
9132d99a349SAlexander V. Chernikov     struct sockopt_data *sd)
914f1220db8SAlexander V. Chernikov {
915d3a4f924SAlexander V. Chernikov 	int error;
916d3a4f924SAlexander V. Chernikov 
917d3a4f924SAlexander V. Chernikov 	switch (op3->version) {
918d3a4f924SAlexander V. Chernikov 	case 0:
9192d99a349SAlexander V. Chernikov 		error = ipfw_dump_table_v0(ch, sd);
920d3a4f924SAlexander V. Chernikov 		break;
921d3a4f924SAlexander V. Chernikov 	case 1:
9222d99a349SAlexander V. Chernikov 		error = ipfw_dump_table_v1(ch, sd);
923d3a4f924SAlexander V. Chernikov 		break;
924d3a4f924SAlexander V. Chernikov 	default:
925d3a4f924SAlexander V. Chernikov 		error = ENOTSUP;
926d3a4f924SAlexander V. Chernikov 	}
927d3a4f924SAlexander V. Chernikov 
928d3a4f924SAlexander V. Chernikov 	return (error);
929d3a4f924SAlexander V. Chernikov }
930d3a4f924SAlexander V. Chernikov 
931d3a4f924SAlexander V. Chernikov /*
932d3a4f924SAlexander V. Chernikov  * Dumps all table data
933ac35ff17SAlexander V. Chernikov  * Data layout (v1)(current):
9342d99a349SAlexander V. Chernikov  * Request: [ ipfw_obj_header ], size = ipfw_xtable_info.size
93581d3153dSAlexander V. Chernikov  * Reply: [ ipfw_obj_header ipfw_xtable_info ipfw_obj_tentry x N ]
936d3a4f924SAlexander V. Chernikov  *
937d3a4f924SAlexander V. Chernikov  * Returns 0 on success
938d3a4f924SAlexander V. Chernikov  */
939d3a4f924SAlexander V. Chernikov static int
9402d99a349SAlexander V. Chernikov ipfw_dump_table_v1(struct ip_fw_chain *ch, struct sockopt_data *sd)
941d3a4f924SAlexander V. Chernikov {
942f1220db8SAlexander V. Chernikov 	struct _ipfw_obj_header *oh;
943f1220db8SAlexander V. Chernikov 	ipfw_xtable_info *i;
944f1220db8SAlexander V. Chernikov 	struct tid_info ti;
945f1220db8SAlexander V. Chernikov 	struct table_config *tc;
946f1220db8SAlexander V. Chernikov 	struct table_algo *ta;
947f1220db8SAlexander V. Chernikov 	struct dump_args da;
948d3a4f924SAlexander V. Chernikov 	uint32_t sz;
949f1220db8SAlexander V. Chernikov 
9502d99a349SAlexander V. Chernikov 	sz = sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info);
9512d99a349SAlexander V. Chernikov 	oh = (struct _ipfw_obj_header *)ipfw_get_sopt_header(sd, sz);
9522d99a349SAlexander V. Chernikov 	if (oh == NULL)
953d3a4f924SAlexander V. Chernikov 		return (EINVAL);
954d3a4f924SAlexander V. Chernikov 
9552d99a349SAlexander V. Chernikov 	i = (ipfw_xtable_info *)(oh + 1);
956d3a4f924SAlexander V. Chernikov 	objheader_to_ti(oh, &ti);
957f1220db8SAlexander V. Chernikov 
958f1220db8SAlexander V. Chernikov 	IPFW_UH_RLOCK(ch);
959f1220db8SAlexander V. Chernikov 	if ((tc = find_table(CHAIN_TO_NI(ch), &ti)) == NULL) {
960f1220db8SAlexander V. Chernikov 		IPFW_UH_RUNLOCK(ch);
961f1220db8SAlexander V. Chernikov 		return (ESRCH);
962f1220db8SAlexander V. Chernikov 	}
963ac35ff17SAlexander V. Chernikov 	export_table_info(ch, tc, i);
9642d99a349SAlexander V. Chernikov 	sz = tc->count;
9652d99a349SAlexander V. Chernikov 
96681d3153dSAlexander V. Chernikov 	if (sd->valsize < sz + tc->count * sizeof(ipfw_obj_tentry)) {
9672d99a349SAlexander V. Chernikov 
9682d99a349SAlexander V. Chernikov 		/*
9692d99a349SAlexander V. Chernikov 		 * Submitted buffer size is not enough.
9702d99a349SAlexander V. Chernikov 		 * WE've already filled in @i structure with
9712d99a349SAlexander V. Chernikov 		 * relevant table info including size, so we
9722d99a349SAlexander V. Chernikov 		 * can return. Buffer will be flushed automatically.
9732d99a349SAlexander V. Chernikov 		 */
974f1220db8SAlexander V. Chernikov 		IPFW_UH_RUNLOCK(ch);
9752d99a349SAlexander V. Chernikov 		return (ENOMEM);
976f1220db8SAlexander V. Chernikov 	}
977f1220db8SAlexander V. Chernikov 
978f1220db8SAlexander V. Chernikov 	/*
979f1220db8SAlexander V. Chernikov 	 * Do the actual dump in eXtended format
980f1220db8SAlexander V. Chernikov 	 */
981d3a4f924SAlexander V. Chernikov 	memset(&da, 0, sizeof(da));
982f1220db8SAlexander V. Chernikov 	da.ti = KIDX_TO_TI(ch, tc->no.kidx);
983f1220db8SAlexander V. Chernikov 	da.tc = tc;
9842d99a349SAlexander V. Chernikov 	da.sd = sd;
985f1220db8SAlexander V. Chernikov 
986f1220db8SAlexander V. Chernikov 	ta = tc->ta;
987f1220db8SAlexander V. Chernikov 
98881d3153dSAlexander V. Chernikov 	ta->foreach(tc->astate, da.ti, dump_table_tentry, &da);
989f1220db8SAlexander V. Chernikov 	IPFW_UH_RUNLOCK(ch);
990f1220db8SAlexander V. Chernikov 
99181d3153dSAlexander V. Chernikov 	return (da.error);
992f1220db8SAlexander V. Chernikov }
993f1220db8SAlexander V. Chernikov 
994d3a4f924SAlexander V. Chernikov /*
995d3a4f924SAlexander V. Chernikov  * Dumps all table data
9962d99a349SAlexander V. Chernikov  * Data layout (version 0)(legacy):
997d3a4f924SAlexander V. Chernikov  * Request: [ ipfw_xtable ], size = IP_FW_TABLE_XGETSIZE()
998d3a4f924SAlexander V. Chernikov  * Reply: [ ipfw_xtable ipfw_table_xentry x N ]
999d3a4f924SAlexander V. Chernikov  *
1000d3a4f924SAlexander V. Chernikov  * Returns 0 on success
1001d3a4f924SAlexander V. Chernikov  */
1002d3a4f924SAlexander V. Chernikov static int
10032d99a349SAlexander V. Chernikov ipfw_dump_table_v0(struct ip_fw_chain *ch, struct sockopt_data *sd)
1004d3a4f924SAlexander V. Chernikov {
1005d3a4f924SAlexander V. Chernikov 	ipfw_xtable *xtbl;
1006d3a4f924SAlexander V. Chernikov 	struct tid_info ti;
1007d3a4f924SAlexander V. Chernikov 	struct table_config *tc;
1008d3a4f924SAlexander V. Chernikov 	struct table_algo *ta;
1009d3a4f924SAlexander V. Chernikov 	struct dump_args da;
1010d3a4f924SAlexander V. Chernikov 	size_t sz;
1011d3a4f924SAlexander V. Chernikov 
10122d99a349SAlexander V. Chernikov 	xtbl = (ipfw_xtable *)ipfw_get_sopt_header(sd, sizeof(ipfw_xtable));
10132d99a349SAlexander V. Chernikov 	if (xtbl == NULL)
1014d3a4f924SAlexander V. Chernikov 		return (EINVAL);
1015d3a4f924SAlexander V. Chernikov 
1016d3a4f924SAlexander V. Chernikov 	memset(&ti, 0, sizeof(ti));
1017d3a4f924SAlexander V. Chernikov 	ti.uidx = xtbl->tbl;
1018d3a4f924SAlexander V. Chernikov 
1019d3a4f924SAlexander V. Chernikov 	IPFW_UH_RLOCK(ch);
1020d3a4f924SAlexander V. Chernikov 	if ((tc = find_table(CHAIN_TO_NI(ch), &ti)) == NULL) {
1021d3a4f924SAlexander V. Chernikov 		IPFW_UH_RUNLOCK(ch);
1022d3a4f924SAlexander V. Chernikov 		return (0);
1023d3a4f924SAlexander V. Chernikov 	}
1024d3a4f924SAlexander V. Chernikov 	sz = tc->count * sizeof(ipfw_table_xentry) + sizeof(ipfw_xtable);
10252d99a349SAlexander V. Chernikov 
10262d99a349SAlexander V. Chernikov 	xtbl->cnt = tc->count;
10272d99a349SAlexander V. Chernikov 	xtbl->size = sz;
10282d99a349SAlexander V. Chernikov 	xtbl->type = tc->no.type;
10292d99a349SAlexander V. Chernikov 	xtbl->tbl = ti.uidx;
10302d99a349SAlexander V. Chernikov 
10312d99a349SAlexander V. Chernikov 	if (sd->valsize < sz) {
10322d99a349SAlexander V. Chernikov 
10332d99a349SAlexander V. Chernikov 		/*
10342d99a349SAlexander V. Chernikov 		 * Submitted buffer size is not enough.
10352d99a349SAlexander V. Chernikov 		 * WE've already filled in @i structure with
10362d99a349SAlexander V. Chernikov 		 * relevant table info including size, so we
10372d99a349SAlexander V. Chernikov 		 * can return. Buffer will be flushed automatically.
10382d99a349SAlexander V. Chernikov 		 */
1039d3a4f924SAlexander V. Chernikov 		IPFW_UH_RUNLOCK(ch);
10402d99a349SAlexander V. Chernikov 		return (ENOMEM);
1041d3a4f924SAlexander V. Chernikov 	}
1042d3a4f924SAlexander V. Chernikov 
1043d3a4f924SAlexander V. Chernikov 	/* Do the actual dump in eXtended format */
1044d3a4f924SAlexander V. Chernikov 	memset(&da, 0, sizeof(da));
1045d3a4f924SAlexander V. Chernikov 	da.ti = KIDX_TO_TI(ch, tc->no.kidx);
1046d3a4f924SAlexander V. Chernikov 	da.tc = tc;
10472d99a349SAlexander V. Chernikov 	da.sd = sd;
10482d99a349SAlexander V. Chernikov 
1049d3a4f924SAlexander V. Chernikov 	ta = tc->ta;
1050d3a4f924SAlexander V. Chernikov 
1051d3a4f924SAlexander V. Chernikov 	ta->foreach(tc->astate, da.ti, dump_table_xentry, &da);
1052d3a4f924SAlexander V. Chernikov 	IPFW_UH_RUNLOCK(ch);
1053d3a4f924SAlexander V. Chernikov 
10542d99a349SAlexander V. Chernikov 	return (0);
1055d3a4f924SAlexander V. Chernikov }
1056d3a4f924SAlexander V. Chernikov 
1057d3a4f924SAlexander V. Chernikov /*
10589490a627SAlexander V. Chernikov  * Creates new table.
1059ac35ff17SAlexander V. Chernikov  * Data layout (v0)(current):
10609490a627SAlexander V. Chernikov  * Request: [ ipfw_obj_header ipfw_xtable_info ]
10619490a627SAlexander V. Chernikov  *
10629490a627SAlexander V. Chernikov  * Returns 0 on success
10639490a627SAlexander V. Chernikov  */
10649490a627SAlexander V. Chernikov int
1065ac35ff17SAlexander V. Chernikov ipfw_create_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
1066ac35ff17SAlexander V. Chernikov     struct sockopt_data *sd)
10679490a627SAlexander V. Chernikov {
10689490a627SAlexander V. Chernikov 	struct _ipfw_obj_header *oh;
10699490a627SAlexander V. Chernikov 	ipfw_xtable_info *i;
10709490a627SAlexander V. Chernikov 	char *tname, *aname;
10719490a627SAlexander V. Chernikov 	struct tid_info ti;
10729490a627SAlexander V. Chernikov 	struct namedobj_instance *ni;
10739490a627SAlexander V. Chernikov 	struct table_config *tc;
10749490a627SAlexander V. Chernikov 	struct table_algo *ta;
10759490a627SAlexander V. Chernikov 	uint16_t kidx;
10769490a627SAlexander V. Chernikov 
1077ac35ff17SAlexander V. Chernikov 	if (sd->valsize != sizeof(*oh) + sizeof(ipfw_xtable_info))
10789490a627SAlexander V. Chernikov 		return (EINVAL);
10799490a627SAlexander V. Chernikov 
1080ac35ff17SAlexander V. Chernikov 	oh = (struct _ipfw_obj_header *)sd->kbuf;
10819490a627SAlexander V. Chernikov 	i = (ipfw_xtable_info *)(oh + 1);
10829490a627SAlexander V. Chernikov 
10839490a627SAlexander V. Chernikov 	/*
10849490a627SAlexander V. Chernikov 	 * Verify user-supplied strings.
10852d99a349SAlexander V. Chernikov 	 * Check for null-terminated/zero-length strings/
10869490a627SAlexander V. Chernikov 	 */
1087ac35ff17SAlexander V. Chernikov 	tname = oh->ntlv.name;
10889490a627SAlexander V. Chernikov 	aname = i->algoname;
1089ac35ff17SAlexander V. Chernikov 	if (ipfw_check_table_name(tname) != 0 ||
10909490a627SAlexander V. Chernikov 	    strnlen(aname, sizeof(i->algoname)) == sizeof(i->algoname))
10919490a627SAlexander V. Chernikov 		return (EINVAL);
10929490a627SAlexander V. Chernikov 
10939490a627SAlexander V. Chernikov 	if (aname[0] == '\0') {
10949490a627SAlexander V. Chernikov 		/* Use default algorithm */
10959490a627SAlexander V. Chernikov 		aname = NULL;
10969490a627SAlexander V. Chernikov 	}
10979490a627SAlexander V. Chernikov 
10989490a627SAlexander V. Chernikov 	objheader_to_ti(oh, &ti);
1099ac35ff17SAlexander V. Chernikov 	ti.type = i->type;
11009490a627SAlexander V. Chernikov 
11019490a627SAlexander V. Chernikov 	ni = CHAIN_TO_NI(ch);
11029490a627SAlexander V. Chernikov 
11039490a627SAlexander V. Chernikov 	IPFW_UH_RLOCK(ch);
11049490a627SAlexander V. Chernikov 	if ((tc = find_table(ni, &ti)) != NULL) {
11059490a627SAlexander V. Chernikov 		IPFW_UH_RUNLOCK(ch);
11069490a627SAlexander V. Chernikov 		return (EEXIST);
11079490a627SAlexander V. Chernikov 	}
11089490a627SAlexander V. Chernikov 	ta = find_table_algo(CHAIN_TO_TCFG(ch), &ti, aname);
11099490a627SAlexander V. Chernikov 	IPFW_UH_RUNLOCK(ch);
11109490a627SAlexander V. Chernikov 
11119490a627SAlexander V. Chernikov 	if (ta == NULL)
11129490a627SAlexander V. Chernikov 		return (ENOTSUP);
11139490a627SAlexander V. Chernikov 
11149490a627SAlexander V. Chernikov 	if ((tc = alloc_table_config(ni, &ti, ta, aname)) == NULL)
11159490a627SAlexander V. Chernikov 		return (ENOMEM);
1116ac35ff17SAlexander V. Chernikov 	/* TODO: move inside alloc_table_config() */
1117ac35ff17SAlexander V. Chernikov 	tc->vtype = i->vtype;
11189490a627SAlexander V. Chernikov 
11199490a627SAlexander V. Chernikov 	IPFW_UH_WLOCK(ch);
1120ac35ff17SAlexander V. Chernikov 	if (ipfw_objhash_alloc_idx(ni, &kidx) != 0) {
11219490a627SAlexander V. Chernikov 		IPFW_UH_WUNLOCK(ch);
11229490a627SAlexander V. Chernikov 		printf("Unable to allocate table index for table %s in set %u."
11239490a627SAlexander V. Chernikov 		    " Consider increasing net.inet.ip.fw.tables_max",
11249490a627SAlexander V. Chernikov 		    tname, ti.set);
11259490a627SAlexander V. Chernikov 		free_table_config(ni, tc);
11269490a627SAlexander V. Chernikov 		return (EBUSY);
11279490a627SAlexander V. Chernikov 	}
11289490a627SAlexander V. Chernikov 
11299490a627SAlexander V. Chernikov 	tc->no.kidx = kidx;
11309490a627SAlexander V. Chernikov 
11319490a627SAlexander V. Chernikov 	IPFW_WLOCK(ch);
11329490a627SAlexander V. Chernikov 	link_table(ch, tc);
11339490a627SAlexander V. Chernikov 	IPFW_WUNLOCK(ch);
11349490a627SAlexander V. Chernikov 
11359490a627SAlexander V. Chernikov 	IPFW_UH_WUNLOCK(ch);
11369490a627SAlexander V. Chernikov 
11379490a627SAlexander V. Chernikov 	return (0);
11389490a627SAlexander V. Chernikov }
11399490a627SAlexander V. Chernikov 
1140d3a4f924SAlexander V. Chernikov void
1141d3a4f924SAlexander V. Chernikov objheader_to_ti(struct _ipfw_obj_header *oh, struct tid_info *ti)
1142d3a4f924SAlexander V. Chernikov {
1143d3a4f924SAlexander V. Chernikov 
1144d3a4f924SAlexander V. Chernikov 	memset(ti, 0, sizeof(struct tid_info));
114581d3153dSAlexander V. Chernikov 	ti->set = oh->ntlv.set;
1146d3a4f924SAlexander V. Chernikov 	ti->uidx = oh->idx;
1147d3a4f924SAlexander V. Chernikov 	ti->tlvs = &oh->ntlv;
1148d3a4f924SAlexander V. Chernikov 	ti->tlen = oh->ntlv.head.length;
1149d3a4f924SAlexander V. Chernikov }
1150d3a4f924SAlexander V. Chernikov 
1151563b5ab1SAlexander V. Chernikov int
1152563b5ab1SAlexander V. Chernikov ipfw_export_table_ntlv(struct ip_fw_chain *ch, uint16_t kidx,
1153563b5ab1SAlexander V. Chernikov     struct sockopt_data *sd)
1154563b5ab1SAlexander V. Chernikov {
1155563b5ab1SAlexander V. Chernikov 	struct namedobj_instance *ni;
1156563b5ab1SAlexander V. Chernikov 	struct named_object *no;
1157563b5ab1SAlexander V. Chernikov 	ipfw_obj_ntlv *ntlv;
1158563b5ab1SAlexander V. Chernikov 
1159563b5ab1SAlexander V. Chernikov 	ni = CHAIN_TO_NI(ch);
1160563b5ab1SAlexander V. Chernikov 
1161ac35ff17SAlexander V. Chernikov 	no = ipfw_objhash_lookup_kidx(ni, kidx);
1162563b5ab1SAlexander V. Chernikov 	KASSERT(no != NULL, ("invalid table kidx passed"));
1163563b5ab1SAlexander V. Chernikov 
1164563b5ab1SAlexander V. Chernikov 	ntlv = (ipfw_obj_ntlv *)ipfw_get_sopt_space(sd, sizeof(*ntlv));
1165563b5ab1SAlexander V. Chernikov 	if (ntlv == NULL)
1166563b5ab1SAlexander V. Chernikov 		return (ENOMEM);
1167563b5ab1SAlexander V. Chernikov 
1168563b5ab1SAlexander V. Chernikov 	ntlv->head.type = IPFW_TLV_TBL_NAME;
1169563b5ab1SAlexander V. Chernikov 	ntlv->head.length = sizeof(*ntlv);
1170563b5ab1SAlexander V. Chernikov 	ntlv->idx = no->kidx;
1171563b5ab1SAlexander V. Chernikov 	strlcpy(ntlv->name, no->name, sizeof(ntlv->name));
1172563b5ab1SAlexander V. Chernikov 
1173563b5ab1SAlexander V. Chernikov 	return (0);
1174563b5ab1SAlexander V. Chernikov }
1175563b5ab1SAlexander V. Chernikov 
11769f7d47b0SAlexander V. Chernikov static void
1177ac35ff17SAlexander V. Chernikov export_table_info(struct ip_fw_chain *ch, struct table_config *tc,
1178ac35ff17SAlexander V. Chernikov     ipfw_xtable_info *i)
11799f7d47b0SAlexander V. Chernikov {
1180ac35ff17SAlexander V. Chernikov 	struct table_info *ti;
11819f7d47b0SAlexander V. Chernikov 
11829f7d47b0SAlexander V. Chernikov 	i->type = tc->no.type;
1183ac35ff17SAlexander V. Chernikov 	i->vtype = tc->vtype;
11849f7d47b0SAlexander V. Chernikov 	i->set = tc->no.set;
11859f7d47b0SAlexander V. Chernikov 	i->kidx = tc->no.kidx;
11869f7d47b0SAlexander V. Chernikov 	i->refcnt = tc->no.refcnt;
11879f7d47b0SAlexander V. Chernikov 	i->count = tc->count;
118881d3153dSAlexander V. Chernikov 	i->size = tc->count * sizeof(ipfw_obj_tentry);
1189f1220db8SAlexander V. Chernikov 	i->size += sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info);
11909f7d47b0SAlexander V. Chernikov 	strlcpy(i->tablename, tc->tablename, sizeof(i->tablename));
1191ac35ff17SAlexander V. Chernikov 	if (tc->ta->print_config != NULL) {
1192ac35ff17SAlexander V. Chernikov 		/* Use algo function to print table config to string */
1193ac35ff17SAlexander V. Chernikov 		ti = KIDX_TO_TI(ch, tc->no.kidx);
1194ac35ff17SAlexander V. Chernikov 		tc->ta->print_config(tc->astate, ti, i->algoname,
1195ac35ff17SAlexander V. Chernikov 		    sizeof(i->algoname));
1196ac35ff17SAlexander V. Chernikov 	} else
1197ac35ff17SAlexander V. Chernikov 		strlcpy(i->algoname, tc->ta->name, sizeof(i->algoname));
11989f7d47b0SAlexander V. Chernikov }
11999f7d47b0SAlexander V. Chernikov 
1200ac35ff17SAlexander V. Chernikov struct dump_table_args {
1201ac35ff17SAlexander V. Chernikov 	struct ip_fw_chain *ch;
1202ac35ff17SAlexander V. Chernikov 	struct sockopt_data *sd;
1203ac35ff17SAlexander V. Chernikov };
1204ac35ff17SAlexander V. Chernikov 
12059f7d47b0SAlexander V. Chernikov static void
12069f7d47b0SAlexander V. Chernikov export_table_internal(struct namedobj_instance *ni, struct named_object *no,
12079f7d47b0SAlexander V. Chernikov     void *arg)
12083b3a8eb9SGleb Smirnoff {
12099f7d47b0SAlexander V. Chernikov 	ipfw_xtable_info *i;
1210ac35ff17SAlexander V. Chernikov 	struct dump_table_args *dta;
12113b3a8eb9SGleb Smirnoff 
1212ac35ff17SAlexander V. Chernikov 	dta = (struct dump_table_args *)arg;
1213ac35ff17SAlexander V. Chernikov 
1214ac35ff17SAlexander V. Chernikov 	i = (ipfw_xtable_info *)ipfw_get_sopt_space(dta->sd, sizeof(*i));
12152d99a349SAlexander V. Chernikov 	KASSERT(i == 0, ("previously checked buffer is not enough"));
12169f7d47b0SAlexander V. Chernikov 
1217ac35ff17SAlexander V. Chernikov 	export_table_info(dta->ch, (struct table_config *)no, i);
12189f7d47b0SAlexander V. Chernikov }
12199f7d47b0SAlexander V. Chernikov 
1220f1220db8SAlexander V. Chernikov /*
1221f1220db8SAlexander V. Chernikov  * Export all tables as ipfw_xtable_info structures to
12222d99a349SAlexander V. Chernikov  * storage provided by @sd.
1223f1220db8SAlexander V. Chernikov  * Returns 0 on success.
1224f1220db8SAlexander V. Chernikov  */
1225f1220db8SAlexander V. Chernikov static int
12262d99a349SAlexander V. Chernikov export_tables(struct ip_fw_chain *ch, ipfw_obj_lheader *olh,
12272d99a349SAlexander V. Chernikov     struct sockopt_data *sd)
12289f7d47b0SAlexander V. Chernikov {
12299f7d47b0SAlexander V. Chernikov 	uint32_t size;
12309f7d47b0SAlexander V. Chernikov 	uint32_t count;
1231ac35ff17SAlexander V. Chernikov 	struct dump_table_args dta;
12329f7d47b0SAlexander V. Chernikov 
12339f7d47b0SAlexander V. Chernikov 	count = ipfw_objhash_count(CHAIN_TO_NI(ch));
12349f7d47b0SAlexander V. Chernikov 	size = count * sizeof(ipfw_xtable_info) + sizeof(ipfw_obj_lheader);
12352d99a349SAlexander V. Chernikov 
12362d99a349SAlexander V. Chernikov 	/* Fill in header regadless of buffer size */
1237f1220db8SAlexander V. Chernikov 	olh->count = count;
1238f1220db8SAlexander V. Chernikov 	olh->objsize = sizeof(ipfw_xtable_info);
12392d99a349SAlexander V. Chernikov 
12402d99a349SAlexander V. Chernikov 	if (size > olh->size) {
12412d99a349SAlexander V. Chernikov 		/* Store necessary size */
12422d99a349SAlexander V. Chernikov 		olh->size = size;
12439f7d47b0SAlexander V. Chernikov 		return (ENOMEM);
1244f1220db8SAlexander V. Chernikov 	}
12459f7d47b0SAlexander V. Chernikov 	olh->size = size;
12462d99a349SAlexander V. Chernikov 
1247ac35ff17SAlexander V. Chernikov 	dta.ch = ch;
1248ac35ff17SAlexander V. Chernikov 	dta.sd = sd;
1249ac35ff17SAlexander V. Chernikov 
1250ac35ff17SAlexander V. Chernikov 	ipfw_objhash_foreach(CHAIN_TO_NI(ch), export_table_internal, &dta);
12519f7d47b0SAlexander V. Chernikov 
12523b3a8eb9SGleb Smirnoff 	return (0);
12533b3a8eb9SGleb Smirnoff }
12543b3a8eb9SGleb Smirnoff 
125581d3153dSAlexander V. Chernikov /*
125681d3153dSAlexander V. Chernikov  * Legacy IP_FW_TABLE_GETSIZE handler
125781d3153dSAlexander V. Chernikov  */
12583b3a8eb9SGleb Smirnoff int
1259b074b7bbSAlexander V. Chernikov ipfw_count_table(struct ip_fw_chain *ch, struct tid_info *ti, uint32_t *cnt)
12603b3a8eb9SGleb Smirnoff {
1261b074b7bbSAlexander V. Chernikov 	struct table_config *tc;
12623b3a8eb9SGleb Smirnoff 
1263b074b7bbSAlexander V. Chernikov 	if ((tc = find_table(CHAIN_TO_NI(ch), ti)) == NULL)
1264b074b7bbSAlexander V. Chernikov 		return (ESRCH);
12659f7d47b0SAlexander V. Chernikov 	*cnt = tc->count;
12663b3a8eb9SGleb Smirnoff 	return (0);
12673b3a8eb9SGleb Smirnoff }
12683b3a8eb9SGleb Smirnoff 
12699f7d47b0SAlexander V. Chernikov 
127081d3153dSAlexander V. Chernikov /*
127181d3153dSAlexander V. Chernikov  * Legacy IP_FW_TABLE_XGETSIZE handler
127281d3153dSAlexander V. Chernikov  */
12739f7d47b0SAlexander V. Chernikov int
12749f7d47b0SAlexander V. Chernikov ipfw_count_xtable(struct ip_fw_chain *ch, struct tid_info *ti, uint32_t *cnt)
12753b3a8eb9SGleb Smirnoff {
12769f7d47b0SAlexander V. Chernikov 	struct table_config *tc;
12779f7d47b0SAlexander V. Chernikov 
1278d3a4f924SAlexander V. Chernikov 	if ((tc = find_table(CHAIN_TO_NI(ch), ti)) == NULL) {
1279d3a4f924SAlexander V. Chernikov 		*cnt = 0;
12809f7d47b0SAlexander V. Chernikov 		return (0); /* 'table all list' requires success */
1281d3a4f924SAlexander V. Chernikov 	}
12829f7d47b0SAlexander V. Chernikov 	*cnt = tc->count * sizeof(ipfw_table_xentry);
12839f7d47b0SAlexander V. Chernikov 	if (tc->count > 0)
12849f7d47b0SAlexander V. Chernikov 		*cnt += sizeof(ipfw_xtable);
12859f7d47b0SAlexander V. Chernikov 	return (0);
12869f7d47b0SAlexander V. Chernikov }
12879f7d47b0SAlexander V. Chernikov 
12889f7d47b0SAlexander V. Chernikov static int
12899f7d47b0SAlexander V. Chernikov dump_table_entry(void *e, void *arg)
12909f7d47b0SAlexander V. Chernikov {
12919f7d47b0SAlexander V. Chernikov 	struct dump_args *da;
12929f7d47b0SAlexander V. Chernikov 	struct table_config *tc;
12939f7d47b0SAlexander V. Chernikov 	struct table_algo *ta;
12943b3a8eb9SGleb Smirnoff 	ipfw_table_entry *ent;
129581d3153dSAlexander V. Chernikov 	int error;
12963b3a8eb9SGleb Smirnoff 
12979f7d47b0SAlexander V. Chernikov 	da = (struct dump_args *)arg;
12989f7d47b0SAlexander V. Chernikov 
12999f7d47b0SAlexander V. Chernikov 	tc = da->tc;
13009f7d47b0SAlexander V. Chernikov 	ta = tc->ta;
13019f7d47b0SAlexander V. Chernikov 
13029f7d47b0SAlexander V. Chernikov 	/* Out of memory, returning */
1303f1220db8SAlexander V. Chernikov 	if (da->cnt == da->size)
13043b3a8eb9SGleb Smirnoff 		return (1);
1305f1220db8SAlexander V. Chernikov 	ent = da->ent++;
1306f1220db8SAlexander V. Chernikov 	ent->tbl = da->uidx;
1307f1220db8SAlexander V. Chernikov 	da->cnt++;
13089f7d47b0SAlexander V. Chernikov 
130981d3153dSAlexander V. Chernikov 	error = ta->dump_tentry(tc->astate, da->ti, e, &da->tent);
131081d3153dSAlexander V. Chernikov 	if (error != 0)
131181d3153dSAlexander V. Chernikov 		return (error);
131281d3153dSAlexander V. Chernikov 
131381d3153dSAlexander V. Chernikov 	ent->addr = da->tent.k.addr.s_addr;
131481d3153dSAlexander V. Chernikov 	ent->masklen = da->tent.masklen;
131581d3153dSAlexander V. Chernikov 	ent->value = da->tent.value;
131681d3153dSAlexander V. Chernikov 
131781d3153dSAlexander V. Chernikov 	return (0);
13183b3a8eb9SGleb Smirnoff }
13193b3a8eb9SGleb Smirnoff 
1320f1220db8SAlexander V. Chernikov /*
1321f1220db8SAlexander V. Chernikov  * Dumps table in pre-8.1 legacy format.
1322f1220db8SAlexander V. Chernikov  */
13233b3a8eb9SGleb Smirnoff int
1324f1220db8SAlexander V. Chernikov ipfw_dump_table_legacy(struct ip_fw_chain *ch, struct tid_info *ti,
1325f1220db8SAlexander V. Chernikov     ipfw_table *tbl)
13263b3a8eb9SGleb Smirnoff {
1327b074b7bbSAlexander V. Chernikov 	struct table_config *tc;
13289f7d47b0SAlexander V. Chernikov 	struct table_algo *ta;
13299f7d47b0SAlexander V. Chernikov 	struct dump_args da;
13303b3a8eb9SGleb Smirnoff 
13313b3a8eb9SGleb Smirnoff 	tbl->cnt = 0;
13323b3a8eb9SGleb Smirnoff 
1333b074b7bbSAlexander V. Chernikov 	if ((tc = find_table(CHAIN_TO_NI(ch), ti)) == NULL)
1334b074b7bbSAlexander V. Chernikov 		return (0);	/* XXX: We should return ESRCH */
13359f7d47b0SAlexander V. Chernikov 
13369f7d47b0SAlexander V. Chernikov 	ta = tc->ta;
13379f7d47b0SAlexander V. Chernikov 
133881d3153dSAlexander V. Chernikov 	/* This dump format supports IPv4 only */
133981d3153dSAlexander V. Chernikov 	if (tc->no.type != IPFW_TABLE_CIDR)
134081d3153dSAlexander V. Chernikov 		return (0);
13419f7d47b0SAlexander V. Chernikov 
1342d3a4f924SAlexander V. Chernikov 	memset(&da, 0, sizeof(da));
13439f7d47b0SAlexander V. Chernikov 	da.ti = KIDX_TO_TI(ch, tc->no.kidx);
13449f7d47b0SAlexander V. Chernikov 	da.tc = tc;
1345f1220db8SAlexander V. Chernikov 	da.ent = &tbl->ent[0];
1346f1220db8SAlexander V. Chernikov 	da.size = tbl->size;
13479f7d47b0SAlexander V. Chernikov 
13489f7d47b0SAlexander V. Chernikov 	tbl->cnt = 0;
13499f7d47b0SAlexander V. Chernikov 	ta->foreach(tc->astate, da.ti, dump_table_entry, &da);
1350f1220db8SAlexander V. Chernikov 	tbl->cnt = da.cnt;
13519f7d47b0SAlexander V. Chernikov 
13523b3a8eb9SGleb Smirnoff 	return (0);
13533b3a8eb9SGleb Smirnoff }
13543b3a8eb9SGleb Smirnoff 
13559490a627SAlexander V. Chernikov /*
135681d3153dSAlexander V. Chernikov  * Dumps table entry in eXtended format (v1)(current).
135781d3153dSAlexander V. Chernikov  */
135881d3153dSAlexander V. Chernikov static int
135981d3153dSAlexander V. Chernikov dump_table_tentry(void *e, void *arg)
136081d3153dSAlexander V. Chernikov {
136181d3153dSAlexander V. Chernikov 	struct dump_args *da;
136281d3153dSAlexander V. Chernikov 	struct table_config *tc;
136381d3153dSAlexander V. Chernikov 	struct table_algo *ta;
136481d3153dSAlexander V. Chernikov 	ipfw_obj_tentry *tent;
136581d3153dSAlexander V. Chernikov 
136681d3153dSAlexander V. Chernikov 	da = (struct dump_args *)arg;
136781d3153dSAlexander V. Chernikov 
136881d3153dSAlexander V. Chernikov 	tc = da->tc;
136981d3153dSAlexander V. Chernikov 	ta = tc->ta;
137081d3153dSAlexander V. Chernikov 
137181d3153dSAlexander V. Chernikov 	tent = (ipfw_obj_tentry *)ipfw_get_sopt_space(da->sd, sizeof(*tent));
137281d3153dSAlexander V. Chernikov 	/* Out of memory, returning */
137381d3153dSAlexander V. Chernikov 	if (tent == NULL) {
137481d3153dSAlexander V. Chernikov 		da->error = ENOMEM;
137581d3153dSAlexander V. Chernikov 		return (1);
137681d3153dSAlexander V. Chernikov 	}
137781d3153dSAlexander V. Chernikov 	tent->head.length = sizeof(ipfw_obj_tentry);
137881d3153dSAlexander V. Chernikov 	tent->idx = da->uidx;
137981d3153dSAlexander V. Chernikov 
138081d3153dSAlexander V. Chernikov 	return (ta->dump_tentry(tc->astate, da->ti, e, tent));
138181d3153dSAlexander V. Chernikov }
138281d3153dSAlexander V. Chernikov 
138381d3153dSAlexander V. Chernikov /*
138481d3153dSAlexander V. Chernikov  * Dumps table entry in eXtended format (v0).
13859490a627SAlexander V. Chernikov  */
13863b3a8eb9SGleb Smirnoff static int
13879f7d47b0SAlexander V. Chernikov dump_table_xentry(void *e, void *arg)
13883b3a8eb9SGleb Smirnoff {
13899f7d47b0SAlexander V. Chernikov 	struct dump_args *da;
13909f7d47b0SAlexander V. Chernikov 	struct table_config *tc;
13919f7d47b0SAlexander V. Chernikov 	struct table_algo *ta;
13923b3a8eb9SGleb Smirnoff 	ipfw_table_xentry *xent;
139381d3153dSAlexander V. Chernikov 	ipfw_obj_tentry *tent;
139481d3153dSAlexander V. Chernikov 	int error;
13953b3a8eb9SGleb Smirnoff 
13969f7d47b0SAlexander V. Chernikov 	da = (struct dump_args *)arg;
13979f7d47b0SAlexander V. Chernikov 
13989f7d47b0SAlexander V. Chernikov 	tc = da->tc;
13999f7d47b0SAlexander V. Chernikov 	ta = tc->ta;
14009f7d47b0SAlexander V. Chernikov 
14012d99a349SAlexander V. Chernikov 	xent = (ipfw_table_xentry *)ipfw_get_sopt_space(da->sd, sizeof(*xent));
14023b3a8eb9SGleb Smirnoff 	/* Out of memory, returning */
14032d99a349SAlexander V. Chernikov 	if (xent == NULL)
14043b3a8eb9SGleb Smirnoff 		return (1);
14053b3a8eb9SGleb Smirnoff 	xent->len = sizeof(ipfw_table_xentry);
1406f1220db8SAlexander V. Chernikov 	xent->tbl = da->uidx;
14079f7d47b0SAlexander V. Chernikov 
140881d3153dSAlexander V. Chernikov 	memset(&da->tent, 0, sizeof(da->tent));
140981d3153dSAlexander V. Chernikov 	tent = &da->tent;
141081d3153dSAlexander V. Chernikov 	error = ta->dump_tentry(tc->astate, da->ti, e, tent);
141181d3153dSAlexander V. Chernikov 	if (error != 0)
141281d3153dSAlexander V. Chernikov 		return (error);
141381d3153dSAlexander V. Chernikov 
141481d3153dSAlexander V. Chernikov 	/* Convert current format to previous one */
141581d3153dSAlexander V. Chernikov 	xent->masklen = tent->masklen;
141681d3153dSAlexander V. Chernikov 	xent->value = tent->value;
141781d3153dSAlexander V. Chernikov 	/* Apply some hacks */
141881d3153dSAlexander V. Chernikov 	if (tc->no.type == IPFW_TABLE_CIDR && tent->subtype == AF_INET) {
141981d3153dSAlexander V. Chernikov 		xent->k.addr6.s6_addr32[3] = tent->k.addr.s_addr;
142081d3153dSAlexander V. Chernikov 		xent->flags = IPFW_TCF_INET;
142181d3153dSAlexander V. Chernikov 	} else
142281d3153dSAlexander V. Chernikov 		memcpy(&xent->k, &tent->k, sizeof(xent->k));
142381d3153dSAlexander V. Chernikov 
142481d3153dSAlexander V. Chernikov 	return (0);
14259f7d47b0SAlexander V. Chernikov }
14269f7d47b0SAlexander V. Chernikov 
14279f7d47b0SAlexander V. Chernikov /*
14289f7d47b0SAlexander V. Chernikov  * Table algorithms
14299f7d47b0SAlexander V. Chernikov  */
14303b3a8eb9SGleb Smirnoff 
14319f7d47b0SAlexander V. Chernikov /*
14329490a627SAlexander V. Chernikov  * Finds algoritm by index, table type or supplied name
14339f7d47b0SAlexander V. Chernikov  */
14349f7d47b0SAlexander V. Chernikov static struct table_algo *
14359490a627SAlexander V. Chernikov find_table_algo(struct tables_config *tcfg, struct tid_info *ti, char *name)
14369f7d47b0SAlexander V. Chernikov {
14379490a627SAlexander V. Chernikov 	int i, l;
14389490a627SAlexander V. Chernikov 	struct table_algo *ta;
14399f7d47b0SAlexander V. Chernikov 
14409f7d47b0SAlexander V. Chernikov 	/* Search by index */
14419f7d47b0SAlexander V. Chernikov 	if (ti->atype != 0) {
14429f7d47b0SAlexander V. Chernikov 		if (ti->atype > tcfg->algo_count)
14439f7d47b0SAlexander V. Chernikov 			return (NULL);
14449f7d47b0SAlexander V. Chernikov 		return (tcfg->algo[ti->atype]);
14459f7d47b0SAlexander V. Chernikov 	}
14469f7d47b0SAlexander V. Chernikov 
14479490a627SAlexander V. Chernikov 	/* Search by name if supplied */
14489490a627SAlexander V. Chernikov 	if (name != NULL) {
14499490a627SAlexander V. Chernikov 		/* TODO: better search */
14509490a627SAlexander V. Chernikov 		for (i = 1; i <= tcfg->algo_count; i++) {
14519490a627SAlexander V. Chernikov 			ta = tcfg->algo[i];
14529490a627SAlexander V. Chernikov 
14539490a627SAlexander V. Chernikov 			/*
14549490a627SAlexander V. Chernikov 			 * One can supply additional algorithm
14559490a627SAlexander V. Chernikov 			 * parameters so we compare only the first word
14569490a627SAlexander V. Chernikov 			 * of supplied name:
14579490a627SAlexander V. Chernikov 			 * 'hash_cidr hsize=32'
14589490a627SAlexander V. Chernikov 			 * '^^^^^^^^^'
14599490a627SAlexander V. Chernikov 			 *
14609490a627SAlexander V. Chernikov 			 */
14619490a627SAlexander V. Chernikov 			l = strlen(ta->name);
14629490a627SAlexander V. Chernikov 			if (strncmp(name, ta->name, l) == 0) {
14639490a627SAlexander V. Chernikov 				if (name[l] == '\0' || name[l] == ' ')
14649490a627SAlexander V. Chernikov 					return (ta);
14659490a627SAlexander V. Chernikov 			}
14669490a627SAlexander V. Chernikov 		}
14679490a627SAlexander V. Chernikov 
14689490a627SAlexander V. Chernikov 		return (NULL);
14699490a627SAlexander V. Chernikov 	}
14709490a627SAlexander V. Chernikov 
14719f7d47b0SAlexander V. Chernikov 	/* Search by type */
14729f7d47b0SAlexander V. Chernikov 	switch (ti->type) {
14733b3a8eb9SGleb Smirnoff 	case IPFW_TABLE_CIDR:
14749f7d47b0SAlexander V. Chernikov 		return (&radix_cidr);
14753b3a8eb9SGleb Smirnoff 	case IPFW_TABLE_INTERFACE:
14769f7d47b0SAlexander V. Chernikov 		return (&radix_iface);
14773b3a8eb9SGleb Smirnoff 	}
14783b3a8eb9SGleb Smirnoff 
14799f7d47b0SAlexander V. Chernikov 	return (NULL);
14803b3a8eb9SGleb Smirnoff }
14813b3a8eb9SGleb Smirnoff 
14829f7d47b0SAlexander V. Chernikov void
14839f7d47b0SAlexander V. Chernikov ipfw_add_table_algo(struct ip_fw_chain *ch, struct table_algo *ta)
14843b3a8eb9SGleb Smirnoff {
14859f7d47b0SAlexander V. Chernikov 	struct tables_config *tcfg;
14863b3a8eb9SGleb Smirnoff 
14879f7d47b0SAlexander V. Chernikov 	tcfg = CHAIN_TO_TCFG(ch);
1488b074b7bbSAlexander V. Chernikov 
14899f7d47b0SAlexander V. Chernikov 	KASSERT(tcfg->algo_count < 255, ("Increase algo array size"));
14909f7d47b0SAlexander V. Chernikov 
14919f7d47b0SAlexander V. Chernikov 	tcfg->algo[++tcfg->algo_count] = ta;
14929f7d47b0SAlexander V. Chernikov 	ta->idx = tcfg->algo_count;
14933b3a8eb9SGleb Smirnoff }
14943b3a8eb9SGleb Smirnoff 
14959f7d47b0SAlexander V. Chernikov 
1496b074b7bbSAlexander V. Chernikov /*
1497b074b7bbSAlexander V. Chernikov  * Tables rewriting code
1498b074b7bbSAlexander V. Chernikov  *
1499b074b7bbSAlexander V. Chernikov  */
1500b074b7bbSAlexander V. Chernikov 
1501b074b7bbSAlexander V. Chernikov /*
1502b074b7bbSAlexander V. Chernikov  * Determine table number and lookup type for @cmd.
1503b074b7bbSAlexander V. Chernikov  * Fill @tbl and @type with appropriate values.
1504b074b7bbSAlexander V. Chernikov  * Returns 0 for relevant opcodes, 1 otherwise.
1505b074b7bbSAlexander V. Chernikov  */
1506b074b7bbSAlexander V. Chernikov static int
1507b074b7bbSAlexander V. Chernikov classify_table_opcode(ipfw_insn *cmd, uint16_t *puidx, uint8_t *ptype)
1508b074b7bbSAlexander V. Chernikov {
1509b074b7bbSAlexander V. Chernikov 	ipfw_insn_if *cmdif;
1510b074b7bbSAlexander V. Chernikov 	int skip;
1511b074b7bbSAlexander V. Chernikov 	uint16_t v;
1512b074b7bbSAlexander V. Chernikov 
1513b074b7bbSAlexander V. Chernikov 	skip = 1;
1514b074b7bbSAlexander V. Chernikov 
1515b074b7bbSAlexander V. Chernikov 	switch (cmd->opcode) {
1516b074b7bbSAlexander V. Chernikov 	case O_IP_SRC_LOOKUP:
1517b074b7bbSAlexander V. Chernikov 	case O_IP_DST_LOOKUP:
1518b074b7bbSAlexander V. Chernikov 		/* Basic IPv4/IPv6 or u32 lookups */
1519b074b7bbSAlexander V. Chernikov 		*puidx = cmd->arg1;
1520b074b7bbSAlexander V. Chernikov 		/* Assume CIDR by default */
1521b074b7bbSAlexander V. Chernikov 		*ptype = IPFW_TABLE_CIDR;
1522b074b7bbSAlexander V. Chernikov 		skip = 0;
1523b074b7bbSAlexander V. Chernikov 
1524b074b7bbSAlexander V. Chernikov 		if (F_LEN(cmd) > F_INSN_SIZE(ipfw_insn_u32)) {
1525b074b7bbSAlexander V. Chernikov 			/*
1526b074b7bbSAlexander V. Chernikov 			 * generic lookup. The key must be
1527b074b7bbSAlexander V. Chernikov 			 * in 32bit big-endian format.
1528b074b7bbSAlexander V. Chernikov 			 */
1529b074b7bbSAlexander V. Chernikov 			v = ((ipfw_insn_u32 *)cmd)->d[1];
1530b074b7bbSAlexander V. Chernikov 			switch (v) {
1531b074b7bbSAlexander V. Chernikov 			case 0:
1532b074b7bbSAlexander V. Chernikov 			case 1:
1533b074b7bbSAlexander V. Chernikov 				/* IPv4 src/dst */
1534b074b7bbSAlexander V. Chernikov 				break;
1535b074b7bbSAlexander V. Chernikov 			case 2:
1536b074b7bbSAlexander V. Chernikov 			case 3:
1537b074b7bbSAlexander V. Chernikov 				/* src/dst port */
1538b074b7bbSAlexander V. Chernikov 				//type = IPFW_TABLE_U16;
1539b074b7bbSAlexander V. Chernikov 				break;
1540b074b7bbSAlexander V. Chernikov 			case 4:
1541b074b7bbSAlexander V. Chernikov 				/* uid/gid */
1542b074b7bbSAlexander V. Chernikov 				//type = IPFW_TABLE_U32;
1543b074b7bbSAlexander V. Chernikov 			case 5:
1544b074b7bbSAlexander V. Chernikov 				//type = IPFW_TABLE_U32;
1545b074b7bbSAlexander V. Chernikov 				/* jid */
1546b074b7bbSAlexander V. Chernikov 			case 6:
1547b074b7bbSAlexander V. Chernikov 				//type = IPFW_TABLE_U16;
1548b074b7bbSAlexander V. Chernikov 				/* dscp */
1549b074b7bbSAlexander V. Chernikov 				break;
1550b074b7bbSAlexander V. Chernikov 			}
1551b074b7bbSAlexander V. Chernikov 		}
1552b074b7bbSAlexander V. Chernikov 		break;
1553b074b7bbSAlexander V. Chernikov 	case O_XMIT:
1554b074b7bbSAlexander V. Chernikov 	case O_RECV:
1555b074b7bbSAlexander V. Chernikov 	case O_VIA:
1556b074b7bbSAlexander V. Chernikov 		/* Interface table, possibly */
1557b074b7bbSAlexander V. Chernikov 		cmdif = (ipfw_insn_if *)cmd;
1558b074b7bbSAlexander V. Chernikov 		if (cmdif->name[0] != '\1')
1559b074b7bbSAlexander V. Chernikov 			break;
1560b074b7bbSAlexander V. Chernikov 
1561b074b7bbSAlexander V. Chernikov 		*ptype = IPFW_TABLE_INTERFACE;
1562b074b7bbSAlexander V. Chernikov 		*puidx = cmdif->p.glob;
1563b074b7bbSAlexander V. Chernikov 		skip = 0;
1564b074b7bbSAlexander V. Chernikov 		break;
1565b074b7bbSAlexander V. Chernikov 	}
1566b074b7bbSAlexander V. Chernikov 
1567b074b7bbSAlexander V. Chernikov 	return (skip);
1568b074b7bbSAlexander V. Chernikov }
1569b074b7bbSAlexander V. Chernikov 
1570b074b7bbSAlexander V. Chernikov /*
1571b074b7bbSAlexander V. Chernikov  * Sets new table value for given opcode.
1572b074b7bbSAlexander V. Chernikov  * Assume the same opcodes as classify_table_opcode()
1573b074b7bbSAlexander V. Chernikov  */
1574b074b7bbSAlexander V. Chernikov static void
1575b074b7bbSAlexander V. Chernikov update_table_opcode(ipfw_insn *cmd, uint16_t idx)
1576b074b7bbSAlexander V. Chernikov {
1577b074b7bbSAlexander V. Chernikov 	ipfw_insn_if *cmdif;
1578b074b7bbSAlexander V. Chernikov 
1579b074b7bbSAlexander V. Chernikov 	switch (cmd->opcode) {
1580b074b7bbSAlexander V. Chernikov 	case O_IP_SRC_LOOKUP:
1581b074b7bbSAlexander V. Chernikov 	case O_IP_DST_LOOKUP:
1582b074b7bbSAlexander V. Chernikov 		/* Basic IPv4/IPv6 or u32 lookups */
1583b074b7bbSAlexander V. Chernikov 		cmd->arg1 = idx;
1584b074b7bbSAlexander V. Chernikov 		break;
1585b074b7bbSAlexander V. Chernikov 	case O_XMIT:
1586b074b7bbSAlexander V. Chernikov 	case O_RECV:
1587b074b7bbSAlexander V. Chernikov 	case O_VIA:
1588b074b7bbSAlexander V. Chernikov 		/* Interface table, possibly */
1589b074b7bbSAlexander V. Chernikov 		cmdif = (ipfw_insn_if *)cmd;
1590b074b7bbSAlexander V. Chernikov 		cmdif->p.glob = idx;
1591b074b7bbSAlexander V. Chernikov 		break;
1592b074b7bbSAlexander V. Chernikov 	}
1593b074b7bbSAlexander V. Chernikov }
1594b074b7bbSAlexander V. Chernikov 
1595ac35ff17SAlexander V. Chernikov /*
1596ac35ff17SAlexander V. Chernikov  * Checks table name for validity.
1597ac35ff17SAlexander V. Chernikov  * Enforce basic length checks, the rest
1598ac35ff17SAlexander V. Chernikov  * should be done in userland.
1599ac35ff17SAlexander V. Chernikov  *
1600ac35ff17SAlexander V. Chernikov  * Returns 0 if name is considered valid.
1601ac35ff17SAlexander V. Chernikov  */
1602ac35ff17SAlexander V. Chernikov int
1603ac35ff17SAlexander V. Chernikov ipfw_check_table_name(char *name)
1604ac35ff17SAlexander V. Chernikov {
1605ac35ff17SAlexander V. Chernikov 	int nsize;
1606ac35ff17SAlexander V. Chernikov 	ipfw_obj_ntlv *ntlv = NULL;
1607ac35ff17SAlexander V. Chernikov 
1608ac35ff17SAlexander V. Chernikov 	nsize = sizeof(ntlv->name);
1609ac35ff17SAlexander V. Chernikov 
1610ac35ff17SAlexander V. Chernikov 	if (strnlen(name, nsize) == nsize)
1611ac35ff17SAlexander V. Chernikov 		return (EINVAL);
1612ac35ff17SAlexander V. Chernikov 
1613ac35ff17SAlexander V. Chernikov 	if (name[0] == '\0')
1614ac35ff17SAlexander V. Chernikov 		return (EINVAL);
1615ac35ff17SAlexander V. Chernikov 
1616ac35ff17SAlexander V. Chernikov 	/*
1617ac35ff17SAlexander V. Chernikov 	 * TODO: do some more complicated checks
1618ac35ff17SAlexander V. Chernikov 	 */
1619ac35ff17SAlexander V. Chernikov 
1620ac35ff17SAlexander V. Chernikov 	return (0);
1621ac35ff17SAlexander V. Chernikov }
1622ac35ff17SAlexander V. Chernikov 
1623ac35ff17SAlexander V. Chernikov /*
1624ac35ff17SAlexander V. Chernikov  * Find tablename TLV by @uid.
1625ac35ff17SAlexander V. Chernikov  * Check @tlvs for valid data inside.
1626ac35ff17SAlexander V. Chernikov  *
1627ac35ff17SAlexander V. Chernikov  * Returns pointer to found TLV or NULL.
1628ac35ff17SAlexander V. Chernikov  */
1629ac35ff17SAlexander V. Chernikov static ipfw_obj_ntlv *
1630b074b7bbSAlexander V. Chernikov find_name_tlv(void *tlvs, int len, uint16_t uidx)
1631b074b7bbSAlexander V. Chernikov {
16329f7d47b0SAlexander V. Chernikov 	ipfw_obj_ntlv *ntlv;
1633b074b7bbSAlexander V. Chernikov 	uintptr_t pa, pe;
1634b074b7bbSAlexander V. Chernikov 	int l;
1635b074b7bbSAlexander V. Chernikov 
1636b074b7bbSAlexander V. Chernikov 	pa = (uintptr_t)tlvs;
1637b074b7bbSAlexander V. Chernikov 	pe = pa + len;
1638b074b7bbSAlexander V. Chernikov 	l = 0;
1639b074b7bbSAlexander V. Chernikov 	for (; pa < pe; pa += l) {
16409f7d47b0SAlexander V. Chernikov 		ntlv = (ipfw_obj_ntlv *)pa;
1641b074b7bbSAlexander V. Chernikov 		l = ntlv->head.length;
1642ac35ff17SAlexander V. Chernikov 
1643ac35ff17SAlexander V. Chernikov 		if (l != sizeof(*ntlv))
1644ac35ff17SAlexander V. Chernikov 			return (NULL);
1645ac35ff17SAlexander V. Chernikov 
1646563b5ab1SAlexander V. Chernikov 		if (ntlv->head.type != IPFW_TLV_TBL_NAME)
1647b074b7bbSAlexander V. Chernikov 			continue;
1648ac35ff17SAlexander V. Chernikov 
1649b074b7bbSAlexander V. Chernikov 		if (ntlv->idx != uidx)
1650b074b7bbSAlexander V. Chernikov 			continue;
1651b074b7bbSAlexander V. Chernikov 
1652ac35ff17SAlexander V. Chernikov 		if (ipfw_check_table_name(ntlv->name) != 0)
1653ac35ff17SAlexander V. Chernikov 			return (NULL);
1654ac35ff17SAlexander V. Chernikov 
1655ac35ff17SAlexander V. Chernikov 		return (ntlv);
1656b074b7bbSAlexander V. Chernikov 	}
1657b074b7bbSAlexander V. Chernikov 
1658b074b7bbSAlexander V. Chernikov 	return (NULL);
1659b074b7bbSAlexander V. Chernikov }
1660b074b7bbSAlexander V. Chernikov 
1661ac35ff17SAlexander V. Chernikov /*
1662ac35ff17SAlexander V. Chernikov  * Finds table config based on either legacy index
1663ac35ff17SAlexander V. Chernikov  * or name in ntlv.
1664ac35ff17SAlexander V. Chernikov  * Note @ti structure contains unchecked data from userland.
1665ac35ff17SAlexander V. Chernikov  *
1666ac35ff17SAlexander V. Chernikov  * Returns pointer to table_config or NULL.
1667ac35ff17SAlexander V. Chernikov  */
1668b074b7bbSAlexander V. Chernikov static struct table_config *
1669b074b7bbSAlexander V. Chernikov find_table(struct namedobj_instance *ni, struct tid_info *ti)
1670b074b7bbSAlexander V. Chernikov {
1671b074b7bbSAlexander V. Chernikov 	char *name, bname[16];
1672b074b7bbSAlexander V. Chernikov 	struct named_object *no;
1673ac35ff17SAlexander V. Chernikov 	ipfw_obj_ntlv *ntlv;
1674ac35ff17SAlexander V. Chernikov 	uint32_t set;
1675b074b7bbSAlexander V. Chernikov 
1676b074b7bbSAlexander V. Chernikov 	if (ti->tlvs != NULL) {
1677ac35ff17SAlexander V. Chernikov 		ntlv = find_name_tlv(ti->tlvs, ti->tlen, ti->uidx);
1678ac35ff17SAlexander V. Chernikov 		if (ntlv == NULL)
1679b074b7bbSAlexander V. Chernikov 			return (NULL);
1680ac35ff17SAlexander V. Chernikov 		name = ntlv->name;
1681ac35ff17SAlexander V. Chernikov 		set = ntlv->set;
1682b074b7bbSAlexander V. Chernikov 	} else {
1683b074b7bbSAlexander V. Chernikov 		snprintf(bname, sizeof(bname), "%d", ti->uidx);
1684b074b7bbSAlexander V. Chernikov 		name = bname;
1685ac35ff17SAlexander V. Chernikov 		set = 0;
1686b074b7bbSAlexander V. Chernikov 	}
1687b074b7bbSAlexander V. Chernikov 
1688ac35ff17SAlexander V. Chernikov 	no = ipfw_objhash_lookup_name(ni, set, name);
1689b074b7bbSAlexander V. Chernikov 
1690b074b7bbSAlexander V. Chernikov 	return ((struct table_config *)no);
1691b074b7bbSAlexander V. Chernikov }
1692b074b7bbSAlexander V. Chernikov 
1693b074b7bbSAlexander V. Chernikov static struct table_config *
16949f7d47b0SAlexander V. Chernikov alloc_table_config(struct namedobj_instance *ni, struct tid_info *ti,
16959490a627SAlexander V. Chernikov     struct table_algo *ta, char *aname)
1696b074b7bbSAlexander V. Chernikov {
1697b074b7bbSAlexander V. Chernikov 	char *name, bname[16];
1698b074b7bbSAlexander V. Chernikov 	struct table_config *tc;
1699b074b7bbSAlexander V. Chernikov 	int error;
1700ac35ff17SAlexander V. Chernikov 	ipfw_obj_ntlv *ntlv;
1701ac35ff17SAlexander V. Chernikov 	uint32_t set;
1702b074b7bbSAlexander V. Chernikov 
1703b074b7bbSAlexander V. Chernikov 	if (ti->tlvs != NULL) {
1704ac35ff17SAlexander V. Chernikov 		ntlv = find_name_tlv(ti->tlvs, ti->tlen, ti->uidx);
1705ac35ff17SAlexander V. Chernikov 		if (ntlv == NULL)
1706b074b7bbSAlexander V. Chernikov 			return (NULL);
1707ac35ff17SAlexander V. Chernikov 		name = ntlv->name;
1708ac35ff17SAlexander V. Chernikov 		set = ntlv->set;
1709b074b7bbSAlexander V. Chernikov 	} else {
1710b074b7bbSAlexander V. Chernikov 		snprintf(bname, sizeof(bname), "%d", ti->uidx);
1711b074b7bbSAlexander V. Chernikov 		name = bname;
1712ac35ff17SAlexander V. Chernikov 		set = 0;
1713b074b7bbSAlexander V. Chernikov 	}
1714b074b7bbSAlexander V. Chernikov 
1715b074b7bbSAlexander V. Chernikov 	tc = malloc(sizeof(struct table_config), M_IPFW, M_WAITOK | M_ZERO);
1716b074b7bbSAlexander V. Chernikov 	tc->no.name = tc->tablename;
1717b074b7bbSAlexander V. Chernikov 	tc->no.type = ti->type;
1718ac35ff17SAlexander V. Chernikov 	tc->no.set = set;
17199f7d47b0SAlexander V. Chernikov 	tc->ta = ta;
1720b074b7bbSAlexander V. Chernikov 	strlcpy(tc->tablename, name, sizeof(tc->tablename));
1721ac35ff17SAlexander V. Chernikov 	/* Set default value type to u32 for compability reasons */
1722ac35ff17SAlexander V. Chernikov 	tc->vtype = IPFW_VTYPE_U32;
1723b074b7bbSAlexander V. Chernikov 
1724b074b7bbSAlexander V. Chernikov 	if (ti->tlvs == NULL) {
1725b074b7bbSAlexander V. Chernikov 		tc->no.compat = 1;
1726b074b7bbSAlexander V. Chernikov 		tc->no.uidx = ti->uidx;
1727b074b7bbSAlexander V. Chernikov 	}
1728b074b7bbSAlexander V. Chernikov 
1729b074b7bbSAlexander V. Chernikov 	/* Preallocate data structures for new tables */
17309490a627SAlexander V. Chernikov 	error = ta->init(&tc->astate, &tc->ti, aname);
1731b074b7bbSAlexander V. Chernikov 	if (error != 0) {
1732b074b7bbSAlexander V. Chernikov 		free(tc, M_IPFW);
1733b074b7bbSAlexander V. Chernikov 		return (NULL);
1734b074b7bbSAlexander V. Chernikov 	}
1735b074b7bbSAlexander V. Chernikov 
1736b074b7bbSAlexander V. Chernikov 	return (tc);
1737b074b7bbSAlexander V. Chernikov }
1738b074b7bbSAlexander V. Chernikov 
1739b074b7bbSAlexander V. Chernikov static void
1740b074b7bbSAlexander V. Chernikov free_table_config(struct namedobj_instance *ni, struct table_config *tc)
1741b074b7bbSAlexander V. Chernikov {
1742b074b7bbSAlexander V. Chernikov 
1743b074b7bbSAlexander V. Chernikov 	if (tc->linked == 0)
17449f7d47b0SAlexander V. Chernikov 		tc->ta->destroy(&tc->astate, &tc->ti);
1745b074b7bbSAlexander V. Chernikov 
1746b074b7bbSAlexander V. Chernikov 	free(tc, M_IPFW);
1747b074b7bbSAlexander V. Chernikov }
1748b074b7bbSAlexander V. Chernikov 
1749b074b7bbSAlexander V. Chernikov /*
1750b074b7bbSAlexander V. Chernikov  * Links @tc to @chain table named instance.
1751b074b7bbSAlexander V. Chernikov  * Sets appropriate type/states in @chain table info.
1752b074b7bbSAlexander V. Chernikov  */
1753b074b7bbSAlexander V. Chernikov static void
17549f7d47b0SAlexander V. Chernikov link_table(struct ip_fw_chain *ch, struct table_config *tc)
1755b074b7bbSAlexander V. Chernikov {
1756b074b7bbSAlexander V. Chernikov 	struct namedobj_instance *ni;
17579f7d47b0SAlexander V. Chernikov 	struct table_info *ti;
1758b074b7bbSAlexander V. Chernikov 	uint16_t kidx;
1759b074b7bbSAlexander V. Chernikov 
17609f7d47b0SAlexander V. Chernikov 	IPFW_UH_WLOCK_ASSERT(ch);
17619f7d47b0SAlexander V. Chernikov 	IPFW_WLOCK_ASSERT(ch);
1762b074b7bbSAlexander V. Chernikov 
17639f7d47b0SAlexander V. Chernikov 	ni = CHAIN_TO_NI(ch);
1764b074b7bbSAlexander V. Chernikov 	kidx = tc->no.kidx;
1765b074b7bbSAlexander V. Chernikov 
1766b074b7bbSAlexander V. Chernikov 	ipfw_objhash_add(ni, &tc->no);
17679f7d47b0SAlexander V. Chernikov 
17689f7d47b0SAlexander V. Chernikov 	ti = KIDX_TO_TI(ch, kidx);
17699f7d47b0SAlexander V. Chernikov 	*ti = tc->ti;
1770b074b7bbSAlexander V. Chernikov 
1771b074b7bbSAlexander V. Chernikov 	tc->linked = 1;
1772b074b7bbSAlexander V. Chernikov }
1773b074b7bbSAlexander V. Chernikov 
1774b074b7bbSAlexander V. Chernikov /*
1775b074b7bbSAlexander V. Chernikov  * Unlinks @tc from @chain table named instance.
1776b074b7bbSAlexander V. Chernikov  * Zeroes states in @chain and stores them in @tc.
1777b074b7bbSAlexander V. Chernikov  */
1778b074b7bbSAlexander V. Chernikov static void
17799f7d47b0SAlexander V. Chernikov unlink_table(struct ip_fw_chain *ch, struct table_config *tc)
1780b074b7bbSAlexander V. Chernikov {
1781b074b7bbSAlexander V. Chernikov 	struct namedobj_instance *ni;
17829f7d47b0SAlexander V. Chernikov 	struct table_info *ti;
1783b074b7bbSAlexander V. Chernikov 	uint16_t kidx;
1784b074b7bbSAlexander V. Chernikov 
17859f7d47b0SAlexander V. Chernikov 	IPFW_UH_WLOCK_ASSERT(ch);
17869f7d47b0SAlexander V. Chernikov 	IPFW_WLOCK_ASSERT(ch);
1787b074b7bbSAlexander V. Chernikov 
17889f7d47b0SAlexander V. Chernikov 	ni = CHAIN_TO_NI(ch);
1789b074b7bbSAlexander V. Chernikov 	kidx = tc->no.kidx;
1790b074b7bbSAlexander V. Chernikov 
17919f7d47b0SAlexander V. Chernikov 	/* Clear state. @ti copy is already saved inside @tc */
1792b074b7bbSAlexander V. Chernikov 	ipfw_objhash_del(ni, &tc->no);
17939f7d47b0SAlexander V. Chernikov 	ti = KIDX_TO_TI(ch, kidx);
17949f7d47b0SAlexander V. Chernikov 	memset(ti, 0, sizeof(struct table_info));
1795b074b7bbSAlexander V. Chernikov 	tc->linked = 0;
1796b074b7bbSAlexander V. Chernikov }
1797b074b7bbSAlexander V. Chernikov 
1798b074b7bbSAlexander V. Chernikov /*
1799b074b7bbSAlexander V. Chernikov  * Finds named object by @uidx number.
1800b074b7bbSAlexander V. Chernikov  * Refs found object, allocate new index for non-existing object.
18019490a627SAlexander V. Chernikov  * Fills in @oib with userland/kernel indexes.
18029490a627SAlexander V. Chernikov  * First free oidx pointer is saved back in @oib.
1803b074b7bbSAlexander V. Chernikov  *
1804b074b7bbSAlexander V. Chernikov  * Returns 0 on success.
1805b074b7bbSAlexander V. Chernikov  */
1806b074b7bbSAlexander V. Chernikov static int
18079490a627SAlexander V. Chernikov bind_table_rule(struct ip_fw_chain *ch, struct ip_fw *rule,
18089490a627SAlexander V. Chernikov     struct rule_check_info *ci, struct obj_idx **oib, struct tid_info *ti)
1809b074b7bbSAlexander V. Chernikov {
1810b074b7bbSAlexander V. Chernikov 	struct table_config *tc;
18119490a627SAlexander V. Chernikov 	struct namedobj_instance *ni;
18129490a627SAlexander V. Chernikov 	struct named_object *no;
18139490a627SAlexander V. Chernikov 	int error, l, cmdlen;
18149490a627SAlexander V. Chernikov 	ipfw_insn *cmd;
18159490a627SAlexander V. Chernikov 	struct obj_idx *pidx, *p;
18169490a627SAlexander V. Chernikov 
18179490a627SAlexander V. Chernikov 	pidx = *oib;
18189490a627SAlexander V. Chernikov 	l = rule->cmd_len;
18199490a627SAlexander V. Chernikov 	cmd = rule->cmd;
18209490a627SAlexander V. Chernikov 	cmdlen = 0;
18219490a627SAlexander V. Chernikov 	error = 0;
18229490a627SAlexander V. Chernikov 
18239490a627SAlexander V. Chernikov 	IPFW_UH_WLOCK(ch);
18249490a627SAlexander V. Chernikov 	ni = CHAIN_TO_NI(ch);
18259490a627SAlexander V. Chernikov 
18269490a627SAlexander V. Chernikov 	for ( ;	l > 0 ; l -= cmdlen, cmd += cmdlen) {
18279490a627SAlexander V. Chernikov 		cmdlen = F_LEN(cmd);
18289490a627SAlexander V. Chernikov 
18299490a627SAlexander V. Chernikov 		if (classify_table_opcode(cmd, &ti->uidx, &ti->type) != 0)
18309490a627SAlexander V. Chernikov 			continue;
1831b074b7bbSAlexander V. Chernikov 
1832b074b7bbSAlexander V. Chernikov 		pidx->uidx = ti->uidx;
1833b074b7bbSAlexander V. Chernikov 		pidx->type = ti->type;
1834b074b7bbSAlexander V. Chernikov 
18359490a627SAlexander V. Chernikov 		if ((tc = find_table(ni, ti)) != NULL) {
18369490a627SAlexander V. Chernikov 			if (tc->no.type != ti->type) {
18379490a627SAlexander V. Chernikov 				/* Incompatible types */
18389490a627SAlexander V. Chernikov 				error = EINVAL;
18399490a627SAlexander V. Chernikov 				break;
18409490a627SAlexander V. Chernikov 			}
18419f7d47b0SAlexander V. Chernikov 
18429490a627SAlexander V. Chernikov 			/* Reference found table and save kidx */
18439490a627SAlexander V. Chernikov 			tc->no.refcnt++;
18449490a627SAlexander V. Chernikov 			pidx->kidx = tc->no.kidx;
18459490a627SAlexander V. Chernikov 			pidx++;
18469490a627SAlexander V. Chernikov 			continue;
18479490a627SAlexander V. Chernikov 		}
18489490a627SAlexander V. Chernikov 
18499490a627SAlexander V. Chernikov 		/* Table not found. Allocate new index and save for later */
1850ac35ff17SAlexander V. Chernikov 		if (ipfw_objhash_alloc_idx(ni, &pidx->kidx) != 0) {
1851ac35ff17SAlexander V. Chernikov 			printf("Unable to allocate table %s index in set %u."
1852b074b7bbSAlexander V. Chernikov 			    " Consider increasing net.inet.ip.fw.tables_max",
1853ac35ff17SAlexander V. Chernikov 			    "", ti->set);
18549490a627SAlexander V. Chernikov 			error = EBUSY;
18559490a627SAlexander V. Chernikov 			break;
1856b074b7bbSAlexander V. Chernikov 		}
1857b074b7bbSAlexander V. Chernikov 
1858b074b7bbSAlexander V. Chernikov 		ci->new_tables++;
18599490a627SAlexander V. Chernikov 		pidx->new = 1;
18609490a627SAlexander V. Chernikov 		pidx++;
1861b074b7bbSAlexander V. Chernikov 	}
1862b074b7bbSAlexander V. Chernikov 
18639490a627SAlexander V. Chernikov 	if (error != 0) {
18649490a627SAlexander V. Chernikov 		/* Unref everything we have already done */
18659490a627SAlexander V. Chernikov 		for (p = *oib; p < pidx; p++) {
18669490a627SAlexander V. Chernikov 			if (p->new != 0) {
1867ac35ff17SAlexander V. Chernikov 				ipfw_objhash_free_idx(ni, p->kidx);
18689490a627SAlexander V. Chernikov 				continue;
18699490a627SAlexander V. Chernikov 			}
1870b074b7bbSAlexander V. Chernikov 
18719490a627SAlexander V. Chernikov 			/* Find & unref by existing idx */
1872ac35ff17SAlexander V. Chernikov 			no = ipfw_objhash_lookup_kidx(ni, p->kidx);
18739490a627SAlexander V. Chernikov 			KASSERT(no != NULL, ("Ref'd table %d disappeared",
18749490a627SAlexander V. Chernikov 			    p->kidx));
1875b074b7bbSAlexander V. Chernikov 
18769490a627SAlexander V. Chernikov 			no->refcnt--;
18779490a627SAlexander V. Chernikov 		}
18789490a627SAlexander V. Chernikov 	}
18799490a627SAlexander V. Chernikov 	IPFW_UH_WUNLOCK(ch);
1880b074b7bbSAlexander V. Chernikov 
18819490a627SAlexander V. Chernikov 	*oib = pidx;
18829490a627SAlexander V. Chernikov 
18839490a627SAlexander V. Chernikov 	return (error);
1884b074b7bbSAlexander V. Chernikov }
1885b074b7bbSAlexander V. Chernikov 
1886b074b7bbSAlexander V. Chernikov /*
1887b074b7bbSAlexander V. Chernikov  * Compatibility function for old ipfw(8) binaries.
1888b074b7bbSAlexander V. Chernikov  * Rewrites table kernel indices with userland ones.
1889b074b7bbSAlexander V. Chernikov  * Works for \d+ talbes only (e.g. for tables, converted
1890b074b7bbSAlexander V. Chernikov  * from old numbered system calls).
1891b074b7bbSAlexander V. Chernikov  *
1892b074b7bbSAlexander V. Chernikov  * Returns 0 on success.
1893b074b7bbSAlexander V. Chernikov  * Raises error on any other tables.
1894b074b7bbSAlexander V. Chernikov  */
1895b074b7bbSAlexander V. Chernikov int
1896b074b7bbSAlexander V. Chernikov ipfw_rewrite_table_kidx(struct ip_fw_chain *chain, struct ip_fw *rule)
1897b074b7bbSAlexander V. Chernikov {
18981832a7b3SAlexander V. Chernikov 	int cmdlen, error, l;
1899b074b7bbSAlexander V. Chernikov 	ipfw_insn *cmd;
19001832a7b3SAlexander V. Chernikov 	uint16_t kidx, uidx;
1901b074b7bbSAlexander V. Chernikov 	uint8_t type;
1902b074b7bbSAlexander V. Chernikov 	struct named_object *no;
1903b074b7bbSAlexander V. Chernikov 	struct namedobj_instance *ni;
1904b074b7bbSAlexander V. Chernikov 
1905b074b7bbSAlexander V. Chernikov 	ni = CHAIN_TO_NI(chain);
19061832a7b3SAlexander V. Chernikov 	error = 0;
1907b074b7bbSAlexander V. Chernikov 
1908b074b7bbSAlexander V. Chernikov 	l = rule->cmd_len;
1909b074b7bbSAlexander V. Chernikov 	cmd = rule->cmd;
1910b074b7bbSAlexander V. Chernikov 	cmdlen = 0;
1911b074b7bbSAlexander V. Chernikov 	for ( ;	l > 0 ; l -= cmdlen, cmd += cmdlen) {
1912b074b7bbSAlexander V. Chernikov 		cmdlen = F_LEN(cmd);
1913b074b7bbSAlexander V. Chernikov 
1914b074b7bbSAlexander V. Chernikov 		if (classify_table_opcode(cmd, &kidx, &type) != 0)
1915b074b7bbSAlexander V. Chernikov 			continue;
1916b074b7bbSAlexander V. Chernikov 
1917ac35ff17SAlexander V. Chernikov 		if ((no = ipfw_objhash_lookup_kidx(ni, kidx)) == NULL)
1918b074b7bbSAlexander V. Chernikov 			return (1);
1919b074b7bbSAlexander V. Chernikov 
19201832a7b3SAlexander V. Chernikov 		uidx = no->uidx;
19211832a7b3SAlexander V. Chernikov 		if (no->compat == 0) {
1922b074b7bbSAlexander V. Chernikov 
19231832a7b3SAlexander V. Chernikov 			/*
19241832a7b3SAlexander V. Chernikov 			 * We are called via legacy opcode.
19251832a7b3SAlexander V. Chernikov 			 * Save error and show table as fake number
19261832a7b3SAlexander V. Chernikov 			 * not to make ipfw(8) hang.
19271832a7b3SAlexander V. Chernikov 			 */
19281832a7b3SAlexander V. Chernikov 			uidx = 65535;
19291832a7b3SAlexander V. Chernikov 			error = 2;
1930b074b7bbSAlexander V. Chernikov 		}
1931b074b7bbSAlexander V. Chernikov 
19321832a7b3SAlexander V. Chernikov 		update_table_opcode(cmd, uidx);
19331832a7b3SAlexander V. Chernikov 	}
19341832a7b3SAlexander V. Chernikov 
19351832a7b3SAlexander V. Chernikov 	return (error);
1936b074b7bbSAlexander V. Chernikov }
1937b074b7bbSAlexander V. Chernikov 
1938563b5ab1SAlexander V. Chernikov /*
1939563b5ab1SAlexander V. Chernikov  * Sets every table kidx in @bmask which is used in rule @rule.
1940563b5ab1SAlexander V. Chernikov  *
1941563b5ab1SAlexander V. Chernikov  * Returns number of newly-referenced tables.
1942563b5ab1SAlexander V. Chernikov  */
1943563b5ab1SAlexander V. Chernikov int
1944563b5ab1SAlexander V. Chernikov ipfw_mark_table_kidx(struct ip_fw_chain *chain, struct ip_fw *rule,
1945563b5ab1SAlexander V. Chernikov     uint32_t *bmask)
1946563b5ab1SAlexander V. Chernikov {
1947563b5ab1SAlexander V. Chernikov 	int cmdlen, l, count;
1948563b5ab1SAlexander V. Chernikov 	ipfw_insn *cmd;
1949563b5ab1SAlexander V. Chernikov 	uint16_t kidx;
1950563b5ab1SAlexander V. Chernikov 	uint8_t type;
1951563b5ab1SAlexander V. Chernikov 
1952563b5ab1SAlexander V. Chernikov 	l = rule->cmd_len;
1953563b5ab1SAlexander V. Chernikov 	cmd = rule->cmd;
1954563b5ab1SAlexander V. Chernikov 	cmdlen = 0;
1955563b5ab1SAlexander V. Chernikov 	count = 0;
1956563b5ab1SAlexander V. Chernikov 	for ( ;	l > 0 ; l -= cmdlen, cmd += cmdlen) {
1957563b5ab1SAlexander V. Chernikov 		cmdlen = F_LEN(cmd);
1958563b5ab1SAlexander V. Chernikov 
1959563b5ab1SAlexander V. Chernikov 		if (classify_table_opcode(cmd, &kidx, &type) != 0)
1960563b5ab1SAlexander V. Chernikov 			continue;
1961563b5ab1SAlexander V. Chernikov 
1962563b5ab1SAlexander V. Chernikov 		if ((bmask[kidx / 32] & (1 << (kidx % 32))) == 0)
1963563b5ab1SAlexander V. Chernikov 			count++;
1964563b5ab1SAlexander V. Chernikov 
1965563b5ab1SAlexander V. Chernikov 		bmask[kidx / 32] |= 1 << (kidx % 32);
1966563b5ab1SAlexander V. Chernikov 	}
1967563b5ab1SAlexander V. Chernikov 
1968563b5ab1SAlexander V. Chernikov 	return (count);
1969563b5ab1SAlexander V. Chernikov }
1970563b5ab1SAlexander V. Chernikov 
1971563b5ab1SAlexander V. Chernikov 
1972b074b7bbSAlexander V. Chernikov 
1973b074b7bbSAlexander V. Chernikov /*
1974b074b7bbSAlexander V. Chernikov  * Checks is opcode is referencing table of appropriate type.
1975b074b7bbSAlexander V. Chernikov  * Adds reference count for found table if true.
1976b074b7bbSAlexander V. Chernikov  * Rewrites user-supplied opcode values with kernel ones.
1977b074b7bbSAlexander V. Chernikov  *
1978b074b7bbSAlexander V. Chernikov  * Returns 0 on success and appropriate error code otherwise.
1979b074b7bbSAlexander V. Chernikov  */
1980b074b7bbSAlexander V. Chernikov int
1981b074b7bbSAlexander V. Chernikov ipfw_rewrite_table_uidx(struct ip_fw_chain *chain,
1982b074b7bbSAlexander V. Chernikov     struct rule_check_info *ci)
1983b074b7bbSAlexander V. Chernikov {
1984b074b7bbSAlexander V. Chernikov 	int cmdlen, error, ftype, l;
1985b074b7bbSAlexander V. Chernikov 	ipfw_insn *cmd;
1986b074b7bbSAlexander V. Chernikov 	uint16_t uidx;
1987b074b7bbSAlexander V. Chernikov 	uint8_t type;
1988b074b7bbSAlexander V. Chernikov 	struct table_config *tc;
19899f7d47b0SAlexander V. Chernikov 	struct table_algo *ta;
1990b074b7bbSAlexander V. Chernikov 	struct namedobj_instance *ni;
1991b074b7bbSAlexander V. Chernikov 	struct named_object *no, *no_n, *no_tmp;
19929490a627SAlexander V. Chernikov 	struct obj_idx *p, *pidx_first, *pidx_last;
1993b074b7bbSAlexander V. Chernikov 	struct namedobjects_head nh;
1994b074b7bbSAlexander V. Chernikov 	struct tid_info ti;
1995b074b7bbSAlexander V. Chernikov 
1996b074b7bbSAlexander V. Chernikov 	ni = CHAIN_TO_NI(chain);
1997b074b7bbSAlexander V. Chernikov 
19989490a627SAlexander V. Chernikov 	/* Prepare queue to store configs */
19999490a627SAlexander V. Chernikov 	TAILQ_INIT(&nh);
20009490a627SAlexander V. Chernikov 
2001b074b7bbSAlexander V. Chernikov 	/*
2002b074b7bbSAlexander V. Chernikov 	 * Prepare an array for storing opcode indices.
2003b074b7bbSAlexander V. Chernikov 	 * Use stack allocation by default.
2004b074b7bbSAlexander V. Chernikov 	 */
2005b074b7bbSAlexander V. Chernikov 	if (ci->table_opcodes <= (sizeof(ci->obuf)/sizeof(ci->obuf[0]))) {
2006b074b7bbSAlexander V. Chernikov 		/* Stack */
20079490a627SAlexander V. Chernikov 		pidx_first = ci->obuf;
2008b074b7bbSAlexander V. Chernikov 	} else
20099490a627SAlexander V. Chernikov 		pidx_first = malloc(ci->table_opcodes * sizeof(struct obj_idx),
2010b074b7bbSAlexander V. Chernikov 		    M_IPFW, M_WAITOK | M_ZERO);
2011b074b7bbSAlexander V. Chernikov 
20129490a627SAlexander V. Chernikov 	pidx_last = pidx_first;
2013b074b7bbSAlexander V. Chernikov 	error = 0;
2014b074b7bbSAlexander V. Chernikov 
2015b074b7bbSAlexander V. Chernikov 	type = 0;
2016b074b7bbSAlexander V. Chernikov 	ftype = 0;
2017b074b7bbSAlexander V. Chernikov 
2018b074b7bbSAlexander V. Chernikov 	memset(&ti, 0, sizeof(ti));
20191832a7b3SAlexander V. Chernikov 
20201832a7b3SAlexander V. Chernikov 	/*
20211832a7b3SAlexander V. Chernikov 	 * Use default set for looking up tables (old way) or
20221832a7b3SAlexander V. Chernikov 	 * use set rule is assigned to (new way).
20231832a7b3SAlexander V. Chernikov 	 */
20241832a7b3SAlexander V. Chernikov 	ti.set = (V_fw_tables_sets != 0) ? ci->krule->set : 0;
20256c2997ffSAlexander V. Chernikov 	if (ci->ctlv != NULL) {
20266c2997ffSAlexander V. Chernikov 		ti.tlvs = (void *)(ci->ctlv + 1);
20276c2997ffSAlexander V. Chernikov 		ti.tlen = ci->ctlv->head.length - sizeof(ipfw_obj_ctlv);
20286c2997ffSAlexander V. Chernikov 	}
2029b074b7bbSAlexander V. Chernikov 
2030b074b7bbSAlexander V. Chernikov 	/*
20319490a627SAlexander V. Chernikov 	 * Stage 1: reference existing tables, determine number
20329490a627SAlexander V. Chernikov 	 * of tables we need to allocate and allocate indexes for each.
2033b074b7bbSAlexander V. Chernikov 	 */
20349490a627SAlexander V. Chernikov 	error = bind_table_rule(chain, ci->krule, ci, &pidx_last, &ti);
2035b074b7bbSAlexander V. Chernikov 
2036b074b7bbSAlexander V. Chernikov 	if (error != 0) {
20379490a627SAlexander V. Chernikov 		if (pidx_first != ci->obuf)
20389490a627SAlexander V. Chernikov 			free(pidx_first, M_IPFW);
2039b074b7bbSAlexander V. Chernikov 
2040b074b7bbSAlexander V. Chernikov 		return (error);
2041b074b7bbSAlexander V. Chernikov 	}
2042b074b7bbSAlexander V. Chernikov 
2043b074b7bbSAlexander V. Chernikov 	/*
2044b074b7bbSAlexander V. Chernikov 	 * Stage 2: allocate table configs for every non-existent table
2045b074b7bbSAlexander V. Chernikov 	 */
2046b074b7bbSAlexander V. Chernikov 
20479f7d47b0SAlexander V. Chernikov 	if (ci->new_tables > 0) {
20489490a627SAlexander V. Chernikov 		for (p = pidx_first; p < pidx_last; p++) {
2049b074b7bbSAlexander V. Chernikov 			if (p->new == 0)
2050b074b7bbSAlexander V. Chernikov 				continue;
2051b074b7bbSAlexander V. Chernikov 
2052b074b7bbSAlexander V. Chernikov 			ti.uidx = p->uidx;
2053b074b7bbSAlexander V. Chernikov 			ti.type = p->type;
20549f7d47b0SAlexander V. Chernikov 			ti.atype = 0;
2055b074b7bbSAlexander V. Chernikov 
20569490a627SAlexander V. Chernikov 			ta = find_table_algo(CHAIN_TO_TCFG(chain), &ti, NULL);
20579f7d47b0SAlexander V. Chernikov 			if (ta == NULL) {
20589f7d47b0SAlexander V. Chernikov 				error = ENOTSUP;
20599f7d47b0SAlexander V. Chernikov 				goto free;
20609f7d47b0SAlexander V. Chernikov 			}
20619490a627SAlexander V. Chernikov 			tc = alloc_table_config(ni, &ti, ta, NULL);
2062b074b7bbSAlexander V. Chernikov 
2063b074b7bbSAlexander V. Chernikov 			if (tc == NULL) {
2064b074b7bbSAlexander V. Chernikov 				error = ENOMEM;
2065b074b7bbSAlexander V. Chernikov 				goto free;
2066b074b7bbSAlexander V. Chernikov 			}
2067b074b7bbSAlexander V. Chernikov 
2068b074b7bbSAlexander V. Chernikov 			tc->no.kidx = p->kidx;
2069b074b7bbSAlexander V. Chernikov 			tc->no.refcnt = 1;
2070b074b7bbSAlexander V. Chernikov 
2071b074b7bbSAlexander V. Chernikov 			/* Add to list */
2072b074b7bbSAlexander V. Chernikov 			TAILQ_INSERT_TAIL(&nh, &tc->no, nn_next);
2073b074b7bbSAlexander V. Chernikov 		}
2074b074b7bbSAlexander V. Chernikov 
2075b074b7bbSAlexander V. Chernikov 		/*
2076b074b7bbSAlexander V. Chernikov 		 * Stage 2.1: Check if we're going to create 2 tables
2077b074b7bbSAlexander V. Chernikov 		 * with the same name, but different table types.
2078b074b7bbSAlexander V. Chernikov 		 */
2079b074b7bbSAlexander V. Chernikov 		TAILQ_FOREACH(no, &nh, nn_next) {
2080b074b7bbSAlexander V. Chernikov 			TAILQ_FOREACH(no_tmp, &nh, nn_next) {
20819490a627SAlexander V. Chernikov 				if (ipfw_objhash_same_name(ni, no, no_tmp) == 0)
2082b074b7bbSAlexander V. Chernikov 					continue;
2083b074b7bbSAlexander V. Chernikov 				if (no->type != no_tmp->type) {
2084b074b7bbSAlexander V. Chernikov 					error = EINVAL;
2085b074b7bbSAlexander V. Chernikov 					goto free;
2086b074b7bbSAlexander V. Chernikov 				}
2087b074b7bbSAlexander V. Chernikov 			}
2088b074b7bbSAlexander V. Chernikov 		}
20899f7d47b0SAlexander V. Chernikov 	}
2090b074b7bbSAlexander V. Chernikov 
20919f7d47b0SAlexander V. Chernikov 	IPFW_UH_WLOCK(chain);
20929f7d47b0SAlexander V. Chernikov 
20939f7d47b0SAlexander V. Chernikov 	if (ci->new_tables > 0) {
2094b074b7bbSAlexander V. Chernikov 		/*
2095b074b7bbSAlexander V. Chernikov 		 * Stage 3: link & reference new table configs
2096b074b7bbSAlexander V. Chernikov 		 */
2097b074b7bbSAlexander V. Chernikov 
2098b074b7bbSAlexander V. Chernikov 
2099b074b7bbSAlexander V. Chernikov 		/*
2100b074b7bbSAlexander V. Chernikov 		 * Step 3.1: Check if some tables we need to create have been
2101b074b7bbSAlexander V. Chernikov 		 * already created with different table type.
2102b074b7bbSAlexander V. Chernikov 		 */
2103b074b7bbSAlexander V. Chernikov 
2104b074b7bbSAlexander V. Chernikov 		error = 0;
2105b074b7bbSAlexander V. Chernikov 		TAILQ_FOREACH_SAFE(no, &nh, nn_next, no_tmp) {
2106b074b7bbSAlexander V. Chernikov 			no_n = ipfw_objhash_lookup_name(ni, no->set, no->name);
2107b074b7bbSAlexander V. Chernikov 			if (no_n == NULL)
2108b074b7bbSAlexander V. Chernikov 				continue;
2109b074b7bbSAlexander V. Chernikov 
2110b074b7bbSAlexander V. Chernikov 			if (no_n->type != no->type) {
2111b074b7bbSAlexander V. Chernikov 				error = EINVAL;
2112b074b7bbSAlexander V. Chernikov 				break;
2113b074b7bbSAlexander V. Chernikov 			}
2114b074b7bbSAlexander V. Chernikov 
2115b074b7bbSAlexander V. Chernikov 		}
2116b074b7bbSAlexander V. Chernikov 
2117b074b7bbSAlexander V. Chernikov 		if (error != 0) {
2118b074b7bbSAlexander V. Chernikov 			/*
2119b074b7bbSAlexander V. Chernikov 			 * Someone has allocated table with different table type.
2120b074b7bbSAlexander V. Chernikov 			 * We have to rollback everything.
2121b074b7bbSAlexander V. Chernikov 			 */
2122b074b7bbSAlexander V. Chernikov 			IPFW_UH_WUNLOCK(chain);
2123b074b7bbSAlexander V. Chernikov 			goto free;
2124b074b7bbSAlexander V. Chernikov 		}
2125b074b7bbSAlexander V. Chernikov 
2126b074b7bbSAlexander V. Chernikov 		/*
21279f7d47b0SAlexander V. Chernikov 		 * Attach new tables.
21289f7d47b0SAlexander V. Chernikov 		 * We need to set table pointers for each new table,
2129b074b7bbSAlexander V. Chernikov 		 * so we have to acquire main WLOCK.
2130b074b7bbSAlexander V. Chernikov 		 */
2131b074b7bbSAlexander V. Chernikov 		IPFW_WLOCK(chain);
2132b074b7bbSAlexander V. Chernikov 		TAILQ_FOREACH_SAFE(no, &nh, nn_next, no_tmp) {
2133b074b7bbSAlexander V. Chernikov 			no_n = ipfw_objhash_lookup_name(ni, no->set, no->name);
2134b074b7bbSAlexander V. Chernikov 
21359490a627SAlexander V. Chernikov 			if (no_n == NULL) {
21369490a627SAlexander V. Chernikov 				/* New table. Attach to runtime hash */
21379490a627SAlexander V. Chernikov 				TAILQ_REMOVE(&nh, no, nn_next);
21389490a627SAlexander V. Chernikov 				link_table(chain, (struct table_config *)no);
2139b074b7bbSAlexander V. Chernikov 				continue;
2140b074b7bbSAlexander V. Chernikov 			}
2141b074b7bbSAlexander V. Chernikov 
21429490a627SAlexander V. Chernikov 			/*
21439490a627SAlexander V. Chernikov 			 * Newly-allocated table with the same type.
21449490a627SAlexander V. Chernikov 			 * Reference it and update out @pidx array
21459490a627SAlexander V. Chernikov 			 * rewrite info.
21469490a627SAlexander V. Chernikov 			 */
21479490a627SAlexander V. Chernikov 			no_n->refcnt++;
21489490a627SAlexander V. Chernikov 			/* Keep oib array in sync: update kidx */
21499490a627SAlexander V. Chernikov 			for (p = pidx_first; p < pidx_last; p++) {
21509490a627SAlexander V. Chernikov 				if (p->kidx != no->kidx)
21519490a627SAlexander V. Chernikov 					continue;
21529490a627SAlexander V. Chernikov 				/* Update kidx */
21539490a627SAlexander V. Chernikov 				p->kidx = no_n->kidx;
21549490a627SAlexander V. Chernikov 				break;
21559490a627SAlexander V. Chernikov 			}
2156b074b7bbSAlexander V. Chernikov 		}
2157b074b7bbSAlexander V. Chernikov 		IPFW_WUNLOCK(chain);
21589f7d47b0SAlexander V. Chernikov 	}
2159b074b7bbSAlexander V. Chernikov 
2160b074b7bbSAlexander V. Chernikov 	/* Perform rule rewrite */
2161b074b7bbSAlexander V. Chernikov 	l = ci->krule->cmd_len;
2162b074b7bbSAlexander V. Chernikov 	cmd = ci->krule->cmd;
2163b074b7bbSAlexander V. Chernikov 	cmdlen = 0;
21649490a627SAlexander V. Chernikov 	p = pidx_first;
2165b074b7bbSAlexander V. Chernikov 	for ( ;	l > 0 ; l -= cmdlen, cmd += cmdlen) {
2166b074b7bbSAlexander V. Chernikov 		cmdlen = F_LEN(cmd);
2167b074b7bbSAlexander V. Chernikov 
2168b074b7bbSAlexander V. Chernikov 		if (classify_table_opcode(cmd, &uidx, &type) != 0)
2169b074b7bbSAlexander V. Chernikov 			continue;
21709490a627SAlexander V. Chernikov 		update_table_opcode(cmd, p->kidx);
21719490a627SAlexander V. Chernikov 		p++;
2172b074b7bbSAlexander V. Chernikov 	}
2173b074b7bbSAlexander V. Chernikov 
2174b074b7bbSAlexander V. Chernikov 	IPFW_UH_WUNLOCK(chain);
2175b074b7bbSAlexander V. Chernikov 
2176b074b7bbSAlexander V. Chernikov 	error = 0;
2177b074b7bbSAlexander V. Chernikov 
2178b074b7bbSAlexander V. Chernikov 	/*
2179b074b7bbSAlexander V. Chernikov 	 * Stage 4: free resources
2180b074b7bbSAlexander V. Chernikov 	 */
2181b074b7bbSAlexander V. Chernikov free:
21829490a627SAlexander V. Chernikov 	if (!TAILQ_EMPTY(&nh)) {
21839490a627SAlexander V. Chernikov 		/* Free indexes first */
21849490a627SAlexander V. Chernikov 		IPFW_UH_WLOCK(chain);
21859490a627SAlexander V. Chernikov 		TAILQ_FOREACH_SAFE(no, &nh, nn_next, no_tmp) {
2186ac35ff17SAlexander V. Chernikov 			ipfw_objhash_free_idx(ni, no->kidx);
21879490a627SAlexander V. Chernikov 		}
21889490a627SAlexander V. Chernikov 		IPFW_UH_WUNLOCK(chain);
21899490a627SAlexander V. Chernikov 		/* Free configs */
2190b074b7bbSAlexander V. Chernikov 		TAILQ_FOREACH_SAFE(no, &nh, nn_next, no_tmp)
2191b074b7bbSAlexander V. Chernikov 			free_table_config(ni, tc);
21929490a627SAlexander V. Chernikov 	}
2193b074b7bbSAlexander V. Chernikov 
21949490a627SAlexander V. Chernikov 	if (pidx_first != ci->obuf)
21959490a627SAlexander V. Chernikov 		free(pidx_first, M_IPFW);
2196b074b7bbSAlexander V. Chernikov 
2197b074b7bbSAlexander V. Chernikov 	return (error);
2198b074b7bbSAlexander V. Chernikov }
2199b074b7bbSAlexander V. Chernikov 
2200b074b7bbSAlexander V. Chernikov /*
2201b074b7bbSAlexander V. Chernikov  * Remove references from every table used in @rule.
2202b074b7bbSAlexander V. Chernikov  */
2203b074b7bbSAlexander V. Chernikov void
2204b074b7bbSAlexander V. Chernikov ipfw_unbind_table_rule(struct ip_fw_chain *chain, struct ip_fw *rule)
2205b074b7bbSAlexander V. Chernikov {
2206b074b7bbSAlexander V. Chernikov 	int cmdlen, l;
2207b074b7bbSAlexander V. Chernikov 	ipfw_insn *cmd;
2208b074b7bbSAlexander V. Chernikov 	struct namedobj_instance *ni;
2209b074b7bbSAlexander V. Chernikov 	struct named_object *no;
2210b074b7bbSAlexander V. Chernikov 	uint16_t kidx;
2211b074b7bbSAlexander V. Chernikov 	uint8_t type;
2212b074b7bbSAlexander V. Chernikov 
2213b074b7bbSAlexander V. Chernikov 	ni = CHAIN_TO_NI(chain);
2214b074b7bbSAlexander V. Chernikov 
2215b074b7bbSAlexander V. Chernikov 	l = rule->cmd_len;
2216b074b7bbSAlexander V. Chernikov 	cmd = rule->cmd;
2217b074b7bbSAlexander V. Chernikov 	cmdlen = 0;
2218b074b7bbSAlexander V. Chernikov 	for ( ;	l > 0 ; l -= cmdlen, cmd += cmdlen) {
2219b074b7bbSAlexander V. Chernikov 		cmdlen = F_LEN(cmd);
2220b074b7bbSAlexander V. Chernikov 
2221b074b7bbSAlexander V. Chernikov 		if (classify_table_opcode(cmd, &kidx, &type) != 0)
2222b074b7bbSAlexander V. Chernikov 			continue;
2223b074b7bbSAlexander V. Chernikov 
2224ac35ff17SAlexander V. Chernikov 		no = ipfw_objhash_lookup_kidx(ni, kidx);
2225b074b7bbSAlexander V. Chernikov 
2226b074b7bbSAlexander V. Chernikov 		KASSERT(no != NULL, ("table id %d not found", kidx));
2227b074b7bbSAlexander V. Chernikov 		KASSERT(no->type == type, ("wrong type %d (%d) for table id %d",
2228b074b7bbSAlexander V. Chernikov 		    no->type, type, kidx));
2229b074b7bbSAlexander V. Chernikov 		KASSERT(no->refcnt > 0, ("refcount for table %d is %d",
2230b074b7bbSAlexander V. Chernikov 		    kidx, no->refcnt));
2231b074b7bbSAlexander V. Chernikov 
2232b074b7bbSAlexander V. Chernikov 		no->refcnt--;
2233b074b7bbSAlexander V. Chernikov 	}
2234b074b7bbSAlexander V. Chernikov }
2235b074b7bbSAlexander V. Chernikov 
2236b074b7bbSAlexander V. Chernikov 
2237b074b7bbSAlexander V. Chernikov /*
2238b074b7bbSAlexander V. Chernikov  * Removes table bindings for every rule in rule chain @head.
2239b074b7bbSAlexander V. Chernikov  */
2240b074b7bbSAlexander V. Chernikov void
2241b074b7bbSAlexander V. Chernikov ipfw_unbind_table_list(struct ip_fw_chain *chain, struct ip_fw *head)
2242b074b7bbSAlexander V. Chernikov {
2243b074b7bbSAlexander V. Chernikov 	struct ip_fw *rule;
2244b074b7bbSAlexander V. Chernikov 
2245b074b7bbSAlexander V. Chernikov 	while ((rule = head) != NULL) {
2246b074b7bbSAlexander V. Chernikov 		head = head->x_next;
2247b074b7bbSAlexander V. Chernikov 		ipfw_unbind_table_rule(chain, rule);
2248b074b7bbSAlexander V. Chernikov 	}
2249b074b7bbSAlexander V. Chernikov }
2250b074b7bbSAlexander V. Chernikov 
2251b074b7bbSAlexander V. Chernikov 
22523b3a8eb9SGleb Smirnoff /* end of file */
2253