libiptc.c revision 12009531e6a96a62ee398eb0ab3e9ec0b3b57701
112009531e6a96a62ee398eb0ab3e9ec0b3b57701Martin Josefsson/* Library which manipulates firewall rules.  Version $Revision: 1.57 $ */
2e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
3e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Architecture of firewall rules is as follows:
4e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher *
5e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher * Chains go INPUT, FORWARD, OUTPUT then user chains.
6e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher * Each user chain starts with an ERROR node.
7e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher * Every chain ends with an unconditional jump: a RETURN for user chains,
8e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher * and a POLICY for built-ins.
9e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher */
10e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
113ea8f40262386e6b1445a617841f28702fe74d9dHarald Welte/* (C) 1999 Paul ``Rusty'' Russell - Placed under the GNU GPL (See
123ea8f40262386e6b1445a617841f28702fe74d9dHarald Welte * COPYING for details).
13aae69bed019826ddec93f761514652a93d871e49Harald Welte * (C) 2000-2004 by the Netfilter Core Team <coreteam@netfilter.org>
143ea8f40262386e6b1445a617841f28702fe74d9dHarald Welte *
15fbc85236a6140918ab1d0fb0e07e2d72da46ce45Harald Welte * 2003-Jun-20: Harald Welte <laforge@netfilter.org>:
163ea8f40262386e6b1445a617841f28702fe74d9dHarald Welte *	- Reimplementation of chain cache to use offsets instead of entries
17fbc85236a6140918ab1d0fb0e07e2d72da46ce45Harald Welte * 2003-Jun-23: Harald Welte <laforge@netfilter.org>:
180113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte * 	- performance optimization, sponsored by Astaro AG (http://www.astaro.com/)
19fbc85236a6140918ab1d0fb0e07e2d72da46ce45Harald Welte * 	  don't rebuild the chain cache after every operation, instead fix it
20fbc85236a6140918ab1d0fb0e07e2d72da46ce45Harald Welte * 	  up after a ruleset change.
21aae69bed019826ddec93f761514652a93d871e49Harald Welte * 2004-Aug-18: Harald Welte <laforge@netfilter.org>:
22aae69bed019826ddec93f761514652a93d871e49Harald Welte * 	- futher performance work: total reimplementation of libiptc.
23aae69bed019826ddec93f761514652a93d871e49Harald Welte * 	- libiptc now has a real internal (linked-list) represntation of the
24aae69bed019826ddec93f761514652a93d871e49Harald Welte * 	  ruleset and a parser/compiler from/to this internal representation
25aae69bed019826ddec93f761514652a93d871e49Harald Welte * 	- again sponsored by Astaro AG (http://www.astaro.com/)
263ea8f40262386e6b1445a617841f28702fe74d9dHarald Welte */
2715920d160760535e51a57b3834eba45257cfa6d8Harald Welte#include <sys/types.h>
2815920d160760535e51a57b3834eba45257cfa6d8Harald Welte#include <sys/socket.h>
297cd002826d0f329620cb738bc4dc4760ef5e084aStephane Ouellette
30aae69bed019826ddec93f761514652a93d871e49Harald Welte#include "linux_list.h"
31aae69bed019826ddec93f761514652a93d871e49Harald Welte
32aae69bed019826ddec93f761514652a93d871e49Harald Welte//#define IPTC_DEBUG2 1
33aae69bed019826ddec93f761514652a93d871e49Harald Welte
34aae69bed019826ddec93f761514652a93d871e49Harald Welte#ifdef IPTC_DEBUG2
35aae69bed019826ddec93f761514652a93d871e49Harald Welte#include <fcntl.h>
36aae69bed019826ddec93f761514652a93d871e49Harald Welte#define DEBUGP(x, args...)	fprintf(stderr, "%s: " x, __FUNCTION__, ## args)
37aae69bed019826ddec93f761514652a93d871e49Harald Welte#define DEBUGP_C(x, args...)	fprintf(stderr, x, ## args)
38aae69bed019826ddec93f761514652a93d871e49Harald Welte#else
39aae69bed019826ddec93f761514652a93d871e49Harald Welte#define DEBUGP(x, args...)
40aae69bed019826ddec93f761514652a93d871e49Harald Welte#define DEBUGP_C(x, args...)
41aae69bed019826ddec93f761514652a93d871e49Harald Welte#endif
42aae69bed019826ddec93f761514652a93d871e49Harald Welte
43e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#ifndef IPT_LIB_DIR
44e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#define IPT_LIB_DIR "/usr/local/lib/iptables"
45e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#endif
46e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
470113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte#ifndef __OPTIMIZE__
480113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald WelteSTRUCT_ENTRY_TARGET *
490113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald WelteGET_TARGET(STRUCT_ENTRY *e)
500113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte{
510113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	return (void *)e + e->target_offset;
520113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte}
530113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte#endif
540113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
55e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic int sockfd = -1;
56e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic void *iptc_fn = NULL;
57e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
58e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic const char *hooknames[]
5979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell= { [HOOK_PRE_ROUTING]  "PREROUTING",
6079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell    [HOOK_LOCAL_IN]     "INPUT",
6179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell    [HOOK_FORWARD]      "FORWARD",
6279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell    [HOOK_LOCAL_OUT]    "OUTPUT",
6310758b743d6aa076ebe2c3e8f855e73826841e71Rusty Russell    [HOOK_POST_ROUTING] "POSTROUTING",
6410758b743d6aa076ebe2c3e8f855e73826841e71Rusty Russell#ifdef HOOK_DROPPING
6510758b743d6aa076ebe2c3e8f855e73826841e71Rusty Russell    [HOOK_DROPPING]	"DROPPING"
6610758b743d6aa076ebe2c3e8f855e73826841e71Rusty Russell#endif
67e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher};
68e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
69aae69bed019826ddec93f761514652a93d871e49Harald Welte/* Convenience structures */
70aae69bed019826ddec93f761514652a93d871e49Harald Weltestruct ipt_error_target
71aae69bed019826ddec93f761514652a93d871e49Harald Welte{
72aae69bed019826ddec93f761514652a93d871e49Harald Welte	STRUCT_ENTRY_TARGET t;
73aae69bed019826ddec93f761514652a93d871e49Harald Welte	char error[TABLE_MAXNAMELEN];
74aae69bed019826ddec93f761514652a93d871e49Harald Welte};
75aae69bed019826ddec93f761514652a93d871e49Harald Welte
76aae69bed019826ddec93f761514652a93d871e49Harald Weltestruct chain_head;
77aae69bed019826ddec93f761514652a93d871e49Harald Weltestruct rule_head;
78aae69bed019826ddec93f761514652a93d871e49Harald Welte
79e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstruct counter_map
80e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
81e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	enum {
82e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		COUNTER_MAP_NOMAP,
83e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		COUNTER_MAP_NORMAL_MAP,
841cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		COUNTER_MAP_ZEROED,
851cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		COUNTER_MAP_SET
86e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	} maptype;
87e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int mappos;
88e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher};
89e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
90aae69bed019826ddec93f761514652a93d871e49Harald Welteenum iptcc_rule_type {
91aae69bed019826ddec93f761514652a93d871e49Harald Welte	IPTCC_R_STANDARD,		/* standard target (ACCEPT, ...) */
92aae69bed019826ddec93f761514652a93d871e49Harald Welte	IPTCC_R_MODULE,			/* extension module (SNAT, ...) */
93aae69bed019826ddec93f761514652a93d871e49Harald Welte	IPTCC_R_FALLTHROUGH,		/* fallthrough rule */
94aae69bed019826ddec93f761514652a93d871e49Harald Welte	IPTCC_R_JUMP,			/* jump to other chain */
95aae69bed019826ddec93f761514652a93d871e49Harald Welte};
96aae69bed019826ddec93f761514652a93d871e49Harald Welte
97aae69bed019826ddec93f761514652a93d871e49Harald Weltestruct rule_head
98e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
99aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct list_head list;
100aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *chain;
101aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct counter_map counter_map;
102aae69bed019826ddec93f761514652a93d871e49Harald Welte
103aae69bed019826ddec93f761514652a93d871e49Harald Welte	unsigned int index;		/* index (needed for counter_map) */
104aae69bed019826ddec93f761514652a93d871e49Harald Welte	unsigned int offset;		/* offset in rule blob */
105aae69bed019826ddec93f761514652a93d871e49Harald Welte
106aae69bed019826ddec93f761514652a93d871e49Harald Welte	enum iptcc_rule_type type;
107aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *jump;	/* jump target, if IPTCC_R_JUMP */
108aae69bed019826ddec93f761514652a93d871e49Harald Welte
109aae69bed019826ddec93f761514652a93d871e49Harald Welte	unsigned int size;		/* size of entry data */
110aae69bed019826ddec93f761514652a93d871e49Harald Welte	STRUCT_ENTRY entry[0];
111e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher};
112e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
113aae69bed019826ddec93f761514652a93d871e49Harald Weltestruct chain_head
11430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell{
115aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct list_head list;
11679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	char name[TABLE_MAXNAMELEN];
117aae69bed019826ddec93f761514652a93d871e49Harald Welte	unsigned int hooknum;		/* hook number+1 if builtin */
118aae69bed019826ddec93f761514652a93d871e49Harald Welte	unsigned int references;	/* how many jumps reference us */
119aae69bed019826ddec93f761514652a93d871e49Harald Welte	int verdict;			/* verdict if builtin */
120aae69bed019826ddec93f761514652a93d871e49Harald Welte
121aae69bed019826ddec93f761514652a93d871e49Harald Welte	STRUCT_COUNTERS counters;	/* per-chain counters */
122aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct counter_map counter_map;
123aae69bed019826ddec93f761514652a93d871e49Harald Welte
124aae69bed019826ddec93f761514652a93d871e49Harald Welte	unsigned int num_rules;		/* number of rules in list */
125aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct list_head rules;		/* list of rules */
126aae69bed019826ddec93f761514652a93d871e49Harald Welte
127aae69bed019826ddec93f761514652a93d871e49Harald Welte	unsigned int index;		/* index (needed for jump resolval) */
128aae69bed019826ddec93f761514652a93d871e49Harald Welte	unsigned int head_offset;	/* offset in rule blob */
129aae69bed019826ddec93f761514652a93d871e49Harald Welte	unsigned int foot_index;	/* index (needed for counter_map) */
130aae69bed019826ddec93f761514652a93d871e49Harald Welte	unsigned int foot_offset;	/* offset in rule blob */
13130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell};
13230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
13379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellSTRUCT_TC_HANDLE
134e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
135aae69bed019826ddec93f761514652a93d871e49Harald Welte	int changed;			 /* Have changes been made? */
136aae69bed019826ddec93f761514652a93d871e49Harald Welte
137aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct list_head chains;
138aae69bed019826ddec93f761514652a93d871e49Harald Welte
139aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *chain_iterator_cur;
140aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct rule_head *rule_iterator_cur;
141aae69bed019826ddec93f761514652a93d871e49Harald Welte
14279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	STRUCT_GETINFO info;
143aae69bed019826ddec93f761514652a93d871e49Harald Welte	STRUCT_GET_ENTRIES *entries;
144aae69bed019826ddec93f761514652a93d871e49Harald Welte};
145e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
146aae69bed019826ddec93f761514652a93d871e49Harald Welte/* allocate a new chain head for the cache */
147aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic struct chain_head *iptcc_alloc_chain_head(const char *name, int hooknum)
148aae69bed019826ddec93f761514652a93d871e49Harald Welte{
149aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c = malloc(sizeof(*c));
150aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!c)
151aae69bed019826ddec93f761514652a93d871e49Harald Welte		return NULL;
152aae69bed019826ddec93f761514652a93d871e49Harald Welte	memset(c, 0, sizeof(*c));
153aae69bed019826ddec93f761514652a93d871e49Harald Welte
154aae69bed019826ddec93f761514652a93d871e49Harald Welte	strncpy(c->name, name, TABLE_MAXNAMELEN);
155aae69bed019826ddec93f761514652a93d871e49Harald Welte	c->hooknum = hooknum;
156aae69bed019826ddec93f761514652a93d871e49Harald Welte	INIT_LIST_HEAD(&c->rules);
157e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
158aae69bed019826ddec93f761514652a93d871e49Harald Welte	return c;
159aae69bed019826ddec93f761514652a93d871e49Harald Welte}
16030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
161aae69bed019826ddec93f761514652a93d871e49Harald Welte/* allocate and initialize a new rule for the cache */
162aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic struct rule_head *iptcc_alloc_rule(struct chain_head *c, unsigned int size)
163aae69bed019826ddec93f761514652a93d871e49Harald Welte{
164aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct rule_head *r = malloc(sizeof(*r)+size);
165aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!r)
166aae69bed019826ddec93f761514652a93d871e49Harald Welte		return NULL;
167aae69bed019826ddec93f761514652a93d871e49Harald Welte	memset(r, 0, sizeof(*r));
16830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
169aae69bed019826ddec93f761514652a93d871e49Harald Welte	r->chain = c;
170aae69bed019826ddec93f761514652a93d871e49Harald Welte	r->size = size;
171175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell
172aae69bed019826ddec93f761514652a93d871e49Harald Welte	return r;
173aae69bed019826ddec93f761514652a93d871e49Harald Welte}
174e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
175aae69bed019826ddec93f761514652a93d871e49Harald Welte/* notify us that the ruleset has been modified by the user */
176175f64177743e5a417e98d483ef995bf7151f3bcRusty Russellstatic void
17779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellset_changed(TC_HANDLE_T h)
178175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell{
179175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell	h->changed = 1;
180175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell}
181175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell
182380ba5f3074a16fbaa8869d9594962d58b5f8608Harald Welte#ifdef IPTC_DEBUG
18379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellstatic void do_check(TC_HANDLE_T h, unsigned int line);
184849779c4adf8dd65c83fffb65e6b7898df2a55c6Rusty Russell#define CHECK(h) do { if (!getenv("IPTC_NO_CHECK")) do_check((h), __LINE__); } while(0)
18530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell#else
18630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell#define CHECK(h)
18730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell#endif
188e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
189aae69bed019826ddec93f761514652a93d871e49Harald Welte
190aae69bed019826ddec93f761514652a93d871e49Harald Welte/**********************************************************************
191aae69bed019826ddec93f761514652a93d871e49Harald Welte * iptc blob utility functions (iptcb_*)
192aae69bed019826ddec93f761514652a93d871e49Harald Welte **********************************************************************/
193aae69bed019826ddec93f761514652a93d871e49Harald Welte
194e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic inline int
195aae69bed019826ddec93f761514652a93d871e49Harald Welteiptcb_get_number(const STRUCT_ENTRY *i,
19679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	   const STRUCT_ENTRY *seek,
197e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	   unsigned int *pos)
198e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
199e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (i == seek)
200e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 1;
201e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	(*pos)++;
202e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 0;
203e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
204e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
205aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic inline int
206aae69bed019826ddec93f761514652a93d871e49Harald Welteiptcb_get_entry_n(STRUCT_ENTRY *i,
207aae69bed019826ddec93f761514652a93d871e49Harald Welte	    unsigned int number,
208aae69bed019826ddec93f761514652a93d871e49Harald Welte	    unsigned int *pos,
209aae69bed019826ddec93f761514652a93d871e49Harald Welte	    STRUCT_ENTRY **pe)
210aae69bed019826ddec93f761514652a93d871e49Harald Welte{
211aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (*pos == number) {
212aae69bed019826ddec93f761514652a93d871e49Harald Welte		*pe = i;
213aae69bed019826ddec93f761514652a93d871e49Harald Welte		return 1;
214aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
215aae69bed019826ddec93f761514652a93d871e49Harald Welte	(*pos)++;
216aae69bed019826ddec93f761514652a93d871e49Harald Welte	return 0;
217aae69bed019826ddec93f761514652a93d871e49Harald Welte}
218aae69bed019826ddec93f761514652a93d871e49Harald Welte
219aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic inline STRUCT_ENTRY *
220aae69bed019826ddec93f761514652a93d871e49Harald Welteiptcb_get_entry(TC_HANDLE_T h, unsigned int offset)
221aae69bed019826ddec93f761514652a93d871e49Harald Welte{
222aae69bed019826ddec93f761514652a93d871e49Harald Welte	return (STRUCT_ENTRY *)((char *)h->entries->entrytable + offset);
223aae69bed019826ddec93f761514652a93d871e49Harald Welte}
224aae69bed019826ddec93f761514652a93d871e49Harald Welte
225e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic unsigned int
226aae69bed019826ddec93f761514652a93d871e49Harald Welteiptcb_entry2index(const TC_HANDLE_T h, const STRUCT_ENTRY *seek)
227e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
228e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int pos = 0;
229e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
230aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (ENTRY_ITERATE(h->entries->entrytable, h->entries->size,
231aae69bed019826ddec93f761514652a93d871e49Harald Welte			  iptcb_get_number, seek, &pos) == 0) {
232a28d495285ad7dd9f286d63958cf20d74eec6bcbMartin Josefsson		fprintf(stderr, "ERROR: offset %u not an entry!\n",
233aae69bed019826ddec93f761514652a93d871e49Harald Welte			(unsigned int)((char *)seek - (char *)h->entries->entrytable));
234e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		abort();
235e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
236e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return pos;
237e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
238e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
239aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic inline STRUCT_ENTRY *
240aae69bed019826ddec93f761514652a93d871e49Harald Welteiptcb_offset2entry(TC_HANDLE_T h, unsigned int offset)
241e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
242aae69bed019826ddec93f761514652a93d871e49Harald Welte	return (STRUCT_ENTRY *) ((void *)h->entries->entrytable+offset);
243aae69bed019826ddec93f761514652a93d871e49Harald Welte}
244aae69bed019826ddec93f761514652a93d871e49Harald Welte
245aae69bed019826ddec93f761514652a93d871e49Harald Welte
246aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic inline unsigned long
247aae69bed019826ddec93f761514652a93d871e49Harald Welteiptcb_entry2offset(const TC_HANDLE_T h, const STRUCT_ENTRY *e)
248aae69bed019826ddec93f761514652a93d871e49Harald Welte{
249aae69bed019826ddec93f761514652a93d871e49Harald Welte	return (void *)e - (void *)h->entries->entrytable;
250aae69bed019826ddec93f761514652a93d871e49Harald Welte}
251aae69bed019826ddec93f761514652a93d871e49Harald Welte
252aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic inline unsigned int
253aae69bed019826ddec93f761514652a93d871e49Harald Welteiptcb_offset2index(const TC_HANDLE_T h, unsigned int offset)
254aae69bed019826ddec93f761514652a93d871e49Harald Welte{
255aae69bed019826ddec93f761514652a93d871e49Harald Welte	return iptcb_entry2index(h, iptcb_offset2entry(h, offset));
256aae69bed019826ddec93f761514652a93d871e49Harald Welte}
257aae69bed019826ddec93f761514652a93d871e49Harald Welte
258aae69bed019826ddec93f761514652a93d871e49Harald Welte/* Returns 0 if not hook entry, else hooknumber + 1 */
259aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic inline unsigned int
260aae69bed019826ddec93f761514652a93d871e49Harald Welteiptcb_ent_is_hook_entry(STRUCT_ENTRY *e, TC_HANDLE_T h)
261aae69bed019826ddec93f761514652a93d871e49Harald Welte{
262aae69bed019826ddec93f761514652a93d871e49Harald Welte	unsigned int i;
263aae69bed019826ddec93f761514652a93d871e49Harald Welte
264aae69bed019826ddec93f761514652a93d871e49Harald Welte	for (i = 0; i < NUMHOOKS; i++) {
265aae69bed019826ddec93f761514652a93d871e49Harald Welte		if ((h->info.valid_hooks & (1 << i))
266aae69bed019826ddec93f761514652a93d871e49Harald Welte		    && iptcb_get_entry(h, h->info.hook_entry[i]) == e)
267aae69bed019826ddec93f761514652a93d871e49Harald Welte			return i+1;
268aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
269aae69bed019826ddec93f761514652a93d871e49Harald Welte	return 0;
270aae69bed019826ddec93f761514652a93d871e49Harald Welte}
271aae69bed019826ddec93f761514652a93d871e49Harald Welte
272aae69bed019826ddec93f761514652a93d871e49Harald Welte
273aae69bed019826ddec93f761514652a93d871e49Harald Welte/**********************************************************************
274aae69bed019826ddec93f761514652a93d871e49Harald Welte * iptc cache utility functions (iptcc_*)
275aae69bed019826ddec93f761514652a93d871e49Harald Welte **********************************************************************/
276aae69bed019826ddec93f761514652a93d871e49Harald Welte
277aae69bed019826ddec93f761514652a93d871e49Harald Welte/* Is the given chain builtin (1) or user-defined (0) */
278aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic unsigned int iptcc_is_builtin(struct chain_head *c)
279aae69bed019826ddec93f761514652a93d871e49Harald Welte{
280aae69bed019826ddec93f761514652a93d871e49Harald Welte	return (c->hooknum ? 1 : 0);
281aae69bed019826ddec93f761514652a93d871e49Harald Welte}
282aae69bed019826ddec93f761514652a93d871e49Harald Welte
283aae69bed019826ddec93f761514652a93d871e49Harald Welte/* Get a specific rule within a chain */
284aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic struct rule_head *iptcc_get_rule_num(struct chain_head *c,
285aae69bed019826ddec93f761514652a93d871e49Harald Welte					    unsigned int rulenum)
286aae69bed019826ddec93f761514652a93d871e49Harald Welte{
287aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct rule_head *r;
288aae69bed019826ddec93f761514652a93d871e49Harald Welte	unsigned int num = 0;
289aae69bed019826ddec93f761514652a93d871e49Harald Welte
290aae69bed019826ddec93f761514652a93d871e49Harald Welte	list_for_each_entry(r, &c->rules, list) {
291aae69bed019826ddec93f761514652a93d871e49Harald Welte		num++;
292aae69bed019826ddec93f761514652a93d871e49Harald Welte		if (num == rulenum)
293aae69bed019826ddec93f761514652a93d871e49Harald Welte			return r;
294aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
295aae69bed019826ddec93f761514652a93d871e49Harald Welte	return NULL;
296aae69bed019826ddec93f761514652a93d871e49Harald Welte}
297aae69bed019826ddec93f761514652a93d871e49Harald Welte
298aae69bed019826ddec93f761514652a93d871e49Harald Welte/* Returns chain head if found, otherwise NULL. */
299aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic struct chain_head *
300aae69bed019826ddec93f761514652a93d871e49Harald Welteiptcc_find_chain_by_offset(TC_HANDLE_T handle, unsigned int offset)
301aae69bed019826ddec93f761514652a93d871e49Harald Welte{
302aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct list_head *pos;
303aae69bed019826ddec93f761514652a93d871e49Harald Welte
304aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (list_empty(&handle->chains))
305aae69bed019826ddec93f761514652a93d871e49Harald Welte		return NULL;
306aae69bed019826ddec93f761514652a93d871e49Harald Welte
307aae69bed019826ddec93f761514652a93d871e49Harald Welte	list_for_each(pos, &handle->chains) {
308aae69bed019826ddec93f761514652a93d871e49Harald Welte		struct chain_head *c = list_entry(pos, struct chain_head, list);
309aae69bed019826ddec93f761514652a93d871e49Harald Welte		if (offset >= c->head_offset && offset <= c->foot_offset)
310aae69bed019826ddec93f761514652a93d871e49Harald Welte			return c;
311aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
312aae69bed019826ddec93f761514652a93d871e49Harald Welte
313aae69bed019826ddec93f761514652a93d871e49Harald Welte	return NULL;
314aae69bed019826ddec93f761514652a93d871e49Harald Welte}
315aae69bed019826ddec93f761514652a93d871e49Harald Welte/* Returns chain head if found, otherwise NULL. */
316aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic struct chain_head *
317aae69bed019826ddec93f761514652a93d871e49Harald Welteiptcc_find_label(const char *name, TC_HANDLE_T handle)
318aae69bed019826ddec93f761514652a93d871e49Harald Welte{
319aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct list_head *pos;
320aae69bed019826ddec93f761514652a93d871e49Harald Welte
321aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (list_empty(&handle->chains))
322aae69bed019826ddec93f761514652a93d871e49Harald Welte		return NULL;
323aae69bed019826ddec93f761514652a93d871e49Harald Welte
324aae69bed019826ddec93f761514652a93d871e49Harald Welte	list_for_each(pos, &handle->chains) {
325aae69bed019826ddec93f761514652a93d871e49Harald Welte		struct chain_head *c = list_entry(pos, struct chain_head, list);
326aae69bed019826ddec93f761514652a93d871e49Harald Welte		if (!strcmp(c->name, name))
327aae69bed019826ddec93f761514652a93d871e49Harald Welte			return c;
328aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
329aae69bed019826ddec93f761514652a93d871e49Harald Welte
330aae69bed019826ddec93f761514652a93d871e49Harald Welte	return NULL;
331aae69bed019826ddec93f761514652a93d871e49Harald Welte}
332aae69bed019826ddec93f761514652a93d871e49Harald Welte
333aae69bed019826ddec93f761514652a93d871e49Harald Welte/* called when rule is to be removed from cache */
334aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic void iptcc_delete_rule(struct rule_head *r)
335aae69bed019826ddec93f761514652a93d871e49Harald Welte{
336aae69bed019826ddec93f761514652a93d871e49Harald Welte	DEBUGP("deleting rule %p (offset %u)\n", r, r->offset);
337aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* clean up reference count of called chain */
338aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (r->type == IPTCC_R_JUMP
339aae69bed019826ddec93f761514652a93d871e49Harald Welte	    && r->jump)
340aae69bed019826ddec93f761514652a93d871e49Harald Welte		r->jump->references--;
341aae69bed019826ddec93f761514652a93d871e49Harald Welte
342aae69bed019826ddec93f761514652a93d871e49Harald Welte	list_del(&r->list);
343aae69bed019826ddec93f761514652a93d871e49Harald Welte	free(r);
344aae69bed019826ddec93f761514652a93d871e49Harald Welte}
345aae69bed019826ddec93f761514652a93d871e49Harald Welte
346aae69bed019826ddec93f761514652a93d871e49Harald Welte
347aae69bed019826ddec93f761514652a93d871e49Harald Welte/**********************************************************************
348aae69bed019826ddec93f761514652a93d871e49Harald Welte * RULESET PARSER (blob -> cache)
349aae69bed019826ddec93f761514652a93d871e49Harald Welte **********************************************************************/
350aae69bed019826ddec93f761514652a93d871e49Harald Welte
351aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic int alphasort(const void *a, const void *b)
352aae69bed019826ddec93f761514652a93d871e49Harald Welte{
353aae69bed019826ddec93f761514652a93d871e49Harald Welte	return strcmp(((struct chain_head *)a)->name,
354aae69bed019826ddec93f761514652a93d871e49Harald Welte		      ((struct chain_head *)b)->name);
355aae69bed019826ddec93f761514652a93d871e49Harald Welte}
356aae69bed019826ddec93f761514652a93d871e49Harald Welte
357aae69bed019826ddec93f761514652a93d871e49Harald Welte/* Delete policy rule of previous chain, since cache doesn't contain
358aae69bed019826ddec93f761514652a93d871e49Harald Welte * chain policy rules.
359aae69bed019826ddec93f761514652a93d871e49Harald Welte * WARNING: This function has ugly design and relies on a lot of context, only
360aae69bed019826ddec93f761514652a93d871e49Harald Welte * to be called from specific places within the parser */
361aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic int __iptcc_p_del_policy(TC_HANDLE_T h, unsigned int num)
362aae69bed019826ddec93f761514652a93d871e49Harald Welte{
363aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (h->chain_iterator_cur) {
364aae69bed019826ddec93f761514652a93d871e49Harald Welte		/* policy rule is last rule */
365aae69bed019826ddec93f761514652a93d871e49Harald Welte		struct rule_head *pr = (struct rule_head *)
366aae69bed019826ddec93f761514652a93d871e49Harald Welte			h->chain_iterator_cur->rules.prev;
367aae69bed019826ddec93f761514652a93d871e49Harald Welte
368aae69bed019826ddec93f761514652a93d871e49Harald Welte		/* save verdict */
369aae69bed019826ddec93f761514652a93d871e49Harald Welte		h->chain_iterator_cur->verdict =
370aae69bed019826ddec93f761514652a93d871e49Harald Welte			*(int *)GET_TARGET(pr->entry)->data;
371aae69bed019826ddec93f761514652a93d871e49Harald Welte
372aae69bed019826ddec93f761514652a93d871e49Harald Welte		/* save counter and counter_map information */
373aae69bed019826ddec93f761514652a93d871e49Harald Welte		h->chain_iterator_cur->counter_map.maptype =
374aae69bed019826ddec93f761514652a93d871e49Harald Welte						COUNTER_MAP_NORMAL_MAP;
375aae69bed019826ddec93f761514652a93d871e49Harald Welte		h->chain_iterator_cur->counter_map.mappos = num-1;
376aae69bed019826ddec93f761514652a93d871e49Harald Welte		memcpy(&h->chain_iterator_cur->counters, &pr->entry->counters,
377aae69bed019826ddec93f761514652a93d871e49Harald Welte			sizeof(h->chain_iterator_cur->counters));
378aae69bed019826ddec93f761514652a93d871e49Harald Welte
379aae69bed019826ddec93f761514652a93d871e49Harald Welte		/* foot_offset points to verdict rule */
380aae69bed019826ddec93f761514652a93d871e49Harald Welte		h->chain_iterator_cur->foot_index = num;
381aae69bed019826ddec93f761514652a93d871e49Harald Welte		h->chain_iterator_cur->foot_offset = pr->offset;
382aae69bed019826ddec93f761514652a93d871e49Harald Welte
383aae69bed019826ddec93f761514652a93d871e49Harald Welte		/* delete rule from cache */
384aae69bed019826ddec93f761514652a93d871e49Harald Welte		iptcc_delete_rule(pr);
3858d1b38a064d146c77eb8fc951717663e1a713cfcMartin Josefsson		h->chain_iterator_cur->num_rules--;
386aae69bed019826ddec93f761514652a93d871e49Harald Welte
387e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 1;
388e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
389e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 0;
390e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
391e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
392aae69bed019826ddec93f761514652a93d871e49Harald Welte/* Another ugly helper function split out of cache_add_entry to make it less
393aae69bed019826ddec93f761514652a93d871e49Harald Welte * spaghetti code */
394aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic void __iptcc_p_add_chain(TC_HANDLE_T h, struct chain_head *c,
395aae69bed019826ddec93f761514652a93d871e49Harald Welte				unsigned int offset, unsigned int *num)
396e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
397aae69bed019826ddec93f761514652a93d871e49Harald Welte	__iptcc_p_del_policy(h, *num);
398e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
399aae69bed019826ddec93f761514652a93d871e49Harald Welte	c->head_offset = offset;
400aae69bed019826ddec93f761514652a93d871e49Harald Welte	c->index = *num;
401e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
402aae69bed019826ddec93f761514652a93d871e49Harald Welte	list_add_tail(&c->list, &h->chains);
403aae69bed019826ddec93f761514652a93d871e49Harald Welte	h->chain_iterator_cur = c;
404e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
405e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
406aae69bed019826ddec93f761514652a93d871e49Harald Welte/* main parser function: add an entry from the blob to the cache */
407aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic int cache_add_entry(STRUCT_ENTRY *e,
408aae69bed019826ddec93f761514652a93d871e49Harald Welte			   TC_HANDLE_T h,
409aae69bed019826ddec93f761514652a93d871e49Harald Welte			   STRUCT_ENTRY **prev,
410aae69bed019826ddec93f761514652a93d871e49Harald Welte			   unsigned int *num)
411e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
412aae69bed019826ddec93f761514652a93d871e49Harald Welte	unsigned int builtin;
413aae69bed019826ddec93f761514652a93d871e49Harald Welte	unsigned int offset = (char *)e - (char *)h->entries->entrytable;
414aae69bed019826ddec93f761514652a93d871e49Harald Welte
415aae69bed019826ddec93f761514652a93d871e49Harald Welte	DEBUGP("entering...");
416aae69bed019826ddec93f761514652a93d871e49Harald Welte
417aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* Last entry ("policy rule"). End it.*/
418aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (iptcb_entry2offset(h,e) + e->next_offset == h->entries->size) {
419aae69bed019826ddec93f761514652a93d871e49Harald Welte		/* This is the ERROR node at the end of the chain */
420aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP_C("%u:%u: end of table:\n", *num, offset);
421aae69bed019826ddec93f761514652a93d871e49Harald Welte
422aae69bed019826ddec93f761514652a93d871e49Harald Welte		__iptcc_p_del_policy(h, *num);
423aae69bed019826ddec93f761514652a93d871e49Harald Welte
424aae69bed019826ddec93f761514652a93d871e49Harald Welte		h->chain_iterator_cur = NULL;
425aae69bed019826ddec93f761514652a93d871e49Harald Welte		goto out_inc;
426aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
427aae69bed019826ddec93f761514652a93d871e49Harald Welte
428aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* We know this is the start of a new chain if it's an ERROR
429aae69bed019826ddec93f761514652a93d871e49Harald Welte	 * target, or a hook entry point */
430aae69bed019826ddec93f761514652a93d871e49Harald Welte
431aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (strcmp(GET_TARGET(e)->u.user.name, ERROR_TARGET) == 0) {
432aae69bed019826ddec93f761514652a93d871e49Harald Welte		struct chain_head *c =
433aae69bed019826ddec93f761514652a93d871e49Harald Welte			iptcc_alloc_chain_head((const char *)GET_TARGET(e)->data, 0);
434aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP_C("%u:%u:new userdefined chain %s: %p\n", *num, offset,
435aae69bed019826ddec93f761514652a93d871e49Harald Welte			(char *)c->name, c);
436aae69bed019826ddec93f761514652a93d871e49Harald Welte		if (!c) {
437aae69bed019826ddec93f761514652a93d871e49Harald Welte			errno = -ENOMEM;
438aae69bed019826ddec93f761514652a93d871e49Harald Welte			return -1;
439aae69bed019826ddec93f761514652a93d871e49Harald Welte		}
440aae69bed019826ddec93f761514652a93d871e49Harald Welte
441aae69bed019826ddec93f761514652a93d871e49Harald Welte		__iptcc_p_add_chain(h, c, offset, num);
442aae69bed019826ddec93f761514652a93d871e49Harald Welte
443aae69bed019826ddec93f761514652a93d871e49Harald Welte	} else if ((builtin = iptcb_ent_is_hook_entry(e, h)) != 0) {
444aae69bed019826ddec93f761514652a93d871e49Harald Welte		struct chain_head *c =
445aae69bed019826ddec93f761514652a93d871e49Harald Welte			iptcc_alloc_chain_head((char *)hooknames[builtin-1],
446aae69bed019826ddec93f761514652a93d871e49Harald Welte						builtin);
447aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP_C("%u:%u new builtin chain: %p (rules=%p)\n",
448aae69bed019826ddec93f761514652a93d871e49Harald Welte			*num, offset, c, &c->rules);
449aae69bed019826ddec93f761514652a93d871e49Harald Welte		if (!c) {
450aae69bed019826ddec93f761514652a93d871e49Harald Welte			errno = -ENOMEM;
451aae69bed019826ddec93f761514652a93d871e49Harald Welte			return -1;
452aae69bed019826ddec93f761514652a93d871e49Harald Welte		}
453aae69bed019826ddec93f761514652a93d871e49Harald Welte
454aae69bed019826ddec93f761514652a93d871e49Harald Welte		c->hooknum = builtin;
455aae69bed019826ddec93f761514652a93d871e49Harald Welte
456aae69bed019826ddec93f761514652a93d871e49Harald Welte		__iptcc_p_add_chain(h, c, offset, num);
457aae69bed019826ddec93f761514652a93d871e49Harald Welte
458aae69bed019826ddec93f761514652a93d871e49Harald Welte		/* FIXME: this is ugly. */
459aae69bed019826ddec93f761514652a93d871e49Harald Welte		goto new_rule;
460aae69bed019826ddec93f761514652a93d871e49Harald Welte	} else {
461aae69bed019826ddec93f761514652a93d871e49Harald Welte		/* has to be normal rule */
462aae69bed019826ddec93f761514652a93d871e49Harald Welte		struct rule_head *r;
463aae69bed019826ddec93f761514652a93d871e49Harald Weltenew_rule:
464aae69bed019826ddec93f761514652a93d871e49Harald Welte
465aae69bed019826ddec93f761514652a93d871e49Harald Welte		if (!(r = iptcc_alloc_rule(h->chain_iterator_cur,
466aae69bed019826ddec93f761514652a93d871e49Harald Welte					   e->next_offset))) {
467aae69bed019826ddec93f761514652a93d871e49Harald Welte			errno = ENOMEM;
468aae69bed019826ddec93f761514652a93d871e49Harald Welte			return -1;
469aae69bed019826ddec93f761514652a93d871e49Harald Welte		}
470aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP_C("%u:%u normal rule: %p: ", *num, offset, r);
471aae69bed019826ddec93f761514652a93d871e49Harald Welte
472aae69bed019826ddec93f761514652a93d871e49Harald Welte		r->index = *num;
473aae69bed019826ddec93f761514652a93d871e49Harald Welte		r->offset = offset;
474aae69bed019826ddec93f761514652a93d871e49Harald Welte		memcpy(r->entry, e, e->next_offset);
475aae69bed019826ddec93f761514652a93d871e49Harald Welte		r->counter_map.maptype = COUNTER_MAP_NORMAL_MAP;
476aae69bed019826ddec93f761514652a93d871e49Harald Welte		r->counter_map.mappos = r->index;
477aae69bed019826ddec93f761514652a93d871e49Harald Welte
478aae69bed019826ddec93f761514652a93d871e49Harald Welte		/* handling of jumps, etc. */
479aae69bed019826ddec93f761514652a93d871e49Harald Welte		if (!strcmp(GET_TARGET(e)->u.user.name, STANDARD_TARGET)) {
480aae69bed019826ddec93f761514652a93d871e49Harald Welte			STRUCT_STANDARD_TARGET *t;
481aae69bed019826ddec93f761514652a93d871e49Harald Welte
482aae69bed019826ddec93f761514652a93d871e49Harald Welte			t = (STRUCT_STANDARD_TARGET *)GET_TARGET(e);
483aae69bed019826ddec93f761514652a93d871e49Harald Welte			if (t->target.u.target_size
484aae69bed019826ddec93f761514652a93d871e49Harald Welte			    != ALIGN(sizeof(STRUCT_STANDARD_TARGET))) {
485aae69bed019826ddec93f761514652a93d871e49Harald Welte				errno = EINVAL;
486aae69bed019826ddec93f761514652a93d871e49Harald Welte				return -1;
487aae69bed019826ddec93f761514652a93d871e49Harald Welte			}
488aae69bed019826ddec93f761514652a93d871e49Harald Welte
489aae69bed019826ddec93f761514652a93d871e49Harald Welte			if (t->verdict < 0) {
490aae69bed019826ddec93f761514652a93d871e49Harald Welte				DEBUGP_C("standard, verdict=%d\n", t->verdict);
491aae69bed019826ddec93f761514652a93d871e49Harald Welte				r->type = IPTCC_R_STANDARD;
492aae69bed019826ddec93f761514652a93d871e49Harald Welte			} else if (t->verdict == r->offset+e->next_offset) {
493aae69bed019826ddec93f761514652a93d871e49Harald Welte				DEBUGP_C("fallthrough\n");
494aae69bed019826ddec93f761514652a93d871e49Harald Welte				r->type = IPTCC_R_FALLTHROUGH;
495aae69bed019826ddec93f761514652a93d871e49Harald Welte			} else {
496aae69bed019826ddec93f761514652a93d871e49Harald Welte				DEBUGP_C("jump, target=%u\n", t->verdict);
497aae69bed019826ddec93f761514652a93d871e49Harald Welte				r->type = IPTCC_R_JUMP;
498aae69bed019826ddec93f761514652a93d871e49Harald Welte				/* Jump target fixup has to be deferred
499aae69bed019826ddec93f761514652a93d871e49Harald Welte				 * until second pass, since we migh not
500aae69bed019826ddec93f761514652a93d871e49Harald Welte				 * yet have parsed the target */
501aae69bed019826ddec93f761514652a93d871e49Harald Welte			}
50252c380208a87191a8c25608d2c501c0dc32aa9adMartin Josefsson		} else {
50352c380208a87191a8c25608d2c501c0dc32aa9adMartin Josefsson			DEBUGP_C("module, target=%s\n", GET_TARGET(e)->u.user.name);
50452c380208a87191a8c25608d2c501c0dc32aa9adMartin Josefsson			r->type = IPTCC_R_MODULE;
505aae69bed019826ddec93f761514652a93d871e49Harald Welte		}
506aae69bed019826ddec93f761514652a93d871e49Harald Welte
507aae69bed019826ddec93f761514652a93d871e49Harald Welte		list_add_tail(&r->list, &h->chain_iterator_cur->rules);
5088d1b38a064d146c77eb8fc951717663e1a713cfcMartin Josefsson		h->chain_iterator_cur->num_rules++;
509aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
510aae69bed019826ddec93f761514652a93d871e49Harald Welteout_inc:
511aae69bed019826ddec93f761514652a93d871e49Harald Welte	(*num)++;
512aae69bed019826ddec93f761514652a93d871e49Harald Welte	return 0;
513e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
514e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
515aae69bed019826ddec93f761514652a93d871e49Harald Welte
516aae69bed019826ddec93f761514652a93d871e49Harald Welte/* parse an iptables blob into it's pieces */
517aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic int parse_table(TC_HANDLE_T h)
518e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
519aae69bed019826ddec93f761514652a93d871e49Harald Welte	STRUCT_ENTRY *prev;
520aae69bed019826ddec93f761514652a93d871e49Harald Welte	unsigned int num = 0;
521aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
522aae69bed019826ddec93f761514652a93d871e49Harald Welte
523aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* First pass: over ruleset blob */
524aae69bed019826ddec93f761514652a93d871e49Harald Welte	ENTRY_ITERATE(h->entries->entrytable, h->entries->size,
525aae69bed019826ddec93f761514652a93d871e49Harald Welte			cache_add_entry, h, &prev, &num);
526aae69bed019826ddec93f761514652a93d871e49Harald Welte
527aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* Second pass: fixup parsed data from first pass */
528aae69bed019826ddec93f761514652a93d871e49Harald Welte	list_for_each_entry(c, &h->chains, list) {
529aae69bed019826ddec93f761514652a93d871e49Harald Welte		struct rule_head *r;
530aae69bed019826ddec93f761514652a93d871e49Harald Welte		list_for_each_entry(r, &c->rules, list) {
531aae69bed019826ddec93f761514652a93d871e49Harald Welte			struct chain_head *c;
532aae69bed019826ddec93f761514652a93d871e49Harald Welte			STRUCT_STANDARD_TARGET *t;
533aae69bed019826ddec93f761514652a93d871e49Harald Welte
534aae69bed019826ddec93f761514652a93d871e49Harald Welte			if (r->type != IPTCC_R_JUMP)
535aae69bed019826ddec93f761514652a93d871e49Harald Welte				continue;
536aae69bed019826ddec93f761514652a93d871e49Harald Welte
537aae69bed019826ddec93f761514652a93d871e49Harald Welte			t = (STRUCT_STANDARD_TARGET *)GET_TARGET(r->entry);
538aae69bed019826ddec93f761514652a93d871e49Harald Welte			c = iptcc_find_chain_by_offset(h, t->verdict);
539aae69bed019826ddec93f761514652a93d871e49Harald Welte			if (!c)
540aae69bed019826ddec93f761514652a93d871e49Harald Welte				return -1;
541aae69bed019826ddec93f761514652a93d871e49Harald Welte			r->jump = c;
542aae69bed019826ddec93f761514652a93d871e49Harald Welte			c->references++;
543aae69bed019826ddec93f761514652a93d871e49Harald Welte		}
544aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
545aae69bed019826ddec93f761514652a93d871e49Harald Welte
546aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* FIXME: sort chains */
547aae69bed019826ddec93f761514652a93d871e49Harald Welte
548aae69bed019826ddec93f761514652a93d871e49Harald Welte	return 1;
5490113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte}
5509e03380e9f78ae347ae4f3f041c4eca50348f2e8Harald Welte
551aae69bed019826ddec93f761514652a93d871e49Harald Welte
552aae69bed019826ddec93f761514652a93d871e49Harald Welte/**********************************************************************
553aae69bed019826ddec93f761514652a93d871e49Harald Welte * RULESET COMPILATION (cache -> blob)
554aae69bed019826ddec93f761514652a93d871e49Harald Welte **********************************************************************/
555aae69bed019826ddec93f761514652a93d871e49Harald Welte
556aae69bed019826ddec93f761514652a93d871e49Harald Welte/* Convenience structures */
557aae69bed019826ddec93f761514652a93d871e49Harald Weltestruct iptcb_chain_start{
558aae69bed019826ddec93f761514652a93d871e49Harald Welte	STRUCT_ENTRY e;
559aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct ipt_error_target name;
560aae69bed019826ddec93f761514652a93d871e49Harald Welte};
561aae69bed019826ddec93f761514652a93d871e49Harald Welte#define IPTCB_CHAIN_START_SIZE	(sizeof(STRUCT_ENTRY) +			\
562aae69bed019826ddec93f761514652a93d871e49Harald Welte				 ALIGN(sizeof(struct ipt_error_target)))
563aae69bed019826ddec93f761514652a93d871e49Harald Welte
564aae69bed019826ddec93f761514652a93d871e49Harald Weltestruct iptcb_chain_foot {
565aae69bed019826ddec93f761514652a93d871e49Harald Welte	STRUCT_ENTRY e;
566aae69bed019826ddec93f761514652a93d871e49Harald Welte	STRUCT_STANDARD_TARGET target;
567aae69bed019826ddec93f761514652a93d871e49Harald Welte};
568aae69bed019826ddec93f761514652a93d871e49Harald Welte#define IPTCB_CHAIN_FOOT_SIZE	(sizeof(STRUCT_ENTRY) +			\
569aae69bed019826ddec93f761514652a93d871e49Harald Welte				 ALIGN(sizeof(STRUCT_STANDARD_TARGET)))
570aae69bed019826ddec93f761514652a93d871e49Harald Welte
571aae69bed019826ddec93f761514652a93d871e49Harald Weltestruct iptcb_chain_error {
572aae69bed019826ddec93f761514652a93d871e49Harald Welte	STRUCT_ENTRY entry;
573aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct ipt_error_target target;
574aae69bed019826ddec93f761514652a93d871e49Harald Welte};
575aae69bed019826ddec93f761514652a93d871e49Harald Welte#define IPTCB_CHAIN_ERROR_SIZE	(sizeof(STRUCT_ENTRY) +			\
576aae69bed019826ddec93f761514652a93d871e49Harald Welte				 ALIGN(sizeof(struct ipt_error_target)))
577aae69bed019826ddec93f761514652a93d871e49Harald Welte
578aae69bed019826ddec93f761514652a93d871e49Harald Welte
579aae69bed019826ddec93f761514652a93d871e49Harald Welte
580aae69bed019826ddec93f761514652a93d871e49Harald Welte/* compile rule from cache into blob */
581aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic inline int iptcc_compile_rule (TC_HANDLE_T h, STRUCT_REPLACE *repl, struct rule_head *r)
5820113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte{
583aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* handle jumps */
584aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (r->type == IPTCC_R_JUMP) {
585aae69bed019826ddec93f761514652a93d871e49Harald Welte		STRUCT_STANDARD_TARGET *t;
586aae69bed019826ddec93f761514652a93d871e49Harald Welte		t = (STRUCT_STANDARD_TARGET *)GET_TARGET(r->entry);
587aae69bed019826ddec93f761514652a93d871e49Harald Welte		/* memset for memcmp convenience on delete/replace */
588aae69bed019826ddec93f761514652a93d871e49Harald Welte		memset(t->target.u.user.name, 0, FUNCTION_MAXNAMELEN);
589aae69bed019826ddec93f761514652a93d871e49Harald Welte		strcpy(t->target.u.user.name, STANDARD_TARGET);
590aae69bed019826ddec93f761514652a93d871e49Harald Welte		/* Jumps can only happen to builtin chains, so we
591aae69bed019826ddec93f761514652a93d871e49Harald Welte		 * can safely assume that they always have a header */
592aae69bed019826ddec93f761514652a93d871e49Harald Welte		t->verdict = r->jump->head_offset + IPTCB_CHAIN_START_SIZE;
593aae69bed019826ddec93f761514652a93d871e49Harald Welte	} else if (r->type == IPTCC_R_FALLTHROUGH) {
594aae69bed019826ddec93f761514652a93d871e49Harald Welte		STRUCT_STANDARD_TARGET *t;
595aae69bed019826ddec93f761514652a93d871e49Harald Welte		t = (STRUCT_STANDARD_TARGET *)GET_TARGET(r->entry);
596aae69bed019826ddec93f761514652a93d871e49Harald Welte		t->verdict = r->offset + r->size;
597aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
598aae69bed019826ddec93f761514652a93d871e49Harald Welte
599aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* copy entry from cache to blob */
600aae69bed019826ddec93f761514652a93d871e49Harald Welte	memcpy((char *)repl->entries+r->offset, r->entry, r->size);
601aae69bed019826ddec93f761514652a93d871e49Harald Welte
602aae69bed019826ddec93f761514652a93d871e49Harald Welte	return 1;
603e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
604e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
605aae69bed019826ddec93f761514652a93d871e49Harald Welte/* compile chain from cache into blob */
606aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic int iptcc_compile_chain(TC_HANDLE_T h, STRUCT_REPLACE *repl, struct chain_head *c)
6073ea8f40262386e6b1445a617841f28702fe74d9dHarald Welte{
608aae69bed019826ddec93f761514652a93d871e49Harald Welte	int ret;
609aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct rule_head *r;
610aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct iptcb_chain_start *head;
611aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct iptcb_chain_foot *foot;
612aae69bed019826ddec93f761514652a93d871e49Harald Welte
613aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* only user-defined chains have heaer */
614aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!iptcc_is_builtin(c)) {
615aae69bed019826ddec93f761514652a93d871e49Harald Welte		/* put chain header in place */
616aae69bed019826ddec93f761514652a93d871e49Harald Welte		head = (void *)repl->entries + c->head_offset;
617aae69bed019826ddec93f761514652a93d871e49Harald Welte		head->e.target_offset = sizeof(STRUCT_ENTRY);
618aae69bed019826ddec93f761514652a93d871e49Harald Welte		head->e.next_offset = IPTCB_CHAIN_START_SIZE;
619aae69bed019826ddec93f761514652a93d871e49Harald Welte		strcpy(head->name.t.u.user.name, ERROR_TARGET);
620aae69bed019826ddec93f761514652a93d871e49Harald Welte		head->name.t.u.target_size =
621aae69bed019826ddec93f761514652a93d871e49Harald Welte				ALIGN(sizeof(struct ipt_error_target));
622aae69bed019826ddec93f761514652a93d871e49Harald Welte		strcpy(head->name.error, c->name);
623aae69bed019826ddec93f761514652a93d871e49Harald Welte	} else {
624aae69bed019826ddec93f761514652a93d871e49Harald Welte		repl->hook_entry[c->hooknum-1] = c->head_offset;
625aae69bed019826ddec93f761514652a93d871e49Harald Welte		repl->underflow[c->hooknum-1] = c->foot_offset;
626aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
627aae69bed019826ddec93f761514652a93d871e49Harald Welte
628aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* iterate over rules */
629aae69bed019826ddec93f761514652a93d871e49Harald Welte	list_for_each_entry(r, &c->rules, list) {
630aae69bed019826ddec93f761514652a93d871e49Harald Welte		ret = iptcc_compile_rule(h, repl, r);
631aae69bed019826ddec93f761514652a93d871e49Harald Welte		if (ret < 0)
632aae69bed019826ddec93f761514652a93d871e49Harald Welte			return ret;
633aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
634aae69bed019826ddec93f761514652a93d871e49Harald Welte
635aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* put chain footer in place */
636aae69bed019826ddec93f761514652a93d871e49Harald Welte	foot = (void *)repl->entries + c->foot_offset;
637aae69bed019826ddec93f761514652a93d871e49Harald Welte	foot->e.target_offset = sizeof(STRUCT_ENTRY);
638aae69bed019826ddec93f761514652a93d871e49Harald Welte	foot->e.next_offset = IPTCB_CHAIN_FOOT_SIZE;
639aae69bed019826ddec93f761514652a93d871e49Harald Welte	strcpy(foot->target.target.u.user.name, STANDARD_TARGET);
640aae69bed019826ddec93f761514652a93d871e49Harald Welte	foot->target.target.u.target_size =
641aae69bed019826ddec93f761514652a93d871e49Harald Welte				ALIGN(sizeof(STRUCT_STANDARD_TARGET));
642aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* builtin targets have verdict, others return */
643aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (iptcc_is_builtin(c))
644aae69bed019826ddec93f761514652a93d871e49Harald Welte		foot->target.verdict = c->verdict;
645aae69bed019826ddec93f761514652a93d871e49Harald Welte	else
646aae69bed019826ddec93f761514652a93d871e49Harald Welte		foot->target.verdict = RETURN;
647aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* set policy-counters */
648aae69bed019826ddec93f761514652a93d871e49Harald Welte	memcpy(&foot->e.counters, &c->counters, sizeof(STRUCT_COUNTERS));
649aae69bed019826ddec93f761514652a93d871e49Harald Welte
650aae69bed019826ddec93f761514652a93d871e49Harald Welte	return 0;
6513ea8f40262386e6b1445a617841f28702fe74d9dHarald Welte}
6523ea8f40262386e6b1445a617841f28702fe74d9dHarald Welte
653aae69bed019826ddec93f761514652a93d871e49Harald Welte/* calculate offset and number for every rule in the cache */
654aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic int iptcc_compile_chain_offsets(TC_HANDLE_T h, struct chain_head *c,
655aae69bed019826ddec93f761514652a93d871e49Harald Welte				       int *offset, int *num)
6563ea8f40262386e6b1445a617841f28702fe74d9dHarald Welte{
657aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct rule_head *r;
658aae69bed019826ddec93f761514652a93d871e49Harald Welte
659aae69bed019826ddec93f761514652a93d871e49Harald Welte	c->head_offset = *offset;
660aae69bed019826ddec93f761514652a93d871e49Harald Welte	DEBUGP("%s: chain_head %u, offset=%u\n", c->name, *num, *offset);
661aae69bed019826ddec93f761514652a93d871e49Harald Welte
662aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!iptcc_is_builtin(c))  {
663aae69bed019826ddec93f761514652a93d871e49Harald Welte		/* Chain has header */
664aae69bed019826ddec93f761514652a93d871e49Harald Welte		*offset += sizeof(STRUCT_ENTRY)
665aae69bed019826ddec93f761514652a93d871e49Harald Welte			     + ALIGN(sizeof(struct ipt_error_target));
666aae69bed019826ddec93f761514652a93d871e49Harald Welte		(*num)++;
667aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
668aae69bed019826ddec93f761514652a93d871e49Harald Welte
669aae69bed019826ddec93f761514652a93d871e49Harald Welte	list_for_each_entry(r, &c->rules, list) {
670aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP("rule %u, offset=%u, index=%u\n", *num, *offset, *num);
671aae69bed019826ddec93f761514652a93d871e49Harald Welte		r->offset = *offset;
672aae69bed019826ddec93f761514652a93d871e49Harald Welte		r->index = *num;
673aae69bed019826ddec93f761514652a93d871e49Harald Welte		*offset += r->size;
674aae69bed019826ddec93f761514652a93d871e49Harald Welte		(*num)++;
675aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
676aae69bed019826ddec93f761514652a93d871e49Harald Welte
677aae69bed019826ddec93f761514652a93d871e49Harald Welte	DEBUGP("%s; chain_foot %u, offset=%u, index=%u\n", c->name, *num,
678aae69bed019826ddec93f761514652a93d871e49Harald Welte		*offset, *num);
679aae69bed019826ddec93f761514652a93d871e49Harald Welte	c->foot_offset = *offset;
680aae69bed019826ddec93f761514652a93d871e49Harald Welte	c->foot_index = *num;
681aae69bed019826ddec93f761514652a93d871e49Harald Welte	*offset += sizeof(STRUCT_ENTRY)
682aae69bed019826ddec93f761514652a93d871e49Harald Welte		   + ALIGN(sizeof(STRUCT_STANDARD_TARGET));
683aae69bed019826ddec93f761514652a93d871e49Harald Welte	(*num)++;
684aae69bed019826ddec93f761514652a93d871e49Harald Welte
685aae69bed019826ddec93f761514652a93d871e49Harald Welte	return 1;
6863ea8f40262386e6b1445a617841f28702fe74d9dHarald Welte}
6873ea8f40262386e6b1445a617841f28702fe74d9dHarald Welte
688aae69bed019826ddec93f761514652a93d871e49Harald Welte/* put the pieces back together again */
689aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic int iptcc_compile_table_prep(TC_HANDLE_T h, unsigned int *size)
690aae69bed019826ddec93f761514652a93d871e49Harald Welte{
691aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
692aae69bed019826ddec93f761514652a93d871e49Harald Welte	unsigned int offset = 0, num = 0;
693aae69bed019826ddec93f761514652a93d871e49Harald Welte	int ret = 0;
6943ea8f40262386e6b1445a617841f28702fe74d9dHarald Welte
695aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* First pass: calculate offset for every rule */
696aae69bed019826ddec93f761514652a93d871e49Harald Welte	list_for_each_entry(c, &h->chains, list) {
697aae69bed019826ddec93f761514652a93d871e49Harald Welte		ret = iptcc_compile_chain_offsets(h, c, &offset, &num);
698aae69bed019826ddec93f761514652a93d871e49Harald Welte		if (ret < 0)
699aae69bed019826ddec93f761514652a93d871e49Harald Welte			return ret;
700aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
701aae69bed019826ddec93f761514652a93d871e49Harald Welte
702aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* Append one error rule at end of chain */
703aae69bed019826ddec93f761514652a93d871e49Harald Welte	num++;
704aae69bed019826ddec93f761514652a93d871e49Harald Welte	offset += sizeof(STRUCT_ENTRY)
705aae69bed019826ddec93f761514652a93d871e49Harald Welte		  + ALIGN(sizeof(struct ipt_error_target));
706aae69bed019826ddec93f761514652a93d871e49Harald Welte
707aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* ruleset size is now in offset */
708aae69bed019826ddec93f761514652a93d871e49Harald Welte	*size = offset;
709aae69bed019826ddec93f761514652a93d871e49Harald Welte	return num;
710aae69bed019826ddec93f761514652a93d871e49Harald Welte}
711aae69bed019826ddec93f761514652a93d871e49Harald Welte
712aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic int iptcc_compile_table(TC_HANDLE_T h, STRUCT_REPLACE *repl)
7130113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte{
714aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
715aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct iptcb_chain_error *error;
7160113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
717aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* Second pass: copy from cache to offsets, fill in jumps */
718aae69bed019826ddec93f761514652a93d871e49Harald Welte	list_for_each_entry(c, &h->chains, list) {
719aae69bed019826ddec93f761514652a93d871e49Harald Welte		int ret = iptcc_compile_chain(h, repl, c);
720aae69bed019826ddec93f761514652a93d871e49Harald Welte		if (ret < 0)
721aae69bed019826ddec93f761514652a93d871e49Harald Welte			return ret;
7220113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	}
7230113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
724aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* Append error rule at end of chain */
725aae69bed019826ddec93f761514652a93d871e49Harald Welte	error = (void *)repl->entries + repl->size - IPTCB_CHAIN_ERROR_SIZE;
726aae69bed019826ddec93f761514652a93d871e49Harald Welte	error->entry.target_offset = sizeof(STRUCT_ENTRY);
727aae69bed019826ddec93f761514652a93d871e49Harald Welte	error->entry.next_offset = IPTCB_CHAIN_ERROR_SIZE;
728aae69bed019826ddec93f761514652a93d871e49Harald Welte	error->target.t.u.user.target_size =
729aae69bed019826ddec93f761514652a93d871e49Harald Welte		ALIGN(sizeof(struct ipt_error_target));
730aae69bed019826ddec93f761514652a93d871e49Harald Welte	strcpy((char *)&error->target.t.u.user.name, ERROR_TARGET);
731aae69bed019826ddec93f761514652a93d871e49Harald Welte	strcpy((char *)&error->target.error, "ERROR");
732aae69bed019826ddec93f761514652a93d871e49Harald Welte
733aae69bed019826ddec93f761514652a93d871e49Harald Welte	return 1;
7340113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte}
735e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
736aae69bed019826ddec93f761514652a93d871e49Harald Welte/**********************************************************************
737aae69bed019826ddec93f761514652a93d871e49Harald Welte * EXTERNAL API (operates on cache only)
738aae69bed019826ddec93f761514652a93d871e49Harald Welte **********************************************************************/
739aae69bed019826ddec93f761514652a93d871e49Harald Welte
740e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Allocate handle of given size */
74179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellstatic TC_HANDLE_T
7420113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Weltealloc_handle(const char *tablename, unsigned int size, unsigned int num_rules)
743e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
744e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	size_t len;
74579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	TC_HANDLE_T h;
746e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
747aae69bed019826ddec93f761514652a93d871e49Harald Welte	len = sizeof(STRUCT_TC_HANDLE) + size;
748e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
749aae69bed019826ddec93f761514652a93d871e49Harald Welte	h = malloc(sizeof(STRUCT_TC_HANDLE));
750aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!h) {
751e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOMEM;
752e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return NULL;
753e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
754aae69bed019826ddec93f761514652a93d871e49Harald Welte	memset(h, 0, sizeof(*h));
755aae69bed019826ddec93f761514652a93d871e49Harald Welte	INIT_LIST_HEAD(&h->chains);
756e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	strcpy(h->info.name, tablename);
757aae69bed019826ddec93f761514652a93d871e49Harald Welte
7580371c0c5eb17c81e8dd44c4aa31b58318e9b7b72Harald Welte	h->entries = malloc(sizeof(STRUCT_GET_ENTRIES) + size);
759aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!h->entries)
760aae69bed019826ddec93f761514652a93d871e49Harald Welte		goto out_free_handle;
761aae69bed019826ddec93f761514652a93d871e49Harald Welte
762aae69bed019826ddec93f761514652a93d871e49Harald Welte	strcpy(h->entries->name, tablename);
7630371c0c5eb17c81e8dd44c4aa31b58318e9b7b72Harald Welte	h->entries->size = size;
764e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
765e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return h;
766aae69bed019826ddec93f761514652a93d871e49Harald Welte
767aae69bed019826ddec93f761514652a93d871e49Harald Welteout_free_handle:
768aae69bed019826ddec93f761514652a93d871e49Harald Welte	free(h);
769aae69bed019826ddec93f761514652a93d871e49Harald Welte
770aae69bed019826ddec93f761514652a93d871e49Harald Welte	return NULL;
771e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
772e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
773aae69bed019826ddec93f761514652a93d871e49Harald Welte
77479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_HANDLE_T
77579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_INIT(const char *tablename)
776e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
77779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	TC_HANDLE_T h;
77879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	STRUCT_GETINFO info;
779e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	int tmp;
780e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	socklen_t s;
781e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
78279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	iptc_fn = TC_INIT;
783e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
784e560fd604284180f3ab522993c5b8e6f424ef1d9Martin Josefsson	if (sockfd != -1) {
785366454bc69f781fdafc3a30eb6dd77155ee4efb6Harald Welte		close(sockfd);
786e560fd604284180f3ab522993c5b8e6f424ef1d9Martin Josefsson		sockfd = -1;
787e560fd604284180f3ab522993c5b8e6f424ef1d9Martin Josefsson	}
788366454bc69f781fdafc3a30eb6dd77155ee4efb6Harald Welte
789841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson	if (strlen(tablename) >= TABLE_MAXNAMELEN) {
790841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson		errno = EINVAL;
791841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson		return NULL;
792841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson	}
793841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson
79479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	sockfd = socket(TC_AF, SOCK_RAW, IPPROTO_RAW);
795e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (sockfd < 0)
796e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return NULL;
797e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
798e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	s = sizeof(info);
799841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson
800e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	strcpy(info.name, tablename);
80179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	if (getsockopt(sockfd, TC_IPPROTO, SO_GET_INFO, &info, &s) < 0)
802e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return NULL;
803e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
804aae69bed019826ddec93f761514652a93d871e49Harald Welte	DEBUGP("valid_hooks=0x%08x, num_entries=%u, size=%u\n",
805aae69bed019826ddec93f761514652a93d871e49Harald Welte		info.valid_hooks, info.num_entries, info.size);
806aae69bed019826ddec93f761514652a93d871e49Harald Welte
8070113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	if ((h = alloc_handle(info.name, info.size, info.num_entries))
808841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson	    == NULL) {
809841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson		close(sockfd);
810e560fd604284180f3ab522993c5b8e6f424ef1d9Martin Josefsson		sockfd = -1;
811e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return NULL;
812841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson	}
813e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
814e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Initialize current state */
815e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	h->info = info;
8160113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
817aae69bed019826ddec93f761514652a93d871e49Harald Welte	h->entries->size = h->info.size;
818e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
81979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	tmp = sizeof(STRUCT_GET_ENTRIES) + h->info.size;
820e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
821aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (getsockopt(sockfd, TC_IPPROTO, SO_GET_ENTRIES, h->entries,
822aae69bed019826ddec93f761514652a93d871e49Harald Welte		       &tmp) < 0)
823aae69bed019826ddec93f761514652a93d871e49Harald Welte		goto error;
824aae69bed019826ddec93f761514652a93d871e49Harald Welte
825aae69bed019826ddec93f761514652a93d871e49Harald Welte#ifdef IPTC_DEBUG2
826aae69bed019826ddec93f761514652a93d871e49Harald Welte	{
827aae69bed019826ddec93f761514652a93d871e49Harald Welte		int fd = open("/tmp/libiptc-so_get_entries.blob",
828aae69bed019826ddec93f761514652a93d871e49Harald Welte				O_CREAT|O_WRONLY);
829aae69bed019826ddec93f761514652a93d871e49Harald Welte		if (fd >= 0) {
830aae69bed019826ddec93f761514652a93d871e49Harald Welte			write(fd, h->entries, tmp);
831aae69bed019826ddec93f761514652a93d871e49Harald Welte			close(fd);
832aae69bed019826ddec93f761514652a93d871e49Harald Welte		}
833e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
834aae69bed019826ddec93f761514652a93d871e49Harald Welte#endif
835aae69bed019826ddec93f761514652a93d871e49Harald Welte
836aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (parse_table(h) < 0)
837aae69bed019826ddec93f761514652a93d871e49Harald Welte		goto error;
8387e53bf9c2a697abdb6f1385557338423a86612a3Rusty Russell
839e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	CHECK(h);
840e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return h;
841aae69bed019826ddec93f761514652a93d871e49Harald Welteerror:
842aae69bed019826ddec93f761514652a93d871e49Harald Welte	TC_FREE(&h);
843aae69bed019826ddec93f761514652a93d871e49Harald Welte	return NULL;
844e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
845e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
846841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefssonvoid
847841e4aed2349046eb2c0b1375139c06569a93bd0Martin JosefssonTC_FREE(TC_HANDLE_T *h)
848841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson{
849aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c, *tmp;
850aae69bed019826ddec93f761514652a93d871e49Harald Welte
851841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson	close(sockfd);
852e560fd604284180f3ab522993c5b8e6f424ef1d9Martin Josefsson	sockfd = -1;
853aae69bed019826ddec93f761514652a93d871e49Harald Welte
854aae69bed019826ddec93f761514652a93d871e49Harald Welte	list_for_each_entry_safe(c, tmp, &(*h)->chains, list) {
855aae69bed019826ddec93f761514652a93d871e49Harald Welte		struct rule_head *r, *rtmp;
856aae69bed019826ddec93f761514652a93d871e49Harald Welte
857aae69bed019826ddec93f761514652a93d871e49Harald Welte		list_for_each_entry_safe(r, rtmp, &c->rules, list) {
858aae69bed019826ddec93f761514652a93d871e49Harald Welte			free(r);
859aae69bed019826ddec93f761514652a93d871e49Harald Welte		}
860aae69bed019826ddec93f761514652a93d871e49Harald Welte
861aae69bed019826ddec93f761514652a93d871e49Harald Welte		free(c);
862aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
863aae69bed019826ddec93f761514652a93d871e49Harald Welte
864aae69bed019826ddec93f761514652a93d871e49Harald Welte	free((*h)->entries);
865841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson	free(*h);
866aae69bed019826ddec93f761514652a93d871e49Harald Welte
867841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson	*h = NULL;
868841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson}
869841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson
870e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic inline int
87179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellprint_match(const STRUCT_ENTRY_MATCH *m)
872e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
873228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell	printf("Match name: `%s'\n", m->u.user.name);
874e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 0;
875e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
876e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
87779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellstatic int dump_entry(STRUCT_ENTRY *e, const TC_HANDLE_T handle);
87879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell
879e6869a8f59d779ff4d5a0984c86d80db7078496Marc Bouchervoid
88079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_DUMP_ENTRIES(const TC_HANDLE_T handle)
881e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
882e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	CHECK(handle);
883aae69bed019826ddec93f761514652a93d871e49Harald Welte#if 0
884e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	printf("libiptc v%s.  %u entries, %u bytes.\n",
88580fe35d6339b53a12ddaec41885613e4e37ed031Harald Welte	       IPTABLES_VERSION,
886aae69bed019826ddec93f761514652a93d871e49Harald Welte	       handle->new_number, handle->entries->size);
887e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	printf("Table `%s'\n", handle->info.name);
888e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	printf("Hooks: pre/in/fwd/out/post = %u/%u/%u/%u/%u\n",
88967088e73ce7707229c56987868f112051defca5aRusty Russell	       handle->info.hook_entry[HOOK_PRE_ROUTING],
89067088e73ce7707229c56987868f112051defca5aRusty Russell	       handle->info.hook_entry[HOOK_LOCAL_IN],
89167088e73ce7707229c56987868f112051defca5aRusty Russell	       handle->info.hook_entry[HOOK_FORWARD],
89267088e73ce7707229c56987868f112051defca5aRusty Russell	       handle->info.hook_entry[HOOK_LOCAL_OUT],
89367088e73ce7707229c56987868f112051defca5aRusty Russell	       handle->info.hook_entry[HOOK_POST_ROUTING]);
894e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	printf("Underflows: pre/in/fwd/out/post = %u/%u/%u/%u/%u\n",
89567088e73ce7707229c56987868f112051defca5aRusty Russell	       handle->info.underflow[HOOK_PRE_ROUTING],
89667088e73ce7707229c56987868f112051defca5aRusty Russell	       handle->info.underflow[HOOK_LOCAL_IN],
89767088e73ce7707229c56987868f112051defca5aRusty Russell	       handle->info.underflow[HOOK_FORWARD],
89867088e73ce7707229c56987868f112051defca5aRusty Russell	       handle->info.underflow[HOOK_LOCAL_OUT],
89967088e73ce7707229c56987868f112051defca5aRusty Russell	       handle->info.underflow[HOOK_POST_ROUTING]);
900e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
901aae69bed019826ddec93f761514652a93d871e49Harald Welte	ENTRY_ITERATE(handle->entries->entrytable, handle->entries->size,
90279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		      dump_entry, handle);
903aae69bed019826ddec93f761514652a93d871e49Harald Welte#endif
9040113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte}
905e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
906e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Does this chain exist? */
90779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellint TC_IS_CHAIN(const char *chain, const TC_HANDLE_T handle)
908e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
909aae69bed019826ddec93f761514652a93d871e49Harald Welte	return iptcc_find_label(chain, handle) != NULL;
910e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
911e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
912aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic void iptcc_chain_iterator_advance(TC_HANDLE_T handle)
913aae69bed019826ddec93f761514652a93d871e49Harald Welte{
914aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c = handle->chain_iterator_cur;
915aae69bed019826ddec93f761514652a93d871e49Harald Welte
916aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (c->list.next == &handle->chains)
917aae69bed019826ddec93f761514652a93d871e49Harald Welte		handle->chain_iterator_cur = NULL;
918aae69bed019826ddec93f761514652a93d871e49Harald Welte	else
919aae69bed019826ddec93f761514652a93d871e49Harald Welte		handle->chain_iterator_cur =
920aae69bed019826ddec93f761514652a93d871e49Harald Welte			list_entry(c->list.next, struct chain_head, list);
921aae69bed019826ddec93f761514652a93d871e49Harald Welte}
922e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
92330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell/* Iterator functions to run through the chains. */
924e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherconst char *
9258c700900e2a0cf87d7917cb62578583a60ad1210Philip BlundellTC_FIRST_CHAIN(TC_HANDLE_T *handle)
926e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
927aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c = list_entry((*handle)->chains.next,
928aae69bed019826ddec93f761514652a93d871e49Harald Welte					  struct chain_head, list);
929aae69bed019826ddec93f761514652a93d871e49Harald Welte
930aae69bed019826ddec93f761514652a93d871e49Harald Welte	iptc_fn = TC_FIRST_CHAIN;
931aae69bed019826ddec93f761514652a93d871e49Harald Welte
932aae69bed019826ddec93f761514652a93d871e49Harald Welte
933aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (list_empty(&(*handle)->chains)) {
934aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP(": no chains\n");
9350113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		return NULL;
936aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
9370113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
938aae69bed019826ddec93f761514652a93d871e49Harald Welte	(*handle)->chain_iterator_cur = c;
939aae69bed019826ddec93f761514652a93d871e49Harald Welte	iptcc_chain_iterator_advance(*handle);
94030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
941aae69bed019826ddec93f761514652a93d871e49Harald Welte	DEBUGP(": returning `%s'\n", c->name);
942aae69bed019826ddec93f761514652a93d871e49Harald Welte	return c->name;
94330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell}
94430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
94530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell/* Iterator functions to run through the chains.  Returns NULL at end. */
94630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russellconst char *
94779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_NEXT_CHAIN(TC_HANDLE_T *handle)
94830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell{
949aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c = (*handle)->chain_iterator_cur;
950aae69bed019826ddec93f761514652a93d871e49Harald Welte
951aae69bed019826ddec93f761514652a93d871e49Harald Welte	iptc_fn = TC_NEXT_CHAIN;
95230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
953aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!c) {
954aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP(": no more chains\n");
95530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		return NULL;
956aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
95730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
958aae69bed019826ddec93f761514652a93d871e49Harald Welte	iptcc_chain_iterator_advance(*handle);
959aae69bed019826ddec93f761514652a93d871e49Harald Welte
960aae69bed019826ddec93f761514652a93d871e49Harald Welte	DEBUGP(": returning `%s'\n", c->name);
961aae69bed019826ddec93f761514652a93d871e49Harald Welte	return c->name;
96230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell}
96330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
96430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell/* Get first rule in the given chain: NULL for empty chain. */
96579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellconst STRUCT_ENTRY *
9668c700900e2a0cf87d7917cb62578583a60ad1210Philip BlundellTC_FIRST_RULE(const char *chain, TC_HANDLE_T *handle)
96730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell{
968aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
969aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct rule_head *r;
970aae69bed019826ddec93f761514652a93d871e49Harald Welte
971aae69bed019826ddec93f761514652a93d871e49Harald Welte	iptc_fn = TC_FIRST_RULE;
97230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
973aae69bed019826ddec93f761514652a93d871e49Harald Welte	DEBUGP("first rule(%s): ", chain);
974aae69bed019826ddec93f761514652a93d871e49Harald Welte
975aae69bed019826ddec93f761514652a93d871e49Harald Welte	c = iptcc_find_label(chain, *handle);
97630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	if (!c) {
97730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		errno = ENOENT;
97830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		return NULL;
979e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
980e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
98130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	/* Empty chain: single return/policy rule */
982aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (list_empty(&c->rules)) {
983aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP_C("no rules, returning NULL\n");
98430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		return NULL;
985aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
986aae69bed019826ddec93f761514652a93d871e49Harald Welte
987aae69bed019826ddec93f761514652a93d871e49Harald Welte	r = list_entry(c->rules.next, struct rule_head, list);
988aae69bed019826ddec93f761514652a93d871e49Harald Welte	(*handle)->rule_iterator_cur = r;
989aae69bed019826ddec93f761514652a93d871e49Harald Welte	DEBUGP_C("%p\n", r);
99030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
991aae69bed019826ddec93f761514652a93d871e49Harald Welte	return r->entry;
992e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
993e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
99430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell/* Returns NULL when rules run out. */
99579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellconst STRUCT_ENTRY *
9968c700900e2a0cf87d7917cb62578583a60ad1210Philip BlundellTC_NEXT_RULE(const STRUCT_ENTRY *prev, TC_HANDLE_T *handle)
99730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell{
998aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct rule_head *r;
999aae69bed019826ddec93f761514652a93d871e49Harald Welte
1000aae69bed019826ddec93f761514652a93d871e49Harald Welte	DEBUGP("rule_iterator_cur=%p...", (*handle)->rule_iterator_cur);
1001aae69bed019826ddec93f761514652a93d871e49Harald Welte
1002aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(*handle)->rule_iterator_cur) {
1003aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP_C("returning NULL\n");
100430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		return NULL;
1005aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
1006aae69bed019826ddec93f761514652a93d871e49Harald Welte
1007aae69bed019826ddec93f761514652a93d871e49Harald Welte	r = list_entry((*handle)->rule_iterator_cur->list.next,
1008aae69bed019826ddec93f761514652a93d871e49Harald Welte			struct rule_head, list);
100930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
1010aae69bed019826ddec93f761514652a93d871e49Harald Welte	iptc_fn = TC_NEXT_RULE;
1011aae69bed019826ddec93f761514652a93d871e49Harald Welte
1012aae69bed019826ddec93f761514652a93d871e49Harald Welte	DEBUGP_C("next=%p, head=%p...", &r->list,
1013aae69bed019826ddec93f761514652a93d871e49Harald Welte		&(*handle)->rule_iterator_cur->chain->rules);
1014aae69bed019826ddec93f761514652a93d871e49Harald Welte
1015aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (&r->list == &(*handle)->rule_iterator_cur->chain->rules) {
1016aae69bed019826ddec93f761514652a93d871e49Harald Welte		(*handle)->rule_iterator_cur = NULL;
1017aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP_C("finished, returning NULL\n");
1018aae69bed019826ddec93f761514652a93d871e49Harald Welte		return NULL;
1019aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
1020aae69bed019826ddec93f761514652a93d871e49Harald Welte
1021aae69bed019826ddec93f761514652a93d871e49Harald Welte	(*handle)->rule_iterator_cur = r;
1022aae69bed019826ddec93f761514652a93d871e49Harald Welte
1023aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* NOTE: prev is without any influence ! */
1024aae69bed019826ddec93f761514652a93d871e49Harald Welte	DEBUGP_C("returning rule %p\n", r);
1025aae69bed019826ddec93f761514652a93d871e49Harald Welte	return r->entry;
102630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell}
102730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
1028e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* How many rules in this chain? */
1029e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherunsigned int
103079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_NUM_RULES(const char *chain, TC_HANDLE_T *handle)
1031e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1032aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
1033aae69bed019826ddec93f761514652a93d871e49Harald Welte	iptc_fn = TC_NUM_RULES;
1034e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	CHECK(*handle);
1035aae69bed019826ddec93f761514652a93d871e49Harald Welte
1036aae69bed019826ddec93f761514652a93d871e49Harald Welte	c = iptcc_find_label(chain, *handle);
1037aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!c) {
1038e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
1039e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return (unsigned int)-1;
1040e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1041aae69bed019826ddec93f761514652a93d871e49Harald Welte
1042aae69bed019826ddec93f761514652a93d871e49Harald Welte	return c->num_rules;
1043e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1044e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
104579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellconst STRUCT_ENTRY *TC_GET_RULE(const char *chain,
104679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell				unsigned int n,
104779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell				TC_HANDLE_T *handle)
1048e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1049aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
1050aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct rule_head *r;
1051aae69bed019826ddec93f761514652a93d871e49Harald Welte
1052aae69bed019826ddec93f761514652a93d871e49Harald Welte	iptc_fn = TC_GET_RULE;
1053e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1054e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	CHECK(*handle);
1055aae69bed019826ddec93f761514652a93d871e49Harald Welte
1056aae69bed019826ddec93f761514652a93d871e49Harald Welte	c = iptcc_find_label(chain, *handle);
1057aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!c) {
1058e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
1059e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return NULL;
1060e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1061e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1062aae69bed019826ddec93f761514652a93d871e49Harald Welte	r = iptcc_get_rule_num(c, n);
1063aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!r)
1064aae69bed019826ddec93f761514652a93d871e49Harald Welte		return NULL;
1065aae69bed019826ddec93f761514652a93d871e49Harald Welte	return r->entry;
1066e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1067e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1068aae69bed019826ddec93f761514652a93d871e49Harald Welte/* Returns a pointer to the target name of this position. */
1069aae69bed019826ddec93f761514652a93d871e49Harald Welteconst char *standard_target_map(int verdict)
1070e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1071aae69bed019826ddec93f761514652a93d871e49Harald Welte	switch (verdict) {
1072aae69bed019826ddec93f761514652a93d871e49Harald Welte		case RETURN:
107379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell			return LABEL_RETURN;
1074aae69bed019826ddec93f761514652a93d871e49Harald Welte			break;
1075aae69bed019826ddec93f761514652a93d871e49Harald Welte		case -NF_ACCEPT-1:
107679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell			return LABEL_ACCEPT;
1077aae69bed019826ddec93f761514652a93d871e49Harald Welte			break;
1078aae69bed019826ddec93f761514652a93d871e49Harald Welte		case -NF_DROP-1:
1079aae69bed019826ddec93f761514652a93d871e49Harald Welte			return LABEL_DROP;
1080aae69bed019826ddec93f761514652a93d871e49Harald Welte			break;
1081aae69bed019826ddec93f761514652a93d871e49Harald Welte		case -NF_QUEUE-1:
1082aae69bed019826ddec93f761514652a93d871e49Harald Welte			return LABEL_QUEUE;
1083aae69bed019826ddec93f761514652a93d871e49Harald Welte			break;
1084aae69bed019826ddec93f761514652a93d871e49Harald Welte		default:
1085aae69bed019826ddec93f761514652a93d871e49Harald Welte			fprintf(stderr, "ERROR: %d not a valid target)\n",
1086aae69bed019826ddec93f761514652a93d871e49Harald Welte				verdict);
1087aae69bed019826ddec93f761514652a93d871e49Harald Welte			abort();
1088aae69bed019826ddec93f761514652a93d871e49Harald Welte			break;
1089e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1090aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* not reached */
1091aae69bed019826ddec93f761514652a93d871e49Harald Welte	return NULL;
1092e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1093e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1094aae69bed019826ddec93f761514652a93d871e49Harald Welte/* Returns a pointer to the target name of this position. */
1095aae69bed019826ddec93f761514652a93d871e49Harald Welteconst char *TC_GET_TARGET(const STRUCT_ENTRY *ce,
1096aae69bed019826ddec93f761514652a93d871e49Harald Welte			  TC_HANDLE_T *handle)
1097e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1098aae69bed019826ddec93f761514652a93d871e49Harald Welte	STRUCT_ENTRY *e = (STRUCT_ENTRY *)ce;
1099aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct rule_head *r = container_of(e, struct rule_head, entry);
1100e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1101aae69bed019826ddec93f761514652a93d871e49Harald Welte	iptc_fn = TC_GET_TARGET;
11020113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1103aae69bed019826ddec93f761514652a93d871e49Harald Welte	switch(r->type) {
1104aae69bed019826ddec93f761514652a93d871e49Harald Welte		int spos;
1105aae69bed019826ddec93f761514652a93d871e49Harald Welte		case IPTCC_R_FALLTHROUGH:
1106aae69bed019826ddec93f761514652a93d871e49Harald Welte			return "";
1107aae69bed019826ddec93f761514652a93d871e49Harald Welte			break;
1108aae69bed019826ddec93f761514652a93d871e49Harald Welte		case IPTCC_R_JUMP:
1109aae69bed019826ddec93f761514652a93d871e49Harald Welte			DEBUGP("r=%p, jump=%p, name=`%s'\n", r, r->jump, r->jump->name);
1110aae69bed019826ddec93f761514652a93d871e49Harald Welte			return r->jump->name;
1111aae69bed019826ddec93f761514652a93d871e49Harald Welte			break;
1112aae69bed019826ddec93f761514652a93d871e49Harald Welte		case IPTCC_R_STANDARD:
1113aae69bed019826ddec93f761514652a93d871e49Harald Welte			spos = *(int *)GET_TARGET(e)->data;
1114aae69bed019826ddec93f761514652a93d871e49Harald Welte			DEBUGP("r=%p, spos=%d'\n", r, spos);
1115aae69bed019826ddec93f761514652a93d871e49Harald Welte			return standard_target_map(spos);
1116aae69bed019826ddec93f761514652a93d871e49Harald Welte			break;
1117aae69bed019826ddec93f761514652a93d871e49Harald Welte		case IPTCC_R_MODULE:
1118aae69bed019826ddec93f761514652a93d871e49Harald Welte			return GET_TARGET(e)->u.user.name;
1119aae69bed019826ddec93f761514652a93d871e49Harald Welte			break;
11200113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	}
1121aae69bed019826ddec93f761514652a93d871e49Harald Welte	return NULL;
1122aae69bed019826ddec93f761514652a93d871e49Harald Welte}
1123aae69bed019826ddec93f761514652a93d871e49Harald Welte/* Is this a built-in chain?  Actually returns hook + 1. */
1124aae69bed019826ddec93f761514652a93d871e49Harald Welteint
1125aae69bed019826ddec93f761514652a93d871e49Harald WelteTC_BUILTIN(const char *chain, const TC_HANDLE_T handle)
1126aae69bed019826ddec93f761514652a93d871e49Harald Welte{
1127aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
1128aae69bed019826ddec93f761514652a93d871e49Harald Welte
1129aae69bed019826ddec93f761514652a93d871e49Harald Welte	iptc_fn = TC_BUILTIN;
11300113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1131aae69bed019826ddec93f761514652a93d871e49Harald Welte	c = iptcc_find_label(chain, handle);
1132aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!c) {
1133aae69bed019826ddec93f761514652a93d871e49Harald Welte		errno = ENOENT;
1134b0f3d2d7261be3fe256a66abcc237241fea43a02Martin Josefsson		return 0;
11350113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	}
11360113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1137aae69bed019826ddec93f761514652a93d871e49Harald Welte	return iptcc_is_builtin(c);
11380113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte}
11390113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1140aae69bed019826ddec93f761514652a93d871e49Harald Welte/* Get the policy of a given built-in chain */
1141aae69bed019826ddec93f761514652a93d871e49Harald Welteconst char *
1142aae69bed019826ddec93f761514652a93d871e49Harald WelteTC_GET_POLICY(const char *chain,
1143aae69bed019826ddec93f761514652a93d871e49Harald Welte	      STRUCT_COUNTERS *counters,
1144aae69bed019826ddec93f761514652a93d871e49Harald Welte	      TC_HANDLE_T *handle)
11450113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte{
1146aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
11470113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1148aae69bed019826ddec93f761514652a93d871e49Harald Welte	iptc_fn = TC_GET_POLICY;
1149fbc85236a6140918ab1d0fb0e07e2d72da46ce45Harald Welte
1150aae69bed019826ddec93f761514652a93d871e49Harald Welte	DEBUGP("called for chain %s\n", chain);
11510113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1152aae69bed019826ddec93f761514652a93d871e49Harald Welte	c = iptcc_find_label(chain, *handle);
1153aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!c) {
1154aae69bed019826ddec93f761514652a93d871e49Harald Welte		errno = ENOENT;
1155aae69bed019826ddec93f761514652a93d871e49Harald Welte		return NULL;
11560113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	}
11570113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1158aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!iptcc_is_builtin(c))
1159aae69bed019826ddec93f761514652a93d871e49Harald Welte		return NULL;
11600113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1161aae69bed019826ddec93f761514652a93d871e49Harald Welte	*counters = c->counters;
11620113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1163aae69bed019826ddec93f761514652a93d871e49Harald Welte	return standard_target_map(c->verdict);
11640113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte}
1165e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1166e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic int
1167aae69bed019826ddec93f761514652a93d871e49Harald Welteiptcc_standard_map(struct rule_head *r, int verdict)
1168e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1169aae69bed019826ddec93f761514652a93d871e49Harald Welte	STRUCT_ENTRY *e = r->entry;
117079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	STRUCT_STANDARD_TARGET *t;
1171e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
117279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	t = (STRUCT_STANDARD_TARGET *)GET_TARGET(e);
1173e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
117467088e73ce7707229c56987868f112051defca5aRusty Russell	if (t->target.u.target_size
11758c700900e2a0cf87d7917cb62578583a60ad1210Philip Blundell	    != ALIGN(sizeof(STRUCT_STANDARD_TARGET))) {
1176e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EINVAL;
1177e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1178e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1179e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* memset for memcmp convenience on delete/replace */
118079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	memset(t->target.u.user.name, 0, FUNCTION_MAXNAMELEN);
118179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	strcpy(t->target.u.user.name, STANDARD_TARGET);
1182e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	t->verdict = verdict;
1183e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1184aae69bed019826ddec93f761514652a93d871e49Harald Welte	r->type = IPTCC_R_STANDARD;
1185aae69bed019826ddec93f761514652a93d871e49Harald Welte
1186e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 1;
1187e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
11887e53bf9c2a697abdb6f1385557338423a86612a3Rusty Russell
1189e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic int
1190aae69bed019826ddec93f761514652a93d871e49Harald Welteiptcc_map_target(const TC_HANDLE_T handle,
1191aae69bed019826ddec93f761514652a93d871e49Harald Welte	   struct rule_head *r)
1192e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1193aae69bed019826ddec93f761514652a93d871e49Harald Welte	STRUCT_ENTRY *e = r->entry;
11940113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	STRUCT_ENTRY_TARGET *t = GET_TARGET(e);
1195e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1196e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Maybe it's empty (=> fall through) */
1197aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (strcmp(t->u.user.name, "") == 0) {
1198aae69bed019826ddec93f761514652a93d871e49Harald Welte		r->type = IPTCC_R_FALLTHROUGH;
1199aae69bed019826ddec93f761514652a93d871e49Harald Welte		return 1;
1200aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
1201e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Maybe it's a standard target name... */
120279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	else if (strcmp(t->u.user.name, LABEL_ACCEPT) == 0)
1203aae69bed019826ddec93f761514652a93d871e49Harald Welte		return iptcc_standard_map(r, -NF_ACCEPT - 1);
120479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	else if (strcmp(t->u.user.name, LABEL_DROP) == 0)
1205aae69bed019826ddec93f761514652a93d871e49Harald Welte		return iptcc_standard_map(r, -NF_DROP - 1);
120667088e73ce7707229c56987868f112051defca5aRusty Russell	else if (strcmp(t->u.user.name, LABEL_QUEUE) == 0)
1207aae69bed019826ddec93f761514652a93d871e49Harald Welte		return iptcc_standard_map(r, -NF_QUEUE - 1);
120879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	else if (strcmp(t->u.user.name, LABEL_RETURN) == 0)
1209aae69bed019826ddec93f761514652a93d871e49Harald Welte		return iptcc_standard_map(r, RETURN);
121079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	else if (TC_BUILTIN(t->u.user.name, handle)) {
1211e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		/* Can't jump to builtins. */
1212e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EINVAL;
1213e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1214e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	} else {
1215e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		/* Maybe it's an existing chain name. */
1216aae69bed019826ddec93f761514652a93d871e49Harald Welte		struct chain_head *c;
1217aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP("trying to find chain `%s': ", t->u.user.name);
1218aae69bed019826ddec93f761514652a93d871e49Harald Welte
1219aae69bed019826ddec93f761514652a93d871e49Harald Welte		c = iptcc_find_label(t->u.user.name, handle);
1220aae69bed019826ddec93f761514652a93d871e49Harald Welte		if (c) {
1221aae69bed019826ddec93f761514652a93d871e49Harald Welte			DEBUGP_C("found!\n");
1222aae69bed019826ddec93f761514652a93d871e49Harald Welte			r->type = IPTCC_R_JUMP;
1223aae69bed019826ddec93f761514652a93d871e49Harald Welte			r->jump = c;
1224aae69bed019826ddec93f761514652a93d871e49Harald Welte			c->references++;
1225aae69bed019826ddec93f761514652a93d871e49Harald Welte			return 1;
1226aae69bed019826ddec93f761514652a93d871e49Harald Welte		}
1227aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP_C("not found :(\n");
1228e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1229e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1230e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Must be a module?  If not, kernel will reject... */
1231e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* memset to all 0 for your memcmp convenience. */
1232228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell	memset(t->u.user.name + strlen(t->u.user.name),
1233e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       0,
123479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	       FUNCTION_MAXNAMELEN - strlen(t->u.user.name));
1235e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1236aae69bed019826ddec93f761514652a93d871e49Harald Welte	set_changed(handle);
1237aae69bed019826ddec93f761514652a93d871e49Harald Welte	return 1;
1238e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1239e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
12400113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte/* Insert the entry `fw' in chain `chain' into position `rulenum'. */
1241e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
124279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_INSERT_ENTRY(const IPT_CHAINLABEL chain,
124379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		const STRUCT_ENTRY *e,
124479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		unsigned int rulenum,
124579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		TC_HANDLE_T *handle)
1246e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1247aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
1248eb066cc4fb75a616400eaf38dfa31c052c76cf5cMartin Josefsson	struct rule_head *r;
1249eb066cc4fb75a616400eaf38dfa31c052c76cf5cMartin Josefsson	struct list_head *prev;
1250e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
125179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	iptc_fn = TC_INSERT_ENTRY;
1252aae69bed019826ddec93f761514652a93d871e49Harald Welte
1253aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(c = iptcc_find_label(chain, *handle))) {
1254e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
1255e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1256e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1257e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1258eb066cc4fb75a616400eaf38dfa31c052c76cf5cMartin Josefsson	/* first rulenum index = 0
1259eb066cc4fb75a616400eaf38dfa31c052c76cf5cMartin Josefsson	   first c->num_rules index = 1 */
1260eb066cc4fb75a616400eaf38dfa31c052c76cf5cMartin Josefsson	if (rulenum > c->num_rules) {
1261e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = E2BIG;
1262e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1263e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1264e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1265eb066cc4fb75a616400eaf38dfa31c052c76cf5cMartin Josefsson	/* Try to get the rule we want to insert after.
1266eb066cc4fb75a616400eaf38dfa31c052c76cf5cMartin Josefsson	   In case of no rules, insert after chain head. */
1267eb066cc4fb75a616400eaf38dfa31c052c76cf5cMartin Josefsson	r = iptcc_get_rule_num(c, rulenum + 1);
1268eb066cc4fb75a616400eaf38dfa31c052c76cf5cMartin Josefsson	if (r)
1269eb066cc4fb75a616400eaf38dfa31c052c76cf5cMartin Josefsson		prev = &r->list;
1270eb066cc4fb75a616400eaf38dfa31c052c76cf5cMartin Josefsson	else
1271eb066cc4fb75a616400eaf38dfa31c052c76cf5cMartin Josefsson		prev = &c->rules;
1272eb066cc4fb75a616400eaf38dfa31c052c76cf5cMartin Josefsson
1273aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(r = iptcc_alloc_rule(c, e->next_offset))) {
1274aae69bed019826ddec93f761514652a93d871e49Harald Welte		errno = ENOMEM;
1275aae69bed019826ddec93f761514652a93d871e49Harald Welte		return 0;
1276aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
1277aae69bed019826ddec93f761514652a93d871e49Harald Welte
1278aae69bed019826ddec93f761514652a93d871e49Harald Welte	memcpy(r->entry, e, e->next_offset);
1279aae69bed019826ddec93f761514652a93d871e49Harald Welte	r->counter_map.maptype = COUNTER_MAP_SET;
1280aae69bed019826ddec93f761514652a93d871e49Harald Welte
1281aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!iptcc_map_target(*handle, r)) {
1282aae69bed019826ddec93f761514652a93d871e49Harald Welte		free(r);
12830113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		return 0;
1284aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
1285aae69bed019826ddec93f761514652a93d871e49Harald Welte
1286eb066cc4fb75a616400eaf38dfa31c052c76cf5cMartin Josefsson	list_add_tail(&r->list, prev);
1287aae69bed019826ddec93f761514652a93d871e49Harald Welte	c->num_rules++;
1288aae69bed019826ddec93f761514652a93d871e49Harald Welte
1289aae69bed019826ddec93f761514652a93d871e49Harald Welte	set_changed(*handle);
1290e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1291aae69bed019826ddec93f761514652a93d871e49Harald Welte	return 1;
1292e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1293e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1294e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Atomically replace rule `rulenum' in `chain' with `fw'. */
1295e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
129679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_REPLACE_ENTRY(const IPT_CHAINLABEL chain,
129779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		 const STRUCT_ENTRY *e,
129879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		 unsigned int rulenum,
129979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		 TC_HANDLE_T *handle)
1300e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1301aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
1302aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct rule_head *r, *old;
1303e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
130479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	iptc_fn = TC_REPLACE_ENTRY;
1305e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1306aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(c = iptcc_find_label(chain, *handle))) {
1307e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
1308e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1309e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1310e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
13118e795b0ad07174eed4172f8d7237b3abdd9d0e15Martin Josefsson	if (!(old = iptcc_get_rule_num(c, rulenum + 1))) {
1312e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = E2BIG;
1313e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1314e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1315e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1316aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(r = iptcc_alloc_rule(c, e->next_offset))) {
1317aae69bed019826ddec93f761514652a93d871e49Harald Welte		errno = ENOMEM;
1318e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1319aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
1320aae69bed019826ddec93f761514652a93d871e49Harald Welte
1321aae69bed019826ddec93f761514652a93d871e49Harald Welte	memcpy(r->entry, e, e->next_offset);
1322aae69bed019826ddec93f761514652a93d871e49Harald Welte	r->counter_map.maptype = COUNTER_MAP_SET;
1323e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1324aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!iptcc_map_target(*handle, r)) {
1325aae69bed019826ddec93f761514652a93d871e49Harald Welte		free(r);
13260113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		return 0;
1327aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
1328aae69bed019826ddec93f761514652a93d871e49Harald Welte
1329aae69bed019826ddec93f761514652a93d871e49Harald Welte	list_add(&r->list, &old->list);
1330aae69bed019826ddec93f761514652a93d871e49Harald Welte	iptcc_delete_rule(old);
13310113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1332aae69bed019826ddec93f761514652a93d871e49Harald Welte	set_changed(*handle);
1333aae69bed019826ddec93f761514652a93d871e49Harald Welte
1334aae69bed019826ddec93f761514652a93d871e49Harald Welte	return 1;
1335e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1336e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
13370113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte/* Append entry `fw' to chain `chain'.  Equivalent to insert with
1338e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher   rulenum = length of chain. */
1339e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
134079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_APPEND_ENTRY(const IPT_CHAINLABEL chain,
134179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		const STRUCT_ENTRY *e,
134279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		TC_HANDLE_T *handle)
1343e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1344aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
1345aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct rule_head *r;
1346e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
134779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	iptc_fn = TC_APPEND_ENTRY;
1348aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(c = iptcc_find_label(chain, *handle))) {
1349aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP("unable to find chain `%s'\n", chain);
1350e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
1351e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1352e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1353e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1354aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(r = iptcc_alloc_rule(c, e->next_offset))) {
1355aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP("unable to allocate rule for chain `%s'\n", chain);
1356aae69bed019826ddec93f761514652a93d871e49Harald Welte		errno = ENOMEM;
1357aae69bed019826ddec93f761514652a93d871e49Harald Welte		return 0;
1358aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
1359aae69bed019826ddec93f761514652a93d871e49Harald Welte
1360aae69bed019826ddec93f761514652a93d871e49Harald Welte	memcpy(r->entry, e, e->next_offset);
1361aae69bed019826ddec93f761514652a93d871e49Harald Welte	r->counter_map.maptype = COUNTER_MAP_SET;
1362aae69bed019826ddec93f761514652a93d871e49Harald Welte
1363aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!iptcc_map_target(*handle, r)) {
136412009531e6a96a62ee398eb0ab3e9ec0b3b57701Martin Josefsson		DEBUGP("unable to map target of rule for chain `%s'\n", chain);
1365aae69bed019826ddec93f761514652a93d871e49Harald Welte		free(r);
13660113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		return 0;
1367aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
1368aae69bed019826ddec93f761514652a93d871e49Harald Welte
1369aae69bed019826ddec93f761514652a93d871e49Harald Welte	list_add_tail(&r->list, &c->rules);
1370aae69bed019826ddec93f761514652a93d871e49Harald Welte	c->num_rules++;
1371aae69bed019826ddec93f761514652a93d871e49Harald Welte
1372aae69bed019826ddec93f761514652a93d871e49Harald Welte	set_changed(*handle);
13730113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1374aae69bed019826ddec93f761514652a93d871e49Harald Welte	return 1;
1375e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1376e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1377e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic inline int
137879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellmatch_different(const STRUCT_ENTRY_MATCH *a,
1379edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell		const unsigned char *a_elems,
1380edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell		const unsigned char *b_elems,
1381edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell		unsigned char **maskptr)
1382e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
138379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	const STRUCT_ENTRY_MATCH *b;
1384edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell	unsigned int i;
1385e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1386e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Offset of b is the same as a. */
138730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	b = (void *)b_elems + ((unsigned char *)a - a_elems);
1388e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1389228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell	if (a->u.match_size != b->u.match_size)
1390e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 1;
1391e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1392228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell	if (strcmp(a->u.user.name, b->u.user.name) != 0)
1393e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 1;
1394e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
139573ef09b21573ddb17ff75e5fd06fd4b52ec8ea40Rusty Russell	*maskptr += ALIGN(sizeof(*a));
1396edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell
139773ef09b21573ddb17ff75e5fd06fd4b52ec8ea40Rusty Russell	for (i = 0; i < a->u.match_size - ALIGN(sizeof(*a)); i++)
1398edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell		if (((a->data[i] ^ b->data[i]) & (*maskptr)[i]) != 0)
1399edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell			return 1;
1400edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell	*maskptr += i;
1401edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell	return 0;
1402edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell}
1403edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell
1404edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russellstatic inline int
1405edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russelltarget_different(const unsigned char *a_targdata,
1406edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell		 const unsigned char *b_targdata,
1407edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell		 unsigned int tdatasize,
1408edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell		 const unsigned char *mask)
1409edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell{
1410edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell	unsigned int i;
1411edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell	for (i = 0; i < tdatasize; i++)
1412edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell		if (((a_targdata[i] ^ b_targdata[i]) & mask[i]) != 0)
141390e712a00913fe2a2f885142439c392392dc08a8Rusty Russell			return 1;
1414e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1415e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 0;
1416e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1417e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
141879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellstatic int
141979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellis_same(const STRUCT_ENTRY *a,
142079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	const STRUCT_ENTRY *b,
142179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	unsigned char *matchmask);
1422e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
14230113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte/* Delete the first rule in `chain' which matches `fw'. */
1424e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
142579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_DELETE_ENTRY(const IPT_CHAINLABEL chain,
142679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		const STRUCT_ENTRY *origfw,
142779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		unsigned char *matchmask,
142879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		TC_HANDLE_T *handle)
1429e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1430aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
1431fe53707285c250c6bb1e434ea6f8271cf061c67bHarald Welte	struct rule_head *r;
14320113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	STRUCT_ENTRY *e, *fw;
1433e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
143479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	iptc_fn = TC_DELETE_ENTRY;
1435aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(c = iptcc_find_label(chain, *handle))) {
1436e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
1437e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1438e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1439e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
14400113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	fw = malloc(origfw->next_offset);
14410113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	if (fw == NULL) {
14420113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		errno = ENOMEM;
14430113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		return 0;
14440113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	}
14450113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1446fe53707285c250c6bb1e434ea6f8271cf061c67bHarald Welte	list_for_each_entry(r, &c->rules, list) {
14470113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
14480113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		memcpy(fw, origfw, origfw->next_offset);
14490113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1450fe53707285c250c6bb1e434ea6f8271cf061c67bHarald Welte#if 0
14510113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		/* FIXME: handle this in is_same --RR */
14520113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		if (!map_target(*handle, fw, offset, &discard)) {
14530113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte			free(fw);
14540113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte			return 0;
14550113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		}
14560113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte#endif
1457fe53707285c250c6bb1e434ea6f8271cf061c67bHarald Welte
1458fe53707285c250c6bb1e434ea6f8271cf061c67bHarald Welte		e = r->entry;
1459fe53707285c250c6bb1e434ea6f8271cf061c67bHarald Welte
14600113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		if (is_same(e, fw, matchmask)) {
1461fe53707285c250c6bb1e434ea6f8271cf061c67bHarald Welte			/* If we are about to delete the rule that is the
1462fe53707285c250c6bb1e434ea6f8271cf061c67bHarald Welte			 * current iterator, move rule iterator back.  next
1463fe53707285c250c6bb1e434ea6f8271cf061c67bHarald Welte			 * pointer will then point to real next node */
1464fe53707285c250c6bb1e434ea6f8271cf061c67bHarald Welte			if (r == (*handle)->rule_iterator_cur) {
1465fe53707285c250c6bb1e434ea6f8271cf061c67bHarald Welte				(*handle)->rule_iterator_cur =
1466fe53707285c250c6bb1e434ea6f8271cf061c67bHarald Welte					list_entry((*handle)->rule_iterator_cur->list.prev,
1467fe53707285c250c6bb1e434ea6f8271cf061c67bHarald Welte						   struct rule_head, list);
1468fe53707285c250c6bb1e434ea6f8271cf061c67bHarald Welte			}
1469fe53707285c250c6bb1e434ea6f8271cf061c67bHarald Welte
1470fe53707285c250c6bb1e434ea6f8271cf061c67bHarald Welte			c->num_rules--;
1471fe53707285c250c6bb1e434ea6f8271cf061c67bHarald Welte			iptcc_delete_rule(r);
14722a5dbbb883fb0cc8a122b47a5d8e08ef3e6ff5bcMartin Josefsson
14732a5dbbb883fb0cc8a122b47a5d8e08ef3e6ff5bcMartin Josefsson			set_changed(*handle);
1474fe53707285c250c6bb1e434ea6f8271cf061c67bHarald Welte			return 1;
1475e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		}
1476e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1477e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
14780113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	free(fw);
1479e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	errno = ENOENT;
1480e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 0;
14817e53bf9c2a697abdb6f1385557338423a86612a3Rusty Russell}
1482aae69bed019826ddec93f761514652a93d871e49Harald Welte
1483e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1484e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Delete the rule in position `rulenum' in `chain'. */
1485e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
148679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_DELETE_NUM_ENTRY(const IPT_CHAINLABEL chain,
148779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		    unsigned int rulenum,
148879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		    TC_HANDLE_T *handle)
1489e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1490aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
1491aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct rule_head *r;
1492e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
149379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	iptc_fn = TC_DELETE_NUM_ENTRY;
1494aae69bed019826ddec93f761514652a93d871e49Harald Welte
1495aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(c = iptcc_find_label(chain, *handle))) {
1496e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
1497e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1498e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1499e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
15008e795b0ad07174eed4172f8d7237b3abdd9d0e15Martin Josefsson	if (!(r = iptcc_get_rule_num(c, rulenum + 1))) {
1501e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = E2BIG;
1502e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1503e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1504e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1505aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* If we are about to delete the rule that is the current
1506aae69bed019826ddec93f761514652a93d871e49Harald Welte	 * iterator, move rule iterator back.  next pointer will then
1507aae69bed019826ddec93f761514652a93d871e49Harald Welte	 * point to real next node */
1508aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (r == (*handle)->rule_iterator_cur) {
1509aae69bed019826ddec93f761514652a93d871e49Harald Welte		(*handle)->rule_iterator_cur =
1510aae69bed019826ddec93f761514652a93d871e49Harald Welte			list_entry((*handle)->rule_iterator_cur->list.prev,
1511aae69bed019826ddec93f761514652a93d871e49Harald Welte				   struct rule_head, list);
15120113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	}
1513e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1514aae69bed019826ddec93f761514652a93d871e49Harald Welte	c->num_rules--;
1515aae69bed019826ddec93f761514652a93d871e49Harald Welte	iptcc_delete_rule(r);
1516aae69bed019826ddec93f761514652a93d871e49Harald Welte
15172a5dbbb883fb0cc8a122b47a5d8e08ef3e6ff5bcMartin Josefsson	set_changed(*handle);
15182a5dbbb883fb0cc8a122b47a5d8e08ef3e6ff5bcMartin Josefsson
1519aae69bed019826ddec93f761514652a93d871e49Harald Welte	return 1;
1520e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1521e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1522e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Check the packet `fw' on chain `chain'.  Returns the verdict, or
1523e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher   NULL and sets errno. */
1524e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherconst char *
152579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_CHECK_PACKET(const IPT_CHAINLABEL chain,
152679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		STRUCT_ENTRY *entry,
152779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		TC_HANDLE_T *handle)
1528e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1529e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	errno = ENOSYS;
1530e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return NULL;
1531e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1532e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1533e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Flushes the entries in the given chain (ie. empties chain). */
1534e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
153579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_FLUSH_ENTRIES(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle)
1536e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1537aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
1538aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct rule_head *r, *tmp;
1539e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
15400113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	iptc_fn = TC_FLUSH_ENTRIES;
1541aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(c = iptcc_find_label(chain, *handle))) {
1542e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
1543e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1544e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1545e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1546aae69bed019826ddec93f761514652a93d871e49Harald Welte	list_for_each_entry_safe(r, tmp, &c->rules, list) {
1547aae69bed019826ddec93f761514652a93d871e49Harald Welte		iptcc_delete_rule(r);
1548aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
1549aae69bed019826ddec93f761514652a93d871e49Harald Welte
1550aae69bed019826ddec93f761514652a93d871e49Harald Welte	c->num_rules = 0;
1551aae69bed019826ddec93f761514652a93d871e49Harald Welte
1552aae69bed019826ddec93f761514652a93d871e49Harald Welte	set_changed(*handle);
1553aae69bed019826ddec93f761514652a93d871e49Harald Welte
1554aae69bed019826ddec93f761514652a93d871e49Harald Welte	return 1;
1555e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1556e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1557e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Zeroes the counters in a chain. */
1558e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
155979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_ZERO_ENTRIES(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle)
1560e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1561aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
1562aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct rule_head *r;
15637e53bf9c2a697abdb6f1385557338423a86612a3Rusty Russell
1564aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(c = iptcc_find_label(chain, *handle))) {
1565e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
1566e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1567e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1568e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1569aae69bed019826ddec93f761514652a93d871e49Harald Welte	list_for_each_entry(r, &c->rules, list) {
1570aae69bed019826ddec93f761514652a93d871e49Harald Welte		if (r->counter_map.maptype == COUNTER_MAP_NORMAL_MAP)
1571aae69bed019826ddec93f761514652a93d871e49Harald Welte			r->counter_map.maptype = COUNTER_MAP_ZEROED;
1572e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1573aae69bed019826ddec93f761514652a93d871e49Harald Welte
1574175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell	set_changed(*handle);
1575e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1576e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 1;
1577e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1578e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
15791cef74d943055668b5e356eebea877fdaa1ce3e0Harald WelteSTRUCT_COUNTERS *
15801cef74d943055668b5e356eebea877fdaa1ce3e0Harald WelteTC_READ_COUNTER(const IPT_CHAINLABEL chain,
15811cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		unsigned int rulenum,
15821cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		TC_HANDLE_T *handle)
15831cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte{
1584aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
1585aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct rule_head *r;
15861cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
15871cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	iptc_fn = TC_READ_COUNTER;
15881cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	CHECK(*handle);
15891cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
1590aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(c = iptcc_find_label(chain, *handle))) {
15911cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		errno = ENOENT;
15921cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		return NULL;
15931cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	}
15941cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
1595aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(r = iptcc_get_rule_num(c, rulenum))) {
15960113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		errno = E2BIG;
15970113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		return NULL;
15980113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	}
15990113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1600aae69bed019826ddec93f761514652a93d871e49Harald Welte	return &r->entry[0].counters;
16011cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte}
16021cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
16031cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welteint
16041cef74d943055668b5e356eebea877fdaa1ce3e0Harald WelteTC_ZERO_COUNTER(const IPT_CHAINLABEL chain,
16051cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		unsigned int rulenum,
16061cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		TC_HANDLE_T *handle)
16071cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte{
1608aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
1609aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct rule_head *r;
16101cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
16111cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	iptc_fn = TC_ZERO_COUNTER;
16121cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	CHECK(*handle);
16131cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
1614aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(c = iptcc_find_label(chain, *handle))) {
16151cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		errno = ENOENT;
16161cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		return 0;
16171cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	}
16181cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
1619aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(r = iptcc_get_rule_num(c, rulenum))) {
16200113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		errno = E2BIG;
16210113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		return 0;
16220113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	}
16230113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1624aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (r->counter_map.maptype == COUNTER_MAP_NORMAL_MAP)
1625aae69bed019826ddec93f761514652a93d871e49Harald Welte		r->counter_map.maptype = COUNTER_MAP_ZEROED;
16261cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
16271cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	set_changed(*handle);
16281cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
16291cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	return 1;
16301cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte}
16311cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
16321cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welteint
16331cef74d943055668b5e356eebea877fdaa1ce3e0Harald WelteTC_SET_COUNTER(const IPT_CHAINLABEL chain,
16341cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	       unsigned int rulenum,
16351cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	       STRUCT_COUNTERS *counters,
16361cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	       TC_HANDLE_T *handle)
16371cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte{
1638aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
1639aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct rule_head *r;
16401cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	STRUCT_ENTRY *e;
16411cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
16421cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	iptc_fn = TC_SET_COUNTER;
16431cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	CHECK(*handle);
16441cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
1645aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(c = iptcc_find_label(chain, *handle))) {
16461cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		errno = ENOENT;
16471cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		return 0;
16481cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	}
16490113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1650aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(r = iptcc_get_rule_num(c, rulenum))) {
16510113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		errno = E2BIG;
16520113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		return 0;
16530113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	}
16540113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1655aae69bed019826ddec93f761514652a93d871e49Harald Welte	e = r->entry;
1656aae69bed019826ddec93f761514652a93d871e49Harald Welte	r->counter_map.maptype = COUNTER_MAP_SET;
16570113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
16580113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	memcpy(&e->counters, counters, sizeof(STRUCT_COUNTERS));
16591cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
16601cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	set_changed(*handle);
16611cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
16621cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	return 1;
16631cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte}
16641cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
1665e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Creates a new chain. */
1666e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* To create a chain, create two rules: error node and unconditional
1667e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher * return. */
1668e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
166979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_CREATE_CHAIN(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle)
1670e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1671aae69bed019826ddec93f761514652a93d871e49Harald Welte	static struct chain_head *c;
1672e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
167379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	iptc_fn = TC_CREATE_CHAIN;
1674e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1675e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* find_label doesn't cover built-in targets: DROP, ACCEPT,
1676e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher           QUEUE, RETURN. */
1677aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (iptcc_find_label(chain, *handle)
167879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    || strcmp(chain, LABEL_DROP) == 0
167979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    || strcmp(chain, LABEL_ACCEPT) == 0
168067088e73ce7707229c56987868f112051defca5aRusty Russell	    || strcmp(chain, LABEL_QUEUE) == 0
168179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    || strcmp(chain, LABEL_RETURN) == 0) {
1682aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP("Chain `%s' already exists\n", chain);
1683e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EEXIST;
1684e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1685e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1686e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
168779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	if (strlen(chain)+1 > sizeof(IPT_CHAINLABEL)) {
1688aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP("Chain name `%s' too long\n", chain);
1689e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EINVAL;
1690e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1691e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1692e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1693aae69bed019826ddec93f761514652a93d871e49Harald Welte	c = iptcc_alloc_chain_head(chain, 0);
1694aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!c) {
1695aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP("Cannot allocate memory for chain `%s'\n", chain);
1696aae69bed019826ddec93f761514652a93d871e49Harald Welte		errno = ENOMEM;
1697aae69bed019826ddec93f761514652a93d871e49Harald Welte		return 0;
1698e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1699aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
1700e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1701aae69bed019826ddec93f761514652a93d871e49Harald Welte	DEBUGP("Creating chain `%s'\n", chain);
1702aae69bed019826ddec93f761514652a93d871e49Harald Welte	list_add_tail(&c->list, &(*handle)->chains);
1703e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1704aae69bed019826ddec93f761514652a93d871e49Harald Welte	set_changed(*handle);
1705e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1706aae69bed019826ddec93f761514652a93d871e49Harald Welte	return 1;
1707e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1708e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1709e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Get the number of references to this chain. */
1710e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
171179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_GET_REFERENCES(unsigned int *ref, const IPT_CHAINLABEL chain,
171279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		  TC_HANDLE_T *handle)
1713e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1714aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
1715e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1716aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(c = iptcc_find_label(chain, *handle))) {
1717e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
1718e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1719e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1720e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1721aae69bed019826ddec93f761514652a93d871e49Harald Welte	*ref = c->references;
1722aae69bed019826ddec93f761514652a93d871e49Harald Welte
1723e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 1;
1724e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1725e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1726e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Deletes a chain. */
1727e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
172879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_DELETE_CHAIN(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle)
1729e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1730e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int references;
1731aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
17327e53bf9c2a697abdb6f1385557338423a86612a3Rusty Russell
173379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	iptc_fn = TC_DELETE_CHAIN;
1734e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1735aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(c = iptcc_find_label(chain, *handle))) {
1736aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP("cannot find chain `%s'\n", chain);
1737aae69bed019826ddec93f761514652a93d871e49Harald Welte		errno = ENOENT;
1738aae69bed019826ddec93f761514652a93d871e49Harald Welte		return 0;
1739aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
1740aae69bed019826ddec93f761514652a93d871e49Harald Welte
174179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	if (TC_BUILTIN(chain, *handle)) {
1742aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP("cannot remove builtin chain `%s'\n", chain);
1743e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EINVAL;
1744e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1745e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1746e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1747aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!TC_GET_REFERENCES(&references, chain, handle)) {
1748aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP("cannot get references on chain `%s'\n", chain);
1749e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1750e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1751e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1752aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (references > 0) {
1753aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP("chain `%s' still has references\n", chain);
1754aae69bed019826ddec93f761514652a93d871e49Harald Welte		errno = EMLINK;
1755e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1756e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1757e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1758aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (c->num_rules) {
1759aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP("chain `%s' is not empty\n", chain);
1760e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOTEMPTY;
1761e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1762e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1763e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1764aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* If we are about to delete the chain that is the current
1765aae69bed019826ddec93f761514652a93d871e49Harald Welte	 * iterator, move chain iterator firward. */
1766aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (c == (*handle)->chain_iterator_cur)
1767aae69bed019826ddec93f761514652a93d871e49Harald Welte		iptcc_chain_iterator_advance(*handle);
1768aae69bed019826ddec93f761514652a93d871e49Harald Welte
1769aae69bed019826ddec93f761514652a93d871e49Harald Welte	list_del(&c->list);
1770aae69bed019826ddec93f761514652a93d871e49Harald Welte	free(c);
17710113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1772aae69bed019826ddec93f761514652a93d871e49Harald Welte	DEBUGP("chain `%s' deleted\n", chain);
17730113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1774aae69bed019826ddec93f761514652a93d871e49Harald Welte	set_changed(*handle);
1775aae69bed019826ddec93f761514652a93d871e49Harald Welte
1776aae69bed019826ddec93f761514652a93d871e49Harald Welte	return 1;
1777e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1778e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1779e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Renames a chain. */
178079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellint TC_RENAME_CHAIN(const IPT_CHAINLABEL oldname,
178179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		    const IPT_CHAINLABEL newname,
178279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		    TC_HANDLE_T *handle)
1783e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1784aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
178579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	iptc_fn = TC_RENAME_CHAIN;
1786e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
17871de804642d4c8e9c71b7e225a1528fff15fa7faaHarald Welte	/* find_label doesn't cover built-in targets: DROP, ACCEPT,
17881de804642d4c8e9c71b7e225a1528fff15fa7faaHarald Welte           QUEUE, RETURN. */
1789aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (iptcc_find_label(newname, *handle)
179079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    || strcmp(newname, LABEL_DROP) == 0
179179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    || strcmp(newname, LABEL_ACCEPT) == 0
17921de804642d4c8e9c71b7e225a1528fff15fa7faaHarald Welte	    || strcmp(newname, LABEL_QUEUE) == 0
179379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    || strcmp(newname, LABEL_RETURN) == 0) {
1794e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EEXIST;
1795e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1796e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1797e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1798aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(c = iptcc_find_label(oldname, *handle))
179979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    || TC_BUILTIN(oldname, *handle)) {
1800e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
1801e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1802e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1803e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
180479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	if (strlen(newname)+1 > sizeof(IPT_CHAINLABEL)) {
1805e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EINVAL;
1806e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1807e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1808e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1809aae69bed019826ddec93f761514652a93d871e49Harald Welte	strncpy(c->name, newname, sizeof(IPT_CHAINLABEL));
1810aae69bed019826ddec93f761514652a93d871e49Harald Welte
18110113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	set_changed(*handle);
18120113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1813e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 1;
1814e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1815e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1816e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Sets the policy on a built-in chain. */
1817e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
181879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_SET_POLICY(const IPT_CHAINLABEL chain,
181979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	      const IPT_CHAINLABEL policy,
18201cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	      STRUCT_COUNTERS *counters,
182179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	      TC_HANDLE_T *handle)
1822e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1823aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
1824e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
182579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	iptc_fn = TC_SET_POLICY;
1826aae69bed019826ddec93f761514652a93d871e49Harald Welte
1827aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(c = iptcc_find_label(chain, *handle))) {
1828aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP("cannot find chain `%s'\n", chain);
1829c8264991454b5e77279830736f80ea3153b6f814Marc Boucher		errno = ENOENT;
1830e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1831aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
1832e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1833aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!iptcc_is_builtin(c)) {
1834aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP("cannot set policy of userdefinedchain `%s'\n", chain);
1835aae69bed019826ddec93f761514652a93d871e49Harald Welte		errno = ENOENT;
18369e03380e9f78ae347ae4f3f041c4eca50348f2e8Harald Welte		return 0;
18379e03380e9f78ae347ae4f3f041c4eca50348f2e8Harald Welte	}
18389e03380e9f78ae347ae4f3f041c4eca50348f2e8Harald Welte
183979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	if (strcmp(policy, LABEL_ACCEPT) == 0)
1840aae69bed019826ddec93f761514652a93d871e49Harald Welte		c->verdict = -NF_ACCEPT - 1;
184179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	else if (strcmp(policy, LABEL_DROP) == 0)
1842aae69bed019826ddec93f761514652a93d871e49Harald Welte		c->verdict = -NF_DROP - 1;
1843e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	else {
1844e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EINVAL;
1845e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1846e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
18471cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
18481cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	if (counters) {
18491cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		/* set byte and packet counters */
1850aae69bed019826ddec93f761514652a93d871e49Harald Welte		memcpy(&c->counters, counters, sizeof(STRUCT_COUNTERS));
1851aae69bed019826ddec93f761514652a93d871e49Harald Welte		c->counter_map.maptype = COUNTER_MAP_SET;
18521cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	} else {
1853aae69bed019826ddec93f761514652a93d871e49Harald Welte		c->counter_map.maptype = COUNTER_MAP_NOMAP;
18541cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	}
18551cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
1856175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell	set_changed(*handle);
1857e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1858e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 1;
1859e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1860e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1861e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Without this, on gcc 2.7.2.3, we get:
186279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell   libiptc.c: In function `TC_COMMIT':
1863e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher   libiptc.c:833: fixed or forbidden register was spilled.
1864e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher   This may be due to a compiler bug or to impossible asm
1865e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher   statements or clauses.
1866e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher*/
1867e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic void
186879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellsubtract_counters(STRUCT_COUNTERS *answer,
186979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		  const STRUCT_COUNTERS *a,
187079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		  const STRUCT_COUNTERS *b)
1871e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1872e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	answer->pcnt = a->pcnt - b->pcnt;
1873e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	answer->bcnt = a->bcnt - b->bcnt;
1874e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1875e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1876aae69bed019826ddec93f761514652a93d871e49Harald Welte
1877aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic void counters_nomap(STRUCT_COUNTERS_INFO *newcounters,
1878aae69bed019826ddec93f761514652a93d871e49Harald Welte			   unsigned int index)
1879aae69bed019826ddec93f761514652a93d871e49Harald Welte{
1880aae69bed019826ddec93f761514652a93d871e49Harald Welte	newcounters->counters[index] = ((STRUCT_COUNTERS) { 0, 0});
1881aae69bed019826ddec93f761514652a93d871e49Harald Welte	DEBUGP_C("NOMAP => zero\n");
1882aae69bed019826ddec93f761514652a93d871e49Harald Welte}
1883aae69bed019826ddec93f761514652a93d871e49Harald Welte
1884aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic void counters_normal_map(STRUCT_COUNTERS_INFO *newcounters,
1885aae69bed019826ddec93f761514652a93d871e49Harald Welte				STRUCT_REPLACE *repl,
1886aae69bed019826ddec93f761514652a93d871e49Harald Welte				unsigned int index,
1887aae69bed019826ddec93f761514652a93d871e49Harald Welte				unsigned int mappos)
1888aae69bed019826ddec93f761514652a93d871e49Harald Welte{
1889aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* Original read: X.
1890aae69bed019826ddec93f761514652a93d871e49Harald Welte	 * Atomic read on replacement: X + Y.
1891aae69bed019826ddec93f761514652a93d871e49Harald Welte	 * Currently in kernel: Z.
1892aae69bed019826ddec93f761514652a93d871e49Harald Welte	 * Want in kernel: X + Y + Z.
1893aae69bed019826ddec93f761514652a93d871e49Harald Welte	 * => Add in X + Y
1894aae69bed019826ddec93f761514652a93d871e49Harald Welte	 * => Add in replacement read.
1895aae69bed019826ddec93f761514652a93d871e49Harald Welte	 */
1896aae69bed019826ddec93f761514652a93d871e49Harald Welte	newcounters->counters[index] = repl->counters[mappos];
1897aae69bed019826ddec93f761514652a93d871e49Harald Welte	DEBUGP_C("NORMAL_MAP => mappos %u \n", mappos);
1898aae69bed019826ddec93f761514652a93d871e49Harald Welte}
1899aae69bed019826ddec93f761514652a93d871e49Harald Welte
1900aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic void counters_map_zeroed(STRUCT_COUNTERS_INFO *newcounters,
1901aae69bed019826ddec93f761514652a93d871e49Harald Welte				STRUCT_REPLACE *repl,
1902aae69bed019826ddec93f761514652a93d871e49Harald Welte				unsigned int index,
1903aae69bed019826ddec93f761514652a93d871e49Harald Welte				unsigned int mappos,
1904aae69bed019826ddec93f761514652a93d871e49Harald Welte				STRUCT_COUNTERS *counters)
1905aae69bed019826ddec93f761514652a93d871e49Harald Welte{
1906aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* Original read: X.
1907aae69bed019826ddec93f761514652a93d871e49Harald Welte	 * Atomic read on replacement: X + Y.
1908aae69bed019826ddec93f761514652a93d871e49Harald Welte	 * Currently in kernel: Z.
1909aae69bed019826ddec93f761514652a93d871e49Harald Welte	 * Want in kernel: Y + Z.
1910aae69bed019826ddec93f761514652a93d871e49Harald Welte	 * => Add in Y.
1911aae69bed019826ddec93f761514652a93d871e49Harald Welte	 * => Add in (replacement read - original read).
1912aae69bed019826ddec93f761514652a93d871e49Harald Welte	 */
1913aae69bed019826ddec93f761514652a93d871e49Harald Welte	subtract_counters(&newcounters->counters[index],
1914aae69bed019826ddec93f761514652a93d871e49Harald Welte			  &repl->counters[mappos],
1915aae69bed019826ddec93f761514652a93d871e49Harald Welte			  counters);
1916aae69bed019826ddec93f761514652a93d871e49Harald Welte	DEBUGP_C("ZEROED => mappos %u\n", mappos);
1917aae69bed019826ddec93f761514652a93d871e49Harald Welte}
1918aae69bed019826ddec93f761514652a93d871e49Harald Welte
1919aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic void counters_map_set(STRUCT_COUNTERS_INFO *newcounters,
1920aae69bed019826ddec93f761514652a93d871e49Harald Welte			     unsigned int index,
1921aae69bed019826ddec93f761514652a93d871e49Harald Welte			     STRUCT_COUNTERS *counters)
1922aae69bed019826ddec93f761514652a93d871e49Harald Welte{
1923aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* Want to set counter (iptables-restore) */
1924aae69bed019826ddec93f761514652a93d871e49Harald Welte
1925aae69bed019826ddec93f761514652a93d871e49Harald Welte	memcpy(&newcounters->counters[index], counters,
1926aae69bed019826ddec93f761514652a93d871e49Harald Welte		sizeof(STRUCT_COUNTERS));
1927aae69bed019826ddec93f761514652a93d871e49Harald Welte
1928aae69bed019826ddec93f761514652a93d871e49Harald Welte	DEBUGP_C("SET\n");
1929aae69bed019826ddec93f761514652a93d871e49Harald Welte}
1930aae69bed019826ddec93f761514652a93d871e49Harald Welte
1931aae69bed019826ddec93f761514652a93d871e49Harald Welte
1932e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
193379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_COMMIT(TC_HANDLE_T *handle)
1934e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1935e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Replace, then map back the counters. */
193679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	STRUCT_REPLACE *repl;
193779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	STRUCT_COUNTERS_INFO *newcounters;
1938aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
1939aae69bed019826ddec93f761514652a93d871e49Harald Welte	int ret;
1940841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson	size_t counterlen;
1941aae69bed019826ddec93f761514652a93d871e49Harald Welte	int new_number;
1942aae69bed019826ddec93f761514652a93d871e49Harald Welte	unsigned int new_size;
1943e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1944e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	CHECK(*handle);
1945841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson
1946e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#if 0
194754c307e0ff401f40a6fe382af4ae5bff0f5b40baRusty Russell	TC_DUMP_ENTRIES(*handle);
1948e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#endif
1949e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1950e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Don't commit if nothing changed. */
1951e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!(*handle)->changed)
1952e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		goto finished;
1953e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1954aae69bed019826ddec93f761514652a93d871e49Harald Welte	new_number = iptcc_compile_table_prep(*handle, &new_size);
1955aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (new_number < 0) {
1956aae69bed019826ddec93f761514652a93d871e49Harald Welte		errno = ENOMEM;
1957aae69bed019826ddec93f761514652a93d871e49Harald Welte		return 0;
1958aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
1959aae69bed019826ddec93f761514652a93d871e49Harald Welte
1960aae69bed019826ddec93f761514652a93d871e49Harald Welte	repl = malloc(sizeof(*repl) + new_size);
1961e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!repl) {
1962e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOMEM;
1963e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1964e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1965ad3b4f9973ac15981b98b8fc4d364ef1ce524212Martin Josefsson	memset(repl, 0, sizeof(*repl) + new_size);
1966aae69bed019826ddec93f761514652a93d871e49Harald Welte
1967aae69bed019826ddec93f761514652a93d871e49Harald Welte	counterlen = sizeof(STRUCT_COUNTERS_INFO)
1968aae69bed019826ddec93f761514652a93d871e49Harald Welte			+ sizeof(STRUCT_COUNTERS) * new_number;
1969e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1970e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* These are the old counters we will get from kernel */
197179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	repl->counters = malloc(sizeof(STRUCT_COUNTERS)
1972e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				* (*handle)->info.num_entries);
1973e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!repl->counters) {
1974e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		free(repl);
1975e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOMEM;
1976e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1977e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1978e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* These are the counters we're going to put back, later. */
1979e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	newcounters = malloc(counterlen);
1980e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!newcounters) {
1981e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		free(repl->counters);
1982e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		free(repl);
1983e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOMEM;
1984e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1985e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1986aae69bed019826ddec93f761514652a93d871e49Harald Welte	memset(newcounters, 0, counterlen);
1987e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1988e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	strcpy(repl->name, (*handle)->info.name);
1989aae69bed019826ddec93f761514652a93d871e49Harald Welte	repl->num_entries = new_number;
1990aae69bed019826ddec93f761514652a93d871e49Harald Welte	repl->size = new_size;
1991aae69bed019826ddec93f761514652a93d871e49Harald Welte
1992e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	repl->num_counters = (*handle)->info.num_entries;
1993e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	repl->valid_hooks = (*handle)->info.valid_hooks;
1994aae69bed019826ddec93f761514652a93d871e49Harald Welte
1995aae69bed019826ddec93f761514652a93d871e49Harald Welte	DEBUGP("num_entries=%u, size=%u, num_counters=%u\n",
1996aae69bed019826ddec93f761514652a93d871e49Harald Welte		repl->num_entries, repl->size, repl->num_counters);
1997aae69bed019826ddec93f761514652a93d871e49Harald Welte
1998aae69bed019826ddec93f761514652a93d871e49Harald Welte	ret = iptcc_compile_table(*handle, repl);
1999aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (ret < 0) {
2000aae69bed019826ddec93f761514652a93d871e49Harald Welte		errno = ret;
2001aae69bed019826ddec93f761514652a93d871e49Harald Welte		free(repl->counters);
2002aae69bed019826ddec93f761514652a93d871e49Harald Welte		free(repl);
2003aae69bed019826ddec93f761514652a93d871e49Harald Welte		return 0;
2004aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
2005aae69bed019826ddec93f761514652a93d871e49Harald Welte
2006aae69bed019826ddec93f761514652a93d871e49Harald Welte
2007aae69bed019826ddec93f761514652a93d871e49Harald Welte#ifdef IPTC_DEBUG2
2008aae69bed019826ddec93f761514652a93d871e49Harald Welte	{
2009aae69bed019826ddec93f761514652a93d871e49Harald Welte		int fd = open("/tmp/libiptc-so_set_replace.blob",
2010aae69bed019826ddec93f761514652a93d871e49Harald Welte				O_CREAT|O_WRONLY);
2011aae69bed019826ddec93f761514652a93d871e49Harald Welte		if (fd >= 0) {
2012aae69bed019826ddec93f761514652a93d871e49Harald Welte			write(fd, repl, sizeof(*repl) + repl->size);
2013aae69bed019826ddec93f761514652a93d871e49Harald Welte			close(fd);
2014aae69bed019826ddec93f761514652a93d871e49Harald Welte		}
2015aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
2016aae69bed019826ddec93f761514652a93d871e49Harald Welte#endif
2017e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
201879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	if (setsockopt(sockfd, TC_IPPROTO, SO_SET_REPLACE, repl,
2019aae69bed019826ddec93f761514652a93d871e49Harald Welte		       sizeof(*repl) + repl->size) < 0) {
2020e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		free(repl->counters);
2021e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		free(repl);
2022e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		free(newcounters);
2023e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
2024e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
2025e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
2026e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Put counters back. */
2027e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	strcpy(newcounters->name, (*handle)->info.name);
2028aae69bed019826ddec93f761514652a93d871e49Harald Welte	newcounters->num_counters = new_number;
2029aae69bed019826ddec93f761514652a93d871e49Harald Welte
2030aae69bed019826ddec93f761514652a93d871e49Harald Welte	list_for_each_entry(c, &(*handle)->chains, list) {
2031aae69bed019826ddec93f761514652a93d871e49Harald Welte		struct rule_head *r;
2032aae69bed019826ddec93f761514652a93d871e49Harald Welte
2033aae69bed019826ddec93f761514652a93d871e49Harald Welte		/* Builtin chains have their own counters */
2034aae69bed019826ddec93f761514652a93d871e49Harald Welte		if (iptcc_is_builtin(c)) {
2035aae69bed019826ddec93f761514652a93d871e49Harald Welte			DEBUGP("counter for chain-index %u: ", c->foot_index);
2036aae69bed019826ddec93f761514652a93d871e49Harald Welte			switch(c->counter_map.maptype) {
2037aae69bed019826ddec93f761514652a93d871e49Harald Welte			case COUNTER_MAP_NOMAP:
2038aae69bed019826ddec93f761514652a93d871e49Harald Welte				counters_nomap(newcounters, c->foot_index);
2039aae69bed019826ddec93f761514652a93d871e49Harald Welte				break;
2040aae69bed019826ddec93f761514652a93d871e49Harald Welte			case COUNTER_MAP_NORMAL_MAP:
2041aae69bed019826ddec93f761514652a93d871e49Harald Welte				counters_normal_map(newcounters, repl,
2042aae69bed019826ddec93f761514652a93d871e49Harald Welte						    c->foot_index,
2043aae69bed019826ddec93f761514652a93d871e49Harald Welte						    c->counter_map.mappos);
2044aae69bed019826ddec93f761514652a93d871e49Harald Welte				break;
2045aae69bed019826ddec93f761514652a93d871e49Harald Welte			case COUNTER_MAP_ZEROED:
2046aae69bed019826ddec93f761514652a93d871e49Harald Welte				counters_map_zeroed(newcounters, repl,
2047aae69bed019826ddec93f761514652a93d871e49Harald Welte						    c->foot_index,
2048aae69bed019826ddec93f761514652a93d871e49Harald Welte						    c->counter_map.mappos,
2049aae69bed019826ddec93f761514652a93d871e49Harald Welte						    &c->counters);
2050aae69bed019826ddec93f761514652a93d871e49Harald Welte				break;
2051aae69bed019826ddec93f761514652a93d871e49Harald Welte			case COUNTER_MAP_SET:
2052aae69bed019826ddec93f761514652a93d871e49Harald Welte				counters_map_set(newcounters, c->foot_index,
2053aae69bed019826ddec93f761514652a93d871e49Harald Welte						 &c->counters);
2054aae69bed019826ddec93f761514652a93d871e49Harald Welte				break;
2055aae69bed019826ddec93f761514652a93d871e49Harald Welte			}
2056aae69bed019826ddec93f761514652a93d871e49Harald Welte		}
20571cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
2058aae69bed019826ddec93f761514652a93d871e49Harald Welte		list_for_each_entry(r, &c->rules, list) {
2059aae69bed019826ddec93f761514652a93d871e49Harald Welte			DEBUGP("counter for index %u: ", r->index);
2060aae69bed019826ddec93f761514652a93d871e49Harald Welte			switch (r->counter_map.maptype) {
2061aae69bed019826ddec93f761514652a93d871e49Harald Welte			case COUNTER_MAP_NOMAP:
2062aae69bed019826ddec93f761514652a93d871e49Harald Welte				counters_nomap(newcounters, r->index);
2063aae69bed019826ddec93f761514652a93d871e49Harald Welte				break;
2064aae69bed019826ddec93f761514652a93d871e49Harald Welte
2065aae69bed019826ddec93f761514652a93d871e49Harald Welte			case COUNTER_MAP_NORMAL_MAP:
2066aae69bed019826ddec93f761514652a93d871e49Harald Welte				counters_normal_map(newcounters, repl,
2067aae69bed019826ddec93f761514652a93d871e49Harald Welte						    r->index,
2068aae69bed019826ddec93f761514652a93d871e49Harald Welte						    r->counter_map.mappos);
2069aae69bed019826ddec93f761514652a93d871e49Harald Welte				break;
2070aae69bed019826ddec93f761514652a93d871e49Harald Welte
2071aae69bed019826ddec93f761514652a93d871e49Harald Welte			case COUNTER_MAP_ZEROED:
2072aae69bed019826ddec93f761514652a93d871e49Harald Welte				counters_map_zeroed(newcounters, repl,
2073aae69bed019826ddec93f761514652a93d871e49Harald Welte						    r->index,
2074aae69bed019826ddec93f761514652a93d871e49Harald Welte						    r->counter_map.mappos,
2075aae69bed019826ddec93f761514652a93d871e49Harald Welte						    &r->entry->counters);
2076aae69bed019826ddec93f761514652a93d871e49Harald Welte				break;
2077aae69bed019826ddec93f761514652a93d871e49Harald Welte
2078aae69bed019826ddec93f761514652a93d871e49Harald Welte			case COUNTER_MAP_SET:
2079aae69bed019826ddec93f761514652a93d871e49Harald Welte				counters_map_set(newcounters, r->index,
2080aae69bed019826ddec93f761514652a93d871e49Harald Welte						 &r->entry->counters);
2081aae69bed019826ddec93f761514652a93d871e49Harald Welte				break;
2082aae69bed019826ddec93f761514652a93d871e49Harald Welte			}
2083e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		}
2084e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
208562527ce5f0ffaa5b18aa118f64c21af238ddc156Rusty Russell
2086aae69bed019826ddec93f761514652a93d871e49Harald Welte
208762527ce5f0ffaa5b18aa118f64c21af238ddc156Rusty Russell#ifdef KERNEL_64_USERSPACE_32
208862527ce5f0ffaa5b18aa118f64c21af238ddc156Rusty Russell	{
208962527ce5f0ffaa5b18aa118f64c21af238ddc156Rusty Russell		/* Kernel will think that pointer should be 64-bits, and get
209062527ce5f0ffaa5b18aa118f64c21af238ddc156Rusty Russell		   padding.  So we accomodate here (assumption: alignment of
209162527ce5f0ffaa5b18aa118f64c21af238ddc156Rusty Russell		   `counters' is on 64-bit boundary). */
209262527ce5f0ffaa5b18aa118f64c21af238ddc156Rusty Russell		u_int64_t *kernptr = (u_int64_t *)&newcounters->counters;
209362527ce5f0ffaa5b18aa118f64c21af238ddc156Rusty Russell		if ((unsigned long)&newcounters->counters % 8 != 0) {
209462527ce5f0ffaa5b18aa118f64c21af238ddc156Rusty Russell			fprintf(stderr,
209562527ce5f0ffaa5b18aa118f64c21af238ddc156Rusty Russell				"counters alignment incorrect! Mail rusty!\n");
209662527ce5f0ffaa5b18aa118f64c21af238ddc156Rusty Russell			abort();
209762527ce5f0ffaa5b18aa118f64c21af238ddc156Rusty Russell		}
209862527ce5f0ffaa5b18aa118f64c21af238ddc156Rusty Russell		*kernptr = newcounters->counters;
209954c307e0ff401f40a6fe382af4ae5bff0f5b40baRusty Russell	}
210062527ce5f0ffaa5b18aa118f64c21af238ddc156Rusty Russell#endif /* KERNEL_64_USERSPACE_32 */
2101e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
2102aae69bed019826ddec93f761514652a93d871e49Harald Welte#ifdef IPTC_DEBUG2
2103aae69bed019826ddec93f761514652a93d871e49Harald Welte	{
2104aae69bed019826ddec93f761514652a93d871e49Harald Welte		int fd = open("/tmp/libiptc-so_set_add_counters.blob",
2105aae69bed019826ddec93f761514652a93d871e49Harald Welte				O_CREAT|O_WRONLY);
2106aae69bed019826ddec93f761514652a93d871e49Harald Welte		if (fd >= 0) {
2107aae69bed019826ddec93f761514652a93d871e49Harald Welte			write(fd, newcounters, counterlen);
2108aae69bed019826ddec93f761514652a93d871e49Harald Welte			close(fd);
2109aae69bed019826ddec93f761514652a93d871e49Harald Welte		}
2110aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
2111aae69bed019826ddec93f761514652a93d871e49Harald Welte#endif
2112aae69bed019826ddec93f761514652a93d871e49Harald Welte
211379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	if (setsockopt(sockfd, TC_IPPROTO, SO_SET_ADD_COUNTERS,
211479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		       newcounters, counterlen) < 0) {
2115e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		free(repl->counters);
2116e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		free(repl);
2117e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		free(newcounters);
2118e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
2119e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
2120e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
2121e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	free(repl->counters);
2122e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	free(repl);
2123e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	free(newcounters);
2124e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
2125e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher finished:
2126841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson	TC_FREE(handle);
2127e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 1;
2128e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
2129e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
2130e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Get raw socket. */
2131e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
213279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_GET_RAW_SOCKET()
2133e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
2134e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return sockfd;
2135e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
2136e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
2137e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Translates errno numbers into more human-readable form than strerror. */
2138e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherconst char *
213979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_STRERROR(int err)
2140e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
2141e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int i;
2142e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct table_struct {
2143e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		void *fn;
2144e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		int err;
2145e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		const char *message;
2146e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	} table [] =
21474ccfa630d9a588d4b852abef8bc467642427c8cfHarald Welte	  { { TC_INIT, EPERM, "Permission denied (you must be root)" },
214879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_INIT, EINVAL, "Module is wrong version" },
21494ccfa630d9a588d4b852abef8bc467642427c8cfHarald Welte	    { TC_INIT, ENOENT,
21504ccfa630d9a588d4b852abef8bc467642427c8cfHarald Welte		    "Table does not exist (do you need to insmod?)" },
215179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_DELETE_CHAIN, ENOTEMPTY, "Chain is not empty" },
215279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_DELETE_CHAIN, EINVAL, "Can't delete built-in chain" },
215379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_DELETE_CHAIN, EMLINK,
2154e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	      "Can't delete chain with references left" },
215579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_CREATE_CHAIN, EEXIST, "Chain already exists" },
215679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_INSERT_ENTRY, E2BIG, "Index of insertion too big" },
215779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_REPLACE_ENTRY, E2BIG, "Index of replacement too big" },
215879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_DELETE_NUM_ENTRY, E2BIG, "Index of deletion too big" },
21591cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	    { TC_READ_COUNTER, E2BIG, "Index of counter too big" },
21601cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	    { TC_ZERO_COUNTER, E2BIG, "Index of counter too big" },
216179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_INSERT_ENTRY, ELOOP, "Loop found in table" },
216279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_INSERT_ENTRY, EINVAL, "Target problem" },
2163e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    /* EINVAL for CHECK probably means bad interface. */
216479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_CHECK_PACKET, EINVAL,
2165c8264991454b5e77279830736f80ea3153b6f814Marc Boucher	      "Bad arguments (does that interface exist?)" },
21664ccfa630d9a588d4b852abef8bc467642427c8cfHarald Welte	    { TC_CHECK_PACKET, ENOSYS,
21674ccfa630d9a588d4b852abef8bc467642427c8cfHarald Welte	      "Checking will most likely never get implemented" },
2168e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    /* ENOENT for DELETE probably means no matching rule */
216979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_DELETE_ENTRY, ENOENT,
2170c8264991454b5e77279830736f80ea3153b6f814Marc Boucher	      "Bad rule (does a matching rule exist in that chain?)" },
217179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_SET_POLICY, ENOENT,
2172c8264991454b5e77279830736f80ea3153b6f814Marc Boucher	      "Bad built-in chain name" },
217379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_SET_POLICY, EINVAL,
2174c8264991454b5e77279830736f80ea3153b6f814Marc Boucher	      "Bad policy name" },
21754ccfa630d9a588d4b852abef8bc467642427c8cfHarald Welte
21764ccfa630d9a588d4b852abef8bc467642427c8cfHarald Welte	    { NULL, 0, "Incompatible with this kernel" },
21774ccfa630d9a588d4b852abef8bc467642427c8cfHarald Welte	    { NULL, ENOPROTOOPT, "iptables who? (do you need to insmod?)" },
21784ccfa630d9a588d4b852abef8bc467642427c8cfHarald Welte	    { NULL, ENOSYS, "Will be implemented real soon.  I promise ;)" },
21794ccfa630d9a588d4b852abef8bc467642427c8cfHarald Welte	    { NULL, ENOMEM, "Memory allocation problem" },
21804ccfa630d9a588d4b852abef8bc467642427c8cfHarald Welte	    { NULL, ENOENT, "No chain/target/match by that name" },
2181e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	  };
2182e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
2183e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	for (i = 0; i < sizeof(table)/sizeof(struct table_struct); i++) {
2184e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if ((!table[i].fn || table[i].fn == iptc_fn)
2185e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		    && table[i].err == err)
2186e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			return table[i].message;
2187e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
2188e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
2189e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return strerror(err);
2190e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
2191