libiptc.c revision e560fd604284180f3ab522993c5b8e6f424ef1d9
1e560fd604284180f3ab522993c5b8e6f424ef1d9Martin Josefsson/* Library which manipulates firewall rules.  Version $Revision: 1.37 $ */
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
11e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* (C)1999 Paul ``Rusty'' Russell - Placed under the GNU GPL (See
12e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher   COPYING for details). */
13e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
14e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#ifndef IPT_LIB_DIR
15e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#define IPT_LIB_DIR "/usr/local/lib/iptables"
16e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#endif
17e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
184e242f822ef0add1359c540ed0cf3acdf74c63f3Rusty Russell#ifndef __OPTIMIZE__
19ec81ca7e5e5939eb0bfa4776c5c0c585efdfd1bbHarald WelteSTRUCT_ENTRY_TARGET *
2079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellGET_TARGET(STRUCT_ENTRY *e)
2130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell{
2230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	return (void *)e + e->target_offset;
2330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell}
2430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell#endif
2530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
26e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic int sockfd = -1;
27e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic void *iptc_fn = NULL;
28e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
29e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic const char *hooknames[]
3079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell= { [HOOK_PRE_ROUTING]  "PREROUTING",
3179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell    [HOOK_LOCAL_IN]     "INPUT",
3279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell    [HOOK_FORWARD]      "FORWARD",
3379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell    [HOOK_LOCAL_OUT]    "OUTPUT",
3410758b743d6aa076ebe2c3e8f855e73826841e71Rusty Russell    [HOOK_POST_ROUTING] "POSTROUTING",
3510758b743d6aa076ebe2c3e8f855e73826841e71Rusty Russell#ifdef HOOK_DROPPING
3610758b743d6aa076ebe2c3e8f855e73826841e71Rusty Russell    [HOOK_DROPPING]	"DROPPING"
3710758b743d6aa076ebe2c3e8f855e73826841e71Rusty Russell#endif
38e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher};
39e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
40e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstruct counter_map
41e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
42e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	enum {
43e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		COUNTER_MAP_NOMAP,
44e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		COUNTER_MAP_NORMAL_MAP,
451cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		COUNTER_MAP_ZEROED,
461cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		COUNTER_MAP_SET
47e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	} maptype;
48e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int mappos;
49e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher};
50e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
51e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Convenience structures */
52e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstruct ipt_error_target
53e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
5479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	STRUCT_ENTRY_TARGET t;
5579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	char error[TABLE_MAXNAMELEN];
56e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher};
57e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
5830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russellstruct chain_cache
5930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell{
6079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	char name[TABLE_MAXNAMELEN];
6130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	/* This is the first rule in chain. */
6279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	STRUCT_ENTRY *start;
6330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	/* Last rule in chain */
6479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	STRUCT_ENTRY *end;
6530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell};
6630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
6779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellSTRUCT_TC_HANDLE
68e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
69e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Have changes been made? */
70e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	int changed;
71e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Size in here reflects original state. */
7279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	STRUCT_GETINFO info;
73e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
74e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct counter_map *counter_map;
75e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Array of hook names */
76e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	const char **hooknames;
77e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
7830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	/* Cached position of chain heads (NULL = no cache). */
7930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	unsigned int cache_num_chains;
8030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	unsigned int cache_num_builtins;
8130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	struct chain_cache *cache_chain_heads;
8230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
8330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	/* Chain iterator: current chain cache entry. */
8430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	struct chain_cache *cache_chain_iteration;
8530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
8630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	/* Rule iterator: terminal rule */
8779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	STRUCT_ENTRY *cache_rule_end;
88175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell
89e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Number in here reflects current state. */
90e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int new_number;
9179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	STRUCT_GET_ENTRIES entries;
92e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher};
93e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
94175f64177743e5a417e98d483ef995bf7151f3bcRusty Russellstatic void
9579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellset_changed(TC_HANDLE_T h)
96175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell{
9730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	if (h->cache_chain_heads) {
9830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		free(h->cache_chain_heads);
9930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		h->cache_chain_heads = NULL;
10030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		h->cache_num_chains = 0;
10130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		h->cache_chain_iteration = NULL;
10230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		h->cache_rule_end = NULL;
10330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	}
104175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell	h->changed = 1;
105175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell}
106175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell
107380ba5f3074a16fbaa8869d9594962d58b5f8608Harald Welte#ifdef IPTC_DEBUG
10879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellstatic void do_check(TC_HANDLE_T h, unsigned int line);
109849779c4adf8dd65c83fffb65e6b7898df2a55c6Rusty Russell#define CHECK(h) do { if (!getenv("IPTC_NO_CHECK")) do_check((h), __LINE__); } while(0)
11030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell#else
11130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell#define CHECK(h)
11230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell#endif
113e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
114e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic inline int
11579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellget_number(const STRUCT_ENTRY *i,
11679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	   const STRUCT_ENTRY *seek,
117e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	   unsigned int *pos)
118e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
119e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (i == seek)
120e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 1;
121e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	(*pos)++;
122e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 0;
123e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
124e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
125e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic unsigned int
12679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellentry2index(const TC_HANDLE_T h, const STRUCT_ENTRY *seek)
127e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
128e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int pos = 0;
129e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
130725d97a79cf0b332ed45cb7d254915178328427dRusty Russell	if (ENTRY_ITERATE(h->entries.entrytable, h->entries.size,
13179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell			  get_number, seek, &pos) == 0) {
132e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		fprintf(stderr, "ERROR: offset %i not an entry!\n",
133725d97a79cf0b332ed45cb7d254915178328427dRusty Russell			(char *)seek - (char *)h->entries.entrytable);
134e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		abort();
135e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
136e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return pos;
137e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
138e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
139e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic inline int
14079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellget_entry_n(STRUCT_ENTRY *i,
141e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    unsigned int number,
142e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    unsigned int *pos,
14379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    STRUCT_ENTRY **pe)
144e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
145e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (*pos == number) {
146e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		*pe = i;
147e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 1;
148e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
149e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	(*pos)++;
150e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 0;
151e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
152e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
15379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellstatic STRUCT_ENTRY *
15479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellindex2entry(TC_HANDLE_T h, unsigned int index)
155e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
156e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int pos = 0;
15779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	STRUCT_ENTRY *ret = NULL;
158e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
159725d97a79cf0b332ed45cb7d254915178328427dRusty Russell	ENTRY_ITERATE(h->entries.entrytable, h->entries.size,
16079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		      get_entry_n, index, &pos, &ret);
161e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
162e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return ret;
163e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
164e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
16579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellstatic inline STRUCT_ENTRY *
16679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellget_entry(TC_HANDLE_T h, unsigned int offset)
167e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
168725d97a79cf0b332ed45cb7d254915178328427dRusty Russell	return (STRUCT_ENTRY *)((char *)h->entries.entrytable + offset);
169e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
170e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
171e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic inline unsigned long
17279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellentry2offset(const TC_HANDLE_T h, const STRUCT_ENTRY *e)
173e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
174725d97a79cf0b332ed45cb7d254915178328427dRusty Russell	return (char *)e - (char *)h->entries.entrytable;
175e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
176e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
177e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic unsigned long
17879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellindex2offset(TC_HANDLE_T h, unsigned int index)
179e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
180e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return entry2offset(h, index2entry(h, index));
181e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
182e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
183e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic const char *
18479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellget_errorlabel(TC_HANDLE_T h, unsigned int offset)
185e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
18679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	STRUCT_ENTRY *e;
187e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
188e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	e = get_entry(h, offset);
18967088e73ce7707229c56987868f112051defca5aRusty Russell	if (strcmp(GET_TARGET(e)->u.user.name, ERROR_TARGET) != 0) {
190e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		fprintf(stderr, "ERROR: offset %u not an error node!\n",
191e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			offset);
192e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		abort();
193e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
194e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
19579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	return (const char *)GET_TARGET(e)->data;
196e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
197e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
198e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Allocate handle of given size */
19979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellstatic TC_HANDLE_T
200e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucheralloc_handle(const char *tablename, unsigned int size, unsigned int num_rules)
201e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
202e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	size_t len;
20379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	TC_HANDLE_T h;
204e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
20579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	len = sizeof(STRUCT_TC_HANDLE)
206e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		+ size
207e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		+ num_rules * sizeof(struct counter_map);
208e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
209e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if ((h = malloc(len)) == NULL) {
210e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOMEM;
211e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return NULL;
212e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
213e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
214e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	h->changed = 0;
21530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	h->cache_num_chains = 0;
21630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	h->cache_chain_heads = NULL;
217e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	h->counter_map = (void *)h
21879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		+ sizeof(STRUCT_TC_HANDLE)
219e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		+ size;
220e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	strcpy(h->info.name, tablename);
221e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	strcpy(h->entries.name, tablename);
222e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
223e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return h;
224e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
225e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
22679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_HANDLE_T
22779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_INIT(const char *tablename)
228e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
22979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	TC_HANDLE_T h;
23079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	STRUCT_GETINFO info;
231e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int i;
232e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	int tmp;
233e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	socklen_t s;
234e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
23579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	iptc_fn = TC_INIT;
236e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
237e560fd604284180f3ab522993c5b8e6f424ef1d9Martin Josefsson	if (sockfd != -1) {
238366454bc69f781fdafc3a30eb6dd77155ee4efb6Harald Welte		close(sockfd);
239e560fd604284180f3ab522993c5b8e6f424ef1d9Martin Josefsson		sockfd = -1;
240e560fd604284180f3ab522993c5b8e6f424ef1d9Martin Josefsson	}
241366454bc69f781fdafc3a30eb6dd77155ee4efb6Harald Welte
242841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson	if (strlen(tablename) >= TABLE_MAXNAMELEN) {
243841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson		errno = EINVAL;
244841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson		return NULL;
245841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson	}
246841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson
24779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	sockfd = socket(TC_AF, SOCK_RAW, IPPROTO_RAW);
248e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (sockfd < 0)
249e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return NULL;
250e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
251e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	s = sizeof(info);
252841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson
253e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	strcpy(info.name, tablename);
25479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	if (getsockopt(sockfd, TC_IPPROTO, SO_GET_INFO, &info, &s) < 0)
255e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return NULL;
256e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
257e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if ((h = alloc_handle(info.name, info.size, info.num_entries))
258841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson	    == NULL) {
259841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson		close(sockfd);
260e560fd604284180f3ab522993c5b8e6f424ef1d9Martin Josefsson		sockfd = -1;
261e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return NULL;
262841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson	}
263e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
264e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Too hard --RR */
265e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#if 0
266e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	sprintf(pathname, "%s/%s", IPT_LIB_DIR, info.name);
267e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	dynlib = dlopen(pathname, RTLD_NOW);
268e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!dynlib) {
269e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
270e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return NULL;
271e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
272e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	h->hooknames = dlsym(dynlib, "hooknames");
273e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!h->hooknames) {
274e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
275e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return NULL;
276e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
277e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#else
278e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	h->hooknames = hooknames;
279e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#endif
280e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
281e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Initialize current state */
282e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	h->info = info;
283e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	h->new_number = h->info.num_entries;
284e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	for (i = 0; i < h->info.num_entries; i++)
285e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		h->counter_map[i]
286e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			= ((struct counter_map){COUNTER_MAP_NORMAL_MAP, i});
287e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
288e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	h->entries.size = h->info.size;
289e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
29079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	tmp = sizeof(STRUCT_GET_ENTRIES) + h->info.size;
291e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
29279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	if (getsockopt(sockfd, TC_IPPROTO, SO_GET_ENTRIES, &h->entries,
293e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		       &tmp) < 0) {
294841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson		close(sockfd);
295e560fd604284180f3ab522993c5b8e6f424ef1d9Martin Josefsson		sockfd = -1;
296e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		free(h);
297e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return NULL;
298e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
2997e53bf9c2a697abdb6f1385557338423a86612a3Rusty Russell
300e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	CHECK(h);
301e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return h;
302e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
303e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
304841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefssonvoid
305841e4aed2349046eb2c0b1375139c06569a93bd0Martin JosefssonTC_FREE(TC_HANDLE_T *h)
306841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson{
307841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson	close(sockfd);
308e560fd604284180f3ab522993c5b8e6f424ef1d9Martin Josefsson	sockfd = -1;
309841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson	if ((*h)->cache_chain_heads)
310841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson		free((*h)->cache_chain_heads);
311841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson	free(*h);
312841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson	*h = NULL;
313841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson}
314841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson
315e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic inline int
31679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellprint_match(const STRUCT_ENTRY_MATCH *m)
317e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
318228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell	printf("Match name: `%s'\n", m->u.user.name);
319e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 0;
320e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
321e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
32279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellstatic int dump_entry(STRUCT_ENTRY *e, const TC_HANDLE_T handle);
32379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell
324e6869a8f59d779ff4d5a0984c86d80db7078496Marc Bouchervoid
32579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_DUMP_ENTRIES(const TC_HANDLE_T handle)
326e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
327e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	CHECK(handle);
328e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
329e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	printf("libiptc v%s.  %u entries, %u bytes.\n",
33080fe35d6339b53a12ddaec41885613e4e37ed031Harald Welte	       IPTABLES_VERSION,
331e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       handle->new_number, handle->entries.size);
332e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	printf("Table `%s'\n", handle->info.name);
333e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	printf("Hooks: pre/in/fwd/out/post = %u/%u/%u/%u/%u\n",
33467088e73ce7707229c56987868f112051defca5aRusty Russell	       handle->info.hook_entry[HOOK_PRE_ROUTING],
33567088e73ce7707229c56987868f112051defca5aRusty Russell	       handle->info.hook_entry[HOOK_LOCAL_IN],
33667088e73ce7707229c56987868f112051defca5aRusty Russell	       handle->info.hook_entry[HOOK_FORWARD],
33767088e73ce7707229c56987868f112051defca5aRusty Russell	       handle->info.hook_entry[HOOK_LOCAL_OUT],
33867088e73ce7707229c56987868f112051defca5aRusty Russell	       handle->info.hook_entry[HOOK_POST_ROUTING]);
339e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	printf("Underflows: pre/in/fwd/out/post = %u/%u/%u/%u/%u\n",
34067088e73ce7707229c56987868f112051defca5aRusty Russell	       handle->info.underflow[HOOK_PRE_ROUTING],
34167088e73ce7707229c56987868f112051defca5aRusty Russell	       handle->info.underflow[HOOK_LOCAL_IN],
34267088e73ce7707229c56987868f112051defca5aRusty Russell	       handle->info.underflow[HOOK_FORWARD],
34367088e73ce7707229c56987868f112051defca5aRusty Russell	       handle->info.underflow[HOOK_LOCAL_OUT],
34467088e73ce7707229c56987868f112051defca5aRusty Russell	       handle->info.underflow[HOOK_POST_ROUTING]);
345e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
346725d97a79cf0b332ed45cb7d254915178328427dRusty Russell	ENTRY_ITERATE(handle->entries.entrytable, handle->entries.size,
34779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		      dump_entry, handle);
348e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
349e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
35030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell/* Returns 0 if not hook entry, else hooknumber + 1 */
35130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russellstatic inline unsigned int
35279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellis_hook_entry(STRUCT_ENTRY *e, TC_HANDLE_T h)
35330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell{
35430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	unsigned int i;
35530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
35679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	for (i = 0; i < NUMHOOKS; i++) {
35730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		if ((h->info.valid_hooks & (1 << i))
35830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		    && get_entry(h, h->info.hook_entry[i]) == e)
35930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell			return i+1;
36030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	}
36130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	return 0;
36230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell}
36330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
364e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic inline int
36579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russelladd_chain(STRUCT_ENTRY *e, TC_HANDLE_T h, STRUCT_ENTRY **prev)
366e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
36730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	unsigned int builtin;
368e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
36930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	/* Last entry.  End it. */
37030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	if (entry2offset(h, e) + e->next_offset == h->entries.size) {
37130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		/* This is the ERROR node at end of the table */
37230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		h->cache_chain_heads[h->cache_num_chains-1].end = *prev;
37330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		return 0;
37430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	}
375e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
37630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	/* We know this is the start of a new chain if it's an ERROR
37730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	   target, or a hook entry point */
37867088e73ce7707229c56987868f112051defca5aRusty Russell	if (strcmp(GET_TARGET(e)->u.user.name, ERROR_TARGET) == 0) {
37930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		/* prev was last entry in previous chain */
38030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		h->cache_chain_heads[h->cache_num_chains-1].end
38130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell			= *prev;
38230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
38330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		strcpy(h->cache_chain_heads[h->cache_num_chains].name,
38479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		       (const char *)GET_TARGET(e)->data);
38530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		h->cache_chain_heads[h->cache_num_chains].start
38630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell			= (void *)e + e->next_offset;
38730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		h->cache_num_chains++;
38830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	} else if ((builtin = is_hook_entry(e, h)) != 0) {
38930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		if (h->cache_num_chains > 0)
39030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell			/* prev was last entry in previous chain */
39130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell			h->cache_chain_heads[h->cache_num_chains-1].end
39230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell				= *prev;
39330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
39430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		strcpy(h->cache_chain_heads[h->cache_num_chains].name,
39530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		       h->hooknames[builtin-1]);
39630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		h->cache_chain_heads[h->cache_num_chains].start
39730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell			= (void *)e;
39830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		h->cache_num_chains++;
39930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	}
40030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
40130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	*prev = e;
402e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 0;
403e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
404e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
40530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russellstatic int alphasort(const void *a, const void *b)
40630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell{
40730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	return strcmp(((struct chain_cache *)a)->name,
40830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		      ((struct chain_cache *)b)->name);
40930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell}
41030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
41179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellstatic int populate_cache(TC_HANDLE_T h)
412e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
413e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int i;
41479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	STRUCT_ENTRY *prev;
415e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
41630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	/* # chains < # rules / 2 + num builtins - 1 */
41730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	h->cache_chain_heads = malloc((h->new_number / 2 + 4)
41830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell				      * sizeof(struct chain_cache));
41930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	if (!h->cache_chain_heads) {
42030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		errno = ENOMEM;
42130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		return 0;
422175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell	}
423175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell
42430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	h->cache_num_chains = 0;
42530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	h->cache_num_builtins = 0;
42630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
42730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	/* Count builtins */
42879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	for (i = 0; i < NUMHOOKS; i++) {
42930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		if (h->info.valid_hooks & (1 << i))
43030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell			h->cache_num_builtins++;
431e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
432e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
43330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	prev = NULL;
434725d97a79cf0b332ed45cb7d254915178328427dRusty Russell	ENTRY_ITERATE(h->entries.entrytable, h->entries.size,
43579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		      add_chain, h, &prev);
43630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
43730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	qsort(h->cache_chain_heads + h->cache_num_builtins,
43830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	      h->cache_num_chains - h->cache_num_builtins,
43930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	      sizeof(struct chain_cache), alphasort);
44030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
44130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	return 1;
44230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell}
44330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
44430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell/* Returns cache ptr if found, otherwise NULL. */
44530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russellstatic struct chain_cache *
44679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellfind_label(const char *name, TC_HANDLE_T handle)
44730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell{
448849779c4adf8dd65c83fffb65e6b7898df2a55c6Rusty Russell	unsigned int i;
44930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
45030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	if (handle->cache_chain_heads == NULL
45130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	    && !populate_cache(handle))
45230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		return NULL;
45330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
454849779c4adf8dd65c83fffb65e6b7898df2a55c6Rusty Russell	/* FIXME: Linear search through builtins, then binary --RR */
455849779c4adf8dd65c83fffb65e6b7898df2a55c6Rusty Russell	for (i = 0; i < handle->cache_num_chains; i++) {
456849779c4adf8dd65c83fffb65e6b7898df2a55c6Rusty Russell		if (strcmp(handle->cache_chain_heads[i].name, name) == 0)
457849779c4adf8dd65c83fffb65e6b7898df2a55c6Rusty Russell			return &handle->cache_chain_heads[i];
458e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
459e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
460849779c4adf8dd65c83fffb65e6b7898df2a55c6Rusty Russell	return NULL;
461e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
462e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
463e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Does this chain exist? */
46479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellint TC_IS_CHAIN(const char *chain, const TC_HANDLE_T handle)
465e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
46630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	return find_label(chain, handle) != NULL;
467e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
468e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
469e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Returns the position of the final (ie. unconditional) element. */
470e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic unsigned int
47179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellget_chain_end(const TC_HANDLE_T handle, unsigned int start)
472e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
473e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int last_off, off;
47479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	STRUCT_ENTRY *e;
475e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
476e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	last_off = start;
477e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	e = get_entry(handle, start);
478e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
479e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Terminate when we meet a error label or a hook entry. */
480e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	for (off = start + e->next_offset;
481e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	     off < handle->entries.size;
482e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	     last_off = off, off += e->next_offset) {
48379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		STRUCT_ENTRY_TARGET *t;
484e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		unsigned int i;
485e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
486e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		e = get_entry(handle, off);
487e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
488e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		/* We hit an entry point. */
48979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		for (i = 0; i < NUMHOOKS; i++) {
490e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			if ((handle->info.valid_hooks & (1 << i))
491e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			    && off == handle->info.hook_entry[i])
492e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				return last_off;
493e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		}
494e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
495e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		/* We hit a user chain label */
49679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		t = GET_TARGET(e);
49767088e73ce7707229c56987868f112051defca5aRusty Russell		if (strcmp(t->u.user.name, ERROR_TARGET) == 0)
498e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			return last_off;
499e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
500e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* SHOULD NEVER HAPPEN */
501e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	fprintf(stderr, "ERROR: Off end (%u) of chain from %u!\n",
502e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		handle->entries.size, off);
503e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	abort();
504e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
505e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
50630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell/* Iterator functions to run through the chains. */
507e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherconst char *
5088c700900e2a0cf87d7917cb62578583a60ad1210Philip BlundellTC_FIRST_CHAIN(TC_HANDLE_T *handle)
509e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
51030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	if ((*handle)->cache_chain_heads == NULL
51130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	    && !populate_cache(*handle))
512e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return NULL;
513e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
51430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	(*handle)->cache_chain_iteration
51530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		= &(*handle)->cache_chain_heads[0];
51630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
51730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	return (*handle)->cache_chain_iteration->name;
51830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell}
51930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
52030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell/* Iterator functions to run through the chains.  Returns NULL at end. */
52130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russellconst char *
52279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_NEXT_CHAIN(TC_HANDLE_T *handle)
52330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell{
52430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	(*handle)->cache_chain_iteration++;
52530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
52630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	if ((*handle)->cache_chain_iteration - (*handle)->cache_chain_heads
527841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson	    == (*handle)->cache_num_chains)
52830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		return NULL;
52930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
53030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	return (*handle)->cache_chain_iteration->name;
53130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell}
53230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
53330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell/* Get first rule in the given chain: NULL for empty chain. */
53479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellconst STRUCT_ENTRY *
5358c700900e2a0cf87d7917cb62578583a60ad1210Philip BlundellTC_FIRST_RULE(const char *chain, TC_HANDLE_T *handle)
53630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell{
53730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	struct chain_cache *c;
53830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
53930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	c = find_label(chain, *handle);
54030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	if (!c) {
54130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		errno = ENOENT;
54230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		return NULL;
543e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
544e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
54530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	/* Empty chain: single return/policy rule */
54630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	if (c->start == c->end)
54730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		return NULL;
54830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
54930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	(*handle)->cache_rule_end = c->end;
55030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	return c->start;
551e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
552e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
55330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell/* Returns NULL when rules run out. */
55479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellconst STRUCT_ENTRY *
5558c700900e2a0cf87d7917cb62578583a60ad1210Philip BlundellTC_NEXT_RULE(const STRUCT_ENTRY *prev, TC_HANDLE_T *handle)
55630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell{
55730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	if ((void *)prev + prev->next_offset
55830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	    == (void *)(*handle)->cache_rule_end)
55930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		return NULL;
56030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
56130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	return (void *)prev + prev->next_offset;
56230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell}
56330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
56430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell#if 0
565e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* How many rules in this chain? */
566e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherunsigned int
56779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_NUM_RULES(const char *chain, TC_HANDLE_T *handle)
568e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
569e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int off = 0;
57079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	STRUCT_ENTRY *start, *end;
571e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
572e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	CHECK(*handle);
573e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!find_label(&off, chain, *handle)) {
574e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
575e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return (unsigned int)-1;
576e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
577e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
578e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	start = get_entry(*handle, off);
579e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	end = get_entry(*handle, get_chain_end(*handle, off));
580e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
581e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return entry2index(*handle, end) - entry2index(*handle, start);
582e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
583e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
584e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Get n'th rule in this chain. */
58579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellconst STRUCT_ENTRY *TC_GET_RULE(const char *chain,
58679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell				unsigned int n,
58779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell				TC_HANDLE_T *handle)
588e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
589e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int pos = 0, chainindex;
590e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
591e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	CHECK(*handle);
592e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!find_label(&pos, chain, *handle)) {
593e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
594e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return NULL;
595e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
596e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
597e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	chainindex = entry2index(*handle, get_entry(*handle, pos));
598e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
599e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return index2entry(*handle, chainindex + n);
600e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
60130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell#endif
602e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
60330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russellstatic const char *
60479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russelltarget_name(TC_HANDLE_T handle, const STRUCT_ENTRY *ce)
605e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
606e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	int spos;
607e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int labelidx;
60879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	STRUCT_ENTRY *jumpto;
609e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
61030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	/* To avoid const warnings */
61179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	STRUCT_ENTRY *e = (STRUCT_ENTRY *)ce;
61230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
61379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	if (strcmp(GET_TARGET(e)->u.user.name, STANDARD_TARGET) != 0)
61479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		return GET_TARGET(e)->u.user.name;
615e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
616e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Standard target: evaluate */
61779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	spos = *(int *)GET_TARGET(e)->data;
618e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (spos < 0) {
61979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		if (spos == RETURN)
62079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell			return LABEL_RETURN;
621e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		else if (spos == -NF_ACCEPT-1)
62279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell			return LABEL_ACCEPT;
623e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		else if (spos == -NF_DROP-1)
62479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell			return LABEL_DROP;
6252f4e5d92c73906e0dc2ae42fee5c05740528e92bJames Morris		else if (spos == -NF_QUEUE-1)
62667088e73ce7707229c56987868f112051defca5aRusty Russell			return LABEL_QUEUE;
627e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
628e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		fprintf(stderr, "ERROR: off %lu/%u not a valid target (%i)\n",
629e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			entry2offset(handle, e), handle->entries.size,
630e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			spos);
631e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		abort();
632e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
633e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
634e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	jumpto = get_entry(handle, spos);
635e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
636e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Fall through rule */
637e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (jumpto == (void *)e + e->next_offset)
638e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return "";
639e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
640e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Must point to head of a chain: ie. after error rule */
641e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	labelidx = entry2index(handle, jumpto) - 1;
642e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return get_errorlabel(handle, index2offset(handle, labelidx));
643e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
644e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
645e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Returns a pointer to the target name of this position. */
64679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellconst char *TC_GET_TARGET(const STRUCT_ENTRY *e,
64779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell			  TC_HANDLE_T *handle)
648e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
649e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return target_name(*handle, e);
650e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
651e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
652e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Is this a built-in chain?  Actually returns hook + 1. */
653e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
65479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_BUILTIN(const char *chain, const TC_HANDLE_T handle)
655e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
656e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int i;
657e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
65879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	for (i = 0; i < NUMHOOKS; i++) {
659e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if ((handle->info.valid_hooks & (1 << i))
660e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		    && handle->hooknames[i]
661e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		    && strcmp(handle->hooknames[i], chain) == 0)
662e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			return i+1;
663e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
664e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 0;
665e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
666e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
667e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Get the policy of a given built-in chain */
668e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherconst char *
66979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_GET_POLICY(const char *chain,
67079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	      STRUCT_COUNTERS *counters,
67179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	      TC_HANDLE_T *handle)
672e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
673e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int start;
67479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	STRUCT_ENTRY *e;
675e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	int hook;
676e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
67779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	hook = TC_BUILTIN(chain, *handle);
678e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (hook != 0)
679e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		start = (*handle)->info.hook_entry[hook-1];
680e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	else
681e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return NULL;
682e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
683e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	e = get_entry(*handle, get_chain_end(*handle, start));
684e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	*counters = e->counters;
685e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
686e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return target_name(*handle, e);
687e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
688e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
689e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic int
69079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellcorrect_verdict(STRUCT_ENTRY *e,
691725d97a79cf0b332ed45cb7d254915178328427dRusty Russell		char *base,
692e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		unsigned int offset, int delta_offset)
693e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
69479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	STRUCT_STANDARD_TARGET *t = (void *)GET_TARGET(e);
695725d97a79cf0b332ed45cb7d254915178328427dRusty Russell	unsigned int curr = (char *)e - base;
696e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
697e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Trap: insert of fall-through rule.  Don't change fall-through
698e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	   verdict to jump-over-next-rule. */
69979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	if (strcmp(t->target.u.user.name, STANDARD_TARGET) == 0
700e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    && t->verdict > (int)offset
701e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    && !(curr == offset &&
702e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		 t->verdict == curr + e->next_offset)) {
703e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		t->verdict += delta_offset;
704e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
705e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
706e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 0;
707e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
708e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
709e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Adjusts standard verdict jump positions after an insertion/deletion. */
710e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic int
71179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellset_verdict(unsigned int offset, int delta_offset, TC_HANDLE_T *handle)
712e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
713725d97a79cf0b332ed45cb7d254915178328427dRusty Russell	ENTRY_ITERATE((*handle)->entries.entrytable,
71479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		      (*handle)->entries.size,
715725d97a79cf0b332ed45cb7d254915178328427dRusty Russell		      correct_verdict, (char *)(*handle)->entries.entrytable,
71679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		      offset, delta_offset);
717e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
718175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell	set_changed(*handle);
719e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 1;
720e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
721e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
722e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* If prepend is set, then we are prepending to a chain: if the
723e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher * insertion position is an entry point, keep the entry point. */
724e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic int
725e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherinsert_rules(unsigned int num_rules, unsigned int rules_size,
72679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	     const STRUCT_ENTRY *insert,
727e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	     unsigned int offset, unsigned int num_rules_offset,
728e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	     int prepend,
72979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	     TC_HANDLE_T *handle)
730e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
73179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	TC_HANDLE_T newh;
73279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	STRUCT_GETINFO newinfo;
733e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int i;
734e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
735e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (offset >= (*handle)->entries.size) {
736e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EINVAL;
737e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
738e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
739e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
740e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	newinfo = (*handle)->info;
741e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
742e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Fix up entry points. */
74379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	for (i = 0; i < NUMHOOKS; i++) {
744e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		/* Entry points to START of chain, so keep same if
745e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher                   inserting on at that point. */
746e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if ((*handle)->info.hook_entry[i] > offset)
747e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			newinfo.hook_entry[i] += rules_size;
748e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
749e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		/* Underflow always points to END of chain (policy),
750e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		   so if something is inserted at same point, it
751e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		   should be advanced. */
752e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if ((*handle)->info.underflow[i] >= offset)
753e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			newinfo.underflow[i] += rules_size;
754e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
755e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
756e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	newh = alloc_handle((*handle)->info.name,
7573c7a6c479f3eccd65a78dc103f33f4085e8e4703Rusty Russell			    (*handle)->entries.size + rules_size,
7581de804642d4c8e9c71b7e225a1528fff15fa7faaHarald Welte			    (*handle)->new_number + num_rules);
759e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!newh)
760e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
761e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	newh->info = newinfo;
762e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
763e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Copy pre... */
764725d97a79cf0b332ed45cb7d254915178328427dRusty Russell	memcpy(newh->entries.entrytable, (*handle)->entries.entrytable,offset);
765e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* ... Insert new ... */
766725d97a79cf0b332ed45cb7d254915178328427dRusty Russell	memcpy((char *)newh->entries.entrytable + offset, insert, rules_size);
767e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* ... copy post */
768725d97a79cf0b332ed45cb7d254915178328427dRusty Russell	memcpy((char *)newh->entries.entrytable + offset + rules_size,
769725d97a79cf0b332ed45cb7d254915178328427dRusty Russell	       (char *)(*handle)->entries.entrytable + offset,
770e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       (*handle)->entries.size - offset);
771e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
772e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Move counter map. */
773e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Copy pre... */
774e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	memcpy(newh->counter_map, (*handle)->counter_map,
775e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       sizeof(struct counter_map) * num_rules_offset);
776e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* ... copy post */
777e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	memcpy(newh->counter_map + num_rules_offset + num_rules,
778e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       (*handle)->counter_map + num_rules_offset,
779e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       sizeof(struct counter_map) * ((*handle)->new_number
780e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher					     - num_rules_offset));
781e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Set intermediates to no counter copy */
782e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	for (i = 0; i < num_rules; i++)
783e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		newh->counter_map[num_rules_offset+i]
784e0072945b57dc499327567640648050563b19a5eHarald Welte			= ((struct counter_map){ COUNTER_MAP_SET, 0 });
785e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
786e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	newh->new_number = (*handle)->new_number + num_rules;
787e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	newh->entries.size = (*handle)->entries.size + rules_size;
788e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	newh->hooknames = (*handle)->hooknames;
789e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
79030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	if ((*handle)->cache_chain_heads)
79130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		free((*handle)->cache_chain_heads);
792e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	free(*handle);
793e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	*handle = newh;
794e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
795e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return set_verdict(offset, rules_size, handle);
796e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
797e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
798e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic int
799e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherdelete_rules(unsigned int num_rules, unsigned int rules_size,
800e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	     unsigned int offset, unsigned int num_rules_offset,
80179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	     TC_HANDLE_T *handle)
802e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
803e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int i;
804e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
805e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (offset + rules_size > (*handle)->entries.size) {
806e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EINVAL;
807e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
808e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
809e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
810e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Fix up entry points. */
81179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	for (i = 0; i < NUMHOOKS; i++) {
812e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		/* In practice, we never delete up to a hook entry,
813e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		   since the built-in chains are always first,
814e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		   so these two are never equal */
815e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if ((*handle)->info.hook_entry[i] >= offset + rules_size)
816e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			(*handle)->info.hook_entry[i] -= rules_size;
817e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		else if ((*handle)->info.hook_entry[i] > offset) {
818e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			fprintf(stderr, "ERROR: Deleting entry %u %u %u\n",
819e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				i, (*handle)->info.hook_entry[i], offset);
820e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			abort();
821e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		}
822e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
823e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		/* Underflow points to policy (terminal) rule in
824e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher                   built-in, so sequality is valid here (when deleting
825e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher                   the last rule). */
826e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if ((*handle)->info.underflow[i] >= offset + rules_size)
827e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			(*handle)->info.underflow[i] -= rules_size;
828e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		else if ((*handle)->info.underflow[i] > offset) {
829e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			fprintf(stderr, "ERROR: Deleting uflow %u %u %u\n",
830e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				i, (*handle)->info.underflow[i], offset);
831e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			abort();
832e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		}
833e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
834e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
835e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Move the rules down. */
836725d97a79cf0b332ed45cb7d254915178328427dRusty Russell	memmove((char *)(*handle)->entries.entrytable + offset,
837725d97a79cf0b332ed45cb7d254915178328427dRusty Russell		(char *)(*handle)->entries.entrytable + offset + rules_size,
838e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		(*handle)->entries.size - (offset + rules_size));
839e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
840e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Move the counter map down. */
841e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	memmove(&(*handle)->counter_map[num_rules_offset],
842e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		&(*handle)->counter_map[num_rules_offset + num_rules],
843e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		sizeof(struct counter_map)
844e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		* ((*handle)->new_number - (num_rules + num_rules_offset)));
845e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
846e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Fix numbers */
847e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	(*handle)->new_number -= num_rules;
848e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	(*handle)->entries.size -= rules_size;
849e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
850e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return set_verdict(offset, -(int)rules_size, handle);
851e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
852e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
853e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic int
85479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellstandard_map(STRUCT_ENTRY *e, int verdict)
855e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
85679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	STRUCT_STANDARD_TARGET *t;
857e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
85879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	t = (STRUCT_STANDARD_TARGET *)GET_TARGET(e);
859e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
86067088e73ce7707229c56987868f112051defca5aRusty Russell	if (t->target.u.target_size
8618c700900e2a0cf87d7917cb62578583a60ad1210Philip Blundell	    != ALIGN(sizeof(STRUCT_STANDARD_TARGET))) {
862e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EINVAL;
863e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
864e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
865e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* memset for memcmp convenience on delete/replace */
86679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	memset(t->target.u.user.name, 0, FUNCTION_MAXNAMELEN);
86779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	strcpy(t->target.u.user.name, STANDARD_TARGET);
868e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	t->verdict = verdict;
869e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
870e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 1;
871e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
8727e53bf9c2a697abdb6f1385557338423a86612a3Rusty Russell
873e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic int
87479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellmap_target(const TC_HANDLE_T handle,
87579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	   STRUCT_ENTRY *e,
876e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	   unsigned int offset,
87779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	   STRUCT_ENTRY_TARGET *old)
878e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
87979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	STRUCT_ENTRY_TARGET *t = GET_TARGET(e);
880e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
881e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Save old target (except data, which we don't change, except for
882e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	   standard case, where we don't care). */
883e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	*old = *t;
884e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
885e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Maybe it's empty (=> fall through) */
886228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell	if (strcmp(t->u.user.name, "") == 0)
887e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return standard_map(e, offset + e->next_offset);
888e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Maybe it's a standard target name... */
88979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	else if (strcmp(t->u.user.name, LABEL_ACCEPT) == 0)
890e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return standard_map(e, -NF_ACCEPT - 1);
89179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	else if (strcmp(t->u.user.name, LABEL_DROP) == 0)
892e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return standard_map(e, -NF_DROP - 1);
89367088e73ce7707229c56987868f112051defca5aRusty Russell	else if (strcmp(t->u.user.name, LABEL_QUEUE) == 0)
894e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return standard_map(e, -NF_QUEUE - 1);
89579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	else if (strcmp(t->u.user.name, LABEL_RETURN) == 0)
89679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		return standard_map(e, RETURN);
89779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	else if (TC_BUILTIN(t->u.user.name, handle)) {
898e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		/* Can't jump to builtins. */
899e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EINVAL;
900e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
901e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	} else {
902e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		/* Maybe it's an existing chain name. */
90330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		struct chain_cache *c;
904e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
905228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell		c = find_label(t->u.user.name, handle);
90630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		if (c)
90730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell			return standard_map(e, entry2offset(handle, c->start));
908e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
909e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
910e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Must be a module?  If not, kernel will reject... */
911e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* memset to all 0 for your memcmp convenience. */
912228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell	memset(t->u.user.name + strlen(t->u.user.name),
913e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       0,
91479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	       FUNCTION_MAXNAMELEN - strlen(t->u.user.name));
915e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 1;
916e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
917e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
918e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic void
91979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellunmap_target(STRUCT_ENTRY *e, STRUCT_ENTRY_TARGET *old)
920e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
92179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	STRUCT_ENTRY_TARGET *t = GET_TARGET(e);
922e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
923e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Save old target (except data, which we don't change, except for
924e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	   standard case, where we don't care). */
925e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	*t = *old;
926e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
927e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
928e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Insert the entry `fw' in chain `chain' into position `rulenum'. */
929e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
93079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_INSERT_ENTRY(const IPT_CHAINLABEL chain,
93179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		const STRUCT_ENTRY *e,
93279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		unsigned int rulenum,
93379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		TC_HANDLE_T *handle)
934e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
93530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	unsigned int chainindex, offset;
93679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	STRUCT_ENTRY_TARGET old;
93730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	struct chain_cache *c;
93814a1c9175257f73e936a68ba68d3541278c0e52aRusty Russell	STRUCT_ENTRY *tmp;
939e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	int ret;
940e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
94179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	iptc_fn = TC_INSERT_ENTRY;
94230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	if (!(c = find_label(chain, *handle))) {
943e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
944e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
945e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
946e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
94730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	chainindex = entry2index(*handle, c->start);
948e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
94914a1c9175257f73e936a68ba68d3541278c0e52aRusty Russell	tmp = index2entry(*handle, chainindex + rulenum);
95014a1c9175257f73e936a68ba68d3541278c0e52aRusty Russell	if (!tmp || tmp > c->end) {
951e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = E2BIG;
952e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
953e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
954e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	offset = index2offset(*handle, chainindex + rulenum);
955e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
956e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Mapping target actually alters entry, but that's
957e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher           transparent to the caller. */
95879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	if (!map_target(*handle, (STRUCT_ENTRY *)e, offset, &old))
959e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
960e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
961e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	ret = insert_rules(1, e->next_offset, e, offset,
962e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			   chainindex + rulenum, rulenum == 0, handle);
96379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	unmap_target((STRUCT_ENTRY *)e, &old);
964e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return ret;
965e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
966e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
967e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Atomically replace rule `rulenum' in `chain' with `fw'. */
968e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
96979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_REPLACE_ENTRY(const IPT_CHAINLABEL chain,
97079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		 const STRUCT_ENTRY *e,
97179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		 unsigned int rulenum,
97279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		 TC_HANDLE_T *handle)
973e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
97430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	unsigned int chainindex, offset;
97579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	STRUCT_ENTRY_TARGET old;
97630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	struct chain_cache *c;
97714a1c9175257f73e936a68ba68d3541278c0e52aRusty Russell	STRUCT_ENTRY *tmp;
978e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	int ret;
979e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
98079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	iptc_fn = TC_REPLACE_ENTRY;
981e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
98230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	if (!(c = find_label(chain, *handle))) {
983e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
984e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
985e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
986e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
98730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	chainindex = entry2index(*handle, c->start);
988e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
98914a1c9175257f73e936a68ba68d3541278c0e52aRusty Russell	tmp = index2entry(*handle, chainindex + rulenum);
99014a1c9175257f73e936a68ba68d3541278c0e52aRusty Russell	if (!tmp || tmp >= c->end) {
991e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = E2BIG;
992e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
993e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
994e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
995e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	offset = index2offset(*handle, chainindex + rulenum);
996e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Replace = delete and insert. */
997e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!delete_rules(1, get_entry(*handle, offset)->next_offset,
998e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			  offset, chainindex + rulenum, handle))
999e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1000e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
100179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	if (!map_target(*handle, (STRUCT_ENTRY *)e, offset, &old))
1002e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1003e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1004e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	ret = insert_rules(1, e->next_offset, e, offset,
1005e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			   chainindex + rulenum, 1, handle);
100679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	unmap_target((STRUCT_ENTRY *)e, &old);
1007e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return ret;
1008e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1009e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1010e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Append entry `fw' to chain `chain'.  Equivalent to insert with
1011e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher   rulenum = length of chain. */
1012e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
101379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_APPEND_ENTRY(const IPT_CHAINLABEL chain,
101479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		const STRUCT_ENTRY *e,
101579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		TC_HANDLE_T *handle)
1016e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
101730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	struct chain_cache *c;
101879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	STRUCT_ENTRY_TARGET old;
1019e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	int ret;
1020e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
102179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	iptc_fn = TC_APPEND_ENTRY;
102230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	if (!(c = find_label(chain, *handle))) {
1023e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
1024e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1025e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1026e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
102779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	if (!map_target(*handle, (STRUCT_ENTRY *)e,
102830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell			entry2offset(*handle, c->end), &old))
1029e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1030e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
103130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	ret = insert_rules(1, e->next_offset, e,
103230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell			   entry2offset(*handle, c->end),
103330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell			   entry2index(*handle, c->end),
1034e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			   0, handle);
103579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	unmap_target((STRUCT_ENTRY *)e, &old);
1036e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return ret;
1037e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1038e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1039e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic inline int
104079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellmatch_different(const STRUCT_ENTRY_MATCH *a,
1041edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell		const unsigned char *a_elems,
1042edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell		const unsigned char *b_elems,
1043edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell		unsigned char **maskptr)
1044e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
104579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	const STRUCT_ENTRY_MATCH *b;
1046edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell	unsigned int i;
1047e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1048e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Offset of b is the same as a. */
104930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	b = (void *)b_elems + ((unsigned char *)a - a_elems);
1050e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1051228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell	if (a->u.match_size != b->u.match_size)
1052e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 1;
1053e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1054228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell	if (strcmp(a->u.user.name, b->u.user.name) != 0)
1055e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 1;
1056e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
105773ef09b21573ddb17ff75e5fd06fd4b52ec8ea40Rusty Russell	*maskptr += ALIGN(sizeof(*a));
1058edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell
105973ef09b21573ddb17ff75e5fd06fd4b52ec8ea40Rusty Russell	for (i = 0; i < a->u.match_size - ALIGN(sizeof(*a)); i++)
1060edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell		if (((a->data[i] ^ b->data[i]) & (*maskptr)[i]) != 0)
1061edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell			return 1;
1062edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell	*maskptr += i;
1063edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell	return 0;
1064edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell}
1065edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell
1066edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russellstatic inline int
1067edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russelltarget_different(const unsigned char *a_targdata,
1068edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell		 const unsigned char *b_targdata,
1069edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell		 unsigned int tdatasize,
1070edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell		 const unsigned char *mask)
1071edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell{
1072edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell	unsigned int i;
1073edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell	for (i = 0; i < tdatasize; i++)
1074edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell		if (((a_targdata[i] ^ b_targdata[i]) & mask[i]) != 0)
107590e712a00913fe2a2f885142439c392392dc08a8Rusty Russell			return 1;
1076e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1077e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 0;
1078e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1079e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
108079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellstatic int
108179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellis_same(const STRUCT_ENTRY *a,
108279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	const STRUCT_ENTRY *b,
108379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	unsigned char *matchmask);
1084e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1085e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Delete the first rule in `chain' which matches `fw'. */
1086e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
108779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_DELETE_ENTRY(const IPT_CHAINLABEL chain,
108879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		const STRUCT_ENTRY *origfw,
108979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		unsigned char *matchmask,
109079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		TC_HANDLE_T *handle)
1091e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
109230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	unsigned int offset;
109330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	struct chain_cache *c;
109479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	STRUCT_ENTRY *e, *fw;
1095e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
109679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	iptc_fn = TC_DELETE_ENTRY;
109730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	if (!(c = find_label(chain, *handle))) {
1098e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
1099e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1100e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1101e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1102e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	fw = malloc(origfw->next_offset);
1103e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (fw == NULL) {
1104e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOMEM;
1105e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1106e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1107e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
110830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	for (offset = entry2offset(*handle, c->start);
110930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	     offset < entry2offset(*handle, c->end);
111030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	     offset += e->next_offset) {
111179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		STRUCT_ENTRY_TARGET discard;
1112e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1113e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		memcpy(fw, origfw, origfw->next_offset);
1114e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1115e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		/* FIXME: handle this in is_same --RR */
1116e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (!map_target(*handle, fw, offset, &discard)) {
1117e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			free(fw);
1118e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			return 0;
1119e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		}
1120e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		e = get_entry(*handle, offset);
1121e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1122e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#if 0
1123e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		printf("Deleting:\n");
1124e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		dump_entry(newe);
1125e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#endif
1126edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell		if (is_same(e, fw, matchmask)) {
1127e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			int ret;
1128e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			ret = delete_rules(1, e->next_offset,
1129e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher					   offset, entry2index(*handle, e),
1130e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher					   handle);
1131e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			free(fw);
1132e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			return ret;
1133e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		}
1134e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1135e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1136e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	free(fw);
1137e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	errno = ENOENT;
1138e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 0;
11397e53bf9c2a697abdb6f1385557338423a86612a3Rusty Russell}
1140e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1141e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Delete the rule in position `rulenum' in `chain'. */
1142e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
114379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_DELETE_NUM_ENTRY(const IPT_CHAINLABEL chain,
114479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		    unsigned int rulenum,
114579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		    TC_HANDLE_T *handle)
1146e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1147e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int index;
1148e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	int ret;
114979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	STRUCT_ENTRY *e;
115030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	struct chain_cache *c;
1151e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
115279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	iptc_fn = TC_DELETE_NUM_ENTRY;
115330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	if (!(c = find_label(chain, *handle))) {
1154e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
1155e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1156e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1157e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
115830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	index = entry2index(*handle, c->start) + rulenum;
1159e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
116030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	if (index >= entry2index(*handle, c->end)) {
1161e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = E2BIG;
1162e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1163e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1164e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1165e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	e = index2entry(*handle, index);
1166e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (e == NULL) {
1167e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EINVAL;
1168e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1169e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1170e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1171e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	ret = delete_rules(1, e->next_offset, entry2offset(*handle, e),
1172e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			   index, handle);
1173e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return ret;
1174e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1175e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1176e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Check the packet `fw' on chain `chain'.  Returns the verdict, or
1177e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher   NULL and sets errno. */
1178e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherconst char *
117979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_CHECK_PACKET(const IPT_CHAINLABEL chain,
118079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		STRUCT_ENTRY *entry,
118179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		TC_HANDLE_T *handle)
1182e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1183e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	errno = ENOSYS;
1184e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return NULL;
1185e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1186e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1187e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Flushes the entries in the given chain (ie. empties chain). */
1188e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
118979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_FLUSH_ENTRIES(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle)
1190e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
119130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	unsigned int startindex, endindex;
119230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	struct chain_cache *c;
1193e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	int ret;
1194e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
119579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	iptc_fn = TC_FLUSH_ENTRIES;
119630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	if (!(c = find_label(chain, *handle))) {
1197e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
1198e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1199e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
120030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	startindex = entry2index(*handle, c->start);
120130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	endindex = entry2index(*handle, c->end);
1202e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1203e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	ret = delete_rules(endindex - startindex,
120430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell			   (char *)c->end - (char *)c->start,
120530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell			   entry2offset(*handle, c->start), startindex,
1206e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			   handle);
1207e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return ret;
1208e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1209e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1210e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Zeroes the counters in a chain. */
1211e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
121279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_ZERO_ENTRIES(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle)
1213e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1214e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int i, end;
121530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	struct chain_cache *c;
12167e53bf9c2a697abdb6f1385557338423a86612a3Rusty Russell
121730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	if (!(c = find_label(chain, *handle))) {
1218e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
1219e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1220e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1221e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
122230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	i = entry2index(*handle, c->start);
122330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	end = entry2index(*handle, c->end);
1224e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1225e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	for (; i <= end; i++) {
1226e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if ((*handle)->counter_map[i].maptype ==COUNTER_MAP_NORMAL_MAP)
1227e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			(*handle)->counter_map[i].maptype = COUNTER_MAP_ZEROED;
1228e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1229175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell	set_changed(*handle);
1230e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1231e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 1;
1232e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1233e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
12341cef74d943055668b5e356eebea877fdaa1ce3e0Harald WelteSTRUCT_COUNTERS *
12351cef74d943055668b5e356eebea877fdaa1ce3e0Harald WelteTC_READ_COUNTER(const IPT_CHAINLABEL chain,
12361cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		unsigned int rulenum,
12371cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		TC_HANDLE_T *handle)
12381cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte{
12391cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	STRUCT_ENTRY *e;
12401cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	struct chain_cache *c;
12411cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	unsigned int chainindex, end;
12421cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
12431cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	iptc_fn = TC_READ_COUNTER;
12441cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	CHECK(*handle);
12451cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
12461cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	if (!(c = find_label(chain, *handle))) {
12471cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		errno = ENOENT;
12481cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		return NULL;
12491cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	}
12501cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
12511cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	chainindex = entry2index(*handle, c->start);
12521cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	end = entry2index(*handle, c->end);
12531cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
12541cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	if (chainindex + rulenum > end) {
12551cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		errno = E2BIG;
12561cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		return NULL;
12571cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	}
12581cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
12591cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	e = index2entry(*handle, chainindex + rulenum);
12601cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
12611cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	return &e->counters;
12621cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte}
12631cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
12641cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welteint
12651cef74d943055668b5e356eebea877fdaa1ce3e0Harald WelteTC_ZERO_COUNTER(const IPT_CHAINLABEL chain,
12661cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		unsigned int rulenum,
12671cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		TC_HANDLE_T *handle)
12681cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte{
12691cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	STRUCT_ENTRY *e;
12701cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	struct chain_cache *c;
12711cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	unsigned int chainindex, end;
12721cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
12731cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	iptc_fn = TC_ZERO_COUNTER;
12741cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	CHECK(*handle);
12751cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
12761cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	if (!(c = find_label(chain, *handle))) {
12771cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		errno = ENOENT;
12781cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		return 0;
12791cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	}
12801cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
12811cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	chainindex = entry2index(*handle, c->start);
12821cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	end = entry2index(*handle, c->end);
12831cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
12841cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	if (chainindex + rulenum > end) {
12851cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		errno = E2BIG;
12861cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		return 0;
12871cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	}
12881cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
12891cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	e = index2entry(*handle, chainindex + rulenum);
12901cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
12911cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	if ((*handle)->counter_map[chainindex + rulenum].maptype
12921cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte			== COUNTER_MAP_NORMAL_MAP) {
12931cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		(*handle)->counter_map[chainindex + rulenum].maptype
12941cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte			 = COUNTER_MAP_ZEROED;
12951cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	}
12961cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
12971cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	set_changed(*handle);
12981cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
12991cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	return 1;
13001cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte}
13011cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
13021cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welteint
13031cef74d943055668b5e356eebea877fdaa1ce3e0Harald WelteTC_SET_COUNTER(const IPT_CHAINLABEL chain,
13041cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	       unsigned int rulenum,
13051cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	       STRUCT_COUNTERS *counters,
13061cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	       TC_HANDLE_T *handle)
13071cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte{
13081cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	STRUCT_ENTRY *e;
13091cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	struct chain_cache *c;
13101cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	unsigned int chainindex, end;
13111cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
13121cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	iptc_fn = TC_SET_COUNTER;
13131cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	CHECK(*handle);
13141cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
13151cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	if (!(c = find_label(chain, *handle))) {
13161cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		errno = ENOENT;
13171cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		return 0;
13181cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	}
13191cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
13201cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	chainindex = entry2index(*handle, c->start);
13211cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	end = entry2index(*handle, c->end);
13221cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
13231cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	if (chainindex + rulenum > end) {
13241cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		errno = E2BIG;
13251cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		return 0;
13261cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	}
13271cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
13281cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	e = index2entry(*handle, chainindex + rulenum);
13291cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
13301cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	(*handle)->counter_map[chainindex + rulenum].maptype
13311cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		= COUNTER_MAP_SET;
13321cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
13331cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	memcpy(&e->counters, counters, sizeof(STRUCT_COUNTERS));
13341cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
13351cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	set_changed(*handle);
13361cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
13371cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	return 1;
13381cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte}
13391cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
1340e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Creates a new chain. */
1341e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* To create a chain, create two rules: error node and unconditional
1342e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher * return. */
1343e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
134479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_CREATE_CHAIN(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle)
1345e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1346e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	int ret;
1347e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct {
134879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		STRUCT_ENTRY head;
1349e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		struct ipt_error_target name;
135079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		STRUCT_ENTRY ret;
135179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		STRUCT_STANDARD_TARGET target;
1352e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	} newc;
1353e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
135479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	iptc_fn = TC_CREATE_CHAIN;
1355e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1356e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* find_label doesn't cover built-in targets: DROP, ACCEPT,
1357e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher           QUEUE, RETURN. */
135830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	if (find_label(chain, *handle)
135979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    || strcmp(chain, LABEL_DROP) == 0
136079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    || strcmp(chain, LABEL_ACCEPT) == 0
136167088e73ce7707229c56987868f112051defca5aRusty Russell	    || strcmp(chain, LABEL_QUEUE) == 0
136279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    || strcmp(chain, LABEL_RETURN) == 0) {
1363e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EEXIST;
1364e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1365e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1366e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
136779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	if (strlen(chain)+1 > sizeof(IPT_CHAINLABEL)) {
1368e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EINVAL;
1369e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1370e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1371e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1372e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	memset(&newc, 0, sizeof(newc));
137379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	newc.head.target_offset = sizeof(STRUCT_ENTRY);
1374e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	newc.head.next_offset
137567088e73ce7707229c56987868f112051defca5aRusty Russell		= sizeof(STRUCT_ENTRY)
13768c700900e2a0cf87d7917cb62578583a60ad1210Philip Blundell		+ ALIGN(sizeof(struct ipt_error_target));
137767088e73ce7707229c56987868f112051defca5aRusty Russell	strcpy(newc.name.t.u.user.name, ERROR_TARGET);
13788c700900e2a0cf87d7917cb62578583a60ad1210Philip Blundell	newc.name.t.u.target_size = ALIGN(sizeof(struct ipt_error_target));
1379e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	strcpy(newc.name.error, chain);
1380e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
138179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	newc.ret.target_offset = sizeof(STRUCT_ENTRY);
1382e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	newc.ret.next_offset
138367088e73ce7707229c56987868f112051defca5aRusty Russell		= sizeof(STRUCT_ENTRY)
13848c700900e2a0cf87d7917cb62578583a60ad1210Philip Blundell		+ ALIGN(sizeof(STRUCT_STANDARD_TARGET));
138579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	strcpy(newc.target.target.u.user.name, STANDARD_TARGET);
138667088e73ce7707229c56987868f112051defca5aRusty Russell	newc.target.target.u.target_size
13878c700900e2a0cf87d7917cb62578583a60ad1210Philip Blundell		= ALIGN(sizeof(STRUCT_STANDARD_TARGET));
138879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	newc.target.verdict = RETURN;
1389e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1390e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Add just before terminal entry */
1391e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	ret = insert_rules(2, sizeof(newc), &newc.head,
1392e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			   index2offset(*handle, (*handle)->new_number - 1),
1393e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			   (*handle)->new_number - 1,
1394e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			   0, handle);
1395e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return ret;
1396e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1397e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1398e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic int
139979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellcount_ref(STRUCT_ENTRY *e, unsigned int offset, unsigned int *ref)
1400e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
140179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	STRUCT_STANDARD_TARGET *t;
1402e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
140379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	if (strcmp(GET_TARGET(e)->u.user.name, STANDARD_TARGET) == 0) {
140479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		t = (STRUCT_STANDARD_TARGET *)GET_TARGET(e);
1405e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1406e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (t->verdict == offset)
1407e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			(*ref)++;
1408e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1409e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1410e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 0;
1411e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1412e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1413e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Get the number of references to this chain. */
1414e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
141579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_GET_REFERENCES(unsigned int *ref, const IPT_CHAINLABEL chain,
141679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		  TC_HANDLE_T *handle)
1417e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
141830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	struct chain_cache *c;
1419e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
142030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	if (!(c = find_label(chain, *handle))) {
1421e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
1422e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1423e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1424e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1425e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	*ref = 0;
1426725d97a79cf0b332ed45cb7d254915178328427dRusty Russell	ENTRY_ITERATE((*handle)->entries.entrytable,
142779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		      (*handle)->entries.size,
142879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		      count_ref, entry2offset(*handle, c->start), ref);
1429e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 1;
1430e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1431e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1432e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Deletes a chain. */
1433e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
143479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_DELETE_CHAIN(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle)
1435e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
143630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	unsigned int labelidx, labeloff;
1437e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int references;
143830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	struct chain_cache *c;
1439e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	int ret;
1440e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
144179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	if (!TC_GET_REFERENCES(&references, chain, handle))
1442e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
14437e53bf9c2a697abdb6f1385557338423a86612a3Rusty Russell
144479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	iptc_fn = TC_DELETE_CHAIN;
1445e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
144679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	if (TC_BUILTIN(chain, *handle)) {
1447e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EINVAL;
1448e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1449e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1450e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1451e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (references > 0) {
1452e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EMLINK;
1453e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1454e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1455e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
145630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	if (!(c = find_label(chain, *handle))) {
1457e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
1458e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1459e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1460e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
146130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	if ((void *)c->start != c->end) {
1462e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOTEMPTY;
1463e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1464e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1465e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1466e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Need label index: preceeds chain start */
146730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	labelidx = entry2index(*handle, c->start) - 1;
1468e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	labeloff = index2offset(*handle, labelidx);
1469e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1470e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	ret = delete_rules(2,
1471e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			   get_entry(*handle, labeloff)->next_offset
147230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell			   + c->start->next_offset,
1473e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			   labeloff, labelidx, handle);
1474e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return ret;
1475e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1476e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1477e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Renames a chain. */
147879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellint TC_RENAME_CHAIN(const IPT_CHAINLABEL oldname,
147979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		    const IPT_CHAINLABEL newname,
148079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		    TC_HANDLE_T *handle)
1481e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
148230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	unsigned int labeloff, labelidx;
148330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	struct chain_cache *c;
1484e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ipt_error_target *t;
1485e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
148679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	iptc_fn = TC_RENAME_CHAIN;
1487e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
14881de804642d4c8e9c71b7e225a1528fff15fa7faaHarald Welte	/* find_label doesn't cover built-in targets: DROP, ACCEPT,
14891de804642d4c8e9c71b7e225a1528fff15fa7faaHarald Welte           QUEUE, RETURN. */
149030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	if (find_label(newname, *handle)
149179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    || strcmp(newname, LABEL_DROP) == 0
149279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    || strcmp(newname, LABEL_ACCEPT) == 0
14931de804642d4c8e9c71b7e225a1528fff15fa7faaHarald Welte	    || strcmp(newname, LABEL_QUEUE) == 0
149479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    || strcmp(newname, LABEL_RETURN) == 0) {
1495e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EEXIST;
1496e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1497e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1498e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
149930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	if (!(c = find_label(oldname, *handle))
150079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    || TC_BUILTIN(oldname, *handle)) {
1501e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
1502e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1503e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1504e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
150579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	if (strlen(newname)+1 > sizeof(IPT_CHAINLABEL)) {
1506e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EINVAL;
1507e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1508e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1509e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1510e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Need label index: preceeds chain start */
151130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	labelidx = entry2index(*handle, c->start) - 1;
1512e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	labeloff = index2offset(*handle, labelidx);
1513e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1514e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	t = (struct ipt_error_target *)
151579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		GET_TARGET(get_entry(*handle, labeloff));
1516e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1517e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	memset(t->error, 0, sizeof(t->error));
1518e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	strcpy(t->error, newname);
1519175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell	set_changed(*handle);
1520e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1521e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 1;
1522e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1523e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1524e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Sets the policy on a built-in chain. */
1525e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
152679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_SET_POLICY(const IPT_CHAINLABEL chain,
152779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	      const IPT_CHAINLABEL policy,
15281cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	      STRUCT_COUNTERS *counters,
152979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	      TC_HANDLE_T *handle)
1530e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1531e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int hook;
15321cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	unsigned int policyoff, ctrindex;
153379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	STRUCT_ENTRY *e;
153479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	STRUCT_STANDARD_TARGET *t;
1535e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
153679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	iptc_fn = TC_SET_POLICY;
1537e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Figure out which chain. */
153879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	hook = TC_BUILTIN(chain, *handle);
1539e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (hook == 0) {
1540c8264991454b5e77279830736f80ea3153b6f814Marc Boucher		errno = ENOENT;
1541e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1542e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	} else
1543e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		hook--;
1544e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1545e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	policyoff = get_chain_end(*handle, (*handle)->info.hook_entry[hook]);
1546e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (policyoff != (*handle)->info.underflow[hook]) {
1547e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		printf("ERROR: Policy for `%s' offset %u != underflow %u\n",
1548e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		       chain, policyoff, (*handle)->info.underflow[hook]);
1549e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1550e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1551e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1552e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	e = get_entry(*handle, policyoff);
155379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	t = (STRUCT_STANDARD_TARGET *)GET_TARGET(e);
1554e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
155579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	if (strcmp(policy, LABEL_ACCEPT) == 0)
1556e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		t->verdict = -NF_ACCEPT - 1;
155779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	else if (strcmp(policy, LABEL_DROP) == 0)
1558e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		t->verdict = -NF_DROP - 1;
1559e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	else {
1560e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EINVAL;
1561e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1562e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
15631cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
15641cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	ctrindex = entry2index(*handle, e);
15651cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
15661cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	if (counters) {
15671cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		/* set byte and packet counters */
15681cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		memcpy(&e->counters, counters, sizeof(STRUCT_COUNTERS));
15691cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
15701cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		(*handle)->counter_map[ctrindex].maptype
15711cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte			= COUNTER_MAP_SET;
15721cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
15731cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	} else {
15741cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		(*handle)->counter_map[ctrindex]
15751cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte			= ((struct counter_map){ COUNTER_MAP_NOMAP, 0 });
15761cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	}
15771cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
1578175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell	set_changed(*handle);
1579e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1580e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 1;
1581e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1582e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1583e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Without this, on gcc 2.7.2.3, we get:
158479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell   libiptc.c: In function `TC_COMMIT':
1585e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher   libiptc.c:833: fixed or forbidden register was spilled.
1586e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher   This may be due to a compiler bug or to impossible asm
1587e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher   statements or clauses.
1588e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher*/
1589e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic void
159079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellsubtract_counters(STRUCT_COUNTERS *answer,
159179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		  const STRUCT_COUNTERS *a,
159279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		  const STRUCT_COUNTERS *b)
1593e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1594e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	answer->pcnt = a->pcnt - b->pcnt;
1595e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	answer->bcnt = a->bcnt - b->bcnt;
1596e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1597e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1598e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
159979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_COMMIT(TC_HANDLE_T *handle)
1600e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1601e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Replace, then map back the counters. */
160279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	STRUCT_REPLACE *repl;
160379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	STRUCT_COUNTERS_INFO *newcounters;
1604e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int i;
1605841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson	size_t counterlen;
1606e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1607e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	CHECK(*handle);
1608841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson
1609841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson	counterlen = sizeof(STRUCT_COUNTERS_INFO)
1610841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson			+ sizeof(STRUCT_COUNTERS) * (*handle)->new_number;
1611841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson
1612e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#if 0
161354c307e0ff401f40a6fe382af4ae5bff0f5b40baRusty Russell	TC_DUMP_ENTRIES(*handle);
1614e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#endif
1615e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1616e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Don't commit if nothing changed. */
1617e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!(*handle)->changed)
1618e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		goto finished;
1619e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1620e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	repl = malloc(sizeof(*repl) + (*handle)->entries.size);
1621e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!repl) {
1622e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOMEM;
1623e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1624e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1625e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1626e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* These are the old counters we will get from kernel */
162779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	repl->counters = malloc(sizeof(STRUCT_COUNTERS)
1628e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				* (*handle)->info.num_entries);
1629e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!repl->counters) {
1630e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		free(repl);
1631e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOMEM;
1632e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1633e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
16347e53bf9c2a697abdb6f1385557338423a86612a3Rusty Russell
1635e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* These are the counters we're going to put back, later. */
1636e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	newcounters = malloc(counterlen);
1637e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!newcounters) {
1638e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		free(repl->counters);
1639e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		free(repl);
1640e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOMEM;
1641e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1642e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1643e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1644e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	strcpy(repl->name, (*handle)->info.name);
1645e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	repl->num_entries = (*handle)->new_number;
1646e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	repl->size = (*handle)->entries.size;
1647e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	memcpy(repl->hook_entry, (*handle)->info.hook_entry,
1648e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       sizeof(repl->hook_entry));
1649e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	memcpy(repl->underflow, (*handle)->info.underflow,
1650e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       sizeof(repl->underflow));
1651e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	repl->num_counters = (*handle)->info.num_entries;
1652e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	repl->valid_hooks = (*handle)->info.valid_hooks;
1653725d97a79cf0b332ed45cb7d254915178328427dRusty Russell	memcpy(repl->entries, (*handle)->entries.entrytable,
1654e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       (*handle)->entries.size);
1655e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
165679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	if (setsockopt(sockfd, TC_IPPROTO, SO_SET_REPLACE, repl,
1657e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		       sizeof(*repl) + (*handle)->entries.size) < 0) {
1658e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		free(repl->counters);
1659e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		free(repl);
1660e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		free(newcounters);
1661e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1662e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1663e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1664e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Put counters back. */
1665e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	strcpy(newcounters->name, (*handle)->info.name);
1666e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	newcounters->num_counters = (*handle)->new_number;
1667e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	for (i = 0; i < (*handle)->new_number; i++) {
1668e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		unsigned int mappos = (*handle)->counter_map[i].mappos;
1669e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		switch ((*handle)->counter_map[i].maptype) {
1670e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		case COUNTER_MAP_NOMAP:
1671e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			newcounters->counters[i]
167279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell				= ((STRUCT_COUNTERS){ 0, 0 });
1673e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			break;
1674e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1675e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		case COUNTER_MAP_NORMAL_MAP:
1676e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			/* Original read: X.
1677e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			 * Atomic read on replacement: X + Y.
1678e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			 * Currently in kernel: Z.
1679e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			 * Want in kernel: X + Y + Z.
1680e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			 * => Add in X + Y
1681e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			 * => Add in replacement read.
1682e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			 */
1683e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			newcounters->counters[i] = repl->counters[mappos];
1684e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			break;
1685e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1686e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		case COUNTER_MAP_ZEROED:
1687e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			/* Original read: X.
1688e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			 * Atomic read on replacement: X + Y.
1689e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			 * Currently in kernel: Z.
1690e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			 * Want in kernel: Y + Z.
1691e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			 * => Add in Y.
1692e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			 * => Add in (replacement read - original read).
1693e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			 */
1694e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			subtract_counters(&newcounters->counters[i],
1695e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher					  &repl->counters[mappos],
1696e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher					  &index2entry(*handle, i)->counters);
1697e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			break;
16981cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
16991cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		case COUNTER_MAP_SET:
17001cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte			/* Want to set counter (iptables-restore) */
17011cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
17021cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte			memcpy(&newcounters->counters[i],
17031cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte			       &index2entry(*handle, i)->counters,
17041cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte			       sizeof(STRUCT_COUNTERS));
17051cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
17061cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte			break;
1707e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		}
1708e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
170962527ce5f0ffaa5b18aa118f64c21af238ddc156Rusty Russell
171062527ce5f0ffaa5b18aa118f64c21af238ddc156Rusty Russell#ifdef KERNEL_64_USERSPACE_32
171162527ce5f0ffaa5b18aa118f64c21af238ddc156Rusty Russell	{
171262527ce5f0ffaa5b18aa118f64c21af238ddc156Rusty Russell		/* Kernel will think that pointer should be 64-bits, and get
171362527ce5f0ffaa5b18aa118f64c21af238ddc156Rusty Russell		   padding.  So we accomodate here (assumption: alignment of
171462527ce5f0ffaa5b18aa118f64c21af238ddc156Rusty Russell		   `counters' is on 64-bit boundary). */
171562527ce5f0ffaa5b18aa118f64c21af238ddc156Rusty Russell		u_int64_t *kernptr = (u_int64_t *)&newcounters->counters;
171662527ce5f0ffaa5b18aa118f64c21af238ddc156Rusty Russell		if ((unsigned long)&newcounters->counters % 8 != 0) {
171762527ce5f0ffaa5b18aa118f64c21af238ddc156Rusty Russell			fprintf(stderr,
171862527ce5f0ffaa5b18aa118f64c21af238ddc156Rusty Russell				"counters alignment incorrect! Mail rusty!\n");
171962527ce5f0ffaa5b18aa118f64c21af238ddc156Rusty Russell			abort();
172062527ce5f0ffaa5b18aa118f64c21af238ddc156Rusty Russell		}
172162527ce5f0ffaa5b18aa118f64c21af238ddc156Rusty Russell		*kernptr = newcounters->counters;
172254c307e0ff401f40a6fe382af4ae5bff0f5b40baRusty Russell	}
172362527ce5f0ffaa5b18aa118f64c21af238ddc156Rusty Russell#endif /* KERNEL_64_USERSPACE_32 */
1724e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
172579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	if (setsockopt(sockfd, TC_IPPROTO, SO_SET_ADD_COUNTERS,
172679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		       newcounters, counterlen) < 0) {
1727e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		free(repl->counters);
1728e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		free(repl);
1729e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		free(newcounters);
1730e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1731e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1732e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1733e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	free(repl->counters);
1734e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	free(repl);
1735e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	free(newcounters);
1736e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1737e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher finished:
1738841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson	TC_FREE(handle);
1739e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 1;
1740e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1741e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1742e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Get raw socket. */
1743e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
174479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_GET_RAW_SOCKET()
1745e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1746e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return sockfd;
1747e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1748e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1749e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Translates errno numbers into more human-readable form than strerror. */
1750e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherconst char *
175179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_STRERROR(int err)
1752e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1753e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int i;
1754e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct table_struct {
1755e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		void *fn;
1756e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		int err;
1757e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		const char *message;
1758e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	} table [] =
17594ccfa630d9a588d4b852abef8bc467642427c8cfHarald Welte	  { { TC_INIT, EPERM, "Permission denied (you must be root)" },
176079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_INIT, EINVAL, "Module is wrong version" },
17614ccfa630d9a588d4b852abef8bc467642427c8cfHarald Welte	    { TC_INIT, ENOENT,
17624ccfa630d9a588d4b852abef8bc467642427c8cfHarald Welte		    "Table does not exist (do you need to insmod?)" },
176379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_DELETE_CHAIN, ENOTEMPTY, "Chain is not empty" },
176479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_DELETE_CHAIN, EINVAL, "Can't delete built-in chain" },
176579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_DELETE_CHAIN, EMLINK,
1766e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	      "Can't delete chain with references left" },
176779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_CREATE_CHAIN, EEXIST, "Chain already exists" },
176879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_INSERT_ENTRY, E2BIG, "Index of insertion too big" },
176979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_REPLACE_ENTRY, E2BIG, "Index of replacement too big" },
177079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_DELETE_NUM_ENTRY, E2BIG, "Index of deletion too big" },
17711cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	    { TC_READ_COUNTER, E2BIG, "Index of counter too big" },
17721cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	    { TC_ZERO_COUNTER, E2BIG, "Index of counter too big" },
177379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_INSERT_ENTRY, ELOOP, "Loop found in table" },
177479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_INSERT_ENTRY, EINVAL, "Target problem" },
1775e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    /* EINVAL for CHECK probably means bad interface. */
177679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_CHECK_PACKET, EINVAL,
1777c8264991454b5e77279830736f80ea3153b6f814Marc Boucher	      "Bad arguments (does that interface exist?)" },
17784ccfa630d9a588d4b852abef8bc467642427c8cfHarald Welte	    { TC_CHECK_PACKET, ENOSYS,
17794ccfa630d9a588d4b852abef8bc467642427c8cfHarald Welte	      "Checking will most likely never get implemented" },
1780e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    /* ENOENT for DELETE probably means no matching rule */
178179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_DELETE_ENTRY, ENOENT,
1782c8264991454b5e77279830736f80ea3153b6f814Marc Boucher	      "Bad rule (does a matching rule exist in that chain?)" },
178379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_SET_POLICY, ENOENT,
1784c8264991454b5e77279830736f80ea3153b6f814Marc Boucher	      "Bad built-in chain name" },
178579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_SET_POLICY, EINVAL,
1786c8264991454b5e77279830736f80ea3153b6f814Marc Boucher	      "Bad policy name" },
17874ccfa630d9a588d4b852abef8bc467642427c8cfHarald Welte
17884ccfa630d9a588d4b852abef8bc467642427c8cfHarald Welte	    { NULL, 0, "Incompatible with this kernel" },
17894ccfa630d9a588d4b852abef8bc467642427c8cfHarald Welte	    { NULL, ENOPROTOOPT, "iptables who? (do you need to insmod?)" },
17904ccfa630d9a588d4b852abef8bc467642427c8cfHarald Welte	    { NULL, ENOSYS, "Will be implemented real soon.  I promise ;)" },
17914ccfa630d9a588d4b852abef8bc467642427c8cfHarald Welte	    { NULL, ENOMEM, "Memory allocation problem" },
17924ccfa630d9a588d4b852abef8bc467642427c8cfHarald Welte	    { NULL, ENOENT, "No chain/target/match by that name" },
1793e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	  };
1794e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1795e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	for (i = 0; i < sizeof(table)/sizeof(struct table_struct); i++) {
1796e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if ((!table[i].fn || table[i].fn == iptc_fn)
1797e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		    && table[i].err == err)
1798e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			return table[i].message;
1799e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1800e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1801e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return strerror(err);
1802e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1803